@thread-memory/core 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/package.json +2 -2
  2. package/dist/assets.test.d.ts +0 -1
  3. package/dist/assets.test.js +0 -88
  4. package/dist/assets.test.js.map +0 -1
  5. package/dist/events.test.d.ts +0 -1
  6. package/dist/events.test.js +0 -46
  7. package/dist/events.test.js.map +0 -1
  8. package/dist/feedback-guard.test.d.ts +0 -1
  9. package/dist/feedback-guard.test.js +0 -67
  10. package/dist/feedback-guard.test.js.map +0 -1
  11. package/dist/index.test.d.ts +0 -1
  12. package/dist/index.test.js +0 -8
  13. package/dist/index.test.js.map +0 -1
  14. package/dist/isolation.test.d.ts +0 -1
  15. package/dist/isolation.test.js +0 -100
  16. package/dist/isolation.test.js.map +0 -1
  17. package/dist/light-confirm.test.d.ts +0 -1
  18. package/dist/light-confirm.test.js +0 -236
  19. package/dist/light-confirm.test.js.map +0 -1
  20. package/dist/lineage.test.d.ts +0 -1
  21. package/dist/lineage.test.js +0 -56
  22. package/dist/lineage.test.js.map +0 -1
  23. package/dist/migrate.test.d.ts +0 -1
  24. package/dist/migrate.test.js +0 -111
  25. package/dist/migrate.test.js.map +0 -1
  26. package/dist/nav.test.d.ts +0 -1
  27. package/dist/nav.test.js +0 -100
  28. package/dist/nav.test.js.map +0 -1
  29. package/dist/project-key.test.d.ts +0 -1
  30. package/dist/project-key.test.js +0 -29
  31. package/dist/project-key.test.js.map +0 -1
  32. package/dist/query.test.d.ts +0 -1
  33. package/dist/query.test.js +0 -165
  34. package/dist/query.test.js.map +0 -1
  35. package/dist/schema.test.d.ts +0 -1
  36. package/dist/schema.test.js +0 -167
  37. package/dist/schema.test.js.map +0 -1
  38. package/dist/sediment.test.d.ts +0 -1
  39. package/dist/sediment.test.js +0 -89
  40. package/dist/sediment.test.js.map +0 -1
  41. package/dist/segment.test.d.ts +0 -1
  42. package/dist/segment.test.js +0 -37
  43. package/dist/segment.test.js.map +0 -1
  44. package/dist/state-delta.test.d.ts +0 -1
  45. package/dist/state-delta.test.js +0 -90
  46. package/dist/state-delta.test.js.map +0 -1
  47. package/dist/status-card.test.d.ts +0 -1
  48. package/dist/status-card.test.js +0 -126
  49. package/dist/status-card.test.js.map +0 -1
  50. package/dist/store.test.d.ts +0 -1
  51. package/dist/store.test.js +0 -394
  52. package/dist/store.test.js.map +0 -1
  53. package/dist/v7.test.d.ts +0 -1
  54. package/dist/v7.test.js +0 -106
  55. package/dist/v7.test.js.map +0 -1
