bluera-knowledge 0.9.32 → 0.9.34

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 (196) hide show
  1. package/.claude/hooks/post-edit-check.sh +5 -3
  2. package/.claude/skills/atomic-commits/SKILL.md +3 -1
  3. package/.husky/pre-commit +3 -2
  4. package/.prettierrc +9 -0
  5. package/.versionrc.json +1 -1
  6. package/CHANGELOG.md +33 -0
  7. package/CLAUDE.md +6 -0
  8. package/README.md +25 -13
  9. package/bun.lock +277 -33
  10. package/dist/{chunk-L2YVNC63.js → chunk-6FHWC36B.js} +9 -1
  11. package/dist/chunk-6FHWC36B.js.map +1 -0
  12. package/dist/{chunk-RST4XGRL.js → chunk-DC7CGSGT.js} +288 -241
  13. package/dist/chunk-DC7CGSGT.js.map +1 -0
  14. package/dist/{chunk-6PBP5DVD.js → chunk-WFNPNAAP.js} +3212 -3054
  15. package/dist/chunk-WFNPNAAP.js.map +1 -0
  16. package/dist/{chunk-WT2DAEO7.js → chunk-Z2KKVH45.js} +548 -482
  17. package/dist/chunk-Z2KKVH45.js.map +1 -0
  18. package/dist/index.js +871 -758
  19. package/dist/index.js.map +1 -1
  20. package/dist/mcp/server.js +3 -3
  21. package/dist/watch.service-BJV3TI3F.js +7 -0
  22. package/dist/workers/background-worker-cli.js +46 -45
  23. package/dist/workers/background-worker-cli.js.map +1 -1
  24. package/eslint.config.js +43 -1
  25. package/package.json +18 -11
  26. package/plugin.json +8 -0
  27. package/python/requirements.txt +1 -1
  28. package/src/analysis/ast-parser.test.ts +12 -11
  29. package/src/analysis/ast-parser.ts +28 -22
  30. package/src/analysis/code-graph.test.ts +52 -62
  31. package/src/analysis/code-graph.ts +9 -13
  32. package/src/analysis/dependency-usage-analyzer.test.ts +91 -271
  33. package/src/analysis/dependency-usage-analyzer.ts +52 -24
  34. package/src/analysis/go-ast-parser.test.ts +22 -22
  35. package/src/analysis/go-ast-parser.ts +18 -25
  36. package/src/analysis/parser-factory.test.ts +9 -9
  37. package/src/analysis/parser-factory.ts +3 -3
  38. package/src/analysis/python-ast-parser.test.ts +27 -27
  39. package/src/analysis/python-ast-parser.ts +2 -2
  40. package/src/analysis/repo-url-resolver.test.ts +82 -82
  41. package/src/analysis/rust-ast-parser.test.ts +19 -19
  42. package/src/analysis/rust-ast-parser.ts +17 -27
  43. package/src/analysis/tree-sitter-parser.test.ts +3 -3
  44. package/src/analysis/tree-sitter-parser.ts +10 -16
  45. package/src/cli/commands/crawl.test.ts +40 -24
  46. package/src/cli/commands/crawl.ts +186 -166
  47. package/src/cli/commands/index-cmd.test.ts +90 -90
  48. package/src/cli/commands/index-cmd.ts +52 -36
  49. package/src/cli/commands/mcp.test.ts +6 -6
  50. package/src/cli/commands/mcp.ts +2 -2
  51. package/src/cli/commands/plugin-api.test.ts +16 -18
  52. package/src/cli/commands/plugin-api.ts +9 -6
  53. package/src/cli/commands/search.test.ts +16 -7
  54. package/src/cli/commands/search.ts +124 -87
  55. package/src/cli/commands/serve.test.ts +67 -25
  56. package/src/cli/commands/serve.ts +18 -3
  57. package/src/cli/commands/setup.test.ts +176 -101
  58. package/src/cli/commands/setup.ts +140 -117
  59. package/src/cli/commands/store.test.ts +82 -53
  60. package/src/cli/commands/store.ts +56 -37
  61. package/src/cli/program.ts +2 -2
  62. package/src/crawl/article-converter.test.ts +4 -1
  63. package/src/crawl/article-converter.ts +46 -31
  64. package/src/crawl/bridge.test.ts +240 -132
  65. package/src/crawl/bridge.ts +87 -30
  66. package/src/crawl/claude-client.test.ts +124 -56
  67. package/src/crawl/claude-client.ts +7 -15
  68. package/src/crawl/intelligent-crawler.test.ts +65 -22
  69. package/src/crawl/intelligent-crawler.ts +86 -53
  70. package/src/crawl/markdown-utils.ts +1 -4
  71. package/src/db/embeddings.ts +4 -6
  72. package/src/db/lance.test.ts +4 -4
  73. package/src/db/lance.ts +16 -12
  74. package/src/index.ts +26 -17
  75. package/src/logging/index.ts +1 -5
  76. package/src/logging/logger.ts +3 -5
  77. package/src/logging/payload.test.ts +1 -1
  78. package/src/logging/payload.ts +3 -5
  79. package/src/mcp/commands/index.ts +2 -2
  80. package/src/mcp/commands/job.commands.ts +12 -18
  81. package/src/mcp/commands/meta.commands.ts +13 -13
  82. package/src/mcp/commands/registry.ts +5 -8
  83. package/src/mcp/commands/store.commands.ts +19 -19
  84. package/src/mcp/handlers/execute.handler.test.ts +10 -10
  85. package/src/mcp/handlers/execute.handler.ts +4 -5
  86. package/src/mcp/handlers/index.ts +10 -14
  87. package/src/mcp/handlers/job.handler.test.ts +10 -10
  88. package/src/mcp/handlers/job.handler.ts +22 -25
  89. package/src/mcp/handlers/search.handler.test.ts +36 -65
  90. package/src/mcp/handlers/search.handler.ts +135 -104
  91. package/src/mcp/handlers/store.handler.test.ts +41 -52
  92. package/src/mcp/handlers/store.handler.ts +108 -88
  93. package/src/mcp/schemas/index.test.ts +73 -68
  94. package/src/mcp/schemas/index.ts +18 -12
  95. package/src/mcp/server.test.ts +1 -1
  96. package/src/mcp/server.ts +59 -46
  97. package/src/plugin/commands.test.ts +230 -95
  98. package/src/plugin/commands.ts +24 -25
  99. package/src/plugin/dependency-analyzer.test.ts +52 -52
  100. package/src/plugin/dependency-analyzer.ts +85 -22
  101. package/src/plugin/git-clone.test.ts +24 -13
  102. package/src/plugin/git-clone.ts +3 -7
  103. package/src/server/app.test.ts +109 -109
  104. package/src/server/app.ts +32 -23
  105. package/src/server/index.test.ts +64 -66
  106. package/src/services/chunking.service.test.ts +32 -32
  107. package/src/services/chunking.service.ts +16 -9
  108. package/src/services/code-graph.service.test.ts +30 -36
  109. package/src/services/code-graph.service.ts +24 -10
  110. package/src/services/code-unit.service.test.ts +55 -11
  111. package/src/services/code-unit.service.ts +85 -11
  112. package/src/services/config.service.test.ts +37 -18
  113. package/src/services/config.service.ts +30 -7
  114. package/src/services/index.service.test.ts +49 -18
  115. package/src/services/index.service.ts +98 -48
  116. package/src/services/index.ts +6 -9
  117. package/src/services/job.service.test.ts +22 -22
  118. package/src/services/job.service.ts +18 -18
  119. package/src/services/project-root.service.test.ts +1 -3
  120. package/src/services/search.service.test.ts +248 -120
  121. package/src/services/search.service.ts +286 -156
  122. package/src/services/services.test.ts +1 -1
  123. package/src/services/snippet.service.test.ts +14 -6
  124. package/src/services/snippet.service.ts +7 -5
  125. package/src/services/store.service.test.ts +68 -29
  126. package/src/services/store.service.ts +41 -12
  127. package/src/services/watch.service.test.ts +34 -14
  128. package/src/services/watch.service.ts +11 -1
  129. package/src/types/brands.test.ts +3 -1
  130. package/src/types/index.ts +2 -13
  131. package/src/types/search.ts +10 -8
  132. package/src/utils/type-guards.test.ts +20 -15
  133. package/src/utils/type-guards.ts +1 -1
  134. package/src/workers/background-worker-cli.ts +2 -2
  135. package/src/workers/background-worker.test.ts +54 -40
  136. package/src/workers/background-worker.ts +76 -60
  137. package/src/workers/spawn-worker.test.ts +22 -10
  138. package/src/workers/spawn-worker.ts +6 -6
  139. package/tests/analysis/ast-parser.test.ts +3 -3
  140. package/tests/analysis/code-graph.test.ts +5 -5
  141. package/tests/fixtures/code-snippets/api/error-handling.ts +4 -15
  142. package/tests/fixtures/code-snippets/api/rest-controller.ts +3 -9
  143. package/tests/fixtures/code-snippets/auth/jwt-auth.ts +5 -21
  144. package/tests/fixtures/code-snippets/auth/oauth-flow.ts +4 -4
  145. package/tests/fixtures/code-snippets/database/repository-pattern.ts +11 -3
  146. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/handler.ts +2 -2
  147. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/handler.ts +1 -1
  148. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static.ts +2 -2
  149. package/tests/fixtures/corpus/oss-repos/hono/src/client/client.ts +2 -2
  150. package/tests/fixtures/corpus/oss-repos/hono/src/client/types.ts +22 -20
  151. package/tests/fixtures/corpus/oss-repos/hono/src/context.ts +13 -10
  152. package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/accepts.ts +10 -7
  153. package/tests/fixtures/corpus/oss-repos/hono/src/helper/adapter/index.ts +2 -2
  154. package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/index.ts +1 -1
  155. package/tests/fixtures/corpus/oss-repos/hono/src/helper/factory/index.ts +16 -16
  156. package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/ssg.ts +2 -2
  157. package/tests/fixtures/corpus/oss-repos/hono/src/hono-base.ts +3 -3
  158. package/tests/fixtures/corpus/oss-repos/hono/src/hono.ts +1 -1
  159. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/css.ts +2 -2
  160. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/intrinsic-element/components.ts +1 -1
  161. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/render.ts +7 -7
  162. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/hooks/index.ts +3 -3
  163. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/components.ts +1 -1
  164. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/utils.ts +6 -6
  165. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jsx-renderer/index.ts +3 -3
  166. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/serve-static/index.ts +1 -1
  167. package/tests/fixtures/corpus/oss-repos/hono/src/preset/quick.ts +1 -1
  168. package/tests/fixtures/corpus/oss-repos/hono/src/preset/tiny.ts +1 -1
  169. package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/router.ts +2 -2
  170. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/node.ts +4 -4
  171. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/router.ts +1 -1
  172. package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/node.ts +1 -1
  173. package/tests/fixtures/corpus/oss-repos/hono/src/types.ts +166 -169
  174. package/tests/fixtures/corpus/oss-repos/hono/src/utils/body.ts +8 -8
  175. package/tests/fixtures/corpus/oss-repos/hono/src/utils/color.ts +3 -3
  176. package/tests/fixtures/corpus/oss-repos/hono/src/utils/cookie.ts +2 -2
  177. package/tests/fixtures/corpus/oss-repos/hono/src/utils/encode.ts +2 -2
  178. package/tests/fixtures/corpus/oss-repos/hono/src/utils/types.ts +30 -33
  179. package/tests/fixtures/corpus/oss-repos/hono/src/validator/validator.ts +2 -2
  180. package/tests/fixtures/test-server.ts +3 -2
  181. package/tests/helpers/performance-metrics.ts +8 -25
  182. package/tests/helpers/search-relevance.ts +14 -69
  183. package/tests/integration/cli-consistency.test.ts +5 -4
  184. package/tests/integration/python-bridge.test.ts +13 -3
  185. package/tests/mcp/server.test.ts +1 -1
  186. package/tests/services/code-unit.service.test.ts +48 -0
  187. package/tests/services/job.service.test.ts +124 -0
  188. package/tests/services/search.progressive-context.test.ts +2 -2
  189. package/.claude-plugin/plugin.json +0 -13
  190. package/dist/chunk-6PBP5DVD.js.map +0 -1
  191. package/dist/chunk-L2YVNC63.js.map +0 -1
  192. package/dist/chunk-RST4XGRL.js.map +0 -1
  193. package/dist/chunk-WT2DAEO7.js.map +0 -1
  194. package/dist/watch.service-YAIKKDCF.js +0 -7
  195. package/skills/atomic-commits/SKILL.md +0 -77
  196. /package/dist/{watch.service-YAIKKDCF.js.map → watch.service-BJV3TI3F.js.map} +0 -0
