| 1 | import { t } from "./i18n"; |
| 2 | import type { TabMeta } from "./types"; |
| 3 | |
| 4 | export interface ForkWorktreeResultView { |
| 5 | tab: TabMeta; |
| 6 | isolated: boolean; |
| 7 | fallbackToShared?: boolean; |
| 8 | sourceDirty?: boolean; |
| 9 | branch?: string; |
| 10 | } |
| 11 | |
| 12 | export interface ForkBindings { |
| 13 | ForkForTab(tabID: string, turn: number): Promise<TabMeta>; |
| 14 | ForkWorktreeForTab(tabID: string, turn: number): Promise<ForkWorktreeResultView>; |
| 15 | } |
| 16 | |
| 17 | type Notice = (tabId: string, level: "info" | "warn", text: string) => void; |
| 18 | |
| 19 | export async function forkConversationForTab(bindings: ForkBindings, sourceTabId: string, turn: number, isolated: boolean, notice: Notice): Promise<TabMeta | undefined> { |
| 20 | if (!isolated) return bindings.ForkForTab(sourceTabId, turn); |
| 21 | const result = await bindings.ForkWorktreeForTab(sourceTabId, turn); |
| 22 | if (result.sourceDirty) { |
| 23 | notice(sourceTabId, "warn", t("rewind.forkWorktreeDirtySource")); |
| 24 | return undefined; |
| 25 | } |
| 26 | if (result.fallbackToShared && result.tab?.id) { |
| 27 | notice(result.tab.id, "info", t("rewind.forkWorktreeFallbackNotice")); |
| 28 | } |
| 29 | return result.tab; |
| 30 | } |
| 31 | |
| 32 | export async function settleForkConversationForTab( |
| 33 | bindings: ForkBindings, |
| 34 | sourceTabId: string, |
| 35 | turn: number, |
| 36 | isolated: boolean, |
| 37 | notice: Notice, |
| 38 | adopt: (tab: TabMeta) => Promise<unknown>, |
| 39 | sync: () => Promise<unknown>, |
| 40 | ): Promise<{ ok: boolean; tabId?: string; tab?: TabMeta }> { |
| 41 | const tab = await forkConversationForTab(bindings, sourceTabId, turn, isolated, notice); |
| 42 | if (!tab?.id) { |
| 43 | await sync(); |
| 44 | return { ok: false }; |
| 45 | } |
| 46 | await adopt(tab); |
| 47 | return { ok: true, tabId: tab.id, tab }; |
| 48 | } |
| 49 |