bluera-knowledge 0.9.31 → 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 (200) hide show
  1. package/.claude/commands/code-review.md +15 -0
  2. package/.claude/hooks/post-edit-check.sh +5 -3
  3. package/.claude/skills/atomic-commits/SKILL.md +3 -1
  4. package/.claude/skills/code-review-repo/skill.md +62 -0
  5. package/.husky/pre-commit +3 -2
  6. package/.prettierrc +9 -0
  7. package/.versionrc.json +1 -1
  8. package/CHANGELOG.md +35 -0
  9. package/CLAUDE.md +6 -0
  10. package/README.md +25 -13
  11. package/bun.lock +277 -33
  12. package/dist/{chunk-L2YVNC63.js → chunk-6FHWC36B.js} +9 -1
  13. package/dist/chunk-6FHWC36B.js.map +1 -0
  14. package/dist/{chunk-2SJHNRXD.js → chunk-DC7CGSGT.js} +288 -241
  15. package/dist/chunk-DC7CGSGT.js.map +1 -0
  16. package/dist/{chunk-RWSXP3PQ.js → chunk-WFNPNAAP.js} +3194 -3024
  17. package/dist/chunk-WFNPNAAP.js.map +1 -0
  18. package/dist/{chunk-OGEY66FZ.js → chunk-Z2KKVH45.js} +548 -482
  19. package/dist/chunk-Z2KKVH45.js.map +1 -0
  20. package/dist/index.js +871 -754
  21. package/dist/index.js.map +1 -1
  22. package/dist/mcp/server.js +3 -3
  23. package/dist/watch.service-BJV3TI3F.js +7 -0
  24. package/dist/workers/background-worker-cli.js +46 -45
  25. package/dist/workers/background-worker-cli.js.map +1 -1
  26. package/eslint.config.js +43 -1
  27. package/package.json +18 -11
  28. package/plugin.json +8 -0
  29. package/python/requirements.txt +1 -1
  30. package/src/analysis/ast-parser.test.ts +12 -11
  31. package/src/analysis/ast-parser.ts +28 -22
  32. package/src/analysis/code-graph.test.ts +52 -62
  33. package/src/analysis/code-graph.ts +9 -13
  34. package/src/analysis/dependency-usage-analyzer.test.ts +91 -271
  35. package/src/analysis/dependency-usage-analyzer.ts +52 -24
  36. package/src/analysis/go-ast-parser.test.ts +22 -22
  37. package/src/analysis/go-ast-parser.ts +18 -25
  38. package/src/analysis/parser-factory.test.ts +9 -9
  39. package/src/analysis/parser-factory.ts +3 -3
  40. package/src/analysis/python-ast-parser.test.ts +27 -27
  41. package/src/analysis/python-ast-parser.ts +2 -2
  42. package/src/analysis/repo-url-resolver.test.ts +82 -82
  43. package/src/analysis/rust-ast-parser.test.ts +19 -19
  44. package/src/analysis/rust-ast-parser.ts +17 -27
  45. package/src/analysis/tree-sitter-parser.test.ts +3 -3
  46. package/src/analysis/tree-sitter-parser.ts +10 -16
  47. package/src/cli/commands/crawl.test.ts +40 -24
  48. package/src/cli/commands/crawl.ts +186 -161
  49. package/src/cli/commands/index-cmd.test.ts +90 -90
  50. package/src/cli/commands/index-cmd.ts +52 -36
  51. package/src/cli/commands/mcp.test.ts +6 -6
  52. package/src/cli/commands/mcp.ts +2 -2
  53. package/src/cli/commands/plugin-api.test.ts +16 -18
  54. package/src/cli/commands/plugin-api.ts +9 -6
  55. package/src/cli/commands/search.test.ts +16 -7
  56. package/src/cli/commands/search.ts +124 -87
  57. package/src/cli/commands/serve.test.ts +67 -25
  58. package/src/cli/commands/serve.ts +18 -3
  59. package/src/cli/commands/setup.test.ts +176 -101
  60. package/src/cli/commands/setup.ts +140 -117
  61. package/src/cli/commands/store.test.ts +82 -53
  62. package/src/cli/commands/store.ts +56 -37
  63. package/src/cli/program.ts +2 -2
  64. package/src/crawl/article-converter.test.ts +4 -1
  65. package/src/crawl/article-converter.ts +46 -31
  66. package/src/crawl/bridge.test.ts +240 -132
  67. package/src/crawl/bridge.ts +87 -30
  68. package/src/crawl/claude-client.test.ts +124 -56
  69. package/src/crawl/claude-client.ts +7 -15
  70. package/src/crawl/intelligent-crawler.test.ts +65 -22
  71. package/src/crawl/intelligent-crawler.ts +86 -53
  72. package/src/crawl/markdown-utils.ts +1 -4
  73. package/src/db/embeddings.ts +4 -6
  74. package/src/db/lance.test.ts +63 -4
  75. package/src/db/lance.ts +31 -12
  76. package/src/index.ts +26 -17
  77. package/src/logging/index.ts +1 -5
  78. package/src/logging/logger.ts +3 -5
  79. package/src/logging/payload.test.ts +1 -1
  80. package/src/logging/payload.ts +3 -5
  81. package/src/mcp/commands/index.ts +2 -2
  82. package/src/mcp/commands/job.commands.ts +12 -18
  83. package/src/mcp/commands/meta.commands.ts +13 -13
  84. package/src/mcp/commands/registry.ts +5 -8
  85. package/src/mcp/commands/store.commands.ts +19 -19
  86. package/src/mcp/handlers/execute.handler.test.ts +10 -10
  87. package/src/mcp/handlers/execute.handler.ts +4 -5
  88. package/src/mcp/handlers/index.ts +10 -14
  89. package/src/mcp/handlers/job.handler.test.ts +10 -10
  90. package/src/mcp/handlers/job.handler.ts +22 -25
  91. package/src/mcp/handlers/search.handler.test.ts +36 -65
  92. package/src/mcp/handlers/search.handler.ts +135 -104
  93. package/src/mcp/handlers/store.handler.test.ts +41 -52
  94. package/src/mcp/handlers/store.handler.ts +108 -88
  95. package/src/mcp/schemas/index.test.ts +73 -68
  96. package/src/mcp/schemas/index.ts +18 -12
  97. package/src/mcp/server.test.ts +1 -1
  98. package/src/mcp/server.ts +59 -46
  99. package/src/plugin/commands.test.ts +230 -95
  100. package/src/plugin/commands.ts +24 -25
  101. package/src/plugin/dependency-analyzer.test.ts +52 -52
  102. package/src/plugin/dependency-analyzer.ts +85 -22
  103. package/src/plugin/git-clone.test.ts +24 -13
  104. package/src/plugin/git-clone.ts +3 -7
  105. package/src/server/app.test.ts +109 -109
  106. package/src/server/app.ts +32 -23
  107. package/src/server/index.test.ts +64 -66
  108. package/src/services/chunking.service.test.ts +32 -32
  109. package/src/services/chunking.service.ts +16 -9
  110. package/src/services/code-graph.service.test.ts +30 -36
  111. package/src/services/code-graph.service.ts +24 -10
  112. package/src/services/code-unit.service.test.ts +55 -11
  113. package/src/services/code-unit.service.ts +85 -11
  114. package/src/services/config.service.test.ts +37 -18
  115. package/src/services/config.service.ts +30 -7
  116. package/src/services/index.service.test.ts +49 -18
  117. package/src/services/index.service.ts +98 -48
  118. package/src/services/index.ts +8 -10
  119. package/src/services/job.service.test.ts +22 -22
  120. package/src/services/job.service.ts +18 -18
  121. package/src/services/project-root.service.test.ts +1 -3
  122. package/src/services/search.service.test.ts +248 -120
  123. package/src/services/search.service.ts +286 -156
  124. package/src/services/services.test.ts +36 -0
  125. package/src/services/snippet.service.test.ts +14 -6
  126. package/src/services/snippet.service.ts +7 -5
  127. package/src/services/store.service.test.ts +68 -29
  128. package/src/services/store.service.ts +41 -12
  129. package/src/services/watch.service.test.ts +34 -14
  130. package/src/services/watch.service.ts +11 -1
  131. package/src/types/brands.test.ts +3 -1
  132. package/src/types/index.ts +2 -13
  133. package/src/types/search.ts +10 -8
  134. package/src/utils/type-guards.test.ts +20 -15
  135. package/src/utils/type-guards.ts +1 -1
  136. package/src/workers/background-worker-cli.ts +2 -2
  137. package/src/workers/background-worker.test.ts +54 -40
  138. package/src/workers/background-worker.ts +76 -60
  139. package/src/workers/spawn-worker.test.ts +22 -10
  140. package/src/workers/spawn-worker.ts +6 -6
  141. package/tests/analysis/ast-parser.test.ts +3 -3
  142. package/tests/analysis/code-graph.test.ts +5 -5
  143. package/tests/fixtures/code-snippets/api/error-handling.ts +4 -15
  144. package/tests/fixtures/code-snippets/api/rest-controller.ts +3 -9
  145. package/tests/fixtures/code-snippets/auth/jwt-auth.ts +5 -21
  146. package/tests/fixtures/code-snippets/auth/oauth-flow.ts +4 -4
  147. package/tests/fixtures/code-snippets/database/repository-pattern.ts +11 -3
  148. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/handler.ts +2 -2
  149. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/handler.ts +1 -1
  150. package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static.ts +2 -2
  151. package/tests/fixtures/corpus/oss-repos/hono/src/client/client.ts +2 -2
  152. package/tests/fixtures/corpus/oss-repos/hono/src/client/types.ts +22 -20
  153. package/tests/fixtures/corpus/oss-repos/hono/src/context.ts +13 -10
  154. package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/accepts.ts +10 -7
  155. package/tests/fixtures/corpus/oss-repos/hono/src/helper/adapter/index.ts +2 -2
  156. package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/index.ts +1 -1
  157. package/tests/fixtures/corpus/oss-repos/hono/src/helper/factory/index.ts +16 -16
  158. package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/ssg.ts +2 -2
  159. package/tests/fixtures/corpus/oss-repos/hono/src/hono-base.ts +3 -3
  160. package/tests/fixtures/corpus/oss-repos/hono/src/hono.ts +1 -1
  161. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/css.ts +2 -2
  162. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/intrinsic-element/components.ts +1 -1
  163. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/render.ts +7 -7
  164. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/hooks/index.ts +3 -3
  165. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/components.ts +1 -1
  166. package/tests/fixtures/corpus/oss-repos/hono/src/jsx/utils.ts +6 -6
  167. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jsx-renderer/index.ts +3 -3
  168. package/tests/fixtures/corpus/oss-repos/hono/src/middleware/serve-static/index.ts +1 -1
  169. package/tests/fixtures/corpus/oss-repos/hono/src/preset/quick.ts +1 -1
  170. package/tests/fixtures/corpus/oss-repos/hono/src/preset/tiny.ts +1 -1
  171. package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/router.ts +2 -2
  172. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/node.ts +4 -4
  173. package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/router.ts +1 -1
  174. package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/node.ts +1 -1
  175. package/tests/fixtures/corpus/oss-repos/hono/src/types.ts +166 -169
  176. package/tests/fixtures/corpus/oss-repos/hono/src/utils/body.ts +8 -8
  177. package/tests/fixtures/corpus/oss-repos/hono/src/utils/color.ts +3 -3
  178. package/tests/fixtures/corpus/oss-repos/hono/src/utils/cookie.ts +2 -2
  179. package/tests/fixtures/corpus/oss-repos/hono/src/utils/encode.ts +2 -2
  180. package/tests/fixtures/corpus/oss-repos/hono/src/utils/types.ts +30 -33
  181. package/tests/fixtures/corpus/oss-repos/hono/src/validator/validator.ts +2 -2
  182. package/tests/fixtures/test-server.ts +3 -2
  183. package/tests/helpers/performance-metrics.ts +8 -25
  184. package/tests/helpers/search-relevance.ts +14 -69
  185. package/tests/integration/cli-consistency.test.ts +5 -4
  186. package/tests/integration/e2e-workflow.test.ts +2 -0
  187. package/tests/integration/python-bridge.test.ts +13 -3
  188. package/tests/mcp/server.test.ts +1 -1
  189. package/tests/services/code-unit.service.test.ts +48 -0
  190. package/tests/services/job.service.test.ts +124 -0
  191. package/tests/services/search.progressive-context.test.ts +2 -2
  192. package/.claude-plugin/plugin.json +0 -13
  193. package/BUGS-FOUND.md +0 -71
  194. package/dist/chunk-2SJHNRXD.js.map +0 -1
  195. package/dist/chunk-L2YVNC63.js.map +0 -1
  196. package/dist/chunk-OGEY66FZ.js.map +0 -1
  197. package/dist/chunk-RWSXP3PQ.js.map +0 -1
  198. package/dist/watch.service-YAIKKDCF.js +0 -7
  199. package/skills/atomic-commits/SKILL.md +0 -77
  200. /package/dist/{watch.service-YAIKKDCF.js.map → watch.service-BJV3TI3F.js.map} +0 -0