@@ -117,13 +117,33 @@ describe('SearchService - RRF Ranking Algorithm', () => {
117
117
 
118
118
  it('combines vector and FTS results with RRF', async () => {
119
119
  const vectorResults = [
120
- { id: createDocumentId('doc1'), score: 0.9, content: 'result 1', metadata: { type: 'file' as const, storeId, indexedAt: new Date() } },
121
- { id: createDocumentId('doc2'), score: 0.8, content: 'result 2', metadata: { type: 'file' as const, storeId, indexedAt: new Date() } },
120
+ {
121
+ id: createDocumentId('doc1'),
122
+ score: 0.9,
123
+ content: 'result 1',
124
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
125
+ },
126
+ {
127
+ id: createDocumentId('doc2'),
128
+ score: 0.8,
129
+ content: 'result 2',
130
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
131
+ },
122
132
  ];
123
133
 
124
134
  const ftsResults = [
125
- { id: createDocumentId('doc2'), score: 0.95, content: 'result 2', metadata: { type: 'file' as const, storeId, indexedAt: new Date() } },
126
- { id: createDocumentId('doc3'), score: 0.85, content: 'result 3', metadata: { type: 'file' as const, storeId, indexedAt: new Date() } },
135
+ {
136
+ id: createDocumentId('doc2'),
137
+ score: 0.95,
138
+ content: 'result 2',
139
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
140
+ },
141
+ {
142
+ id: createDocumentId('doc3'),
143
+ score: 0.85,
144
+ content: 'result 3',
145
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
146
+ },
127
147
  ];
128
148
 
129
149
  vi.mocked(mockLanceStore.search).mockResolvedValue(vectorResults);
@@ -138,16 +158,36 @@ describe('SearchService - RRF Ranking Algorithm', () => {
138
158
 
139
159
  expect(results.results.length).toBeGreaterThan(0);
140
160
  // doc2 should rank higher as it appears in both results
141
- expect(results.results.some(r => r.id === createDocumentId('doc2'))).toBe(true);
161
+ expect(results.results.some((r) => r.id === createDocumentId('doc2'))).toBe(true);
142
162
  });
143
163
 
144
164
  it('uses web RRF preset for web content (url metadata)', async () => {
145
165
  // Web content has url in metadata - should use web preset (k=30)
146
166
  vi.mocked(mockLanceStore.search).mockResolvedValue([
147
- { id: createDocumentId('doc1'), score: 0.9, content: 'result 1', metadata: { type: 'web' as const, storeId, indexedAt: new Date(), url: 'https://example.com/docs' } },
167
+ {
168
+ id: createDocumentId('doc1'),
169
+ score: 0.9,
170
+ content: 'result 1',
171
+ metadata: {
172
+ type: 'web' as const,
173
+ storeId,
174
+ indexedAt: new Date(),
175
+ url: 'https://example.com/docs',
176
+ },
177
+ },
148
178
  ]);
149
179
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([
150
- { id: createDocumentId('doc1'), score: 0.95, content: 'result 1', metadata: { type: 'web' as const, storeId, indexedAt: new Date(), url: 'https://example.com/docs' } },
180
+ {
181
+ id: createDocumentId('doc1'),
182
+ score: 0.95,
183
+ content: 'result 1',
184
+ metadata: {
185
+ type: 'web' as const,
186
+ storeId,
187
+ indexedAt: new Date(),
188
+ url: 'https://example.com/docs',
189
+ },
190
+ },
151
191
  ]);
152
192
 
153
193
  const results = await searchService.search({
@@ -164,10 +204,25 @@ describe('SearchService - RRF Ranking Algorithm', () => {
164
204
  it('uses code RRF preset for file content (path metadata)', async () => {
165
205
  // File content has path, no url - should use code preset (k=20)
166
206
  vi.mocked(mockLanceStore.search).mockResolvedValue([
167
- { id: createDocumentId('doc1'), score: 0.9, content: 'function test() {}', metadata: { type: 'file' as const, storeId, indexedAt: new Date(), path: '/src/test.ts' } },
207
+ {
208
+ id: createDocumentId('doc1'),
209
+ score: 0.9,
210
+ content: 'function test() {}',
211
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date(), path: '/src/test.ts' },
212
+ },
168
213
  ]);
169
214
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([
170
- { id: createDocumentId('doc2'), score: 0.95, content: 'class Example {}', metadata: { type: 'file' as const, storeId, indexedAt: new Date(), path: '/src/example.ts' } },
215
+ {
216
+ id: createDocumentId('doc2'),
217
+ score: 0.95,
218
+ content: 'class Example {}',
219
+ metadata: {
220
+ type: 'file' as const,
221
+ storeId,
222
+ indexedAt: new Date(),
223
+ path: '/src/example.ts',
224
+ },
225
+ },
171
226
  ]);
172
227
 
173
228
  const results = await searchService.search({
@@ -182,7 +237,12 @@ describe('SearchService - RRF Ranking Algorithm', () => {
182
237
 
183
238
  it('handles documents appearing only in vector results', async () => {
184
239
  vi.mocked(mockLanceStore.search).mockResolvedValue([
185
- { id: createDocumentId('doc1'), score: 0.9, content: 'vector only', metadata: { type: 'file' as const, storeId, indexedAt: new Date() } },
240
+ {
241
+ id: createDocumentId('doc1'),
242
+ score: 0.9,
243
+ content: 'vector only',
244
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
245
+ },
186
246
  ]);
187
247
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
188
248
 
@@ -200,7 +260,12 @@ describe('SearchService - RRF Ranking Algorithm', () => {
200
260
  it('handles documents appearing only in FTS results', async () => {
201
261
  vi.mocked(mockLanceStore.search).mockResolvedValue([]);
202
262
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([
203
- { id: createDocumentId('doc1'), score: 0.9, content: 'fts only', metadata: { type: 'file' as const, storeId, indexedAt: new Date() } },
263
+ {
264
+ id: createDocumentId('doc1'),
265
+ score: 0.9,
266
+ content: 'fts only',
267
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
268
+ },
204
269
  ]);
205
270
 
206
271
  const results = await searchService.search({
@@ -216,11 +281,26 @@ describe('SearchService - RRF Ranking Algorithm', () => {
216
281
 
217
282
  it('normalizes scores to 0-1 range', async () => {
218
283
  vi.mocked(mockLanceStore.search).mockResolvedValue([
219
- { id: createDocumentId('doc1'), score: 0.9, content: 'result 1', metadata: { type: 'file' as const, storeId, indexedAt: new Date() } },
220
- { id: createDocumentId('doc2'), score: 0.5, content: 'result 2', metadata: { type: 'file' as const, storeId, indexedAt: new Date() } },
284
+ {
285
+ id: createDocumentId('doc1'),
286
+ score: 0.9,
287
+ content: 'result 1',
288
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
289
+ },
290
+ {
291
+ id: createDocumentId('doc2'),
292
+ score: 0.5,
293
+ content: 'result 2',
294
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
295
+ },
221
296
  ]);
222
297
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([
223
- { id: createDocumentId('doc1'), score: 0.95, content: 'result 1', metadata: { type: 'file' as const, storeId, indexedAt: new Date() } },
298
+ {
299
+ id: createDocumentId('doc1'),
300
+ score: 0.95,
301
+ content: 'result 1',
302
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
303
+ },
224
304
  ]);
225
305
 
226
306
  const results = await searchService.search({
@@ -231,7 +311,7 @@ describe('SearchService - RRF Ranking Algorithm', () => {
231
311
  });
232
312
 
233
313
  // Scores should be normalized
234
- results.results.forEach(r => {
314
+ results.results.forEach((r) => {
235
315
  expect(r.score).toBeGreaterThanOrEqual(0);
236
316
  expect(r.score).toBeLessThanOrEqual(1);
237
317
  });
@@ -239,8 +319,18 @@ describe('SearchService - RRF Ranking Algorithm', () => {
239
319
 
240
320
  it('handles identical scores correctly', async () => {
241
321
  vi.mocked(mockLanceStore.search).mockResolvedValue([
242
- { id: createDocumentId('doc1'), score: 0.9, content: 'result 1', metadata: { type: 'file' as const, storeId, indexedAt: new Date() } },
243
- { id: createDocumentId('doc2'), score: 0.9, content: 'result 2', metadata: { type: 'file' as const, storeId, indexedAt: new Date() } },
322
+ {
323
+ id: createDocumentId('doc1'),
324
+ score: 0.9,
325
+ content: 'result 1',
326
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
327
+ },
328
+ {
329
+ id: createDocumentId('doc2'),
330
+ score: 0.9,
331
+ content: 'result 2',
332
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
333
+ },
244
334
  ]);
245
335
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
246
336
 
@@ -294,8 +384,8 @@ describe('SearchService - Query Intent Classification', () => {
294
384
  type: 'file' as const,
295
385
  storeId,
296
386
  indexedAt: new Date(),
297
- fileType: 'example'
298
- }
387
+ fileType: 'example',
388
+ },
299
389
  },
300
390
  ]);
301
391
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -330,8 +420,8 @@ describe('SearchService - Query Intent Classification', () => {
330
420
  type: 'file' as const,
331
421
  storeId,
332
422
  indexedAt: new Date(),
333
- fileType: 'source-internal'
334
- }
423
+ fileType: 'source-internal',
424
+ },
335
425
  },
336
426
  ]);
337
427
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -365,8 +455,8 @@ describe('SearchService - Query Intent Classification', () => {
365
455
  type: 'file' as const,
366
456
  storeId,
367
457
  indexedAt: new Date(),
368
- fileType: 'documentation'
369
- }
458
+ fileType: 'documentation',
459
+ },
370
460
  },
371
461
  ]);
372
462
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -400,8 +490,8 @@ describe('SearchService - Query Intent Classification', () => {
400
490
  type: 'file' as const,
401
491
  storeId,
402
492
  indexedAt: new Date(),
403
- fileType: 'documentation-primary'
404
- }
493
+ fileType: 'documentation-primary',
494
+ },
405
495
  },
406
496
  ]);
407
497
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -435,8 +525,8 @@ describe('SearchService - Query Intent Classification', () => {
435
525
  type: 'file' as const,
436
526
  storeId,
437
527
  indexedAt: new Date(),
438
- fileType: 'test'
439
- }
528
+ fileType: 'test',
529
+ },
440
530
  },
441
531
  ]);
442
532
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -462,8 +552,8 @@ describe('SearchService - Query Intent Classification', () => {
462
552
  type: 'file' as const,
463
553
  storeId,
464
554
  indexedAt: new Date(),
465
- fileType: 'documentation'
466
- }
555
+ fileType: 'documentation',
556
+ },
467
557
  },
468
558
  ]);
469
559
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -508,8 +598,8 @@ describe('SearchService - Framework Context Boosting', () => {
508
598
  type: 'file' as const,
509
599
  storeId,
510
600
  indexedAt: new Date(),
511
- path: '/docs/react/components.md'
512
- }
601
+ path: '/docs/react/components.md',
602
+ },
513
603
  },
514
604
  {
515
605
  id: createDocumentId('vue-doc'),
@@ -519,8 +609,8 @@ describe('SearchService - Framework Context Boosting', () => {
519
609
  type: 'file' as const,
520
610
  storeId,
521
611
  indexedAt: new Date(),
522
- path: '/docs/vue/components.md'
523
- }
612
+ path: '/docs/vue/components.md',
613
+ },
524
614
  },
525
615
  ]);
526
616
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -546,8 +636,8 @@ describe('SearchService - Framework Context Boosting', () => {
546
636
  type: 'file' as const,
547
637
  storeId,
548
638
  indexedAt: new Date(),
549
- path: '/node_modules/express/README.md'
550
- }
639
+ path: '/node_modules/express/README.md',
640
+ },
551
641
  },
552
642
  ]);
553
643
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -572,8 +662,8 @@ describe('SearchService - Framework Context Boosting', () => {
572
662
  type: 'file' as const,
573
663
  storeId,
574
664
  indexedAt: new Date(),
575
- path: '/docs/vue3/api.md'
576
- }
665
+ path: '/docs/vue3/api.md',
666
+ },
577
667
  },
578
668
  ]);
579
669
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -598,8 +688,8 @@ describe('SearchService - Framework Context Boosting', () => {
598
688
  type: 'file' as const,
599
689
  storeId,
600
690
  indexedAt: new Date(),
601
- path: '/docs/typescript/generics.md'
602
- }
691
+ path: '/docs/typescript/generics.md',
692
+ },
603
693
  },
604
694
  ]);
605
695
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -624,8 +714,8 @@ describe('SearchService - Framework Context Boosting', () => {
624
714
  type: 'file' as const,
625
715
  storeId,
626
716
  indexedAt: new Date(),
627
- path: '/docs/general.md'
628
- }
717
+ path: '/docs/general.md',
718
+ },
629
719
  },
630
720
  ]);
631
721
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -672,8 +762,8 @@ describe('SearchService - Deduplication Logic', () => {
672
762
  indexedAt: new Date(),
673
763
  path: '/src/file.ts',
674
764
  chunkIndex: 0,
675
- totalChunks: 2
676
- }
765
+ totalChunks: 2,
766
+ },
677
767
  },
678
768
  {
679
769
  id: createDocumentId('chunk2'),
@@ -685,8 +775,8 @@ describe('SearchService - Deduplication Logic', () => {
685
775
  indexedAt: new Date(),
686
776
  path: '/src/file.ts',
687
777
  chunkIndex: 1,
688
- totalChunks: 2
689
- }
778
+ totalChunks: 2,
779
+ },
690
780
  },
691
781
  ]);
