返回 DeepSeek-Reasonix
worktreeMergeLifecycle.ts
根目录 / desktop / frontend / src / lib / worktreeMergeLifecycle.ts
1 import type {
2 CloseMergedWorktreeTabRequest,
3 CloseMergedWorktreeTabResult,
4 TabMeta,
5 WorktreeCleanupRequest,
6 WorktreeCleanupResult,
7 WorktreeMergeResult,
8 } from "./types";
9
10 export interface WorktreeMergeLifecycleDeps {
11 ensureSource(sourceRoot: string): Promise<TabMeta>;
12 isNavigationCurrent(): boolean;
13 seedSource(tab: TabMeta): void;
14 listTabs(): Promise<TabMeta[]>;
15 closeWorktree(request: CloseMergedWorktreeTabRequest): Promise<CloseMergedWorktreeTabResult>;
16 finalize(request: WorktreeCleanupRequest): Promise<WorktreeCleanupResult>;
17 onNavigationPreserved(): void;
18 onCloseBlocked(): void;
19 }
20
21 export type WorktreeMergeLifecycleResult =
22 | { phase: "preserved" }
23 | { phase: "close-blocked" }
24 | { phase: "finalized"; cleanup: WorktreeCleanupResult };
25
26 export async function runWorktreeMergeLifecycle(
27 receipt: WorktreeMergeResult,
28 worktreeTabId: string,
29 navigationIntentToken: string,
30 deps: WorktreeMergeLifecycleDeps,
31 ): Promise<WorktreeMergeLifecycleResult> {
32 if (!receipt.sourceRoot || !receipt.worktreeRoot || !receipt.targetBranch || !receipt.mergedCommit || !receipt.worktreeBranch || !receipt.worktreeHead) {
33 throw new Error(receipt.error || "invalid merge receipt");
34 }
35 const preserveIfStale = (): boolean => {
36 if (deps.isNavigationCurrent()) return false;
37 deps.onNavigationPreserved();
38 return true;
39 };
40
41 const sourceTab = await deps.ensureSource(receipt.sourceRoot);
42 if (preserveIfStale()) return { phase: "preserved" };
43 deps.seedSource(sourceTab);
44
45 await deps.listTabs();
46 if (preserveIfStale()) return { phase: "preserved" };
47 const closed = await deps.closeWorktree({
48 tabId: worktreeTabId,
49 worktreeRoot: receipt.worktreeRoot,
50 sourceTabId: sourceTab.id,
51 sourceRoot: receipt.sourceRoot,
52 navigationIntentToken,
53 });
54 if (!closed.closed) {
55 deps.onCloseBlocked();
56 return { phase: "close-blocked" };
57 }
58 if (preserveIfStale()) return { phase: "preserved" };
59
60 const cleanup = await deps.finalize({
61 worktreeRoot: receipt.worktreeRoot,
62 sourceRoot: receipt.sourceRoot,
63 targetBranch: receipt.targetBranch,
64 mergedCommit: receipt.mergedCommit,
65 worktreeBranch: receipt.worktreeBranch,
66 worktreeHead: receipt.worktreeHead,
67 });
68 return { phase: "finalized", cleanup };
69 }
70
70 lines TYPESCRIPT