diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 4f7c94b1d39c..eb2262dc2ec7 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -356,6 +356,27 @@ function App() { ), ) + // moveGlobal cycles through top-level sessions sorted by most recently updated. + function moveGlobal(direction: number) { + const topLevel = sync.data.session + .filter((x) => !x.parentID) + .toSorted((a, b) => (b.time.updated ?? b.time.created) - (a.time.updated ?? a.time.created)) + + if (topLevel.length <= 1) return + + const currentID = route.data.type === "session" ? route.data.sessionID : undefined + let idx = currentID ? topLevel.findIndex((x) => x.id === currentID) : -1 + + let next = idx + direction + if (next >= topLevel.length) next = 0 + if (next < 0) next = topLevel.length - 1 + + route.navigate({ + type: "session", + sessionID: topLevel[next].id, + }) + } + const connected = useConnected() command.register(() => [ { @@ -412,6 +433,26 @@ function App() { dialog.clear() }, }, + { + title: "Next session", + value: "session.global.next", + keybind: "session_global_cycle", + category: "Session", + onSelect: (dialog) => { + moveGlobal(1) + dialog.clear() + }, + }, + { + title: "Previous session", + value: "session.global.previous", + keybind: "session_global_cycle_reverse", + category: "Session", + onSelect: (dialog) => { + moveGlobal(-1) + dialog.clear() + }, + }, { title: "Switch model", value: "model.list", diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 2b8aa9e03010..0aee01f42655 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -923,6 +923,16 @@ export namespace Config { session_child_first: z.string().optional().default("down").describe("Go to first child session"), session_child_cycle: z.string().optional().default("right").describe("Go to next child session"), session_child_cycle_reverse: z.string().optional().default("left").describe("Go to previous child session"), + session_global_cycle: z + .string() + .optional() + .default("right") + .describe("Go to next session (sorted by recent)"), + session_global_cycle_reverse: z + .string() + .optional() + .default("left") + .describe("Go to previous session (sorted by recent)"), 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"),