692
782
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -714,8 +804,8 @@ describe('SearchService - Deduplication Logic', () => {
714
804
  indexedAt: new Date(),
715
805
  path: '/src/file.ts',
716
806
  chunkIndex: 0,
717
- totalChunks: 2
718
- }
807
+ totalChunks: 2,
808
+ },
719
809
  },
720
810
  {
721
811
  id: createDocumentId('chunk2'),
@@ -727,8 +817,8 @@ describe('SearchService - Deduplication Logic', () => {
727
817
  indexedAt: new Date(),
728
818
  path: '/src/file.ts',
729
819
  chunkIndex: 1,
730
- totalChunks: 2
731
- }
820
+ totalChunks: 2,
821
+ },
732
822
  },
733
823
  ]);
734
824
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -754,8 +844,8 @@ describe('SearchService - Deduplication Logic', () => {
754
844
  type: 'file' as const,
755
845
  storeId,
756
846
  indexedAt: new Date(),
757
- path: '/src/file1.ts'
758
- }
847
+ path: '/src/file1.ts',
848
+ },
759
849
  },
760
850
  {
761
851
  id: createDocumentId('file2'),
@@ -765,8 +855,8 @@ describe('SearchService - Deduplication Logic', () => {
765
855
  type: 'file' as const,
766
856
  storeId,
767
857
  indexedAt: new Date(),
768
- path: '/src/file2.ts'
769
- }
858
+ path: '/src/file2.ts',
859
+ },
770
860
  },
