recallnest 2.6.1 → 3.0.1

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 (207) hide show
  1. package/CHANGELOG.md +292 -0
  2. package/README.md +280 -195
  3. package/README_CN.md +266 -199
  4. package/config.json.example +8 -1
  5. package/docs/api-reference.md +1 -1
  6. package/integrations/README.md +1 -1
  7. package/integrations/agy/README.md +73 -0
  8. package/integrations/agy/setup.sh +75 -0
  9. package/integrations/setup-all.sh +1 -1
  10. package/package.json +7 -5
  11. package/src/access-tracker.ts +10 -1
  12. package/src/activity-counter.ts +69 -11
  13. package/src/age-label.ts +29 -0
  14. package/src/audit-log.ts +35 -0
  15. package/src/auto-gc.ts +97 -30
  16. package/src/capture-engine.ts +26 -4
  17. package/src/cli.ts +224 -10
  18. package/src/consolidation-engine.ts +317 -123
  19. package/src/context-composer-stable.ts +5 -1
  20. package/src/data-checkup.ts +17 -3
  21. package/src/dream-pipeline.ts +90 -12
  22. package/src/embedder.ts +44 -5
  23. package/src/env-config.ts +71 -0
  24. package/src/forget-engine.ts +8 -2
  25. package/src/gateway-server.ts +272 -0
  26. package/src/ingest.ts +248 -22
  27. package/src/kg-extractor.ts +17 -0
  28. package/src/llm-client.ts +86 -25
  29. package/src/mcp-server.ts +2 -1
  30. package/src/mcp-tools-advanced.ts +7 -2
  31. package/src/mcp-tools-core.ts +11 -1
  32. package/src/mcp-tools-governance.ts +45 -3
  33. package/src/memory-evolution.ts +16 -0
  34. package/src/memory-output.ts +47 -8
  35. package/src/memory-promotion.ts +280 -0
  36. package/src/memory-store-port.ts +32 -3
  37. package/src/memory-utility.ts +314 -0
  38. package/src/pivot-apply.ts +52 -1
  39. package/src/pivot-evidence.ts +128 -0
  40. package/src/ppr-traversal.ts +25 -1
  41. package/src/recall-ledger.ts +76 -0
  42. package/src/retriever.ts +82 -9
  43. package/src/runtime-config.ts +9 -0
  44. package/src/scope-policy.ts +22 -1
  45. package/src/session-engine.ts +11 -4
  46. package/src/session-output.ts +13 -4
  47. package/src/session-store.ts +2 -3
  48. package/src/skill-promotion.ts +218 -1
  49. package/src/store.ts +231 -71
  50. package/src/synthesis-contract.ts +286 -0
  51. package/src/version-manager.ts +83 -0
  52. package/src/workflow-observation-schema.ts +26 -0
  53. package/integrations/gemini-cli/README.md +0 -57
  54. package/integrations/gemini-cli/setup.sh +0 -64
  55. package/src/__tests__/access-tracker-novelty.test.ts +0 -304
  56. package/src/__tests__/activity-counter.test.ts +0 -125
  57. package/src/__tests__/adaptive-fidelity.test.ts +0 -102
  58. package/src/__tests__/admission-control.test.ts +0 -206
  59. package/src/__tests__/anchor-generator.test.ts +0 -67
  60. package/src/__tests__/api-server-security.test.ts +0 -102
  61. package/src/__tests__/auto-consolidation.test.ts +0 -168
  62. package/src/__tests__/auto-recall.test.ts +0 -131
  63. package/src/__tests__/babel-integration.test.ts +0 -144
  64. package/src/__tests__/batch-dedup.test.ts +0 -65
  65. package/src/__tests__/belief-history.test.ts +0 -220
  66. package/src/__tests__/canary-eval.test.ts +0 -114
  67. package/src/__tests__/capture-engine.test.ts +0 -1328
  68. package/src/__tests__/capture-heuristic.test.ts +0 -171
  69. package/src/__tests__/cascade-forget.test.ts +0 -210
  70. package/src/__tests__/category-min-scores.test.ts +0 -116
  71. package/src/__tests__/cc8-cc1-essential-context.test.ts +0 -298
  72. package/src/__tests__/circuit-breaker.test.ts +0 -99
  73. package/src/__tests__/cluster-consolidation.test.ts +0 -945
  74. package/src/__tests__/confidence-metadata.test.ts +0 -125
  75. package/src/__tests__/confidence-tracker.test.ts +0 -261
  76. package/src/__tests__/conflict-advisor.test.ts +0 -206
  77. package/src/__tests__/conflict-escalation.test.ts +0 -149
  78. package/src/__tests__/conflict-lifecycle.test.ts +0 -83
  79. package/src/__tests__/conflict-output.test.ts +0 -85
  80. package/src/__tests__/conflict-store.test.ts +0 -418
  81. package/src/__tests__/connector-v1.test.ts +0 -181
  82. package/src/__tests__/consolidation-engine.test.ts +0 -430
  83. package/src/__tests__/constructive-retrieval.test.ts +0 -509
  84. package/src/__tests__/context-collapse-renderer.test.ts +0 -214
  85. package/src/__tests__/context-composer-pins.test.ts +0 -64
  86. package/src/__tests__/context-composer-task-selection.test.ts +0 -24
  87. package/src/__tests__/context-reconstructor.test.ts +0 -65
  88. package/src/__tests__/context-renderer.test.ts +0 -91
  89. package/src/__tests__/continuity-eval.test.ts +0 -275
  90. package/src/__tests__/continuity-schema.test.ts +0 -97
  91. package/src/__tests__/contracts.test.ts +0 -262
  92. package/src/__tests__/conversation-importer.test.ts +0 -692
  93. package/src/__tests__/core-recall-eval.test.ts +0 -235
  94. package/src/__tests__/core-summary.test.ts +0 -109
  95. package/src/__tests__/data-checkup.test.ts +0 -276
  96. package/src/__tests__/decay-exemption.test.ts +0 -129
  97. package/src/__tests__/dedup-actions.test.ts +0 -58
  98. package/src/__tests__/dedup-guard.test.ts +0 -39
  99. package/src/__tests__/deterministic-id.test.ts +0 -39
  100. package/src/__tests__/distill-lock.test.ts +0 -305
  101. package/src/__tests__/distill-session-argshape.test.ts +0 -79
  102. package/src/__tests__/doctor.test.ts +0 -319
  103. package/src/__tests__/dream-pipeline.test.ts +0 -780
  104. package/src/__tests__/drill-down.test.ts +0 -108
  105. package/src/__tests__/embedder.test.ts +0 -122
  106. package/src/__tests__/emotion-decay.test.ts +0 -46
  107. package/src/__tests__/emotion-detector.test.ts +0 -56
  108. package/src/__tests__/emotion-phase1-integration.test.ts +0 -153
  109. package/src/__tests__/emotion-retrieval.test.ts +0 -56
  110. package/src/__tests__/entity-resolver.test.ts +0 -58
  111. package/src/__tests__/env-config.test.ts +0 -151
  112. package/src/__tests__/error-signature-boost.test.ts +0 -87
  113. package/src/__tests__/error-signature.test.ts +0 -95
  114. package/src/__tests__/error-taxonomy.test.ts +0 -129
  115. package/src/__tests__/ethics-layer.test.ts +0 -476
  116. package/src/__tests__/event-segmenter.test.ts +0 -153
  117. package/src/__tests__/feature-flags-integration.test.ts +0 -54
  118. package/src/__tests__/frequency-tracker.test.ts +0 -113
  119. package/src/__tests__/freshness.test.ts +0 -186
  120. package/src/__tests__/graph-export.test.ts +0 -489
  121. package/src/__tests__/hotness-blend.test.ts +0 -283
  122. package/src/__tests__/ingest-chunking.test.ts +0 -44
  123. package/src/__tests__/ingest.test.ts +0 -360
  124. package/src/__tests__/interference-detector.test.ts +0 -203
  125. package/src/__tests__/kg-extractor.test.ts +0 -192
  126. package/src/__tests__/kg-store.test.ts +0 -300
  127. package/src/__tests__/llm-client-pivot.test.ts +0 -628
  128. package/src/__tests__/llm-consolidation.test.ts +0 -226
  129. package/src/__tests__/maintenance-locks.test.ts +0 -189
  130. package/src/__tests__/mcp-efficiency.test.ts +0 -288
  131. package/src/__tests__/mcp-related-scopes.test.ts +0 -151
  132. package/src/__tests__/memory-boundaries.test.ts +0 -282
  133. package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +0 -345
  134. package/src/__tests__/memory-evolution.test.ts +0 -271
  135. package/src/__tests__/memory-health-rebalance.test.ts +0 -144
  136. package/src/__tests__/memory-lint.test.ts +0 -421
  137. package/src/__tests__/memory-output.test.ts +0 -215
  138. package/src/__tests__/memory-promotion.test.ts +0 -315
  139. package/src/__tests__/migrate-dedup-ids.test.ts +0 -65
  140. package/src/__tests__/multi-vector.test.ts +0 -242
  141. package/src/__tests__/narrative-architecture.test.ts +0 -456
  142. package/src/__tests__/noise-filter.test.ts +0 -205
  143. package/src/__tests__/noise-prototype-bank.test.ts +0 -280
  144. package/src/__tests__/obsidian-connector.test.ts +0 -363
  145. package/src/__tests__/omitted-reporting.test.ts +0 -98
  146. package/src/__tests__/pending-review.test.ts +0 -77
  147. package/src/__tests__/pii-redact.test.ts +0 -333
  148. package/src/__tests__/pivot-apply.test.ts +0 -373
  149. package/src/__tests__/pivot-distill-supervisor.test.ts +0 -457
  150. package/src/__tests__/pivot-distill.test.ts +0 -1178
  151. package/src/__tests__/post-retrieval-filter.test.ts +0 -178
  152. package/src/__tests__/ppr-traversal.test.ts +0 -256
  153. package/src/__tests__/prediction-engine.test.ts +0 -349
  154. package/src/__tests__/predictive-prospective-memory.test.ts +0 -416
  155. package/src/__tests__/preference-guard-smoke.test.ts +0 -211
  156. package/src/__tests__/preference-matcher.test.ts +0 -282
  157. package/src/__tests__/preference-slots.test.ts +0 -205
  158. package/src/__tests__/prospective-memory.test.ts +0 -283
  159. package/src/__tests__/pull-from-macbook-sync-only.test.ts +0 -679
  160. package/src/__tests__/query-entity-detector.test.ts +0 -171
  161. package/src/__tests__/query-expander-alias.test.ts +0 -146
  162. package/src/__tests__/query-expander.test.ts +0 -34
  163. package/src/__tests__/recall-gate.test.ts +0 -266
  164. package/src/__tests__/recall-governor.test.ts +0 -227
  165. package/src/__tests__/recall-mode.test.ts +0 -64
  166. package/src/__tests__/resolve-db-path.test.ts +0 -130
  167. package/src/__tests__/resolve-tier.test.ts +0 -64
  168. package/src/__tests__/result-synthesizer.test.ts +0 -198
  169. package/src/__tests__/resume-context.test.ts +0 -4898
  170. package/src/__tests__/retrieval-eval.test.ts +0 -163
  171. package/src/__tests__/retrieval-trace.test.ts +0 -213
  172. package/src/__tests__/retriever-boundary-weight.test.ts +0 -136
  173. package/src/__tests__/retriever-lazy-init-dispatch.test.ts +0 -123
  174. package/src/__tests__/retroactive-boost.test.ts +0 -223
  175. package/src/__tests__/salience-scoring.test.ts +0 -106
  176. package/src/__tests__/scope-inventory.test.ts +0 -200
  177. package/src/__tests__/scope-policy.test.ts +0 -69
  178. package/src/__tests__/scope-suggester.test.ts +0 -80
  179. package/src/__tests__/session-checkpoint.test.ts +0 -291
  180. package/src/__tests__/session-distiller.test.ts +0 -640
  181. package/src/__tests__/session-gc.test.ts +0 -215
  182. package/src/__tests__/skill-engine.test.ts +0 -552
  183. package/src/__tests__/skill-promotion.test.ts +0 -654
  184. package/src/__tests__/skill-verifier.test.ts +0 -122
  185. package/src/__tests__/source-heartbeat.test.ts +0 -250
  186. package/src/__tests__/stable-context-length-contract.test.ts +0 -62
  187. package/src/__tests__/store-patch-metadata.test.ts +0 -205
  188. package/src/__tests__/store-read-consistency.test.ts +0 -122
  189. package/src/__tests__/store-schema-migration.test.ts +0 -87
  190. package/src/__tests__/store-scope-audit.test.ts +0 -81
  191. package/src/__tests__/store-upsert.test.ts +0 -201
  192. package/src/__tests__/supersede-chain.test.ts +0 -154
  193. package/src/__tests__/temporal-parser.test.ts +0 -241
  194. package/src/__tests__/temporal-validity.test.ts +0 -160
  195. package/src/__tests__/term-registry-terminal-roster.test.ts +0 -127
  196. package/src/__tests__/term-registry.test.ts +0 -121
  197. package/src/__tests__/tool-error-surfacing.test.ts +0 -98
  198. package/src/__tests__/tool-output-compressor.test.ts +0 -160
  199. package/src/__tests__/topic-tag.test.ts +0 -113
  200. package/src/__tests__/trusted-memory.test.ts +0 -839
  201. package/src/__tests__/ui-server-security.test.ts +0 -93
  202. package/src/__tests__/usage-tracker.test.ts +0 -287
  203. package/src/__tests__/version-manager.test.ts +0 -213
  204. package/src/__tests__/workflow-observation-skill-outcome.test.ts +0 -352
  205. package/src/__tests__/workflow-observation.test.ts +0 -433
  206. package/src/__tests__/write-verifier.test.ts +0 -122
  207. /package/integrations/{gemini-cli/gemini-md-snippet.md → agy/agy-md-snippet.md} +0 -0
