From 80cbafa3c3aee0f2bea5adeb6ab37ed415408ba4 Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Thu, 21 May 2026 17:45:13 +0530 Subject: [PATCH] refactor(tui): dispatch editable slash commands --- .../cli/cmd/tui/component/prompt/index.tsx | 25 +++++++++++-------- .../src/cli/cmd/tui/routes/session/index.tsx | 18 +++++++++++-- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 05caf1482b..4461c3a893 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -59,7 +59,14 @@ import { DialogWorkspaceUnavailable } from "../dialog-workspace-unavailable" import { useArgs } from "@tui/context/args" import { Flag } from "@opencode-ai/core/flag/flag" import { type WorkspaceStatus } from "../workspace-label" -import { OPENCODE_BASE_MODE, useBindings, useCommandShortcut, useLeaderActive, useOpencodeKeymap } from "../../keymap" +import { + OPENCODE_BASE_MODE, + useBindings, + useCommandShortcut, + useCommandSlashes, + useLeaderActive, + useOpencodeKeymap, +} from "../../keymap" import { useTuiConfig } from "../../context/tui-config" export type PromptProps = { @@ -151,6 +158,7 @@ export function Prompt(props: PromptProps) { const history = usePromptHistory() const stash = usePromptStash() const keymap = useOpencodeKeymap() + const slashCommands = useCommandSlashes() const agentShortcut = useCommandShortcut("agent.cycle") const paletteShortcut = useCommandShortcut("command.palette.show") const renderer = useRenderer() @@ -1145,15 +1153,8 @@ export function Prompt(props: PromptProps) { command: inputText, }) setStore("mode", "normal") - } else if (slash && (slash.name === "compact" || slash.name === "summarize")) { - const instructions = slash.arguments.trim() - const payload = { - sessionID, - modelID: selectedModel.modelID, - providerID: selectedModel.providerID, - ...(instructions ? { $body_instructions: instructions } : {}), - } satisfies Parameters[0] & { $body_instructions?: string } - void sdk.client.session.summarize(payload) + } else if (slash && slashCommand(slash.name)?.input) { + slashCommand(slash.name)?.onSelect() } else if (slash && sync.data.command.some((x) => x.name === slash.name)) { void sdk.client.session.command({ sessionID, @@ -1229,6 +1230,10 @@ export function Prompt(props: PromptProps) { arguments: firstLineArgs.join(" ") + (restOfInput ? "\n" + restOfInput : ""), } } + + function slashCommand(name: string) { + return slashCommands().find((item) => item.name === name || item.aliases?.includes(`/${name}`)) + } const exit = useExit() function pasteText(text: string, virtualText: string) { diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 857e9c0868..260bd5fe1b 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -314,6 +314,17 @@ export function Session() { const dialog = useDialog() const renderer = useRenderer() + function slashArguments(name: string) { + const input = prompt?.current.input + if (!input?.startsWith("/")) return + const firstLineEnd = input.indexOf("\n") + const firstLine = firstLineEnd === -1 ? input : input.slice(0, firstLineEnd) + const [command, ...firstLineArgs] = firstLine.split(" ") + if (command !== `/${name}`) return + const restOfInput = firstLineEnd === -1 ? "" : input.slice(firstLineEnd + 1) + return firstLineArgs.join(" ") + (restOfInput ? "\n" + restOfInput : "") + } + event.on("session.status", (evt) => { if (evt.properties.sessionID !== route.sessionID) return if (evt.properties.status.type !== "retry") return @@ -558,11 +569,14 @@ export function Session() { }) return } - void sdk.client.session.summarize({ + const instructions = slashArguments("compact") ?? slashArguments("summarize") + const payload = { sessionID: route.sessionID, modelID: selectedModel.modelID, providerID: selectedModel.providerID, - }) + ...(instructions?.trim() ? { $body_instructions: instructions.trim() } : {}), + } satisfies Parameters[0] & { $body_instructions?: string } + void sdk.client.session.summarize(payload) dialog.clear() }, },