771
861
  ]);
772
862
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -812,8 +902,8 @@ describe('SearchService - Progressive Context Enhancement', () => {
812
902
  type: 'file' as const,
813
903
  storeId,
814
904
  indexedAt: new Date(),
815
- path: '/src/example.ts'
816
- }
905
+ path: '/src/example.ts',
906
+ },
817
907
  },
818
908
  ]);
819
909
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -841,8 +931,8 @@ describe('SearchService - Progressive Context Enhancement', () => {
841
931
  type: 'file' as const,
842
932
  storeId,
843
933
  indexedAt: new Date(),
844
- path: '/src/Component.tsx'
845
- }
934
+ path: '/src/Component.tsx',
935
+ },
846
936
  },
847
937
  ]);
848
938
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -872,8 +962,8 @@ describe('SearchService - Progressive Context Enhancement', () => {
872
962
  type: 'file' as const,
873
963
  storeId,
874
964
  indexedAt: new Date(),
875
- path: '/src/example.ts'
876
- }
965
+ path: '/src/example.ts',
966
+ },
877
967
  },
878
968
  ]);
879
969
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -903,8 +993,8 @@ describe('SearchService - Progressive Context Enhancement', () => {
903
993
  type: 'file' as const,
904
994
  storeId,
905
995
  indexedAt: new Date(),
906
- path: '/src/api.ts'
907
- }
996
+ path: '/src/api.ts',
997
+ },
908
998
  },
