From 3d80e36549d89934f48ba7347565ae1d4156e71c Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 23 Sep 2025 00:31:02 -0400 Subject: [PATCH] tui: refactor command system and add session management commands --- .../cli/cmd/tui/component/dialog-command.tsx | 13 +++++- .../src/cli/cmd/tui/component/prompt.tsx | 46 ++++--------------- packages/opencode/src/cli/cmd/tui/session.tsx | 25 ++++++++++ packages/opencode/src/cli/cmd/tui/tui.tsx | 8 ++-- .../src/cli/cmd/tui/ui/dialog-select.tsx | 4 +- 5 files changed, 51 insertions(+), 45 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx index 97bf4ea1b..987f51571 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx @@ -16,16 +16,25 @@ const ctx = createContext() function init() { const [registrations, setRegistrations] = createSignal[]>([]) + const dialog = useDialog() const options = createMemo(() => { return registrations().flatMap((x) => x()) }) return { + trigger(name: string) { + for (const option of options()) { + if (option.value === name) { + option.onSelect?.(dialog) + return + } + } + }, register(cb: () => DialogSelectOption[]) { const results = createMemo(cb) - setRegistrations((x) => [...x, results]) + setRegistrations((arr) => [results, ...arr]) onCleanup(() => { - setRegistrations((x) => x.filter((x) => x !== results)) + setRegistrations((arr) => arr.filter((x) => x !== results)) }) }, get options() { diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt.tsx index 6f41df2ad..3d91027b3 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt.tsx @@ -14,6 +14,7 @@ import type { FilePart } from "@opencode-ai/sdk" import fuzzysort from "fuzzysort" import { DialogModel } from "./dialog-model" import { DialogAgent } from "./dialog-agent" +import { useCommandDialog } from "./dialog-command" export type PromptProps = { sessionID?: string @@ -254,6 +255,7 @@ function Autocomplete(props: { const sdk = useSDK() const local = useLocal() const sync = useSync() + const command = useCommandDialog() const [store, setStore] = createStore({ index: 0, @@ -310,12 +312,10 @@ function Autocomplete(props: { }, ) - const route = useRoute() const session = createMemo(() => (props.sessionID ? sync.session.get(props.sessionID) : undefined)) const commands = createMemo((): AutocompleteOption[] => { const results: AutocompleteOption[] = [] const s = session() - const dialog = useDialog() for (const command of sync.data.command) { results.push({ display: "/" + command.name, @@ -341,41 +341,19 @@ function Autocomplete(props: { { display: "/compact", description: "compact the session", - onSelect: () => { - sdk.session.summarize({ - path: { - id: s.id, - }, - body: { - modelID: local.model.current().modelID, - providerID: local.model.current().providerID, - }, - }) - }, + onSelect: () => command.trigger("session.compact"), }, { display: "/share", disabled: !!s.share?.url, description: "share a session", - onSelect: () => { - sdk.session.share({ - path: { - id: s.id, - }, - }) - }, + onSelect: () => command.trigger("session.share"), }, { display: "/unshare", disabled: !s.share, description: "unshare a session", - onSelect: () => { - sdk.session.unshare({ - path: { - id: s.id, - }, - }) - }, + onSelect: () => command.trigger("session.unshare"), }, ) } @@ -383,25 +361,17 @@ function Autocomplete(props: { { display: "/new", description: "create a new session", - onSelect: () => { - route.navigate({ - type: "home", - }) - }, + onSelect: () => command.trigger("session.new"), }, { display: "/models", description: "list models", - onSelect: () => { - dialog.replace(() => ) - }, + onSelect: () => command.trigger("model.list"), }, { display: "/agents", description: "list agents", - onSelect: () => { - dialog.replace(() => ) - }, + onSelect: () => command.trigger("agent.list"), }, ) const max = firstBy(results, [(x) => x.display.length, "desc"])?.display.length diff --git a/packages/opencode/src/cli/cmd/tui/session.tsx b/packages/opencode/src/cli/cmd/tui/session.tsx index c001b8c37..f9ac8ebba 100644 --- a/packages/opencode/src/cli/cmd/tui/session.tsx +++ b/packages/opencode/src/cli/cmd/tui/session.tsx @@ -49,8 +49,27 @@ export function Session() { }) }) + const local = useLocal() + const command = useCommandDialog() command.register(() => [ + { + title: "Compact session", + value: "session.compact", + category: "Session", + onSelect: (dialog) => { + sdk.session.summarize({ + path: { + id: route.sessionID, + }, + body: { + modelID: local.model.current().modelID, + providerID: local.model.current().providerID, + }, + }) + dialog.clear() + }, + }, { title: "Share session", value: "session.share", @@ -79,6 +98,12 @@ export function Session() { dialog.clear() }, }, + { + title: "Rename session", + value: "session.rename", + category: "Session", + onSelect: () => {}, + }, ]) return ( diff --git a/packages/opencode/src/cli/cmd/tui/tui.tsx b/packages/opencode/src/cli/cmd/tui/tui.tsx index 054422fe7..2e7aec0de 100644 --- a/packages/opencode/src/cli/cmd/tui/tui.tsx +++ b/packages/opencode/src/cli/cmd/tui/tui.tsx @@ -137,7 +137,7 @@ function App() { command.register(() => [ { title: "Switch session", - value: "switch-session", + value: "session.list", category: "Session", onSelect: () => { dialog.replace(() => ) @@ -145,7 +145,7 @@ function App() { }, { title: "New session", - value: "new-session", + value: "session.new", category: "Session", onSelect: () => { route.navigate({ @@ -156,7 +156,7 @@ function App() { }, { title: "Switch model", - value: "switch-model", + value: "model.list", category: "Agent", onSelect: () => { dialog.replace(() => ) @@ -164,7 +164,7 @@ function App() { }, { title: "Switch agent", - value: "switch-agent", + value: "agent.list", category: "Agent", onSelect: () => { dialog.replace(() => ) diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx index 7cc76f9af..f819ac6b8 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx @@ -155,7 +155,8 @@ export function DialogSelect(props: DialogSelectProps) { )} - + + {/* n @@ -164,6 +165,7 @@ export function DialogSelect(props: DialogSelectProps) { {" "}r rename + */} )