@@ -1,98 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
-
3
- import { registerAdvancedTools } from "../mcp-tools-advanced.js";
4
- import { registerGovernanceTools } from "../mcp-tools-governance.js";
5
- import { runToolSafely } from "../error-taxonomy.js";
6
-
7
- /**
8
- * P1-7 第二阶段回归:验证「主操作错误」与「C 类逻辑失败」经 registerTool 的
9
- * runToolSafely 包装后带 isError + reason_code,而不是被 handler 自吞成「看起来成功」的文本。
10
- *
11
- * 手法:用注入式 registerTool 捕获真实 handler,并复刻生产 registerTool 的 runToolSafely
12
- * 包装,使测试看到与生产一致的 isError 行为(无需起 MCP server)。
13
- */
14
-
15
- interface ToolResult {
16
- content: { type: string; text: string }[];
17
- isError?: boolean;
18
- }
19
- type CapturedHandler = (args: Record<string, unknown>) => Promise<ToolResult>;
20
-
21
- function captureTools(
22
- register: (deps: any) => void,
23
- getComponents: () => unknown,
24
- ): Map<string, CapturedHandler> {
25
- const handlers = new Map<string, CapturedHandler>();
26
- const deps = {
27
- registerTool: (
28
- name: string,
29
- _desc: string,
30
- _schema: unknown,
31
- handler: (...a: unknown[]) => unknown,
32
- ) => {
33
- // 复刻 mcp-server.ts registerTool 的兜底:把 handler 交给 runToolSafely。
34
- handlers.set(name, (args) => runToolSafely(name, async () => handler(args)) as Promise<ToolResult>);
35
- },
36
- getComponents,
37
- conflictStore: {},
38
- workflowObservationStore: {},
39
- getKGExtractor: () => null,
40
- getKGStore: () => null,
41
- };
42
- register(deps as any);
43
- return handlers;
44
- }
45
-
46
- describe("memory_drill_down error surfacing (P1-7)", () => {
47
- it("surfaces a store error as isError with store_error reason (no swallow)", async () => {
48
- const handlers = captureTools(registerAdvancedTools, () => ({
49
- store: {
50
- getById: async () => {
51
- throw new Error("lancedb table read failed");
52
- },
53
- },
54
- }));
55
- const drill = handlers.get("memory_drill_down");
56
- expect(drill).toBeDefined();
57
- const r = await drill!({ id: "abcd1234", level: "full" });
58
- expect(r.isError).toBe(true);
59
- expect(r.content[0].text).toContain("store_error");
60
- });
61
-
62
- it("still returns plain not-found text (read-only, no isError)", async () => {
63
- const handlers = captureTools(registerAdvancedTools, () => ({
64
- store: { getById: async () => null },
65
- }));
66
- const r = await handlers.get("memory_drill_down")!({ id: "abcd1234", level: "full" });
67
- expect(r.isError).toBeUndefined();
68
- expect(r.content[0].text).toContain("No memory found");
69
- });
70
- });
71
-
72
- describe("forget_memory error surfacing (P1-7 C 类)", () => {
73
- it("throws logic failure into the taxonomy layer (isError) not fake-success text", async () => {
74
- const handlers = captureTools(registerAdvancedTools, () => ({
75
- // store.get → null ⇒ forgetMemory 早返回 success:false(不触碰 kg/audit)
76
- store: { get: async () => null },
77
- }));
78
- const r = await handlers.get("forget_memory")!({ memoryId: "abcd1234", confirm: false });
79
- expect(r.isError).toBe(true);
80
- expect(r.content[0].text).toContain("not found");
81
- });
82
- });
83
-
84
- describe("manage_alias error surfacing (P1-7 C 类)", () => {
85
- it("throws invalid_input on missing add params (not returned as success text)", async () => {
86
- const handlers = captureTools(registerGovernanceTools, () => ({}));
87
- const r = await handlers.get("manage_alias")!({ action: "add" });
88
- expect(r.isError).toBe(true);
89
- expect(r.content[0].text).toContain("invalid_input");
90
- });
91
-
92
- it("throws invalid_input on missing remove trigger", async () => {
93
- const handlers = captureTools(registerGovernanceTools, () => ({}));
94
- const r = await handlers.get("manage_alias")!({ action: "remove" });
95
- expect(r.isError).toBe(true);
96
- expect(r.content[0].text).toContain("invalid_input");
97
- });
98
- });
@@ -1,160 +0,0 @@
1
- import { describe, it, expect } from "bun:test";
2
- import { compressToolOutput } from "../tool-output-compressor.js";
3
-
4
- describe("compressToolOutput", () => {
5
- // ========================================================================
6
- // Base64 replacement
7
- // ========================================================================
8
-
9
- it("replaces large base64 blocks with size placeholder", () => {
10
- const base64 = "A".repeat(2000);
11
- const text = `Here is a screenshot:\n${base64}\nEnd of screenshot.`;
12
- const result = compressToolOutput(text);
13
- expect(result).toContain("[image:");
14
- expect(result).toContain("base64");
15
- expect(result).not.toContain("AAAA");
16
- });
17
-
18
- it("preserves short base64-like strings", () => {
19
- const text = "The hash is abc123==";
20
- expect(compressToolOutput(text)).toBe(text);
21
- });
22
-
23
- // ========================================================================
24
- // Git output compression
25
- // ========================================================================
26
-
27
- it("compresses git push boilerplate", () => {
28
- const text = `$ git push origin main
29
- Enumerating objects: 5, done.
30
- Counting objects: 100% (5/5), done.
31
- Delta compression using up to 8 threads
32
- Compressing objects: 100% (3/3), done.
33
- Writing objects: 100% (3/3), 450 bytes | 450.00 KiB/s, done.
34
- Total 3 (delta 2), reused 0 (delta 0)
35
- remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
36
- To github.com:user/repo.git
37
- abc1234..def5678 main -> main
38
-
39
- Next I'll check the status.`;
40
-
41
- const result = compressToolOutput(text);
42
- expect(result).toContain("[git: ok");
43
- expect(result).toContain("main");
44
- expect(result).not.toContain("Enumerating objects");
45
- expect(result).toContain("Next I'll check the status");
46
- });
47
-
48
- it("preserves git push failures", () => {
49
- const text = `$ git push
50
- Enumerating objects: 5, done.
51
- error: failed to push some refs to 'origin'
52
- hint: Updates were rejected because the tip of your branch is behind -> main`;
53
-
54
- const result = compressToolOutput(text);
55
- expect(result).toContain("error");
56
- expect(result).toContain("rejected");
57
- });
58
-
59
- // ========================================================================
60
- // Test output compression
61
- // ========================================================================
62
-
63
- it("compresses passing test summary", () => {
64
- const text = `$ bun test
65
- running 15 tests
66
- test a ... ok
67
- test b ... ok
68
- test c ... ok
69
- test result: ok. 15 passed; 0 failed; 0 ignored
70
-
71
- All tests passed.`;
72
-
73
- const result = compressToolOutput(text);
74
- expect(result.length).toBeLessThanOrEqual(text.length);
75
- expect(result).toContain("All tests passed");
76
- });
77
-
78
- it("preserves failing test output", () => {
79
- const text = `$ npm test
80
- Tests: 2 failed, 8 passed
81
- FAIL src/main.test.ts
82
- ✕ should handle edge case`;
83
-
84
- const result = compressToolOutput(text);
85
- expect(result).toContain("failed");
86
- expect(result).toContain("FAIL");
87
- });
88
-
89
- // ========================================================================
90
- // Safety: user/AI content untouched
91
- // ========================================================================
92
-
93
- it("never modifies plain conversation text", () => {
94
- const text = "User: How do I fix this git push error?\n\nAssistant: You need to pull first.";
95
- expect(compressToolOutput(text)).toBe(text);
96
- });
97
-
98
- it("preserves AI reasoning about tool results", () => {
99
- const text = "The test result shows 15 passed, which means our fix works.";
100
- expect(compressToolOutput(text)).toBe(text);
101
- });
102
-
103
- // ========================================================================
104
- // Edge cases
105
- // ========================================================================
106
-
107
- it("handles empty input", () => {
108
- expect(compressToolOutput("")).toBe("");
109
- });
110
-
111
- it("handles short input", () => {
112
- expect(compressToolOutput("hi")).toBe("hi");
113
- });
114
-
115
- it("handles text without tool outputs", () => {
116
- const text = "This is a normal conversation.\nNo tool outputs here.";
117
- expect(compressToolOutput(text)).toBe(text);
118
- });
119
-
120
- // ========================================================================
121
- // Large output truncation
122
- // ========================================================================
123
-
124
- it("truncates large unmatched tool output", () => {
125
- // Use content with spaces/special chars to avoid base64 regex match
126
- const largeOutput = Array.from({ length: 150 }, (_, i) => `line ${i}: some detailed output here`).join("\n");
127
- const text = `$ some-command\n${largeOutput}\n\nNext step.`;
128
- const result = compressToolOutput(text);
129
- expect(result).toContain("[...");
130
- expect(result).toContain("chars truncated");
131
- expect(result.length).toBeLessThan(text.length);
132
- });
133
-
134
- // ========================================================================
135
- // 回归:工具输出块位于字符串结尾(原 \z 锚点 bug)
136
- // 旧实现 lookahead 末项是 \z(JS 无此锚点 → 当字面字符 z):
137
- // - 块结尾无字面 z 时整块漏匹配 → 末尾大输出逃过截断
138
- // - 块含字面 z 时惰性匹配在第一个 z 处误截断
139
- // 修复为 (?![\s\S])(字符串绝对结尾)后两种都应正确处理。
140
- // ========================================================================
141
-
142
- it("truncates a large tool output block that ends the string (no trailing marker)", () => {
143
- // 末尾块、无字母 z、后面没有下一个命令/空行大写/## → 旧 \z 实现整块漏匹配
144
- const largeOutput = Array.from({ length: 150 }, (_, i) => `line ${i}: detailed output here`).join("\n");
145
- const text = `$ some-command\n${largeOutput}`;
146
- const result = compressToolOutput(text);
147
- expect(result).toContain("chars truncated");
148
- expect(result.length).toBeLessThan(text.length);
149
- });
150
-
151
- it("does not cut a trailing tool output block at a literal 'z'", () => {
152
- // 末尾大块含字母 z → 旧 \z 实现在第一个 z 处截断匹配,导致块太短逃过截断
153
- const largeOutput = Array.from({ length: 150 }, (_, i) => `line ${i}: zebra output zone`).join("\n");
154
- const text = `$ some-command\n${largeOutput}`;
155
- const result = compressToolOutput(text);
156
- expect(result).toContain("chars truncated");
157
- // 截断尾部应保留块真正的结尾,而不是停在某个 z 之前
158
- expect(result).toContain("zone");
159
- });
160
- });
@@ -1,113 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { detectTopicTag, extractTopicTag, injectTopicTag } from "../topic-tag.js";
3
-
4
- describe("detectTopicTag", () => {
5
- it("detects auth-related content", () => {
6
- expect(detectTopicTag("Implement JWT authentication with OAuth2 flow")).toBe("auth");
7
- });
8
-
9
- it("detects deploy-related content", () => {
10
- expect(detectTopicTag("Set up CI/CD pipeline with GitHub Actions for production deployment")).toBe("deploy");
11
- });
12
-
13
- it("detects infra-related content", () => {
14
- expect(detectTopicTag("Configure Docker containers and Kubernetes cluster")).toBe("infra");
15
- });
16
-
17
- it("detects testing-related content", () => {
18
- expect(detectTopicTag("Write unit tests with bun test and add coverage for the new module")).toBe("testing");
19
- });
20
-
21
- it("detects database-related content", () => {
22
- expect(detectTopicTag("Run SQL migration to add new columns to postgres users table")).toBe("database");
23
- });
24
-
25
- it("detects api-related content", () => {
26
- expect(detectTopicTag("Design REST API endpoints for the new webhook integration")).toBe("api");
27
- });
28
-
29
- it("detects ui-related content", () => {
30
- expect(detectTopicTag("Build React component with Tailwind CSS for the dashboard layout")).toBe("ui");
31
- });
32
-
33
- it("detects performance-related content", () => {
34
- expect(detectTopicTag("Profile cache hit rates and optimize latency bottleneck")).toBe("perf");
35
- });
36
-
37
- it("detects security-related content", () => {
38
- expect(detectTopicTag("Fix XSS vulnerability and add CSRF protection")).toBe("security");
39
- });
40
-
41
- it("detects memory-related content", () => {
42
- expect(detectTopicTag("Improve recall retrieval with better embedding vectors for LanceDB")).toBe("memory");
43
- });
44
-
45
- it("detects mcp-related content", () => {
46
- expect(detectTopicTag("Register new MCP tool in the Model Context Protocol server")).toBe("mcp");
47
- });
48
-
49
- it("detects llm-related content", () => {
50
- expect(detectTopicTag("Optimize prompt engineering for better token efficiency with Claude")).toBe("llm");
51
- });
52
-
53
- it("returns undefined for generic text", () => {
54
- expect(detectTopicTag("Had a great day today")).toBeUndefined();
55
- });
56
-
57
- it("returns undefined for empty text", () => {
58
- expect(detectTopicTag("")).toBeUndefined();
59
- });
60
-
61
- it("picks strongest match when multiple topics present", () => {
62
- const tag = detectTopicTag("Deploy the authentication service to production using Docker");
63
- expect(tag).toBeDefined();
64
- // Multiple topics present; strongest wins
65
- expect(["auth", "deploy", "infra"]).toContain(tag);
66
- });
67
-
68
- it("handles Chinese text with English tech terms", () => {
69
- expect(detectTopicTag("配置 Docker 容器编排和 Kubernetes 集群")).toBe("infra");
70
- });
71
-
72
- it("truncates very long text for efficiency", () => {
73
- const longText = "Fix authentication bug. ".repeat(500);
74
- expect(detectTopicTag(longText)).toBe("auth");
75
- });
76
- });
77
-
78
- describe("extractTopicTag", () => {
79
- it("extracts topicTag from metadata JSON", () => {
80
- expect(extractTopicTag('{"topicTag":"auth","source":"manual"}')).toBe("auth");
81
- });
82
-
83
- it("returns undefined when no topicTag", () => {
84
- expect(extractTopicTag('{"source":"manual"}')).toBeUndefined();
85
- });
86
-
87
- it("returns undefined for invalid JSON", () => {
88
- expect(extractTopicTag("not json")).toBeUndefined();
89
- });
90
-
91
- it("returns undefined for undefined/null metadata", () => {
92
- expect(extractTopicTag(undefined)).toBeUndefined();
93
- expect(extractTopicTag("")).toBeUndefined();
94
- });
95
- });
96
-
97
- describe("injectTopicTag", () => {
98
- it("injects topicTag into metadata JSON", () => {
99
- const result = injectTopicTag('{"source":"manual"}', "deploy");
100
- const parsed = JSON.parse(result);
101
- expect(parsed.topicTag).toBe("deploy");
102
- expect(parsed.source).toBe("manual");
103
- });
104
-
105
- it("overwrites existing topicTag", () => {
106
- const result = injectTopicTag('{"topicTag":"old","source":"manual"}', "new");
107
- expect(JSON.parse(result).topicTag).toBe("new");
108
- });
109
-
110
- it("returns original on invalid JSON", () => {
111
- expect(injectTopicTag("broken", "tag")).toBe("broken");
112
- });
113
- });