909
999
  ]);
910
1000
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -929,8 +1019,8 @@ describe('SearchService - Progressive Context Enhancement', () => {
929
1019
  type: 'file' as const,
930
1020
  storeId,
931
1021
  indexedAt: new Date(),
932
- path: '/src/Component.ts'
933
- }
1022
+ path: '/src/Component.ts',
1023
+ },
934
1024
  },
935
1025
  ]);
936
1026
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1003,8 +1093,8 @@ describe('SearchService - Edge Cases', () => {
1003
1093
  type: 'file' as const,
1004
1094
  storeId,
1005
1095
  indexedAt: new Date(),
1006
- path: `/src/file${i}.ts`
1007
- }
1096
+ path: `/src/file${i}.ts`,
1097
+ },
1008
1098
  }));
1009
1099
 
1010
1100
  vi.mocked(mockLanceStore.search).mockResolvedValue(manyResults);
@@ -1026,19 +1116,23 @@ describe('SearchService - Edge Cases', () => {
1026
1116
 
1027
1117
  vi.mocked(mockLanceStore.search).mockImplementation(async (storeId) => {
1028
1118
  if (storeId === store1) {
1029
- return [{
1030
- id: createDocumentId('doc1'),
1031
- score: 0.9,
1032
- content: 'from store 1',
1033
- metadata: { type: 'file' as const, storeId: store1, indexedAt: new Date() }
1034
- }];
1119
+ return [
1120
+ {
1121
+ id: createDocumentId('doc1'),
1122
+ score: 0.9,
1123
+ content: 'from store 1',
1124
+ metadata: { type: 'file' as const, storeId: store1, indexedAt: new Date() },
1125
+ },
1126
+ ];
1035
1127
  }
1036
- return [{
1037
- id: createDocumentId('doc2'),
1038
- score: 0.8,
1039
- content: 'from store 2',
1040
- metadata: { type: 'file' as const, storeId: store2, indexedAt: new Date() }
1041
- }];
1128
+ return [
1129
+ {
1130
+ id: createDocumentId('doc2'),
1131
+ score: 0.8,
1132
+ content: 'from store 2',
1133
+ metadata: { type: 'file' as const, storeId: store2, indexedAt: new Date() },
1134
+ },
1135
+ ];
1042
1136
  });
1043
1137
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
1044
1138
 
@@ -1072,7 +1166,7 @@ describe('SearchService - Edge Cases', () => {
1072
1166
  id: createDocumentId('doc1'),
1073
1167
  score: 0.95,
1074
1168
  content: 'high score',
1075
- metadata: { type: 'file' as const, storeId, indexedAt: new Date() }
1169
+ metadata: { type: 'file' as const, storeId, indexedAt: new Date() },
1076
1170
  },
1077
1171
  ]);
1078
1172
 
@@ -1123,8 +1217,8 @@ describe('SearchService - Path Keyword Boosting', () => {
1123
1217
  type: 'file' as const,
1124
1218
  storeId,
1125
1219
  indexedAt: new Date(),
1126
- path: '/src/utils/helpers.py'
1127
- }
1220
+ path: '/src/utils/helpers.py',
1221
+ },
1128
1222
  },