@@ -1,236 +0,0 @@
1
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
2
- import { mkdtempSync, rmSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
- import { analyzeTurn, applyAnalysis, applyTurn, detectGoalCompletion } from "./light-confirm.js";
6
- import { sedimentClosingTodos } from "./closing.js";
7
- import { ThreadStore } from "./store.js";
8
- import { canTransition } from "./state.js";
9
- let dir;
10
- let store;
11
- beforeAll(() => {
12
- dir = mkdtempSync(join(tmpdir(), "thread-confirm-"));
13
- store = new ThreadStore({ eventsPath: join(dir, "events.db"), structuredPath: join(dir, "structured.db"), projectKey: "test-proj" });
14
- });
15
- afterAll(() => {
16
- store.close();
17
- rmSync(dir, { recursive: true, force: true });
18
- });
19
- describe("analyzeTurn(2026-08-21 结构通道化:仅目标判定保留,决策/偏好 NL 停用)", () => {
20
- it("detects goals from imperative messages", () => {
21
- const analysis = analyzeTurn({ user_msg: "帮我实现登录功能" });
22
- expect(analysis.goals).toEqual([{ text: "帮我实现登录功能", action: "add" }]);
23
- });
24
- it("does not treat questions as goals", () => {
25
- expect(analyzeTurn({ user_msg: "请问登录怎么做" }).goals).toEqual([]);
26
- expect(analyzeTurn({ user_msg: "帮我查一下这个错误" }).goals).toEqual([]);
27
- });
28
- it("does not treat completion declarations as new goals", () => {
29
- expect(analyzeTurn({ user_msg: "整理研究笔记搞定了" }).goals).toEqual([]);
30
- });
31
- it("system-reminder/指令注入不抽任何结构化行", () => {
32
- const a = analyzeTurn({ user_msg: "<system-reminder>\nUpdated instructions from: AGENTS.md\nThis file changed" });
33
- expect(a.goals).toEqual([]);
34
- });
35
- it("多行粘贴不判目标(md 提示词粘贴守卫,2026-08-21 用户场景)", () => {
36
- const mdPrompt = [
37
- "# 角色",
38
- "你是一个资深工程师",
39
- "帮我实现登录模块",
40
- "## 要求",
41
- "- 支持 JWT",
42
- "- 以后优先用 pnpm",
43
- ].join("\n");
44
- expect(analyzeTurn({ user_msg: mdPrompt }).goals).toEqual([]);
45
- // 附件内联 = 同一入口:单行守卫对多行内容同样生效
46
- expect(analyzeTurn({ user_msg: "文件内容如下:\n帮我修复缓存模块\n(来自 spec.md)" }).goals).toEqual([]);
47
- });
48
- it("长文不判目标(>200 字符守卫)", () => {
49
- const long = `帮我实现一个登录系统具体要求如下${"支持手机号邮箱用户名三种登录方式".repeat(15)}`;
50
- expect(long.length).toBeGreaterThan(200);
51
- expect(analyzeTurn({ user_msg: long }).goals).toEqual([]);
52
- });
53
- it("单行短祈使句正常判目标(守卫不误伤真实指令)", () => {
54
- expect(analyzeTurn({ user_msg: "帮我修复缓存模块" }).goals).toHaveLength(1);
55
- expect(analyzeTurn({ user_msg: "实现一个 BM25 检索模块,支持中文分词和增量索引" }).goals).toHaveLength(1);
56
- });
57
- it("决策/偏好自然语言不再产生任何结构化动作(只留显式通道)", () => {
58
- expect(analyzeTurn({ user_msg: "就按方案 A 吧" })).toEqual({ goals: [] });
59
- expect(analyzeTurn({ user_msg: "以后不要用 jQuery" })).toEqual({ goals: [] });
60
- expect(analyzeTurn({ user_msg: "改成用 Redis" })).toEqual({ goals: [] });
61
- expect(analyzeTurn({ user_msg: "好的" })).toEqual({ goals: [] });
62
- expect(analyzeTurn({ assistant_msg: "我记下了方案 A" })).toEqual({ goals: [] });
63
- expect(analyzeTurn({ assistant_msg: "我决定采用 Vite 构建" })).toEqual({ goals: [] });
64
- });
65
- it("ignores unrelated messages", () => {
66
- expect(analyzeTurn({ user_msg: "用 A 吧" })).toEqual({ goals: [] });
67
- expect(analyzeTurn({})).toEqual({ goals: [] });
68
- });
69
- });
70
- describe("applyTurn", () => {
71
- it("records goals and appends events", () => {
72
- applyTurn(store, "s1", { user_msg: "帮我重构配置模块" });
73
- expect(store.getActiveGoals("s1")).toHaveLength(1);
74
- expect(store.getRecentEvents("s1", 10).some((e) => e.kind === "user_message")).toBe(true);
75
- });
76
- it("applyAnalysis writes structured rows without appending events", () => {
77
- const before = store.getRecentEvents("s2", 100).length;
78
- const ev = store.append({
79
- session_id: "s2",
80
- kind: "user_message",
81
- ts: "2026-08-13T00:00:00.000Z",
82
- body: "帮我编写查询工具",
83
- });
84
- const applied = applyAnalysis(store, "s2", { user_msg: "帮我编写查询工具" }, { sourceEvent: ev.id });
85
- expect(applied.goals).toHaveLength(1);
86
- expect(store.getRecentEvents("s2", 100).length).toBe(before + 1);
87
- });
88
- it("assistant 文本不再进入判定(模型通道 = record_decision 工具)", () => {
89
- const before = store.getDecisions("s2").length;
90
- applyTurn(store, "s2", { assistant_msg: "我决定采用 Webpack 构建" });
91
- expect(store.getDecisions("s2").length).toBe(before);
92
- });
93
- });
94
- describe("decision state machine", () => {
95
- it("allows documented transitions only", () => {
96
- expect(canTransition("proposed", "active")).toBe(true);
97
- expect(canTransition("proposed", "revoked")).toBe(true);
98
- expect(canTransition("active", "superseded")).toBe(true);
99
- expect(canTransition("active", "revoked")).toBe(true);
100
- expect(canTransition("superseded", "active")).toBe(false);
101
- expect(canTransition("revoked", "revoked")).toBe(false);
102
- });
103
- });
104
- describe("显式决策通道(2026-08-21 结构通道化)", () => {
105
- it("addDecision:命令/工具创建直接落 active", () => {
106
- const d = store.addDecision("s-d1", "用 pnpm 管理依赖", { projectKey: "test-proj" });
107
- expect(d.status).toBe("active");
108
- expect(store.getActiveDecisions("s-d1").map((x) => x.text)).toContain("用 pnpm 管理依赖");
109
- // 同文本幂等:重复创建返回既有行,不产生重复 active 决策
110
- const dup = store.addDecision("s-d1", "用 pnpm 管理依赖", { projectKey: "test-proj" });
111
- expect(dup.id).toBe(d.id);
112
- expect(store.getActiveDecisions("s-d1")).toHaveLength(1);
113
- });
114
- it("supersedeDecisionById:旧决策转 superseded + 血缘边 + 字段继承", () => {
115
- const old = store.addDecision("s-d2", "JWT 认证", { projectKey: "test-proj", scope: "project" });
116
- const r = store.supersedeDecisionById("s-d2", old.id, "Session 认证", { ts: "2026-08-13T00:00:05.000Z" });
117
- expect(r).toBeDefined();
118
- expect(r?.superseded.status).toBe("superseded");
119
- expect(r?.superseded.superseded_by).toBe(r?.replacement.id);
120
- expect(r?.replacement.status).toBe("active");
121
- expect(r?.replacement.project_key).toBe("test-proj");
122
- const edges = store.getRelatedEdges("s-d2", "decision", old.id);
123
- expect(edges.some((e) => e.edge_type === "supersedes")).toBe(true);
124
- // 非本会话/非 active 行不可取代
125
- expect(store.supersedeDecisionById("other", old.id, "X")).toBeUndefined();
126
- });
127
- it("deleteDecision:硬删除 + 血缘边清理,事件流水保留", () => {
128
- const d = store.addDecision("s-d3", "临时决策", { projectKey: "test-proj", sourceEvent: 1 });
129
- expect(store.deleteDecision(d.id)).toBe(true);
130
- expect(store.getDecisions("s-d3")).toHaveLength(0);
131
- expect(store.deleteDecision(d.id)).toBe(false);
132
- });
133
- it("promoteCandidate:候选转正为 active 决策(可带修正文本)", () => {
134
- const c = store.addPendingCandidate({ sessionId: "s-d4", text: "开发基线:标准模式为主", kind: "decision", projectKey: "test-proj" });
135
- const d = store.promoteCandidate(c.id);
136
- expect(d?.status).toBe("active");
137
- expect(d?.text).toBe("开发基线:标准模式为主");
138
- expect(store.listPendingCandidates({ sessionId: "s-d4" })).toHaveLength(0);
139
- // 带修正文本转正
140
- const c2 = store.addPendingCandidate({ sessionId: "s-d4", text: "碎片候选文本", kind: "decision", projectKey: "test-proj" });
141
- const d2 = store.promoteCandidate(c2.id, "修正后的决策文本");
142
- expect(d2?.text).toBe("修正后的决策文本");
143
- // 已处理候选不可再转正
144
- expect(store.promoteCandidate(c2.id)).toBeUndefined();
145
- });
146
- });
147
- describe("轻确认候选(§1.5.3d:粗筛-候选,不污染正式表)", () => {
148
- it("候选待处理期不入正式表;转正后进 decisions", () => {
149
- const c = store.addPendingCandidate({ sessionId: "s-p1", text: "用 pnpm", kind: "decision", projectKey: "test-proj" });
150
- expect(store.getDecisions("s-p1")).toHaveLength(0);
151
- store.promoteCandidate(c.id);
152
- expect(store.getDecisions("s-p1").map((d) => d.text)).toContain("用 pnpm");
153
- });
154
- it("忽略候选 → ignored", () => {
155
- const c = store.addPendingCandidate({ sessionId: "s-p3", text: "别用 yarn", kind: "preference", projectKey: "test-proj" });
156
- const ignored = store.ignoreCandidate(c.id);
157
- expect(ignored?.status).toBe("ignored");
158
- expect(store.listPendingCandidates({ sessionId: "s-p3" })).toHaveLength(0);
159
- });
160
- it("提示计数与超时过期", () => {
161
- const c = store.addPendingCandidate({ sessionId: "s-p4", text: "缓存用 LRU", kind: "decision", projectKey: "test-proj" });
162
- store.markCandidatePrompted(c.id);
163
- store.markCandidatePrompted(c.id);
164
- const listed = store.listPendingCandidates({ projectKey: "test-proj" }).find((x) => x.id === c.id);
165
- expect(listed?.prompt_count).toBe(2);
166
- store.structuredDb.prepare(`UPDATE pending_candidates SET last_prompt_ts = ? WHERE id = ?`).run("2026-01-01T00:00:00.000Z", c.id);
167
- const expired = store.expireCandidates({ before: new Date().toISOString(), projectKey: "test-proj" });
168
- expect(expired).toBeGreaterThanOrEqual(1);
169
- expect(store.listPendingCandidates({ projectKey: "test-proj" }).find((x) => x.id === c.id)).toBeUndefined();
170
- });
171
- it("从未被提示的候选(headless 堆积场景)超龄也过期(2026-08-20 收口)", () => {
172
- const c = store.addPendingCandidate({ sessionId: "s-p5", text: "碎片误报候选", kind: "decision", projectKey: "test-proj" });
173
- store.structuredDb.prepare(`UPDATE pending_candidates SET created_at = ? WHERE id = ?`).run("2026-01-01T00:00:00.000Z", c.id);
174
- store.expireCandidates({ before: new Date().toISOString(), projectKey: "test-proj" });
175
- expect(store.listPendingCandidates({ sessionId: "s-p5" })).toHaveLength(0);
176
- });
177
- });
178
- describe("detectGoalCompletion(2026-08-20 收口:明确完成宣告 + 目标命中)", () => {
179
- it("完成宣告命中 active 目标", () => {
180
- const goals = store.addGoal("s-c1", "完成批 5 验证", { projectKey: "test-proj" });
181
- const hit = detectGoalCompletion("批 5 验证完成了", [goals]);
182
- expect(hit?.id).toBe(goals.id);
183
- });
184
- it("否定/疑问不误判", () => {
185
- const goals = store.addGoal("s-c2", "接入弹窗", { projectKey: "test-proj" });
186
- expect(detectGoalCompletion("接入弹窗还没完成", [goals])).toBeUndefined();
187
- expect(detectGoalCompletion("接入弹窗完成了吗", [goals])).toBeUndefined();
188
- });
189
- it("无目标命中不误判", () => {
190
- const goals = store.addGoal("s-c3", "迁移到 monorepo", { projectKey: "test-proj" });
191
- expect(detectGoalCompletion("午饭吃完了", [goals])).toBeUndefined();
192
- });
193
- it("长粘贴文本不触发完成(2026-08-21 狗粮假阳性守卫)", () => {
194
- const goals = store.addGoal("s-c5", "接入弹窗收尾", { projectKey: "test-proj" });
195
- const paste = "以下是 web 界面看到的内容:收到——验证任务那条也标记完成。当前待办还剩两条:接入弹窗收尾(确认/取消/推迟)和 5 条待确认候选的处理。需要继续哪个说一声即可。上下文注入 dsh-thread:收到状态卡——其他会话正在排查清单改动的问题,本会话不介入。";
196
- expect(paste.length).toBeGreaterThan(100);
197
- expect(detectGoalCompletion(paste, [goals])).toBeUndefined();
198
- expect(detectGoalCompletion("接入弹窗收尾完成了", [goals])?.id).toBe(goals.id);
199
- });
200
- it("applyAnalysis 全链:完成宣告 → 目标 completed + todo 自愈 done", () => {
201
- const g = store.addGoal("s-c4", "整理研究笔记", { projectKey: "test-proj" });
202
- sedimentClosingTodos(store, "s-c4", { projectKey: "test-proj" });
203
- expect(store.listTodos({ sessionId: "s-c4" })[0].status).toBe("pending");
204
- applyAnalysis(store, "s-c4", { user_msg: "整理研究笔记搞定了" }, { projectKey: "test-proj" });
205
- expect(store.getActiveGoals("s-c4")).toHaveLength(0);
206
- const completed = store.structuredDb
207
- .prepare(`SELECT id, status FROM goals WHERE session_id = ? AND status = 'completed'`)
208
- .all("s-c4");
209
- expect(completed.map((r) => r.id)).toContain(g.id);
210
- expect(store.listTodos({ sessionId: "s-c4" })[0].status).toBe("done");
211
- });
212
- it("applyAnalysis 跨会话完成(2026-08-21 狗粮修复):目标在旧会话,新会话指认完成", () => {
213
- const g = store.addGoal("s-old", "验证链全绿 110/110 提交", { projectKey: "test-proj" });
214
- sedimentClosingTodos(store, "s-old", { projectKey: "test-proj" });
215
- applyAnalysis(store, "s-new", { user_msg: "验证链全绿(110/110 提交)那条已完成了" }, { projectKey: "test-proj" });
216
- const row = store.structuredDb.prepare(`SELECT status FROM goals WHERE id = ?`).get(g.id);
217
- expect(row.status).toBe("completed");
218
- expect(store.listTodos({ sessionId: "s-old" })[0].status).toBe("done");
219
- expect(store.getActiveGoals("s-new")).toHaveLength(0);
220
- });
221
- it("英文 4 字符窗口不判完成(2026-08-21 狗粮误报:北极星 Thread 被 thread-reg 命中 read)", () => {
222
- const goals = store.addGoal("s-c6", "Thread 定位北极星:让模型工作质量更高(可靠性向),不是让用户更舒服(体验向)——任何功能决策拿它对齐", { projectKey: "test-proj" });
223
- const msg = "重启完成了,我试了一下thread-reg ast,发现两个问题:\n1.changeset记录也在里面\n2.大量的重复";
224
- expect(detectGoalCompletion(msg, [goals])).toBeUndefined();
225
- // 合法中文窗口仍命中(空格归一化)
226
- expect(detectGoalCompletion("Thread定位北极星那条已经完成了", [goals])?.id).toBe(goals.id);
227
- });
228
- it("纯 ASCII 目标需 ≥8 连字符窗口;短英文目标不误判不误伤", () => {
229
- const en = store.addGoal("s-c7", "Ship the MVP by end of August", { projectKey: "test-proj" });
230
- expect(detectGoalCompletion("Ship the MVP by end of August 已经交付了", [en])?.id).toBe(en.id);
231
- // 短英文片段(<8 连字符)不构成重叠——宁可漏判不误判
232
- const short = store.addGoal("s-c8", "MVP", { projectKey: "test-proj" });
233
- expect(detectGoalCompletion("MVP 完成了", [short])).toBeUndefined();
234
- });
235
- });
236
- //# sourceMappingURL=light-confirm.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"light-confirm.test.js","sourceRoot":"","sources":["../src/light-confirm.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AACjG,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,IAAI,GAAW,CAAC;AAChB,IAAI,KAAkB,CAAC;AAEvB,SAAS,CAAC,GAAG,EAAE;IACb,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;IACrD,KAAK,GAAG,IAAI,WAAW,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;AACvI,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,GAAG,EAAE;IACZ,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,mDAAmD,EAAE,GAAG,EAAE;IACjE,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,QAAQ,GAAG,WAAW,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACvD,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,GAAG,WAAW,CAAC,EAAE,QAAQ,EAAE,4EAA4E,EAAE,CAAC,CAAC;QAClH,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,QAAQ,GAAG;YACf,MAAM;YACN,WAAW;YACX,UAAU;YACV,OAAO;YACP,UAAU;YACV,cAAc;SACf,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACb,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9D,4BAA4B;QAC5B,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,iCAAiC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,IAAI,GAAG,mBAAmB,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACpE,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,4BAA4B,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACrE,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACzE,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QACtE,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,WAAW,CAAC,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1E,MAAM,CAAC,WAAW,CAAC,EAAE,aAAa,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;QAClE,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,MAAM,GAAG,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC;QACvD,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;YACtB,UAAU,EAAE,IAAI;YAChB,IAAI,EAAE,cAAc;YACpB,EAAE,EAAE,0BAA0B;YAC9B,IAAI,EAAE,UAAU;SACjB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7F,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QAC/C,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,aAAa,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,aAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvD,MAAM,CAAC,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,MAAM,CAAC,aAAa,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1D,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QAChF,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QACrF,kCAAkC;QAClC,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QAClF,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC1B,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAC/F,MAAM,CAAC,GAAG,KAAK,CAAC,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE,0BAA0B,EAAE,CAAC,CAAC;QACxG,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAChD,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;QAC5D,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,KAAK,CAAC,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAChE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAA4B,CAAC,SAAS,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/F,sBAAsB;QACtB,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC;QACzF,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,GAAG,KAAK,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QAC3H,MAAM,CAAC,GAAG,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACvC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC3E,UAAU;QACV,MAAM,EAAE,GAAG,KAAK,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACvH,MAAM,EAAE,GAAG,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClC,aAAa;QACb,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;IAC3C,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,GAAG,KAAK,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACtH,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnD,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gBAAgB,EAAE,GAAG,EAAE;QACxB,MAAM,CAAC,GAAG,KAAK,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACzH,MAAM,OAAO,GAAG,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;QACnB,MAAM,CAAC,GAAG,KAAK,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACvH,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAClC,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QACnG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,+DAA+D,CAAC,CAAC,GAAG,CAAC,0BAA0B,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAClI,MAAM,OAAO,GAAG,KAAK,CAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACtG,MAAM,CAAC,OAAO,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAC9G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,GAAG,KAAK,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACtH,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,2DAA2D,CAAC,CAAC,GAAG,CAAC,0BAA0B,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9H,KAAK,CAAC,gBAAgB,CAAC,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACtF,MAAM,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,mDAAmD,EAAE,GAAG,EAAE;IACjE,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QAC7E,MAAM,GAAG,GAAG,oBAAoB,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE;QAClB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACzE,MAAM,CAAC,oBAAoB,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QAClE,MAAM,CAAC,oBAAoB,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE;QAClB,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACjF,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QAC3E,MAAM,KAAK,GAAG,oIAAoI,CAAC;QACnJ,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAC1C,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QAC7D,MAAM,CAAC,oBAAoB,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACvE,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACjE,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACrF,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACrD,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY;aACjC,OAAO,CAAC,4EAA4E,CAAC;aACrF,GAAG,CAAC,MAAM,CAA0C,CAAC;QACxD,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,kBAAkB,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QAClF,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QAClE,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,yBAAyB,EAAE,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACpG,MAAM,GAAG,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,uCAAuC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAuB,CAAC;QAChH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvE,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,wDAAwD,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QAC3H,MAAM,GAAG,GAAG,+DAA+D,CAAC;QAC5E,MAAM,CAAC,oBAAoB,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QAC3D,mBAAmB;QACnB,MAAM,CAAC,oBAAoB,CAAC,oBAAoB,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,+BAA+B,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QAC/F,MAAM,CAAC,oBAAoB,CAAC,qCAAqC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC1F,8BAA8B;QAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;QACxE,MAAM,CAAC,oBAAoB,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,56 +0,0 @@
1
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
2
- import { mkdtempSync, rmSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
- import { ThreadStore } from "./store.js";
6
- let dir;
7
- let store;
8
- beforeAll(() => {
9
- dir = mkdtempSync(join(tmpdir(), "thread-lineage-"));
10
- store = new ThreadStore({ eventsPath: join(dir, "events.db"), structuredPath: join(dir, "structured.db"), projectKey: "test-proj" });
11
- });
12
- afterAll(() => {
13
- store.close();
14
- rmSync(dir, { recursive: true, force: true });
15
- });
16
- describe("lineage edges", () => {
17
- it("records touches_file and uses_tool edges on event append", () => {
18
- const ev = store.append({
19
- session_id: "l1",
20
- kind: "tool_call",
21
- ts: "2026-08-13T00:00:00.000Z",
22
- body: "edit src/auth.ts",
23
- meta: { tool_name: "Edit", file_path: "src/auth.ts" },
24
- });
25
- const related = store.getRelatedEvents("l1", ev.id);
26
- const types = related.map((r) => `${r.dst_type}:${r.edge_type}:${r.ref ?? ""}`).sort();
27
- expect(types).toEqual(["file:touches_file:src/auth.ts", "tool:uses_tool:Edit"]);
28
- });
29
- it("finds events touching a file", () => {
30
- const events = store.getEventsForFile("l1", "src/auth.ts");
31
- expect(events.length).toBeGreaterThan(0);
32
- });
33
- it("links decisions to their source event (edge in structured db)", () => {
34
- const ev = store.append({
35
- session_id: "l1",
36
- kind: "tool_call",
37
- ts: "2026-08-13T00:00:01.000Z",
38
- body: "record_decision 调用参数",
39
- meta: { tool_name: "record_decision" },
40
- });
41
- const decision = store.addDecision("l1", "用 JWT 做认证", { sourceEvent: ev.id });
42
- const related = store.getRelatedEdges("l1", "decision", decision.id);
43
- expect(related.some((r) => r.edge_type === "derived_from" && r.dst_id === ev.id)).toBe(true);
44
- });
45
- it("records supersedes edges between decisions", () => {
46
- const old = store.addDecision("l1", "用 JWT 做认证");
47
- const r = store.supersedeDecisionById("l1", old.id, "改用 Session 认证", { ts: "2026-08-13T00:00:02.000Z" });
48
- expect(r?.superseded.status).toBe("superseded");
49
- expect(r?.replacement.status).toBe("active");
50
- const edges = store.getRelatedEdges("l1", "decision", old.id);
51
- const supersedes = edges.filter((e) => e.edge_type === "supersedes");
52
- expect(supersedes).toHaveLength(1);
53
- expect(supersedes[0].dst_id).toBe(r?.replacement.id);
54
- });
55
- });
56
- //# sourceMappingURL=lineage.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"lineage.test.js","sourceRoot":"","sources":["../src/lineage.test.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,111 +0,0 @@
1
- import { afterAll, beforeAll, describe, expect, it } from "vitest";
2
- import Database from "better-sqlite3";
3
- import { existsSync, mkdtempSync, rmSync } from "node:fs";
4
- import { tmpdir } from "node:os";
5
- import { join } from "node:path";
6
- import { hashProjectKey } from "./project-key.js";
7
- import { migrateSplit, replayIncrement, snapshotTableMaxIds } from "./migrate.js";
8
- import { ThreadStore } from "./store.js";
9
- let dir;
10
- let oldPath;
11
- let root;
12
- let store;
13
- let eventsPath;
14
- let structuredPath;
15
- const PK = "d:/test/proj";
16
- beforeAll(() => {
17
- dir = mkdtempSync(join(tmpdir(), "thread-migrate-b4-"));
18
- oldPath = join(dir, "sms.db");
19
- root = join(dir, "thread-root");
20
- // 构造现网形态旧单库:v2 schema + NULL project_key 旧行 + 事件/结构化/血缘
21
- const old = new Database(oldPath);
22
- old.exec(`CREATE TABLE events (
23
- id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, kind TEXT NOT NULL,
24
- ts TEXT NOT NULL, seq INTEGER NOT NULL, body TEXT NOT NULL, meta TEXT,
25
- truncated INTEGER NOT NULL DEFAULT 0, project_key TEXT, scope TEXT NOT NULL DEFAULT 'project',
26
- origin TEXT, spilled INTEGER NOT NULL DEFAULT 0
27
- );
28
- CREATE TABLE episodes (id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, seq_start INTEGER NOT NULL, seq_end INTEGER, status TEXT NOT NULL DEFAULT 'active', summary TEXT, created_at TEXT NOT NULL);
29
- CREATE TABLE spills (id INTEGER PRIMARY KEY AUTOINCREMENT, event_id INTEGER NOT NULL, ref TEXT NOT NULL, blob TEXT, sha256 TEXT NOT NULL, created_at TEXT NOT NULL);
30
- CREATE TABLE goals (id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, text TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'active', source_event INTEGER, created_at TEXT NOT NULL, project_key TEXT, scope TEXT NOT NULL DEFAULT 'project', origin TEXT);
31
- CREATE TABLE decisions (id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, text TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'proposed', superseded_by INTEGER, source_event INTEGER, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, project_key TEXT, scope TEXT NOT NULL DEFAULT 'project', origin TEXT);
32
- CREATE TABLE feedback (id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, text TEXT NOT NULL, kind TEXT NOT NULL DEFAULT 'preference', source_event INTEGER, created_at TEXT NOT NULL, project_key TEXT, scope TEXT NOT NULL DEFAULT 'project', origin TEXT);
33
- CREATE TABLE lineage_edges (id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL, src_type TEXT NOT NULL, src_id INTEGER, dst_type TEXT NOT NULL, dst_id INTEGER, ref TEXT, edge_type TEXT NOT NULL, confidence REAL NOT NULL DEFAULT 1.0, ts TEXT NOT NULL);
34
- CREATE TABLE entities (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, kind TEXT NOT NULL);
35
- CREATE TABLE decision_entities (decision_id INTEGER NOT NULL, entity_id INTEGER NOT NULL, edge TEXT NOT NULL DEFAULT 'references', ts TEXT NOT NULL, PRIMARY KEY (decision_id, entity_id));
36
- CREATE TABLE metrics (id INTEGER PRIMARY KEY AUTOINCREMENT, event_id INTEGER, name TEXT NOT NULL, value REAL NOT NULL, ts TEXT NOT NULL);
37
- INSERT INTO events (id, session_id, kind, ts, seq, body, project_key, origin) VALUES (1, 's1', 'user_message', '2026-08-14T00:00:00.000Z', 1, '旧事件无键', NULL, NULL);
38
- INSERT INTO events (id, session_id, kind, ts, seq, body, project_key, origin) VALUES (2, 's1', 'tool_call', '2026-08-14T00:00:01.000Z', 2, 'edit a.ts', 'd:/test/proj', 'qoder://transcript#t1');
39
- INSERT INTO episodes (id, session_id, seq_start, status, created_at) VALUES (1, 's1', 1, 'active', '2026-08-14T00:00:00.000Z');
40
- INSERT INTO spills (id, event_id, ref, blob, sha256, created_at) VALUES (1, 2, 'spill:2', '原文大块', 'abc', '2026-08-14T00:00:01.000Z');
41
- INSERT INTO goals (id, session_id, text, status, source_event, created_at, project_key, scope, origin) VALUES (1, 's1', '旧目标', 'active', 1, '2026-08-14T00:00:00.000Z', NULL, 'project', NULL);
42
- INSERT INTO feedback (id, session_id, text, kind, source_event, created_at, project_key, scope, origin) VALUES (1, 's1', '全局偏好', 'preference', 1, '2026-08-14T00:00:00.000Z', NULL, 'global', NULL);
43
- INSERT INTO lineage_edges (id, session_id, src_type, src_id, dst_type, dst_id, ref, edge_type, ts) VALUES (1, 's1', 'event', 2, 'file', NULL, 'a.ts', 'touches_file', '2026-08-14T00:00:01.000Z');
44
- INSERT INTO lineage_edges (id, session_id, src_type, src_id, dst_type, dst_id, ref, edge_type, ts) VALUES (2, 's1', 'goal', 1, 'event', 1, NULL, 'derived_from', '2026-08-14T00:00:00.000Z');
45
- `);
46
- old.close();
47
- });
48
- afterAll(() => {
49
- store?.close();
50
- rmSync(dir, { recursive: true, force: true });
51
- });
52
- describe("B④ migrateSplit", () => {
53
- it("splits single db into structured + project event db with backfill and checks", () => {
54
- const result = migrateSplit({ oldPath, root, projectKey: PK, dryRun: false });
55
- expect(result.projectKey).toBe(PK);
56
- // 事件回填:1 行 NULL → PK
57
- expect(result.events.copied).toBe(2);
58
- expect(result.events.backfilled).toBe(1);
59
- // 结构化回填:goal NULL project → 追溯 source_event(1) 无键 → PK;feedback global 留 NULL
60
- expect(result.structured.goals).toBe(1);
61
- expect(result.structured.feedback).toBe(1);
62
- expect(result.structured.backfilled).toBe(1);
63
- // 血缘按域拆分
64
- expect(result.lineage.events).toBe(1);
65
- expect(result.lineage.structured).toBe(1);
66
- expect(result.integrity.events).toBe(true);
67
- expect(result.integrity.structured).toBe(true);
68
- eventsPath = join(root, "projects", hashProjectKey(PK), "events.db");
69
- structuredPath = join(root, "structured.db");
70
- expect(existsSync(eventsPath)).toBe(true);
71
- expect(existsSync(structuredPath)).toBe(true);
72
- store = new ThreadStore({ eventsPath, structuredPath });
73
- // 事件回填正确(列值 = 规范化路径,不是 hash)
74
- const ev = store.eventsDb.prepare("SELECT project_key FROM events WHERE id = 1").get();
75
- expect(ev.project_key).toBe(PK);
76
- // 结构化回填正确
77
- const goal = store.structuredDb.prepare("SELECT project_key, scope FROM goals WHERE id = 1").get();
78
- expect(goal.project_key).toBe(PK);
79
- expect(goal.scope).toBe("project");
80
- const fb = store.structuredDb.prepare("SELECT project_key, scope FROM feedback WHERE id = 1").get();
81
- expect(fb.project_key).toBeNull();
82
- expect(fb.scope).toBe("global");
83
- // 血缘分库正确
84
- expect(store.getEventsForFile("s1", "a.ts").length).toBe(1);
85
- expect(store.getRelatedEdges("s1", "goal", 1).some((r) => r.edge_type === "derived_from")).toBe(true);
86
- // 旧库备份
87
- expect(existsSync(`${oldPath}.bak-b4`)).toBe(true);
88
- });
89
- it("replays increment after snapshot (零差异)", () => {
90
- // 迁移前快照(此时旧库 max(events.id)=2)
91
- const snapshot = snapshotTableMaxIds(oldPath);
92
- expect(snapshot.events).toBe(2);
93
- expect(snapshot.feedback).toBe(1);
94
- // 快照后旧库新增事件 + 结构化行
95
- const old = new Database(oldPath);
96
- old.exec(`INSERT INTO events (id, session_id, kind, ts, seq, body, project_key, origin) VALUES (3, 's2', 'user_message', '2026-08-14T00:00:02.000Z', 1, '增量事件', 'd:/test/proj', 'qoder://transcript#t2');
97
- INSERT INTO feedback (id, session_id, text, kind, source_event, created_at, project_key, scope, origin) VALUES (2, 's2', '增量反馈', 'preference', 3, '2026-08-14T00:00:02.000Z', NULL, 'project', NULL);
98
- INSERT INTO lineage_edges (id, session_id, src_type, src_id, dst_type, dst_id, ref, edge_type, ts) VALUES (3, 's2', 'event', 3, 'file', NULL, 'b.ts', 'touches_file', '2026-08-14T00:00:02.000Z');`);
99
- old.close();
100
- const replayed = replayIncrement(oldPath, root, PK, snapshot);
101
- expect(replayed.events).toBe(1);
102
- store.close();
103
- store = new ThreadStore({ eventsPath, structuredPath });
104
- const total = store.eventsDb.prepare("SELECT COUNT(*) AS c FROM events").get();
105
- expect(total.c).toBe(3);
106
- const fb = store.structuredDb.prepare("SELECT project_key FROM feedback WHERE id = 2").get();
107
- expect(fb.project_key).toBe(PK);
108
- expect(store.getEventsForFile("s2", "b.ts").length).toBe(1);
109
- });
110
- });
111
- //# sourceMappingURL=migrate.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"migrate.test.js","sourceRoot":"","sources":["../src/migrate.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACnE,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,IAAI,GAAW,CAAC;AAChB,IAAI,OAAe,CAAC;AACpB,IAAI,IAAY,CAAC;AACjB,IAAI,KAAkB,CAAC;AACvB,IAAI,UAAkB,CAAC;AACvB,IAAI,cAAsB,CAAC;AAE3B,MAAM,EAAE,GAAG,cAAc,CAAC;AAE1B,SAAS,CAAC,GAAG,EAAE;IACb,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC;IACxD,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC9B,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IAEhC,wDAAwD;IACxD,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,GAAG,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;GAuBR,CAAC,CAAC;IACH,GAAG,CAAC,KAAK,EAAE,CAAC;AACd,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,GAAG,EAAE;IACZ,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,8EAA8E,EAAE,GAAG,EAAE;QACtF,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAE9E,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnC,qBAAqB;QACrB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzC,8EAA8E;QAC9E,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,SAAS;QACT,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE/C,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,CAAC,EAAE,WAAW,CAAC,CAAC;QACrE,cAAc,GAAG,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAC7C,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE9C,KAAK,GAAG,IAAI,WAAW,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC;QACxD,6BAA6B;QAC7B,MAAM,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,6CAA6C,CAAC,CAAC,GAAG,EAA6B,CAAC;QAClH,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChC,UAAU;QACV,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC,GAAG,EAA4C,CAAC;QAC7I,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACnC,MAAM,EAAE,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,sDAAsD,CAAC,CAAC,GAAG,EAAmD,CAAC;QACrJ,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC;QAClC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,SAAS;QACT,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtG,OAAO;QACP,MAAM,CAAC,UAAU,CAAC,GAAG,OAAO,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,+BAA+B;QAC/B,MAAM,QAAQ,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAElC,mBAAmB;QACnB,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClC,GAAG,CAAC,IAAI,CAAC;;uMAE0L,CAAC,CAAC;QACrM,GAAG,CAAC,KAAK,EAAE,CAAC;QAEZ,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;QAE9D,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChC,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,KAAK,GAAG,IAAI,WAAW,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,EAAmB,CAAC;QAChG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,EAAE,GAAG,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,+CAA+C,CAAC,CAAC,GAAG,EAA6B,CAAC;QACxH,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- export {};
package/dist/nav.test.js DELETED
@@ -1,100 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
- import { navigate } from "./nav.js";
6
- import { ThreadStore } from "./store.js";
7
- function makeStore() {
8
- const dir = mkdtempSync(join(tmpdir(), "thread-nav-"));
9
- const store = new ThreadStore({ eventsPath: join(dir, "events.db"), structuredPath: join(dir, "structured.db"), projectKey: "demo" });
10
- return { store, dir };
11
- }
12
- describe("navigate (query primitives ls/cd/cat/grep)", () => {
13
- it("ls session -> assets + todos", () => {
14
- const { store, dir } = makeStore();
15
- try {
16
- store.registerAsset({ sessionId: "s1", path: "docs/a.md", title: "asset A" });
17
- store.addTodo({ sessionId: "s1", text: "todo 1" });
18
- const r = navigate(store, { nav: "ls", target: "s1", viewerSessionId: "s1" });
19
- expect(r.kind).toBe("list");
20
- expect(r.items.map((i) => i.type)).toEqual(["asset", "todo"]);
21
- expect(r.items[0].label).toContain("asset A");
22
- }
23
- finally {
24
- store.close();
25
- rmSync(dir, { recursive: true, force: true });
26
- }
27
- });
28
- it("ls asset -> related edges", () => {
29
- const { store, dir } = makeStore();
30
- try {
31
- const ev = store.append({ session_id: "s1", kind: "tool_call", ts: "t", body: "write" });
32
- const a = store.registerAsset({ sessionId: "s1", path: "docs/a.md", title: "A", sourceEvent: ev.id });
33
- const r = navigate(store, { nav: "ls", target: String(a.id), viewerSessionId: "s1" });
34
- expect(r.kind).toBe("list");
35
- expect(r.items.length).toBeGreaterThan(0);
36
- }
37
- finally {
38
- store.close();
39
- rmSync(dir, { recursive: true, force: true });
40
- }
41
- });
42
- it("cat asset -> file content", () => {
43
- const { store, dir } = makeStore();
44
- try {
45
- const file = join(dir, "notes.md");
46
- writeFileSync(file, "# note title\ncontent body");
47
- const a = store.registerAsset({ sessionId: "s1", path: file, title: "note title" });
48
- const r = navigate(store, { nav: "cat", target: String(a.id), viewerSessionId: "s1" });
49
- expect(r.kind).toBe("content");
50
- expect(r.items[0].label).toContain("note title");
51
- }
52
- finally {
53
- store.close();
54
- rmSync(dir, { recursive: true, force: true });
55
- }
56
- });
57
- it("cat event -> expand body", () => {
58
- const { store, dir } = makeStore();
59
- try {
60
- const ev = store.append({ session_id: "s1", kind: "user_message", ts: "t", body: "hello event" });
61
- const r = navigate(store, { nav: "cat", target: String(ev.id), viewerSessionId: "s1" });
62
- expect(r.items[0].label).toContain("hello event");
63
- }
64
- finally {
65
- store.close();
66
- rmSync(dir, { recursive: true, force: true });
67
- }
68
- });
69
- it("grep -> search hits + asset index matches", () => {
70
- const { store, dir } = makeStore();
71
- try {
72
- store.append({ session_id: "s1", kind: "user_message", ts: "t", body: "discuss the login design" });
73
- store.registerAsset({ sessionId: "s1", path: "docs/login.md", title: "login design doc" });
74
- const r = navigate(store, { nav: "grep", query: "login", sessionId: "s1", viewerSessionId: "s1" });
75
- expect(r.kind).toBe("hits");
76
- expect(r.items.some((i) => i.label.includes("login design doc"))).toBe(true);
77
- }
78
- finally {
79
- store.close();
80
- rmSync(dir, { recursive: true, force: true });
81
- }
82
- });
83
- it("cd path -> asset node", () => {
84
- const { store, dir } = makeStore();
85
- try {
86
- const file = join(dir, "docs", "x.md");
87
- mkdirSync(join(dir, "docs"), { recursive: true });
88
- writeFileSync(file, "# X");
89
- store.registerAsset({ sessionId: "s1", path: file, title: "X" });
90
- const r = navigate(store, { nav: "cd", target: file, viewerSessionId: "s1" });
91
- expect(r.kind).toBe("node");
92
- expect(r.title).toContain("X");
93
- }
94
- finally {
95
- store.close();
96
- rmSync(dir, { recursive: true, force: true });
97
- }
98
- });
99
- });
100
- //# sourceMappingURL=nav.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"nav.test.js","sourceRoot":"","sources":["../src/nav.test.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,29 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { deriveProjectKey, deriveProjectKeyHash } from "./project-key.js";
3
- describe("project key", () => {
4
- it("derives a key for the current repo root", () => {
5
- const key = deriveProjectKey(process.cwd());
6
- expect(key.length).toBeGreaterThan(0);
7
- expect(key).not.toMatch(/\\$/);
8
- });
9
- it("normalizes trailing slashes and separators", () => {
10
- // 同一路径的不同写法应归一(Windows 反斜杠 → 正斜杠 + 盘符小写)
11
- const a = "D:/Agent-work/workspace/Thread/";
12
- const b = "D:\\Agent-work\\workspace\\Thread";
13
- expect(normalizeForTest(a)).toBe(normalizeForTest(b));
14
- });
15
- it("hash is stable and distinct per key", () => {
16
- const h1 = deriveProjectKeyHash("D:/Agent-work/workspace/Thread");
17
- const h2 = deriveProjectKeyHash("D:/Agent-work/workspace/Thread/");
18
- const h3 = deriveProjectKeyHash("D:/Agent-work/workspace/Other");
19
- expect(h1).toBe(h2);
20
- expect(h1).not.toBe(h3);
21
- });
22
- });
23
- function normalizeForTest(p) {
24
- return p
25
- .replace(/\\/g, "/")
26
- .replace(/^([a-zA-Z]):/, (_, d) => d.toLowerCase() + ":")
27
- .replace(/\/+$/, "");
28
- }
29
- //# sourceMappingURL=project-key.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"project-key.test.js","sourceRoot":"","sources":["../src/project-key.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE1E,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,yCAAyC;QACzC,MAAM,CAAC,GAAG,iCAAiC,CAAC;QAC5C,MAAM,CAAC,GAAG,mCAAmC,CAAC;QAC9C,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,EAAE,GAAG,oBAAoB,CAAC,gCAAgC,CAAC,CAAC;QAClE,MAAM,EAAE,GAAG,oBAAoB,CAAC,iCAAiC,CAAC,CAAC;QACnE,MAAM,EAAE,GAAG,oBAAoB,CAAC,+BAA+B,CAAC,CAAC;QACjE,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpB,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,SAAS,gBAAgB,CAAC,CAAS;IACjC,OAAO,CAAC;SACL,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC;SAChE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACzB,CAAC"}
@@ -1 +0,0 @@
1
- export {};