diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 13c95d9b9ea..3756a459920 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -19,6 +19,7 @@ import { DialogHelp } from "./ui/dialog-help" import { CommandProvider, useCommandDialog } from "@tui/component/dialog-command" import { DialogAgent } from "@tui/component/dialog-agent" import { DialogSessionList } from "@tui/component/dialog-session-list" +import { DialogChildSessionList } from "@tui/component/dialog-child-session-list" import { KeybindProvider } from "@tui/context/keybind" import { ThemeProvider, useTheme } from "@tui/context/theme" import { Home } from "@tui/routes/home" @@ -297,6 +298,15 @@ function App() { dialog.clear() }, }, + { + title: "List subagent sessions", + value: "session.child.list", + keybind: "session_child_list", + category: "Session", + onSelect: () => { + dialog.replace(() => ) + }, + }, { title: "Switch model", value: "model.list", diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-child-session-list.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-child-session-list.tsx new file mode 100644 index 00000000000..2070cbfc364 --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-child-session-list.tsx @@ -0,0 +1,57 @@ +import { useDialog } from "@tui/ui/dialog" +import { DialogSelect } from "@tui/ui/dialog-select" +import { useRoute } from "@tui/context/route" +import { useSync } from "@tui/context/sync" +import { createMemo, onMount } from "solid-js" +import { Locale } from "@/util/locale" + +export function DialogChildSessionList() { + const dialog = useDialog() + const sync = useSync() + const route = useRoute() + + const currentSessionID = createMemo(() => (route.data.type === "session" ? route.data.sessionID : undefined)) + const currentSession = createMemo(() => sync.session.get(currentSessionID()!)) + + const options = createMemo(() => { + const current = currentSession() + if (!current) return [] + + const parentID = current.parentID ?? current.id + + const allSessions = sync.data.session + .filter((x) => x.id === parentID || x.parentID === parentID) + .toSorted((b, a) => a.id.localeCompare(b.id)) + + return allSessions.map((x) => { + const isParent = x.id === parentID + const label = isParent ? "Main" : "Subagent" + + return { + title: `${x.title}`, + value: x.id, + category: label, + footer: Locale.time(x.time.updated), + } + }) + }) + + onMount(() => { + dialog.setSize("large") + }) + + return ( + { + route.navigate({ + type: "session", + sessionID: option.value, + }) + dialog.clear() + }} + /> + ) +} diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index cef083ad734..a8be4ec5861 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -314,6 +314,11 @@ export function Autocomplete(props: { description: "list sessions", onSelect: () => command.trigger("session.list"), }, + { + display: "/subagent-sessions", + description: "list subagent sessions", + onSelect: () => command.trigger("session.child.list"), + }, { display: "/status", description: "show status", 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 818b96da43b..ab63d5f3b6d 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -1676,7 +1676,16 @@ ToolRegistry.register({ {keybind.print("session_child_cycle")}, {keybind.print("session_child_cycle_reverse")} - to navigate between subagent sessions + to navigate subagent sessions + + {(key) => ( + <> + {" "} + {key()} + to list subagent sessions + + )} + ) diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index ba9d1973025..4a70e8fc7ae 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -563,6 +563,7 @@ export namespace Config { history_next: z.string().optional().default("down").describe("Next history item"), session_child_cycle: z.string().optional().default("right").describe("Next child session"), session_child_cycle_reverse: z.string().optional().default("left").describe("Previous child session"), + session_child_list: z.string().optional().default("none").describe("List subagent sessions"), session_parent: z.string().optional().default("up").describe("Go to parent session"), terminal_suspend: z.string().optional().default("ctrl+z").describe("Suspend terminal"), terminal_title_toggle: z.string().optional().default("none").describe("Toggle terminal title"), diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 06993d3f930..32d399cdb51 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -954,6 +954,10 @@ export type KeybindsConfig = { * Previous child session */ session_child_cycle_reverse?: string + /** + * List subagent sessions + */ + session_child_list?: string /** * Suspend terminal */ diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 0a31394ed9c..29520c68fc0 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -1133,6 +1133,10 @@ export type KeybindsConfig = { * Previous child session */ session_child_cycle_reverse?: string + /** + * List subagent sessions + */ + session_child_list?: string /** * Go to parent session */ diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index 96ba0720c73..8102b929465 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -7664,6 +7664,11 @@ "default": "left", "type": "string" }, + "session_child_list": { + "description": "List subagent sessions", + "default": "none", + "type": "string" + }, "session_parent": { "description": "Go to parent session", "default": "up",