1129
1223
  {
1130
1224
  id: createDocumentId('dispatcher-file'),
@@ -1134,8 +1228,8 @@ describe('SearchService - Path Keyword Boosting', () => {
1134
1228
  type: 'file' as const,
1135
1229
  storeId,
1136
1230
  indexedAt: new Date(),
1137
- path: '/src/async_dispatcher.py'
1138
- }
1231
+ path: '/src/async_dispatcher.py',
1232
+ },
1139
1233
  },
1140
1234
  ]);
1141
1235
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1161,8 +1255,8 @@ describe('SearchService - Path Keyword Boosting', () => {
1161
1255
  type: 'file' as const,
1162
1256
  storeId,
1163
1257
  indexedAt: new Date(),
1164
- path: '/src/crawler.py'
1165
- }
1258
+ path: '/src/crawler.py',
1259
+ },
1166
1260
  },
1167
1261
  {
1168
1262
  id: createDocumentId('double-match'),
@@ -1172,8 +1266,8 @@ describe('SearchService - Path Keyword Boosting', () => {
1172
1266
  type: 'file' as const,
1173
1267
  storeId,
1174
1268
  indexedAt: new Date(),
1175
- path: '/src/deep_crawling/crawler.py'
1176
- }
1269
+ path: '/src/deep_crawling/crawler.py',
1270
+ },
1177
1271
  },
