返回 DeepSeek-Reasonix
sessionLifecycleFences.ts
根目录 / desktop / frontend / src / lib / sessionLifecycleFences.ts
1 import type { ProjectNode } from "./types";
2 import { projectSessionKeys } from "./projectSessionIdentity";
3
4 type Fence = { generation: number; operationId: string; aliases: readonly string[] };
5
6 /** Application-owned: remounting the sidebar cannot revive a committed archive.
7 * An active directory row with a newer lifecycle proves explicit restoration.
8 * Runtime revisions cannot establish that proof and never release this fence.
9 */
10 export function createSessionLifecycleFences() {
11 const fences = new Map<string, Fence>();
12 return {
13 archive(node: ProjectNode, receipt: { lifecycleGeneration: number; operationId: string; identityAliases?: string[] }) {
14 const aliases = [...new Set([...projectSessionKeys(node), ...(receipt.identityAliases ?? [])])];
15 const fence = { generation: receipt.lifecycleGeneration, operationId: receipt.operationId, aliases };
16 for (const key of aliases) {
17 if ((fences.get(key)?.generation ?? -1) <= fence.generation) fences.set(key, fence);
18 }
19 },
20 observeDirectory(nodes: readonly ProjectNode[]) {
21 const visit = (node: ProjectNode) => {
22 for (const key of projectSessionKeys(node)) {
23 const fence = fences.get(key);
24 if (fence && !node.runtimeOnly && (node.lifecycleGeneration ?? 0) > fence.generation) {
25 for (const alias of fence.aliases) if (fences.get(alias) === fence) fences.delete(alias);
26 }
27 }
28 node.children?.forEach(visit);
29 };
30 nodes.forEach(visit);
31 },
32 keys(): ReadonlySet<string> { return new Set(fences.keys()); },
33 };
34 }
35
36 export const sessionLifecycleFences = createSessionLifecycleFences();
37
37 lines TYPESCRIPT