From 93a93450c227d3139d2c91db50dfdac18a67a9b4 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Fri, 10 Jul 2026 16:24:02 -0700 Subject: [PATCH] fix(FUX-015): address slash-command review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Greptile/CodeRabbit review of the chat slash-command framework: - Composer-wipe race: ChatView and TaskPlannerChatTab cleared the composer inside the command's success callback, silently wiping any text the user typed while the command was in flight. Clear on submit (before the network round-trip) instead — consistent with normal chat send, which also clears immediately and does not restore on failure. - Attachments were silently dropped when dispatching a slash command in ChatView (clearing the composer revokes staged attachment URLs). Block dispatch with a warning toast when attachments are staged. - CHAT_COMMANDS is now a readonly array; helper signatures accept readonly ChatCommand[]. - The planner command menu (commands-only) used skill-menu aria-label/empty copy; use command-specific copy instead. Add regression tests: in-flight text survives command success, composer clears on submit even on failure, attachment dispatch is blocked, and the planner command menu uses command-specific accessible copy. Co-Authored-By: Claude Opus 4.8 --- .../dashboard/app/components/ChatView.tsx | 19 +++++- .../app/components/TaskPlannerChatTab.tsx | 10 ++- .../__tests__/ChatView.chat-commands.test.tsx | 61 ++++++++++++++++++- .../__tests__/TaskPlannerChatTab.test.tsx | 38 ++++++++++++ .../dashboard/app/components/chat-commands.ts | 8 +-- 5 files changed, 127 insertions(+), 9 deletions(-) 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) => (