1178
1272
  ]);
1179
1273
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1199,8 +1293,8 @@ describe('SearchService - Path Keyword Boosting', () => {
1199
1293
  type: 'file' as const,
1200
1294
  storeId,
1201
1295
  indexedAt: new Date(),
1202
- path: '/src/config.ts'
1203
- }
1296
+ path: '/src/config.ts',
1297
+ },
1204
1298
  },
1205
1299
  ]);
1206
1300
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1226,8 +1320,8 @@ describe('SearchService - Path Keyword Boosting', () => {
1226
1320
  type: 'file' as const,
1227
1321
  storeId,
1228
1322
  indexedAt: new Date(),
1229
- path: '/src/utils/helpers.ts'
1230
- }
1323
+ path: '/src/utils/helpers.ts',
1324
+ },
1231
1325
  },
1232
1326
  ]);
1233
1327
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1293,8 +1387,8 @@ describe('SearchService - Code Graph Integration', () => {
1293
1387
  type: 'file' as const,
1294
1388
  storeId,
1295
1389
  indexedAt: new Date(),
1296
- path: '/src/utils.ts'
1297
- }
1390
+ path: '/src/utils.ts',
1391
+ },
1298
1392
  },
1299
1393
  ]);
1300
1394
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1336,8 +1430,8 @@ describe('SearchService - Code Graph Integration', () => {
1336
1430
  type: 'file' as const,
1337
1431
  storeId,
1338
1432
  indexedAt: new Date(),
1339
- path: '/src/readme.md'
1340
- }
1433
+ path: '/src/readme.md',
1434
+ },
1341
1435
  },
1342
1436
  ]);
1343
1437
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1377,8 +1471,8 @@ describe('SearchService - Code Graph Integration', () => {
1377
1471
  type: 'file' as const,
1378
1472
  storeId,
1379
1473
  indexedAt: new Date(),
1380
- path: '/src/empty.ts'
1381
- }
1474
+ path: '/src/empty.ts',
1475
+ },
1382
1476
  },
1383
1477
  ]);
1384
1478
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1400,11 +1494,26 @@ describe('SearchService - Code Graph Integration', () => {
1400
1494
  getCalledByCount: vi.fn().mockReturnValue(2),
1401
1495
  getCallsCount: vi.fn().mockReturnValue(1),
1402
1496
  getIncomingEdges: vi.fn().mockReturnValue([
1403
- { from: '/src/caller.ts:callerFunction', to: '/src/utils.ts:myFunction', type: 'calls', confidence: 0.8 },
1404
- { from: '/src/main.ts:init', to: '/src/utils.ts:myFunction', type: 'calls', confidence: 0.9 },
1497
+ {
1498
+ from: '/src/caller.ts:callerFunction',
1499
+ to: '/src/utils.ts:myFunction',
1500
+ type: 'calls',
1501
+ confidence: 0.8,
1502
+ },
1503
+ {
1504
+ from: '/src/main.ts:init',
1505
+ to: '/src/utils.ts:myFunction',
1506
+ type: 'calls',
1507
+ confidence: 0.9,
1508
+ },
1405
1509
  ]),
1406
1510
  getEdges: vi.fn().mockReturnValue([
1407
- { from: '/src/utils.ts:myFunction', to: '/src/helper.ts:helperFn', type: 'calls', confidence: 0.8 },
1511
+ {
1512
+ from: '/src/utils.ts:myFunction',
1513
+ to: '/src/helper.ts:helperFn',
1514
+ type: 'calls',
1515
+ confidence: 0.8,
1516
+ },
1408
1517
  ]),
1409
1518
  };
1410
1519
 
@@ -1414,13 +1523,14 @@ describe('SearchService - Code Graph Integration', () => {
1414
1523
  {
1415
1524
  id: createDocumentId('doc1'),
1416
1525
  score: 0.9,
1417
- content: '/** My function does stuff */\nexport function myFunction() { return helperFn(); }',
1526
+ content:
1527
+ '/** My function does stuff */\nexport function myFunction() { return helperFn(); }',
1418
1528
  metadata: {
1419
1529
  type: 'file' as const,
1420
1530
  storeId,
1421
1531
  indexedAt: new Date(),
1422
- path: '/src/utils.ts'
1423
- }
1532
+ path: '/src/utils.ts',
1533
+ },
1424
1534
  },
1425
1535
  ]);
