Skip to content

Commit a26d531

Browse files
authored
tui: allow full-session forks from the session dialog (#23339)
1 parent 5eaef6b commit a26d531

2 files changed

Lines changed: 20 additions & 8 deletions

File tree

packages/opencode/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import type { TextPart } from "@opencode-ai/sdk/v2"
55
import { Locale } from "@/util"
66
import { useSDK } from "@tui/context/sdk"
77
import { useRoute } from "@tui/context/route"
8-
import { useDialog } from "../../ui/dialog"
8+
import { useDialog, type DialogContext } from "../../ui/dialog"
99
import type { PromptInfo } from "@tui/component/prompt/history"
1010
import { strip } from "@tui/component/prompt/part"
1111

12-
export function DialogForkFromTimeline(props: { sessionID: string; onMove: (messageID: string) => void }) {
12+
export function DialogForkFromTimeline(props: { sessionID: string; onMove: (messageID?: string) => void }) {
1313
const sync = useSync()
1414
const dialog = useDialog()
1515
const sdk = useSDK()
@@ -19,9 +19,21 @@ export function DialogForkFromTimeline(props: { sessionID: string; onMove: (mess
1919
dialog.setSize("large")
2020
})
2121

22-
const options = createMemo((): DialogSelectOption<string>[] => {
22+
const options = createMemo((): DialogSelectOption<string | undefined>[] => {
2323
const messages = sync.data.message[props.sessionID] ?? []
24-
const result = [] as DialogSelectOption<string>[]
24+
const fullSession = {
25+
title: "Full session",
26+
value: undefined,
27+
onSelect: async (dialog: DialogContext) => {
28+
const forked = await sdk.client.session.fork({ sessionID: props.sessionID })
29+
route.navigate({
30+
sessionID: forked.data!.id,
31+
type: "session",
32+
})
33+
dialog.clear()
34+
},
35+
} satisfies DialogSelectOption<string | undefined>
36+
const result = [] as DialogSelectOption<string | undefined>[]
2537
for (const message of messages) {
2638
if (message.role !== "user") continue
2739
const part = (sync.data.part[message.id] ?? []).find(
@@ -57,9 +69,8 @@ export function DialogForkFromTimeline(props: { sessionID: string; onMove: (mess
5769
},
5870
})
5971
}
60-
result.reverse()
61-
return result
72+
return [fullSession, ...result.reverse()]
6273
})
6374

64-
return <DialogSelect onMove={(option) => props.onMove(option.value)} title="Fork from message" options={options()} />
75+
return <DialogSelect onMove={(option) => props.onMove(option.value)} title="Fork session" options={options()} />
6576
}

packages/opencode/src/cli/cmd/tui/routes/session/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ export function Session() {
451451
},
452452
},
453453
{
454-
title: "Fork from message",
454+
title: "Fork session",
455455
value: "session.fork",
456456
keybind: "session_fork",
457457
category: "Session",
@@ -462,6 +462,7 @@ export function Session() {
462462
dialog.replace(() => (
463463
<DialogForkFromTimeline
464464
onMove={(messageID) => {
465+
if (!messageID) return
465466
const child = scroll.getChildren().find((child) => {
466467
return child.id === messageID
467468
})

0 commit comments

Comments
 (0)