bluera-knowledge 0.9.32 → 0.9.36
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.
- package/.claude/hooks/post-edit-check.sh +5 -3
- package/.claude/skills/atomic-commits/SKILL.md +3 -1
- package/.husky/pre-commit +3 -2
- package/.prettierrc +9 -0
- package/.versionrc.json +1 -1
- package/CHANGELOG.md +70 -0
- package/CLAUDE.md +6 -0
- package/README.md +25 -13
- package/bun.lock +277 -33
- package/dist/{chunk-L2YVNC63.js → chunk-6FHWC36B.js} +9 -1
- package/dist/chunk-6FHWC36B.js.map +1 -0
- package/dist/{chunk-RST4XGRL.js → chunk-DC7CGSGT.js} +288 -241
- package/dist/chunk-DC7CGSGT.js.map +1 -0
- package/dist/{chunk-6PBP5DVD.js → chunk-WFNPNAAP.js} +3212 -3054
- package/dist/chunk-WFNPNAAP.js.map +1 -0
- package/dist/{chunk-WT2DAEO7.js → chunk-Z2KKVH45.js} +548 -482
- package/dist/chunk-Z2KKVH45.js.map +1 -0
- package/dist/index.js +871 -758
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +3 -3
- package/dist/watch.service-BJV3TI3F.js +7 -0
- package/dist/workers/background-worker-cli.js +97 -71
- package/dist/workers/background-worker-cli.js.map +1 -1
- package/eslint.config.js +43 -1
- package/package.json +18 -11
- package/plugin.json +8 -0
- package/python/requirements.txt +1 -1
- package/src/analysis/ast-parser.test.ts +12 -11
- package/src/analysis/ast-parser.ts +28 -22
- package/src/analysis/code-graph.test.ts +52 -62
- package/src/analysis/code-graph.ts +9 -13
- package/src/analysis/dependency-usage-analyzer.test.ts +91 -271
- package/src/analysis/dependency-usage-analyzer.ts +52 -24
- package/src/analysis/go-ast-parser.test.ts +22 -22
- package/src/analysis/go-ast-parser.ts +18 -25
- package/src/analysis/parser-factory.test.ts +9 -9
- package/src/analysis/parser-factory.ts +3 -3
- package/src/analysis/python-ast-parser.test.ts +27 -27
- package/src/analysis/python-ast-parser.ts +2 -2
- package/src/analysis/repo-url-resolver.test.ts +82 -82
- package/src/analysis/rust-ast-parser.test.ts +19 -19
- package/src/analysis/rust-ast-parser.ts +17 -27
- package/src/analysis/tree-sitter-parser.test.ts +3 -3
- package/src/analysis/tree-sitter-parser.ts +10 -16
- package/src/cli/commands/crawl.test.ts +40 -24
- package/src/cli/commands/crawl.ts +186 -166
- package/src/cli/commands/index-cmd.test.ts +90 -90
- package/src/cli/commands/index-cmd.ts +52 -36
- package/src/cli/commands/mcp.test.ts +6 -6
- package/src/cli/commands/mcp.ts +2 -2
- package/src/cli/commands/plugin-api.test.ts +16 -18
- package/src/cli/commands/plugin-api.ts +9 -6
- package/src/cli/commands/search.test.ts +16 -7
- package/src/cli/commands/search.ts +124 -87
- package/src/cli/commands/serve.test.ts +67 -25
- package/src/cli/commands/serve.ts +18 -3
- package/src/cli/commands/setup.test.ts +176 -101
- package/src/cli/commands/setup.ts +140 -117
- package/src/cli/commands/store.test.ts +82 -53
- package/src/cli/commands/store.ts +56 -37
- package/src/cli/program.ts +2 -2
- package/src/crawl/article-converter.test.ts +4 -1
- package/src/crawl/article-converter.ts +46 -31
- package/src/crawl/bridge.test.ts +240 -132
- package/src/crawl/bridge.ts +87 -30
- package/src/crawl/claude-client.test.ts +124 -56
- package/src/crawl/claude-client.ts +7 -15
- package/src/crawl/intelligent-crawler.test.ts +65 -22
- package/src/crawl/intelligent-crawler.ts +86 -53
- package/src/crawl/markdown-utils.ts +1 -4
- package/src/db/embeddings.ts +4 -6
- package/src/db/lance.test.ts +4 -4
- package/src/db/lance.ts +16 -12
- package/src/index.ts +26 -17
- package/src/logging/index.ts +1 -5
- package/src/logging/logger.ts +3 -5
- package/src/logging/payload.test.ts +1 -1
- package/src/logging/payload.ts +3 -5
- package/src/mcp/commands/index.ts +2 -2
- package/src/mcp/commands/job.commands.ts +12 -18
- package/src/mcp/commands/meta.commands.ts +13 -13
- package/src/mcp/commands/registry.ts +5 -8
- package/src/mcp/commands/store.commands.ts +19 -19
- package/src/mcp/handlers/execute.handler.test.ts +10 -10
- package/src/mcp/handlers/execute.handler.ts +4 -5
- package/src/mcp/handlers/index.ts +10 -14
- package/src/mcp/handlers/job.handler.test.ts +10 -10
- package/src/mcp/handlers/job.handler.ts +22 -25
- package/src/mcp/handlers/search.handler.test.ts +36 -65
- package/src/mcp/handlers/search.handler.ts +135 -104
- package/src/mcp/handlers/store.handler.test.ts +41 -52
- package/src/mcp/handlers/store.handler.ts +108 -88
- package/src/mcp/schemas/index.test.ts +73 -68
- package/src/mcp/schemas/index.ts +18 -12
- package/src/mcp/server.test.ts +1 -1
- package/src/mcp/server.ts +59 -46
- package/src/plugin/commands.test.ts +230 -95
- package/src/plugin/commands.ts +24 -25
- package/src/plugin/dependency-analyzer.test.ts +52 -52
- package/src/plugin/dependency-analyzer.ts +85 -22
- package/src/plugin/git-clone.test.ts +24 -13
- package/src/plugin/git-clone.ts +3 -7
- package/src/server/app.test.ts +109 -109
- package/src/server/app.ts +32 -23
- package/src/server/index.test.ts +64 -66
- package/src/services/chunking.service.test.ts +32 -32
- package/src/services/chunking.service.ts +16 -9
- package/src/services/code-graph.service.test.ts +30 -36
- package/src/services/code-graph.service.ts +24 -10
- package/src/services/code-unit.service.test.ts +55 -11
- package/src/services/code-unit.service.ts +85 -11
- package/src/services/config.service.test.ts +37 -18
- package/src/services/config.service.ts +30 -7
- package/src/services/index.service.test.ts +49 -18
- package/src/services/index.service.ts +98 -48
- package/src/services/index.ts +6 -9
- package/src/services/job.service.test.ts +22 -22
- package/src/services/job.service.ts +18 -18
- package/src/services/project-root.service.test.ts +1 -3
- package/src/services/search.service.test.ts +248 -120
- package/src/services/search.service.ts +286 -156
- package/src/services/services.test.ts +1 -1
- package/src/services/snippet.service.test.ts +14 -6
- package/src/services/snippet.service.ts +7 -5
- package/src/services/store.service.test.ts +68 -29
- package/src/services/store.service.ts +41 -12
- package/src/services/watch.service.test.ts +34 -14
- package/src/services/watch.service.ts +11 -1
- package/src/types/brands.test.ts +3 -1
- package/src/types/index.ts +2 -13
- package/src/types/search.ts +10 -8
- package/src/utils/type-guards.test.ts +20 -15
- package/src/utils/type-guards.ts +1 -1
- package/src/workers/background-worker-cli.ts +28 -30
- package/src/workers/background-worker.test.ts +54 -40
- package/src/workers/background-worker.ts +76 -60
- package/src/workers/pid-file.test.ts +167 -0
- package/src/workers/pid-file.ts +82 -0
- package/src/workers/spawn-worker.test.ts +22 -10
- package/src/workers/spawn-worker.ts +6 -6
- package/tests/analysis/ast-parser.test.ts +3 -3
- package/tests/analysis/code-graph.test.ts +5 -5
- package/tests/fixtures/code-snippets/api/error-handling.ts +4 -15
- package/tests/fixtures/code-snippets/api/rest-controller.ts +3 -9
- package/tests/fixtures/code-snippets/auth/jwt-auth.ts +5 -21
- package/tests/fixtures/code-snippets/auth/oauth-flow.ts +4 -4
- package/tests/fixtures/code-snippets/database/repository-pattern.ts +11 -3
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/aws-lambda/handler.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-pages/handler.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/adapter/cloudflare-workers/serve-static.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/client/client.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/client/types.ts +22 -20
- package/tests/fixtures/corpus/oss-repos/hono/src/context.ts +13 -10
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/accepts/accepts.ts +10 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/adapter/index.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/css/index.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/factory/index.ts +16 -16
- package/tests/fixtures/corpus/oss-repos/hono/src/helper/ssg/ssg.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/hono-base.ts +3 -3
- package/tests/fixtures/corpus/oss-repos/hono/src/hono.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/css.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/intrinsic-element/components.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/dom/render.ts +7 -7
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/hooks/index.ts +3 -3
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/intrinsic-element/components.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/jsx/utils.ts +6 -6
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/jsx-renderer/index.ts +3 -3
- package/tests/fixtures/corpus/oss-repos/hono/src/middleware/serve-static/index.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/preset/quick.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/preset/tiny.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/router/pattern-router/router.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/node.ts +4 -4
- package/tests/fixtures/corpus/oss-repos/hono/src/router/reg-exp-router/router.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/router/trie-router/node.ts +1 -1
- package/tests/fixtures/corpus/oss-repos/hono/src/types.ts +166 -169
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/body.ts +8 -8
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/color.ts +3 -3
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/cookie.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/encode.ts +2 -2
- package/tests/fixtures/corpus/oss-repos/hono/src/utils/types.ts +30 -33
- package/tests/fixtures/corpus/oss-repos/hono/src/validator/validator.ts +2 -2
- package/tests/fixtures/test-server.ts +3 -2
- package/tests/helpers/performance-metrics.ts +8 -25
- package/tests/helpers/search-relevance.ts +14 -69
- package/tests/integration/cli-consistency.test.ts +6 -5
- package/tests/integration/python-bridge.test.ts +13 -3
- package/tests/mcp/server.test.ts +1 -1
- package/tests/services/code-unit.service.test.ts +48 -0
- package/tests/services/job.service.test.ts +124 -0
- package/tests/services/search.progressive-context.test.ts +2 -2
- package/.claude-plugin/plugin.json +0 -13
- package/dist/chunk-6PBP5DVD.js.map +0 -1
- package/dist/chunk-L2YVNC63.js.map +0 -1
- package/dist/chunk-RST4XGRL.js.map +0 -1
- package/dist/chunk-WT2DAEO7.js.map +0 -1
- package/dist/watch.service-YAIKKDCF.js +0 -7
- package/skills/atomic-commits/SKILL.md +0 -77
- /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([
|
|
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([
|
|
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([
|
|
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([
|
|
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([
|
|
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(
|
|
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(
|
|
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(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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.
|
|
93
|
+
console.error(`Error: ${result.error.message}`);
|
|
94
|
+
exitCode = 1;
|
|
75
95
|
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
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(
|
|
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
|
package/src/cli/program.ts
CHANGED
|
@@ -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(
|
|
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
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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(
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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: '',
|