summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDax <[email protected]>2026-04-18 16:20:23 -0400
committerGitHub <[email protected]>2026-04-18 20:20:23 +0000
commita26d53151b11151a5580f11790b768ac334fa6a8 (patch)
treef34ace57bd1b367b0e8a7b395ba1034181465584
parent5eaef6b758cbfb683deadb8d440a420c3c1ee1f8 (diff)
downloadopencode-a26d53151b11151a5580f11790b768ac334fa6a8.tar.gz
opencode-a26d53151b11151a5580f11790b768ac334fa6a8.zip
tui: allow full-session forks from the session dialog (#23339)
-rw-r--r--packages/opencode/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx25
-rw-r--r--packages/opencode/src/cli/cmd/tui/routes/session/index.tsx3
2 files changed, 20 insertions, 8 deletions
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx
index 8d1e4438c..7414cefd3 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx
@@ -5,11 +5,11 @@ import type { TextPart } from "@opencode-ai/sdk/v2"
import { Locale } from "@/util"
import { useSDK } from "@tui/context/sdk"
import { useRoute } from "@tui/context/route"
-import { useDialog } from "../../ui/dialog"
+import { useDialog, type DialogContext } from "../../ui/dialog"
import type { PromptInfo } from "@tui/component/prompt/history"
import { strip } from "@tui/component/prompt/part"
-export function DialogForkFromTimeline(props: { sessionID: string; onMove: (messageID: string) => void }) {
+export function DialogForkFromTimeline(props: { sessionID: string; onMove: (messageID?: string) => void }) {
const sync = useSync()
const dialog = useDialog()
const sdk = useSDK()
@@ -19,9 +19,21 @@ export function DialogForkFromTimeline(props: { sessionID: string; onMove: (mess
dialog.setSize("large")
})
- const options = createMemo((): DialogSelectOption<string>[] => {
+ const options = createMemo((): DialogSelectOption<string | undefined>[] => {
const messages = sync.data.message[props.sessionID] ?? []
- const result = [] as DialogSelectOption<string>[]
+ const fullSession = {
+ title: "Full session",
+ value: undefined,
+ onSelect: async (dialog: DialogContext) => {
+ const forked = await sdk.client.session.fork({ sessionID: props.sessionID })
+ route.navigate({
+ sessionID: forked.data!.id,
+ type: "session",
+ })
+ dialog.clear()
+ },
+ } satisfies DialogSelectOption<string | undefined>
+ const result = [] as DialogSelectOption<string | undefined>[]
for (const message of messages) {
if (message.role !== "user") continue
const part = (sync.data.part[message.id] ?? []).find(
@@ -57,9 +69,8 @@ export function DialogForkFromTimeline(props: { sessionID: string; onMove: (mess
},
})
}
- result.reverse()
- return result
+ return [fullSession, ...result.reverse()]
})
- return <DialogSelect onMove={(option) => props.onMove(option.value)} title="Fork from message" options={options()} />
+ return <DialogSelect onMove={(option) => props.onMove(option.value)} title="Fork session" options={options()} />
}
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 ccca4d1eb..06be5dfbe 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx
@@ -451,7 +451,7 @@ export function Session() {
},
},
{
- title: "Fork from message",
+ title: "Fork session",
value: "session.fork",
keybind: "session_fork",
category: "Session",
@@ -462,6 +462,7 @@ export function Session() {
dialog.replace(() => (
<DialogForkFromTimeline
onMove={(messageID) => {
+ if (!messageID) return
const child = scroll.getChildren().find((child) => {
return child.id === messageID
})