diff --git a/packages/dashboard/app/components/ChatView.tsx b/packages/dashboard/app/components/ChatView.tsx index 529f1daaf5..d7836b900a 100644 --- a/packages/dashboard/app/components/ChatView.tsx +++ b/packages/dashboard/app/components/ChatView.tsx @@ -1526,6 +1526,23 @@ export function ChatView({ projectId, addToast, floating = false, compactLayout return; } + /* + FNXC:ChatSlashCommands 2026-07-10-11:40: + Slash commands carry no attachments. Block dispatch (rather than silently dropping) when files are staged, since clearing the composer below revokes their object URLs before they could ever be sent. + */ + if (files.length > 0) { + addToast( + t("chat.commandNoAttachments", "Attachments aren't supported with commands — remove them before sending"), + "warning", + ); + return; + } + + /* + FNXC:ChatSlashCommands 2026-07-10-11:40: + Clear the composer immediately on submit — BEFORE the network round-trip — not inside the success callback. Clearing late wipes any text the user typed while the command was in flight (composer-wipe race, FUX-015). + */ + clearComposerState(); void commandMatch.command .run({ taskId: chatCommandContext.taskId, @@ -1533,7 +1550,6 @@ export function ChatView({ projectId, addToast, floating = false, compactLayout remainder: commandMatch.remainder, }) .then(() => { - clearComposerState(); addToast(t("chat.commandSteerSuccess", "Sent to the running agent"), "success"); }) .catch((error: unknown) => { @@ -2534,6 +2550,7 @@ export function ChatView({ projectId, addToast, floating = false, compactLayout {filteredCommands.length === 0 ? ( -
{t("chat.noSkillsFound", "No skills found")}
+
{t("chat.noCommandsFound", "No commands found")}
) : ( filteredCommands.map((command, index) => (