1426
1536
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1439,13 +1549,19 @@ describe('SearchService - Code Graph Integration', () => {
1439
1549
  expect(results.results[0]?.full?.relatedCode?.length).toBe(3);
1440
1550
 
1441
1551
  // Check incoming (callers)
1442
- const callers = results.results[0]?.full?.relatedCode?.filter(r => r.relationship === 'calls this');
1552
+ const callers = results.results[0]?.full?.relatedCode?.filter(
1553
+ (r) => r.relationship === 'calls this'
1554
+ );
1443
1555
  expect(callers?.length).toBe(2);
1444
- expect(callers?.some(c => c.file === '/src/caller.ts' && c.summary === 'callerFunction()')).toBe(true);
1445
- expect(callers?.some(c => c.file === '/src/main.ts' && c.summary === 'init()')).toBe(true);
1556
+ expect(
1557
+ callers?.some((c) => c.file === '/src/caller.ts' && c.summary === 'callerFunction()')
1558
+ ).toBe(true);
1559
+ expect(callers?.some((c) => c.file === '/src/main.ts' && c.summary === 'init()')).toBe(true);
1446
1560
 
1447
1561
  // Check outgoing (callees)
1448
- const callees = results.results[0]?.full?.relatedCode?.filter(r => r.relationship === 'called by this');
1562
+ const callees = results.results[0]?.full?.relatedCode?.filter(
1563
+ (r) => r.relationship === 'called by this'
1564
+ );
1449
1565
  expect(callees?.length).toBe(1);
1450
1566
  expect(callees?.[0]?.file).toBe('/src/helper.ts');
1451
1567
  expect(callees?.[0]?.summary).toBe('helperFn()');
@@ -1470,8 +1586,8 @@ describe('SearchService - Code Graph Integration', () => {
1470
1586
  type: 'file' as const,
1471
1587
  storeId,
1472
1588
  indexedAt: new Date(),
1473
- path: '/src/notes.txt'
1474
- }
1589
+ path: '/src/notes.txt',
1590
+ },
1475
1591
  },
1476
1592
  ]);
1477
1593
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1496,10 +1612,20 @@ describe('SearchService - Code Graph Integration', () => {
1496
1612
  getCalledByCount: vi.fn().mockReturnValue(0),
1497
1613
  getCallsCount: vi.fn().mockReturnValue(0),
1498
1614
  getIncomingEdges: vi.fn().mockReturnValue([
1499
- { from: '/src/index.ts', to: '/src/utils.ts:myFunction', type: 'imports', confidence: 1.0 },
1615
+ {
1616
+ from: '/src/index.ts',
1617
+ to: '/src/utils.ts:myFunction',
1618
+ type: 'imports',
1619
+ confidence: 1.0,
1620
+ },
1500
1621
  ]),
1501
1622
  getEdges: vi.fn().mockReturnValue([
1502
- { from: '/src/utils.ts:myFunction', to: '/src/types.ts:MyInterface', type: 'implements', confidence: 1.0 },
1623
+ {
1624
+ from: '/src/utils.ts:myFunction',
1625
+ to: '/src/types.ts:MyInterface',
1626
+ type: 'implements',
1627
+ confidence: 1.0,
1628
+ },
1503
1629
  ]),
1504
1630
  };
1505
1631
 
@@ -1514,8 +1640,8 @@ describe('SearchService - Code Graph Integration', () => {
1514
1640
  type: 'file' as const,
1515
1641
  storeId,
1516
1642
  indexedAt: new Date(),
1517
- path: '/src/utils.ts'
1518
- }
1643
+ path: '/src/utils.ts',
1644
+ },
1519
1645
  },
1520
1646
  ]);
1521
1647
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1555,8 +1681,8 @@ describe('SearchService - Code Graph Integration', () => {
1555
1681
  type: 'file' as const,
1556
1682
  storeId,
1557
1683
  indexedAt: new Date(),
1558
- path: '/src/utils.ts'
1559
- }
1684
+ path: '/src/utils.ts',
1685
+ },
1560
1686
  },
1561
1687
  ]);
1562
1688
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1570,7 +1696,9 @@ describe('SearchService - Code Graph Integration', () => {
1570
1696
  });
1571
1697
 
1572
1698
  expect(results.results.length).toBe(1);
1573
- const callers = results.results[0]?.full?.relatedCode?.filter(r => r.relationship === 'calls this');
1699
+ const callers = results.results[0]?.full?.relatedCode?.filter(
1700
+ (r) => r.relationship === 'calls this'
1701
+ );
1574
1702
  expect(callers?.length).toBe(1);
1575
1703
  // When nodeId has no colon, file should be the whole nodeId and symbol should be empty -> 'unknown'
1576
1704
  expect(callers?.[0]?.file).toBe('simpleNodeId');
@@ -1589,8 +1717,8 @@ describe('SearchService - Code Graph Integration', () => {
1589
1717
  type: 'file' as const,
1590
1718
  storeId,
1591
1719
  indexedAt: new Date(),
1592
- path: '/src/utils.ts'
1593
- }
1720
+ path: '/src/utils.ts',
1721
+ },
1594
1722
  },
1595
1723
  ]);
1596
1724
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);
@@ -1615,7 +1743,7 @@ describe('SearchService - Code Graph Integration', () => {
1615
1743
  from: `/src/file${i}.ts:func${i}`,
1616
1744
  to: '/src/utils.ts:myFunction',
1617
1745
  type: 'calls' as const,
1618
- confidence: 0.8
1746
+ confidence: 0.8,
1619
1747
  }));
1620
1748
 
1621
1749
  const mockGraph = {
@@ -1636,8 +1764,8 @@ describe('SearchService - Code Graph Integration', () => {
1636
1764
  type: 'file' as const,
1637
1765
  storeId,
1638
1766
  indexedAt: new Date(),
1639
- path: '/src/utils.ts'
1640
- }
1767
+ path: '/src/utils.ts',
1768
+ },
1641
1769
  },
1642
1770
  ]);
1643
1771
  vi.mocked(mockLanceStore.fullTextSearch).mockResolvedValue([]);