返回 DeepSeek-Reasonix
sessionCatalogBridge.ts
根目录 / desktop / frontend / src / lib / sessionCatalogBridge.ts
1 import { asArray } from "./array";
2 import { desktopHost } from "./desktopHost";
3 import { mockProjectGroups } from "./mockProjectTreeOrganization";
4 import type {
5 ProjectNode,
6 ProjectTopicKey,
7 ProjectTopicPage,
8 ProjectTopicPageRequest,
9 ProjectTreeChangedV2,
10 SessionCatalogBindings,
11 } from "./types";
12
13 export function onProjectTreeChangedV2(cb: (event: ProjectTreeChangedV2) => void): () => void {
14 const host = desktopHost();
15 if (host.kind !== "none") {
16 return host.events.on("project-tree:changed-v2", (payload?: unknown) => {
17 if (!payload || typeof payload !== "object") return;
18 const event = payload as Partial<ProjectTreeChangedV2>;
19 cb({
20 revision: typeof event.revision === "number" ? event.revision : 0,
21 roots: asArray(event.roots).filter((root): root is string => typeof root === "string"),
22 reason: typeof event.reason === "string" ? event.reason : "changed",
23 });
24 });
25 }
26 return () => {};
27 }
28
29 export function makeMockSessionCatalogBindings(cloneProjectTree: () => ProjectNode[]): SessionCatalogBindings {
30 const listProjectTopics = async (req: ProjectTopicPageRequest): Promise<ProjectTopicPage> => {
31 const folder = req.scope === "global"
32 ? cloneProjectTree().find((item) => item.kind === "global_folder")
33 : cloneProjectTree().find((item) => item.kind === "project" && item.root === req.workspaceRoot);
34 const query = (req.query ?? "").trim().toLocaleLowerCase();
35 const created = req.sortMode === "created";
36 const groups = mockProjectGroups(req.scope, req.workspaceRoot ?? "");
37 const grouped = new Set(groups.flatMap((group) => group.topicIds ?? []));
38 const selectedGroup = groups.find((group) => group.id === req.groupId);
39 const all = asArray(folder?.children)
40 .filter((item) => !query || item.label.toLocaleLowerCase().includes(query))
41 .filter((item) => !req.excludePinned || !item.pinned)
42 .filter((item) => req.groupFilter !== "ungrouped" || !grouped.has(item.topicId ?? ""))
43 .filter((item) => req.groupFilter !== "group" || Boolean(selectedGroup?.topicIds?.includes(item.topicId ?? "")))
44 .sort((left, right) => Number(Boolean(right.pinned)) - Number(Boolean(left.pinned))
45 || (created ? right.createdAt || right.lastActivityAt || 0 : right.lastActivityAt || right.createdAt || 0)
46 - (created ? left.createdAt || left.lastActivityAt || 0 : left.lastActivityAt || left.createdAt || 0)
47 || (left.topicId ?? "").localeCompare(right.topicId ?? ""));
48 const start = Math.max(0, Number.parseInt(req.cursor ?? "0", 10) || 0);
49 const limit = Math.min(200, Math.max(1, req.limit ?? 50));
50 const items = all.slice(start, start + limit);
51 return {
52 items,
53 nextCursor: start + items.length < all.length ? String(start + items.length) : undefined,
54 revision: 1,
55 complete: true,
56 readyDirectories: 1,
57 pendingDirectories: 0,
58 failedDirectories: 0,
59 };
60 };
61 return {
62 async GetProjectTreeSnapshot() {
63 return {
64 revision: 1,
65 projects: cloneProjectTree().map((project) => ({
66 ...project,
67 children: asArray(project.children).filter((topic) => Boolean(topic.pinned)),
68 })),
69 catalog: { state: "ready", mode: "memory", revision: 1, indexed: 4, total: 4, repairPending: 0, sourceCount: 4, unindexedTargetCount: 0, canRebuild: false },
70 indexed: 4,
71 total: 4,
72 indexingDone: true,
73 };
74 },
75 ListProjectTopics: listProjectTopics,
76 async GetTopicSummary(key: ProjectTopicKey) {
77 const page = await listProjectTopics({ scope: key.scope, workspaceRoot: key.workspaceRoot, limit: 200 });
78 return page.items.find((item) => item.topicId === key.topicId)
79 ?? { key: "", kind: key.scope === "global" ? "global_topic" : "topic", label: "", children: [] };
80 },
81 async GetSessionCatalogStatus() {
82 return { state: "ready", mode: "memory", revision: 1, indexed: 4, total: 4, repairPending: 0, sourceCount: 4, unindexedTargetCount: 0, canRebuild: false };
83 },
84 async RebuildSessionCatalog() {},
85 };
86 }
87
87 lines TYPESCRIPT