@@ -82,7 +82,7 @@ describe('store command execution', () => {
82
82
  mockServices.store.list.mockResolvedValue(mockStores);
83
83
 
84
84
  const command = createStoreCommand(getOptions);
85
- const listCommand = command.commands.find(c => c.name() === 'list');
85
+ const listCommand = command.commands.find((c) => c.name() === 'list');
86
86
  const actionHandler = listCommand?._actionHandler;
87
87
 
88
88
  await actionHandler!([]);
@@ -109,7 +109,7 @@ describe('store command execution', () => {
109
109
  mockServices.store.list.mockResolvedValue(mockStores);
110
110
 
111
111
  const command = createStoreCommand(getOptions);
112
- const listCommand = command.commands.find(c => c.name() === 'list');
112
+ const listCommand = command.commands.find((c) => c.name() === 'list');
113
113
  const actionHandler = listCommand?._actionHandler;
114
114
 
115
115
  listCommand.parseOptions(['--type', 'file']);
@@ -123,7 +123,7 @@ describe('store command execution', () => {
123
123
  mockServices.store.list.mockResolvedValue([]);
124
124
 
125
125
  const command = createStoreCommand(getOptions);
126
- const listCommand = command.commands.find(c => c.name() === 'list');
126
+ const listCommand = command.commands.find((c) => c.name() === 'list');
127
127
  const actionHandler = listCommand?._actionHandler;
128
128
 
129
129
  await actionHandler!([]);
@@ -153,7 +153,7 @@ describe('store command execution', () => {
153
153
  });
154
154
 
155
155
  const command = createStoreCommand(getOptions);
156
- const listCommand = command.commands.find(c => c.name() === 'list');
156
+ const listCommand = command.commands.find((c) => c.name() === 'list');
157
157
  const actionHandler = listCommand?._actionHandler;
158
158
 
159
159
  await actionHandler!([]);
@@ -193,7 +193,7 @@ describe('store command execution', () => {
193
193
  });
194
194
 
195
195
  const command = createStoreCommand(getOptions);
196
- const listCommand = command.commands.find(c => c.name() === 'list');
196
+ const listCommand = command.commands.find((c) => c.name() === 'list');
197
197
  const actionHandler = listCommand?._actionHandler;
198
198
 
199
199
  await actionHandler!([]);
@@ -221,10 +221,17 @@ describe('store command execution', () => {
221
221
  });
222
222
 
223
223
  const command = createStoreCommand(getOptions);
224
- const createCommand = command.commands.find(c => c.name() === 'create');
224
+ const createCommand = command.commands.find((c) => c.name() === 'create');
225
225
  const actionHandler = createCommand?._actionHandler;
226
226
 
227
- createCommand.parseOptions(['--type', 'file', '--source', '/path/to/files', '--description', 'My file store']);
227
+ createCommand.parseOptions([
228
+ '--type',
229
+ 'file',
230
+ '--source',
231
+ '/path/to/files',
232
+ '--description',
233
+ 'My file store',
234
+ ]);
228
235
  await actionHandler!(['my-files']);
229
236
 
230
237
  expect(mockServices.store.create).toHaveBeenCalledWith({
@@ -257,7 +264,7 @@ describe('store command execution', () => {
257
264
  });
258
265
 
259
266
  const command = createStoreCommand(getOptions);
260
- const createCommand = command.commands.find(c => c.name() === 'create');
267
+ const createCommand = command.commands.find((c) => c.name() === 'create');
261
268
  const actionHandler = createCommand?._actionHandler;
262
269
 
263
270
  createCommand.parseOptions(['--type', 'repo', '--source', '/path/to/repo']);
@@ -271,9 +278,7 @@ describe('store command execution', () => {
271
278
  description: undefined,
272
279
  tags: undefined,
273
280
  });
274
- expect(consoleLogSpy).toHaveBeenCalledWith(
275
- expect.stringContaining('Created store: my-repo')
276
- );
281
+ expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Created store: my-repo'));
277
282
  });
278
283
 
279
284
  it('creates a web store successfully', async () => {
@@ -293,7 +298,7 @@ describe('store command execution', () => {
293
298
  });
294
299
 
295
300
  const command = createStoreCommand(getOptions);
296
- const createCommand = command.commands.find(c => c.name() === 'create');
301
+ const createCommand = command.commands.find((c) => c.name() === 'create');
297
302
  const actionHandler = createCommand?._actionHandler;
298
303
 
299
304
  createCommand.parseOptions(['--type', 'web', '--source', 'https://docs.example.com']);
@@ -307,9 +312,7 @@ describe('store command execution', () => {
307
312
  description: undefined,
308
313
  tags: undefined,
309
314
  });
310
- expect(consoleLogSpy).toHaveBeenCalledWith(
311
- expect.stringContaining('Created store: my-docs')
312
- );
315
+ expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Created store: my-docs'));
313
316
  });
314
317
 
315
318
  it('creates store with tags', async () => {
@@ -329,10 +332,17 @@ describe('store command execution', () => {
329
332
  });
330
333
 
331
334
  const command = createStoreCommand(getOptions);
332
- const createCommand = command.commands.find(c => c.name() === 'create');
335
+ const createCommand = command.commands.find((c) => c.name() === 'create');
333
336
  const actionHandler = createCommand?._actionHandler;
334
337
 
335
- createCommand.parseOptions(['--type', 'file', '--source', '/path/to/files', '--tags', 'typescript, react, frontend']);
338
+ createCommand.parseOptions([
339
+ '--type',
340
+ 'file',
341
+ '--source',
342
+ '/path/to/files',
343
+ '--tags',
344
+ 'typescript, react, frontend',
345
+ ]);
336
346
  await actionHandler!(['tagged-store']);
337
347
 
338
348
  expect(mockServices.store.create).toHaveBeenCalledWith({
@@ -368,7 +378,7 @@ describe('store command execution', () => {
368
378
  });
369
379
 
370
380
  const command = createStoreCommand(getOptions);
371
- const createCommand = command.commands.find(c => c.name() === 'create');
381
+ const createCommand = command.commands.find((c) => c.name() === 'create');
372
382
  const actionHandler = createCommand?._actionHandler;
373
383
 
374
384
  createCommand.parseOptions(['--type', 'file', '--source', '/path/to/files']);
@@ -388,7 +398,7 @@ describe('store command execution', () => {
388
398
  });
389
399
 
390
400
  const command = createStoreCommand(getOptions);
391
- const createCommand = command.commands.find(c => c.name() === 'create');
401
+ const createCommand = command.commands.find((c) => c.name() === 'create');
392
402
  const actionHandler = createCommand?._actionHandler;
393
403
 
394
404
  createCommand.parseOptions(['--type', 'file', '--source', '/path/to/files']);
@@ -414,7 +424,7 @@ describe('store command execution', () => {
414
424
  mockServices.store.getByIdOrName.mockResolvedValue(mockStore);
415
425
 
416
426
  const command = createStoreCommand(getOptions);
417
- const infoCommand = command.commands.find(c => c.name() === 'info');
427
+ const infoCommand = command.commands.find((c) => c.name() === 'info');
418
428
  const actionHandler = infoCommand?._actionHandler;
419
429
 
420
430
  await actionHandler!(['my-store']);
@@ -449,7 +459,7 @@ describe('store command execution', () => {
449
459
  mockServices.store.getByIdOrName.mockResolvedValue(mockStore);
450
460
 
451
461
  const command = createStoreCommand(getOptions);
452
- const infoCommand = command.commands.find(c => c.name() === 'info');
462
+ const infoCommand = command.commands.find((c) => c.name() === 'info');
453
463
  const actionHandler = infoCommand?._actionHandler;
454
464
 
455
465
  await actionHandler!(['my-repo']);
@@ -477,7 +487,7 @@ describe('store command execution', () => {
477
487
  mockServices.store.getByIdOrName.mockResolvedValue(mockStore);
478
488
 
479
489
  const command = createStoreCommand(getOptions);
480
- const infoCommand = command.commands.find(c => c.name() === 'info');
490
+ const infoCommand = command.commands.find((c) => c.name() === 'info');
481
491
  const actionHandler = infoCommand?._actionHandler;
482
492
 
483
493
  await actionHandler!(['my-docs']);
@@ -509,7 +519,7 @@ describe('store command execution', () => {
509
519
  });
510
520
 
511
521
  const command = createStoreCommand(getOptions);
512
- const infoCommand = command.commands.find(c => c.name() === 'info');
522
+ const infoCommand = command.commands.find((c) => c.name() === 'info');
513
523
  const actionHandler = infoCommand?._actionHandler;
514
524
 
515
525
  await actionHandler!(['my-store']);
@@ -523,7 +533,7 @@ describe('store command execution', () => {
523
533
  mockServices.store.getByIdOrName.mockResolvedValue(undefined);
524
534
 
525
535
  const command = createStoreCommand(getOptions);
526
- const infoCommand = command.commands.find(c => c.name() === 'info');
536
+ const infoCommand = command.commands.find((c) => c.name() === 'info');
527
537
  const actionHandler = infoCommand?._actionHandler;
528
538
 
529
539
  await expect(actionHandler!(['nonexistent'])).rejects.toThrow('process.exit: 3');
@@ -546,7 +556,7 @@ describe('store command execution', () => {
546
556
  mockServices.store.getByIdOrName.mockResolvedValue(mockStore);
547
557
 
548
558
  const command = createStoreCommand(getOptions);
549
- const infoCommand = command.commands.find(c => c.name() === 'info');
559
+ const infoCommand = command.commands.find((c) => c.name() === 'info');
550
560
  const actionHandler = infoCommand?._actionHandler;
551
561
 
552
562
  await actionHandler!([storeId]);
@@ -573,7 +583,7 @@ describe('store command execution', () => {
573
583
  });
574
584
 
575
585
  const command = createStoreCommand(getOptions);
576
- const deleteCommand = command.commands.find(c => c.name() === 'delete');
586
+ const deleteCommand = command.commands.find((c) => c.name() === 'delete');
577
587
  const actionHandler = deleteCommand?._actionHandler;
578
588
 
579
589
  deleteCommand.parseOptions(['--force']);
@@ -601,7 +611,7 @@ describe('store command execution', () => {
601
611
  });
602
612
 
603
613
  const command = createStoreCommand(getOptions);
604
- const deleteCommand = command.commands.find(c => c.name() === 'delete');
614
+ const deleteCommand = command.commands.find((c) => c.name() === 'delete');
605
615
  const actionHandler = deleteCommand?._actionHandler;
606
616
 
607
617
  deleteCommand.parseOptions(['--yes']);
@@ -615,7 +625,7 @@ describe('store command execution', () => {
615
625
  mockServices.store.getByIdOrName.mockResolvedValue(undefined);
616
626
 
617
627
  const command = createStoreCommand(getOptions);
618
- const deleteCommand = command.commands.find(c => c.name() === 'delete');
628
+ const deleteCommand = command.commands.find((c) => c.name() === 'delete');
619
629
  const actionHandler = deleteCommand?._actionHandler;
620
630
 
621
631
  deleteCommand.parseOptions(['--force']);
@@ -645,7 +655,7 @@ describe('store command execution', () => {
645
655
  });
646
656
 
647
657
  const command = createStoreCommand(getOptions);
648
- const deleteCommand = command.commands.find(c => c.name() === 'delete');
658
+ const deleteCommand = command.commands.find((c) => c.name() === 'delete');
649
659
  const actionHandler = deleteCommand?._actionHandler;
650
660
 
651
661
  deleteCommand.parseOptions(['--force']);
@@ -675,7 +685,7 @@ describe('store command execution', () => {
675
685
  });
676
686
 
677
687
  const command = createStoreCommand(getOptions);
678
- const deleteCommand = command.commands.find(c => c.name() === 'delete');
688
+ const deleteCommand = command.commands.find((c) => c.name() === 'delete');
679
689
  const actionHandler = deleteCommand?._actionHandler;
680
690
 
681
691
  await expect(actionHandler!(['my-store'])).rejects.toThrow('process.exit: 1');
@@ -728,7 +738,7 @@ describe('store command execution', () => {
728
738
  }));
729
739
 
730
740
  const command = createStoreCommand(getOptions);
731
- const deleteCommand = command.commands.find(c => c.name() === 'delete');
741
+ const deleteCommand = command.commands.find((c) => c.name() === 'delete');
732
742
  const actionHandler = deleteCommand?._actionHandler;
733
743
 
734
744
  await actionHandler!(['my-store']);
@@ -775,7 +785,7 @@ describe('store command execution', () => {
775
785
  }));
776
786
 
777
787
  const command = createStoreCommand(getOptions);
778
- const deleteCommand = command.commands.find(c => c.name() === 'delete');
788
+ const deleteCommand = command.commands.find((c) => c.name() === 'delete');
779
789
  const actionHandler = deleteCommand?._actionHandler;
780
790
 
781
791
  await expect(actionHandler!(['my-store'])).rejects.toThrow('process.exit: 0');
@@ -798,25 +808,25 @@ describe('store command execution', () => {
798
808
 
799
809
  expect(command.name()).toBe('store');
800
810
  expect(command.commands.length).toBe(4);
801
- expect(command.commands.map(c => c.name())).toEqual(['list', 'create', 'info', 'delete']);
811
+ expect(command.commands.map((c) => c.name())).toEqual(['list', 'create', 'info', 'delete']);
802
812
  });
803
813
 
804
814
  it('list subcommand has type option', () => {
805
815
  const command = createStoreCommand(getOptions);
806
- const listCommand = command.commands.find(c => c.name() === 'list');
807
- const typeOption = listCommand?.options.find(o => o.long === '--type');
816
+ const listCommand = command.commands.find((c) => c.name() === 'list');
817
+ const typeOption = listCommand?.options.find((o) => o.long === '--type');
808
818
 
809
819
  expect(typeOption).toBeDefined();
810
820
  });
811
821
 
812
822
  it('create subcommand has required options', () => {
813
823
  const command = createStoreCommand(getOptions);
814
- const createCommand = command.commands.find(c => c.name() === 'create');
824
+ const createCommand = command.commands.find((c) => c.name() === 'create');
815
825
 
816
- const typeOption = createCommand?.options.find(o => o.long === '--type');
817
- const sourceOption = createCommand?.options.find(o => o.long === '--source');
818
- const descriptionOption = createCommand?.options.find(o => o.long === '--description');
819
- const tagsOption = createCommand?.options.find(o => o.long === '--tags');
826
+ const typeOption = createCommand?.options.find((o) => o.long === '--type');
827
+ const sourceOption = createCommand?.options.find((o) => o.long === '--source');
828
+ const descriptionOption = createCommand?.options.find((o) => o.long === '--description');
829
+ const tagsOption = createCommand?.options.find((o) => o.long === '--tags');
820
830
 
821
831
  expect(typeOption).toBeDefined();
822
832
  expect(typeOption?.mandatory).toBe(true);
@@ -830,10 +840,10 @@ describe('store command execution', () => {
830
840
 
831
841
  it('delete subcommand has force and yes options', () => {
832
842
  const command = createStoreCommand(getOptions);
833
- const deleteCommand = command.commands.find(c => c.name() === 'delete');
843
+ const deleteCommand = command.commands.find((c) => c.name() === 'delete');
834
844
 
835
- const forceOption = deleteCommand?.options.find(o => o.long === '--force');
836
- const yesOption = deleteCommand?.options.find(o => o.long === '--yes');
845
+ const forceOption = deleteCommand?.options.find((o) => o.long === '--force');
846
+ const yesOption = deleteCommand?.options.find((o) => o.long === '--yes');
837
847
 
838
848
  expect(forceOption).toBeDefined();
839
849
  expect(yesOption).toBeDefined();
@@ -858,10 +868,17 @@ describe('store command execution', () => {
858
868
  });
859
869
 
860
870
  const command = createStoreCommand(getOptions);
861
- const createCommand = command.commands.find(c => c.name() === 'create');
871
+ const createCommand = command.commands.find((c) => c.name() === 'create');
862
872
  const actionHandler = createCommand?._actionHandler;
863
873
 
864
- createCommand.parseOptions(['--type', 'file', '--source', '/path/to/files', '--tags', 'tag1, tag2, tag3']);
874
+ createCommand.parseOptions([
875
+ '--type',
876
+ 'file',
877
+ '--source',
878
+ '/path/to/files',
879
+ '--tags',
880
+ 'tag1, tag2, tag3',
881
+ ]);
865
882
  await actionHandler!(['tagged-store']);
866
883
 
867
884
  expect(mockServices.store.create).toHaveBeenCalledWith(
@@ -888,10 +905,17 @@ describe('store command execution', () => {
888
905
  });
889
906
 
890
907
  const command = createStoreCommand(getOptions);
891
- const createCommand = command.commands.find(c => c.name() === 'create');
908
+ const createCommand = command.commands.find((c) => c.name() === 'create');
892
909
  const actionHandler = createCommand?._actionHandler;
893
910
 
894
- createCommand.parseOptions(['--type', 'file', '--source', '/path/to/files', '--tags', ' tag1 , tag2 ']);
911
+ createCommand.parseOptions([
912
+ '--type',
913
+ 'file',
914
+ '--source',
915
+ '/path/to/files',
916
+ '--tags',
917
+ ' tag1 , tag2 ',
918
+ ]);
895
919
  await actionHandler!(['tagged-store']);
896
920
 
897
921
  expect(mockServices.store.create).toHaveBeenCalledWith(
@@ -919,7 +943,7 @@ describe('store command execution', () => {
919
943
  });
920
944
 
921
945
  const command = createStoreCommand(getOptions);
922
- const createCommand = command.commands.find(c => c.name() === 'create');
946
+ const createCommand = command.commands.find((c) => c.name() === 'create');
923
947
  const actionHandler = createCommand?._actionHandler;
924
948
 
925
949
  createCommand.parseOptions(['--type', 'file', '--source', '/local/path']);
@@ -951,7 +975,7 @@ describe('store command execution', () => {
951
975
  });
952
976
 
953
977
  const command = createStoreCommand(getOptions);
954
- const createCommand = command.commands.find(c => c.name() === 'create');
978
+ const createCommand = command.commands.find((c) => c.name() === 'create');
955
979
  const actionHandler = createCommand?._actionHandler;
956
980
 
957
981
  createCommand.parseOptions(['--type', 'repo', '--source', '/repo/path']);
@@ -984,7 +1008,7 @@ describe('store command execution', () => {
984
1008
  });
985
1009
 
986
1010
  const command = createStoreCommand(getOptions);
987
- const createCommand = command.commands.find(c => c.name() === 'create');
1011
+ const createCommand = command.commands.find((c) => c.name() === 'create');
988
1012
  const actionHandler = createCommand?._actionHandler;
989
1013
 
990
1014
  createCommand.parseOptions(['--type', 'repo', '--source', 'https://github.com/user/repo']);
@@ -1018,10 +1042,15 @@ describe('store command execution', () => {
1018
1042
  });
1019
1043
 
1020
1044
  const command = createStoreCommand(getOptions);
1021
- const createCommand = command.commands.find(c => c.name() === 'create');
1045
+ const createCommand = command.commands.find((c) => c.name() === 'create');
1022
1046
  const actionHandler = createCommand?._actionHandler;
1023
1047
 
1024
- createCommand.parseOptions(['--type', 'repo', '--source', 'http://internal-git.example.com/repo']);
1048
+ createCommand.parseOptions([
1049
+ '--type',
1050
+ 'repo',
1051
+ '--source',
1052
+ 'http://internal-git.example.com/repo',
1053
+ ]);
1025
1054
  await actionHandler!(['repo-http-store']);
1026
1055
 
1027
1056
  expect(mockServices.store.create).toHaveBeenCalledWith({
@@ -1051,7 +1080,7 @@ describe('store command execution', () => {
1051
1080
  });
1052
1081
 
1053
1082
  const command = createStoreCommand(getOptions);
1054
- const createCommand = command.commands.find(c => c.name() === 'create');
1083
+ const createCommand = command.commands.find((c) => c.name() === 'create');
1055
1084
  const actionHandler = createCommand?._actionHandler;
1056
1085
 
1057
1086
  createCommand.parseOptions(['--type', 'web', '--source', 'https://example.com']);
@@ -1,10 +1,12 @@
1
1
  import { Command } from 'commander';
2
2
  import { createServices, destroyServices } from '../../services/index.js';
3
- import type { GlobalOptions } from '../program.js';
4
3
  import type { StoreType } from '../../types/store.js';
4
+ import type { GlobalOptions } from '../program.js';
5
5
 
6
6
  export function createStoreCommand(getOptions: () => GlobalOptions): Command {
7
- const store = new Command('store').description('Manage knowledge stores (collections of indexed documents)');
7
+ const store = new Command('store').description(
8
+ 'Manage knowledge stores (collections of indexed documents)'
9
+ );
8
10
 
9
11
  store
10
12
  .command('list')
@@ -42,48 +44,63 @@ export function createStoreCommand(getOptions: () => GlobalOptions): Command {
42
44
  store
43
45
  .command('create <name>')
44
46
  .description('Create a new store pointing to a local path or URL')
45
- .requiredOption('-t, --type <type>', 'Store type: file (local dir), repo (git), web (crawled site)')
47
+ .requiredOption(
48
+ '-t, --type <type>',
49
+ 'Store type: file (local dir), repo (git), web (crawled site)'
50
+ )
46
51
  .requiredOption('-s, --source <path>', 'Local path for file/repo stores, URL for web stores')
47
52
  .option('-d, --description <desc>', 'Optional description for the store')
48
53
  .option('--tags <tags>', 'Comma-separated tags for filtering')
49
- .action(async (name: string, options: {
50
- type: StoreType;
51
- source: string;
52
- description?: string;
53
- tags?: string;
54
- }) => {
55
- const globalOpts = getOptions();
56
- const services = await createServices(globalOpts.config, globalOpts.dataDir);
57
- let exitCode = 0;
58
- try {
59
- // Detect if source is a URL (for repo stores that should clone from remote)
60
- const isUrl = options.source.startsWith('http://') || options.source.startsWith('https://');
61
- const result = await services.store.create({
62
- name,
63
- type: options.type,
64
- path: options.type === 'file' || (options.type === 'repo' && !isUrl) ? options.source : undefined,
65
- url: options.type === 'web' || (options.type === 'repo' && isUrl) ? options.source : undefined,
66
- description: options.description,
67
- tags: options.tags?.split(',').map((t) => t.trim()),
68
- });
54
+ .action(
55
+ async (
56
+ name: string,
57
+ options: {
58
+ type: StoreType;
59
+ source: string;
60
+ description?: string;
61
+ tags?: string;
62
+ }
63
+ ) => {
64
+ const globalOpts = getOptions();
65
+ const services = await createServices(globalOpts.config, globalOpts.dataDir);
66
+ let exitCode = 0;
67
+ try {
68
+ // Detect if source is a URL (for repo stores that should clone from remote)
69
+ const isUrl =
70
+ options.source.startsWith('http://') || options.source.startsWith('https://');
71
+ const result = await services.store.create({
72
+ name,
73
+ type: options.type,
74
+ path:
75
+ options.type === 'file' || (options.type === 'repo' && !isUrl)
76
+ ? options.source
77
+ : undefined,
78
+ url:
79
+ options.type === 'web' || (options.type === 'repo' && isUrl)
80
+ ? options.source
81
+ : undefined,
82
+ description: options.description,
83
+ tags: options.tags?.split(',').map((t) => t.trim()),
84
+ });
69
85
 
70
- if (result.success) {
71
- if (globalOpts.format === 'json') {
72
- console.log(JSON.stringify(result.data, null, 2));
86
+ if (result.success) {
87
+ if (globalOpts.format === 'json') {
88
+ console.log(JSON.stringify(result.data, null, 2));
89
+ } else {
90
+ console.log(`\nCreated store: ${result.data.name} (${result.data.id})\n`);
91
+ }
73
92
  } else {
74
- console.log(`\nCreated store: ${result.data.name} (${result.data.id})\n`);
93
+ console.error(`Error: ${result.error.message}`);
94
+ exitCode = 1;
75
95
  }
76
- } else {
77
- console.error(`Error: ${result.error.message}`);
78
- exitCode = 1;
96
+ } finally {
97
+ await destroyServices(services);
98
+ }
99
+ if (exitCode !== 0) {
100
+ process.exit(exitCode);
79
101
  }
80
- } finally {
81
- await destroyServices(services);
82
- }
83
- if (exitCode !== 0) {
84
- process.exit(exitCode);
85
102
  }
86
- });
103
+ );
87
104
 
88
105
  store
89
106
  .command('info <store>')
@@ -137,7 +154,9 @@ export function createStoreCommand(getOptions: () => GlobalOptions): Command {
137
154
  const skipConfirmation = options.force === true || options.yes === true;
138
155
  if (!skipConfirmation) {
139
156
  if (!process.stdin.isTTY) {
140
- console.error('Error: Use --force or -y to delete without confirmation in non-interactive mode');
157
+ console.error(
158
+ 'Error: Use --force or -y to delete without confirmation in non-interactive mode'
159
+ );
141
160
  process.exit(1);
142
161
  }
143
162
  // Interactive confirmation
@@ -1,7 +1,7 @@
1
- import { Command } from 'commander';
2
1
  import { readFileSync } from 'node:fs';
3
- import { fileURLToPath } from 'node:url';
4
2
  import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { Command } from 'commander';
5
5
 
6
6
  interface PackageJson {
7
7
  version: string;
@@ -40,7 +40,10 @@ describe('convertHtmlToMarkdown', () => {
40
40
  const html = '<html><body><article><h1>Title</h1><p>Content</p></article></body></html>';
41
41
  const result = await convertHtmlToMarkdown(html, 'https://example.com');
42
42
 
43
- expect(vi.mocked(articleExtractor.extractFromHtml)).toHaveBeenCalledWith(html, 'https://example.com');
43
+ expect(vi.mocked(articleExtractor.extractFromHtml)).toHaveBeenCalledWith(
44
+ html,
45
+ 'https://example.com'
46
+ );
44
47
  expect(result.success).toBe(true);
45
48
  });
46
49
 
@@ -27,10 +27,7 @@ export interface ConversionResult {
27
27
  * 3. Convert to markdown with Turndown + GFM
28
28
  * 4. Cleanup markdown (regex patterns)
29
29
  */
30
- export async function convertHtmlToMarkdown(
31
- html: string,
32
- url: string,
33
- ): Promise<ConversionResult> {
30
+ export async function convertHtmlToMarkdown(html: string, url: string): Promise<ConversionResult> {
34
31
  logger.debug({ url, htmlLength: html.length }, 'Starting HTML conversion');
35
32
 
36
33
  try {
@@ -40,28 +37,37 @@ export async function convertHtmlToMarkdown(
40
37
 
41
38
  try {
42
39
  const article = await extractFromHtml(html, url);
43
- if (article !== null && article.content !== undefined && article.content !== '') {
40
+ if (article?.content !== undefined && article.content !== '') {
44
41
  articleHtml = article.content;
45
42
  title = article.title !== undefined && article.title !== '' ? article.title : undefined;
46
- logger.debug({
47
- url,
48
- title,
49
- extractedLength: articleHtml.length,
50
- usedFullHtml: false,
51
- }, 'Article content extracted');
43
+ logger.debug(
44
+ {
45
+ url,
46
+ title,
47
+ extractedLength: articleHtml.length,
48
+ usedFullHtml: false,
49
+ },
50
+ 'Article content extracted'
51
+ );
52
52
  } else {
53
53
  // Fallback to full HTML if extraction fails
54
54
  articleHtml = html;
55
- logger.debug({ url, usedFullHtml: true }, 'Article extraction returned empty, using full HTML');
55
+ logger.debug(
56
+ { url, usedFullHtml: true },
57
+ 'Article extraction returned empty, using full HTML'
58
+ );
56
59
  }
57
60
  } catch (extractError) {
58
61
  // Fallback to full HTML if extraction fails
59
62
  articleHtml = html;
60
- logger.debug({
61
- url,
62
- usedFullHtml: true,
63
- error: extractError instanceof Error ? extractError.message : String(extractError),
64
- }, 'Article extraction failed, using full HTML');
63
+ logger.debug(
64
+ {
65
+ url,
66
+ usedFullHtml: true,
67
+ error: extractError instanceof Error ? extractError.message : String(extractError),
68
+ },
69
+ 'Article extraction failed, using full HTML'
70
+ );
65
71
  }
66
72
 
67
73
  // Step 2: Preprocess HTML for code blocks
@@ -100,18 +106,24 @@ export async function convertHtmlToMarkdown(
100
106
  // Step 4: Cleanup markdown with comprehensive regex patterns
101
107
  const markdown = cleanupMarkdown(rawMarkdown);
102
108
 
103
- logger.debug({
104
- url,
105
- title,
106
- rawMarkdownLength: rawMarkdown.length,
107
- finalMarkdownLength: markdown.length,
108
- }, 'HTML to markdown conversion complete');
109
+ logger.debug(
110
+ {
111
+ url,
112
+ title,
113
+ rawMarkdownLength: rawMarkdown.length,
114
+ finalMarkdownLength: markdown.length,
115
+ },
116
+ 'HTML to markdown conversion complete'
117
+ );
109
118
 
110
119
  // Log markdown preview at trace level
111
- logger.trace({
112
- url,
113
- markdownPreview: truncateForLog(markdown, 1000),
114
- }, 'Markdown content preview');
120
+ logger.trace(
121
+ {
122
+ url,
123
+ markdownPreview: truncateForLog(markdown, 1000),
124
+ },
125
+ 'Markdown content preview'
126
+ );
115
127
 
116
128
  return {
117
129
  markdown,
@@ -119,10 +131,13 @@ export async function convertHtmlToMarkdown(
119
131
  success: true,
120
132
  };
121
133
  } catch (error) {
122
- logger.error({
123
- url,
124
- error: error instanceof Error ? error.message : String(error),
125
- }, 'HTML to markdown conversion failed');
134
+ logger.error(
135
+ {
136
+ url,
137
+ error: error instanceof Error ? error.message : String(error),
138
+ },
139
+ 'HTML to markdown conversion failed'
140
+ );
126
141
 
127
142
  return {
128
143
  markdown: '',