@dikolab/kbdb 0.6.1 → 0.6.3
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/README.md +33 -6
- package/README.md.bak +33 -6
- package/dist/README.md +33 -6
- package/dist/cli.cjs +663 -218
- package/dist/cli.cjs.map +3 -3
- package/dist/cli.mjs +663 -218
- package/dist/cli.mjs.map +3 -3
- package/dist/kbdb-worker.cjs +71 -12
- package/dist/kbdb-worker.cjs.map +3 -3
- package/dist/mod.cjs +1 -1
- package/dist/mod.cjs.map +1 -1
- package/dist/mod.mjs +1 -1
- package/dist/mod.mjs.map +1 -1
- package/dist/src/shared/cli/constants/recfile-field-maps.constant.d.ts +3 -1
- package/dist/src/shared/cli/functions/format-command-output.function.d.ts +0 -4
- package/dist/src/shared/cli/functions/format-command-text.function.d.ts +1 -0
- package/dist/src/shared/cli/functions/format-mcp-output.function.d.ts +5 -4
- package/dist/src/shared/cli/functions/format-output.function.d.ts +3 -7
- package/dist/src/shared/cli/functions/format-text-output.function.d.ts +3 -2
- package/dist/src/shared/cli/functions/run-agent-search.function.d.ts +13 -0
- package/dist/src/shared/cli/functions/run-check.function.d.ts +1 -1
- package/dist/src/shared/cli/functions/run-content.function.d.ts +18 -14
- package/dist/src/shared/cli/functions/run-learn.function.d.ts +6 -11
- package/dist/src/shared/cli/functions/run-skill-search.function.d.ts +13 -0
- package/dist/src/shared/cli/functions/wrap-mcp-envelope.function.d.ts +8 -0
- package/dist/src/shared/cli/typings/cli-options.interface.d.ts +6 -0
- package/dist/src/shared/cli/typings/learn-client.interface.d.ts +6 -2
- package/dist/src/shared/cli/typings/learn-result.model.d.ts +4 -0
- package/dist/src/shared/cli/typings/search-display.model.d.ts +2 -2
- package/dist/src/shared/mcp/constants/tool-agent-search.constant.d.ts +3 -0
- package/dist/src/shared/mcp/constants/tool-skill-search.constant.d.ts +3 -0
- package/dist/src/shared/mcp/functions/format-search-results.function.d.ts +25 -0
- package/dist/src/shared/mcp/functions/handle-agent-get.function.d.ts +4 -4
- package/dist/src/shared/mcp/functions/handle-agent-list.function.d.ts +3 -7
- package/dist/src/shared/mcp/functions/handle-agent-search.function.d.ts +11 -0
- package/dist/src/shared/mcp/functions/handle-recall.function.d.ts +1 -1
- package/dist/src/shared/mcp/functions/handle-skill-search.function.d.ts +11 -0
- package/dist/src/shared/mcp/functions/handle-tool-search.function.d.ts +3 -3
- package/dist/src/shared/mcp/typings/mcp-client.interface.d.ts +2 -2
- package/dist/src/shared/mcp/typings/mcp-worker-client.interface.d.ts +2 -2
- package/dist/src/shared/version/constants/version.constant.d.ts +1 -1
- package/dist/src/shared/worker-client/typings/add-section-result.model.d.ts +6 -12
- package/dist/src/shared/worker-client/typings/status-result.model.d.ts +2 -2
- package/dist/src/shared/worker-daemon/functions/strip-recall-by-depth.function.d.ts +22 -0
- package/dist/wasm/fs-database/kbdb_fs_database_bg.wasm +0 -0
- package/dist/wasm/kb-worker/kbdb_worker_bg.wasm +0 -0
- package/dist/worker.mjs +71 -12
- package/dist/worker.mjs.map +3 -3
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -180,6 +180,10 @@ function parseArgs(argv) {
|
|
|
180
180
|
case "-c":
|
|
181
181
|
options.content = true;
|
|
182
182
|
break;
|
|
183
|
+
case "--search":
|
|
184
|
+
case "-s":
|
|
185
|
+
options.search = true;
|
|
186
|
+
break;
|
|
183
187
|
case "--relaxed":
|
|
184
188
|
options.relaxed = true;
|
|
185
189
|
break;
|
|
@@ -216,18 +220,19 @@ function parseArgs(argv) {
|
|
|
216
220
|
}
|
|
217
221
|
|
|
218
222
|
// src/shared/cli/functions/format-text-output.function.ts
|
|
219
|
-
function formatTextOutput(paged) {
|
|
223
|
+
function formatTextOutput(paged, content) {
|
|
220
224
|
if (paged.items.length === 0) return "No results found.";
|
|
221
225
|
const start = paged.offset + 1;
|
|
222
226
|
const end = paged.offset + paged.items.length;
|
|
223
227
|
const lines = paged.items.map((r, i) => {
|
|
224
228
|
const num = paged.offset + i + 1;
|
|
225
|
-
const heading = r.heading
|
|
229
|
+
const heading = r.heading || "(untitled)";
|
|
226
230
|
const terms = r.matched_terms.join(", ");
|
|
227
231
|
const fields = r.matched_fields.join(", ");
|
|
228
232
|
const confidencePct = (r.confidence * 100).toFixed(0);
|
|
233
|
+
const body = content ? r.preview || "(no content)" : r.snippet || r.preview || "(no snippet)";
|
|
229
234
|
return `${String(num)}. [${r.kbid}] ${heading} (score: ${r.score.toFixed(4)}, confidence: ${confidencePct}%)
|
|
230
|
-
${
|
|
235
|
+
${body}
|
|
231
236
|
type: ${r.type} terms: ${terms}` + (fields ? ` fields: ${fields}` : "");
|
|
232
237
|
}).join("\n\n");
|
|
233
238
|
const footer = `
|
|
@@ -238,29 +243,21 @@ Use --offset ${String(end)} to see more` : "";
|
|
|
238
243
|
}
|
|
239
244
|
|
|
240
245
|
// src/shared/cli/functions/format-mcp-output.function.ts
|
|
241
|
-
function formatMcpOutput(paged) {
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
docids: r.docids,
|
|
247
|
-
snippet: r.snippet,
|
|
248
|
-
matched_terms: r.matched_terms,
|
|
249
|
-
matched_fields: r.matched_fields,
|
|
250
|
-
created_at: r.created_at
|
|
251
|
-
}));
|
|
246
|
+
function formatMcpOutput(paged, content) {
|
|
247
|
+
const text = paged.items.length === 0 ? "No results found." : paged.items.map((r) => {
|
|
248
|
+
const body = content ? r.preview || "(no content)" : r.snippet || r.preview;
|
|
249
|
+
return `[${r.kbid}] ${r.heading || "(untitled)"} \u2014 ${body}`;
|
|
250
|
+
}).join("\n");
|
|
252
251
|
return JSON.stringify(
|
|
253
252
|
{
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
has_more: paged.has_more,
|
|
263
|
-
relaxed: paged.relaxed
|
|
253
|
+
jsonrpc: "2.0",
|
|
254
|
+
result: {
|
|
255
|
+
content: [{ type: "text", text }],
|
|
256
|
+
total: paged.total,
|
|
257
|
+
offset: paged.offset,
|
|
258
|
+
limit: paged.limit,
|
|
259
|
+
has_more: paged.has_more
|
|
260
|
+
}
|
|
264
261
|
},
|
|
265
262
|
null,
|
|
266
263
|
2
|
|
@@ -330,15 +327,24 @@ var SEARCH_FIELDS = [
|
|
|
330
327
|
["snippet", "snippet"],
|
|
331
328
|
["level", "level"]
|
|
332
329
|
];
|
|
333
|
-
var
|
|
330
|
+
var SEARCH_CONTENT_FIELDS = [
|
|
334
331
|
["kbid", "kbid"],
|
|
335
|
-
["
|
|
336
|
-
["
|
|
337
|
-
["
|
|
338
|
-
["
|
|
339
|
-
["
|
|
332
|
+
["heading", "heading"],
|
|
333
|
+
["score", "score"],
|
|
334
|
+
["confidence", "confidence"],
|
|
335
|
+
["type", "type"],
|
|
336
|
+
["terms", "matched_terms"],
|
|
337
|
+
["fields", "matched_fields"],
|
|
338
|
+
["content", "preview"],
|
|
340
339
|
["level", "level"]
|
|
341
340
|
];
|
|
341
|
+
var LEARN_FIELDS = [
|
|
342
|
+
["items", "items"],
|
|
343
|
+
["total", "total"],
|
|
344
|
+
["offset", "offset"],
|
|
345
|
+
["superseded", "superseded"],
|
|
346
|
+
["warnings", "warnings"]
|
|
347
|
+
];
|
|
342
348
|
var UNLEARN_FIELDS = [
|
|
343
349
|
["removed", "removed"],
|
|
344
350
|
["elapsed_ms", "elapsed_ms"]
|
|
@@ -366,7 +372,9 @@ var IMPORT_FIELDS = [
|
|
|
366
372
|
];
|
|
367
373
|
var STATUS_FIELDS = [
|
|
368
374
|
["initialized", "initialized"],
|
|
369
|
-
["path", "
|
|
375
|
+
["path", "context_path"],
|
|
376
|
+
["documents", "document_count"],
|
|
377
|
+
["sections", "section_count"],
|
|
370
378
|
["content_cached", "cacheStats.contentCount"],
|
|
371
379
|
["index_cached", "cacheStats.indexCount"]
|
|
372
380
|
];
|
|
@@ -389,16 +397,19 @@ var REBUILD_FIELDS = [
|
|
|
389
397
|
];
|
|
390
398
|
|
|
391
399
|
// src/shared/cli/functions/format-output.function.ts
|
|
392
|
-
function formatOutput(paged, format) {
|
|
400
|
+
function formatOutput(paged, format, content) {
|
|
393
401
|
switch (format) {
|
|
394
402
|
case "json":
|
|
395
403
|
return JSON.stringify(paged, null, 2);
|
|
396
404
|
case "text":
|
|
397
|
-
return formatTextOutput(paged);
|
|
405
|
+
return formatTextOutput(paged, content);
|
|
398
406
|
case "rec":
|
|
399
|
-
return formatRecfileOutput(
|
|
407
|
+
return formatRecfileOutput(
|
|
408
|
+
paged.items,
|
|
409
|
+
content ? SEARCH_CONTENT_FIELDS : SEARCH_FIELDS
|
|
410
|
+
);
|
|
400
411
|
case "mcp":
|
|
401
|
-
return formatMcpOutput(paged);
|
|
412
|
+
return formatMcpOutput(paged, content);
|
|
402
413
|
}
|
|
403
414
|
}
|
|
404
415
|
|
|
@@ -415,6 +426,93 @@ var RECFILE_COMMAND_FIELD_MAP = {
|
|
|
415
426
|
rebuild: REBUILD_FIELDS
|
|
416
427
|
};
|
|
417
428
|
|
|
429
|
+
// src/shared/cli/functions/format-command-text.function.ts
|
|
430
|
+
function str(v) {
|
|
431
|
+
if (typeof v === "string") return v;
|
|
432
|
+
if (typeof v === "number") return String(v);
|
|
433
|
+
if (typeof v === "boolean") return String(v);
|
|
434
|
+
if (v == null) return "";
|
|
435
|
+
return JSON.stringify(v);
|
|
436
|
+
}
|
|
437
|
+
function formatCommandText(data, command) {
|
|
438
|
+
const obj = data;
|
|
439
|
+
switch (command) {
|
|
440
|
+
case "status":
|
|
441
|
+
return formatStatus(obj);
|
|
442
|
+
case "check":
|
|
443
|
+
return formatCheck(obj);
|
|
444
|
+
case "gc":
|
|
445
|
+
return formatGc(obj);
|
|
446
|
+
case "rebuild":
|
|
447
|
+
return formatRebuild(obj);
|
|
448
|
+
case "unlearn":
|
|
449
|
+
return formatUnlearn(obj);
|
|
450
|
+
case "learn":
|
|
451
|
+
return formatLearn(data);
|
|
452
|
+
default:
|
|
453
|
+
return JSON.stringify(data, null, 2);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
function formatStatus(o) {
|
|
457
|
+
const cs = o["cacheStats"];
|
|
458
|
+
const path = o["context_path"] ?? o["contextPath"] ?? "(unknown)";
|
|
459
|
+
const lines = [
|
|
460
|
+
`Initialized: ${str(o["initialized"] ?? false)}`,
|
|
461
|
+
`Path: ${str(path)}`
|
|
462
|
+
];
|
|
463
|
+
if (o["document_count"] != null)
|
|
464
|
+
lines.push(`Documents: ${str(o["document_count"])}`);
|
|
465
|
+
if (o["section_count"] != null)
|
|
466
|
+
lines.push(`Sections: ${str(o["section_count"])}`);
|
|
467
|
+
if (cs) {
|
|
468
|
+
lines.push(
|
|
469
|
+
`Content cached: ${str(cs["contentCount"] ?? 0)}`,
|
|
470
|
+
`Index cached: ${str(cs["indexCount"] ?? 0)}`
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
return lines.join("\n");
|
|
474
|
+
}
|
|
475
|
+
function formatCheck(o) {
|
|
476
|
+
const ok = o["ok"] ? "OK" : "FAILED";
|
|
477
|
+
return `Integrity check: ${ok} (${str(o["sections_checked"] ?? 0)} sections, ${str(o["documents_checked"] ?? 0)} documents, ${str(o["references_checked"] ?? 0)} refs, ${str(o["elapsed_ms"] ?? 0)}ms)`;
|
|
478
|
+
}
|
|
479
|
+
function formatGc(o) {
|
|
480
|
+
return `GC: removed ${str(o["removed_sections"] ?? 0)} sections, reclaimed ${str(o["removed_bytes"] ?? 0)} bytes (${str(o["elapsed_ms"] ?? 0)}ms)`;
|
|
481
|
+
}
|
|
482
|
+
function formatRebuild(o) {
|
|
483
|
+
return `Rebuild: ${str(o["sections_reindexed"] ?? 0)} sections reindexed, ${str(o["terms_indexed"] ?? 0)} terms (${str(o["elapsed_ms"] ?? 0)}ms)`;
|
|
484
|
+
}
|
|
485
|
+
function formatUnlearn(o) {
|
|
486
|
+
const removed = o["removed"];
|
|
487
|
+
if (Array.isArray(removed)) {
|
|
488
|
+
return `Removed: ${removed.length.toString()} section(s)`;
|
|
489
|
+
}
|
|
490
|
+
return `Removed: ${str(removed ?? false)} (${str(o["elapsed_ms"] ?? 0)}ms)`;
|
|
491
|
+
}
|
|
492
|
+
function formatLearn(data) {
|
|
493
|
+
const obj = data;
|
|
494
|
+
const items = obj["items"];
|
|
495
|
+
if (Array.isArray(items)) {
|
|
496
|
+
return items.map((id) => `Learned: ${str(id)}`).join("\n");
|
|
497
|
+
}
|
|
498
|
+
return JSON.stringify(data, null, 2);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// src/shared/cli/functions/wrap-mcp-envelope.function.ts
|
|
502
|
+
function wrapMcpEnvelope(data, command) {
|
|
503
|
+
const text = formatCommandText(data, command);
|
|
504
|
+
return JSON.stringify(
|
|
505
|
+
{
|
|
506
|
+
jsonrpc: "2.0",
|
|
507
|
+
result: {
|
|
508
|
+
content: [{ type: "text", text }]
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
null,
|
|
512
|
+
2
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
|
|
418
516
|
// src/shared/cli/functions/format-command-output.function.ts
|
|
419
517
|
function formatCommandOutput(data, format, command) {
|
|
420
518
|
switch (format) {
|
|
@@ -423,9 +521,11 @@ function formatCommandOutput(data, format, command) {
|
|
|
423
521
|
return fields ? formatRecfileOutput(data, fields) : JSON.stringify(data, null, 2);
|
|
424
522
|
}
|
|
425
523
|
case "json":
|
|
524
|
+
return JSON.stringify(data, null, 2);
|
|
426
525
|
case "text":
|
|
526
|
+
return formatCommandText(data, command);
|
|
427
527
|
case "mcp":
|
|
428
|
-
return
|
|
528
|
+
return wrapMcpEnvelope(data, command);
|
|
429
529
|
}
|
|
430
530
|
}
|
|
431
531
|
|
|
@@ -516,7 +616,7 @@ async function runSearch(client, options) {
|
|
|
516
616
|
return {
|
|
517
617
|
items: results.items.map((r) => ({
|
|
518
618
|
kbid: r.kbid,
|
|
519
|
-
heading: r.heading,
|
|
619
|
+
heading: r.heading || "(untitled)",
|
|
520
620
|
type: r.type,
|
|
521
621
|
docids: r.docids,
|
|
522
622
|
score: r.score,
|
|
@@ -542,6 +642,11 @@ async function runSearch(client, options) {
|
|
|
542
642
|
var SECTION_TYPES = ["text", "code", "image"];
|
|
543
643
|
async function resolveKbidPrefix(prefix, client) {
|
|
544
644
|
if (prefix.length >= 26) return prefix;
|
|
645
|
+
if (prefix.length < 2) {
|
|
646
|
+
const msg = `prefix "${prefix}" is too short (minimum 2 characters)`;
|
|
647
|
+
log(msg, 3 /* ERROR */);
|
|
648
|
+
throw new Error(msg);
|
|
649
|
+
}
|
|
545
650
|
const seen = /* @__PURE__ */ new Set();
|
|
546
651
|
for (const type of SECTION_TYPES) {
|
|
547
652
|
const records = await client.listByType(type);
|
|
@@ -550,7 +655,7 @@ async function resolveKbidPrefix(prefix, client) {
|
|
|
550
655
|
}
|
|
551
656
|
}
|
|
552
657
|
if (seen.size === 0) {
|
|
553
|
-
const msg = `no section matches prefix "${prefix}"`;
|
|
658
|
+
const msg = `no section matches prefix "${prefix}". Try "kbdb content --search <query>" to find by keyword`;
|
|
554
659
|
log(msg, 3 /* ERROR */);
|
|
555
660
|
throw new Error(msg);
|
|
556
661
|
}
|
|
@@ -664,7 +769,9 @@ async function runLearn(client, options, io) {
|
|
|
664
769
|
replace: options.replace,
|
|
665
770
|
level: options.level
|
|
666
771
|
});
|
|
667
|
-
results.push(
|
|
772
|
+
results.push(
|
|
773
|
+
mapAddSectionResult(result, "-", content.length, "text")
|
|
774
|
+
);
|
|
668
775
|
continue;
|
|
669
776
|
}
|
|
670
777
|
const files = collectFiles(target);
|
|
@@ -682,7 +789,7 @@ async function runLearn(client, options, io) {
|
|
|
682
789
|
level: options.level ?? computeDirectoryLevel(file, target)
|
|
683
790
|
});
|
|
684
791
|
results.push(
|
|
685
|
-
mapAddSectionResult(result, file, content.length)
|
|
792
|
+
mapAddSectionResult(result, file, content.length, "text")
|
|
686
793
|
);
|
|
687
794
|
}
|
|
688
795
|
}
|
|
@@ -692,9 +799,11 @@ async function runLearn(client, options, io) {
|
|
|
692
799
|
);
|
|
693
800
|
return results;
|
|
694
801
|
}
|
|
695
|
-
function mapAddSectionResult(result, path, size) {
|
|
802
|
+
function mapAddSectionResult(result, path, size, sectionType) {
|
|
696
803
|
return {
|
|
697
|
-
kbid: result.
|
|
804
|
+
kbid: result.items[0] ?? "",
|
|
805
|
+
indexed_terms_count: 0,
|
|
806
|
+
type: sectionType,
|
|
698
807
|
path,
|
|
699
808
|
size,
|
|
700
809
|
skipped: false,
|
|
@@ -731,11 +840,26 @@ async function runUnlearn(client, options) {
|
|
|
731
840
|
// src/shared/cli/functions/run-content.function.ts
|
|
732
841
|
async function runContent(client, options) {
|
|
733
842
|
log("running content", 0 /* DEBUG */);
|
|
843
|
+
if (options.search) {
|
|
844
|
+
return runContentSearch(client, options);
|
|
845
|
+
}
|
|
734
846
|
const resolved = await Promise.all(
|
|
735
847
|
options.args.map((a) => resolveKbidPrefix(a, client))
|
|
736
848
|
);
|
|
737
849
|
return client.content(resolved);
|
|
738
850
|
}
|
|
851
|
+
async function runContentSearch(client, options) {
|
|
852
|
+
const query = options.args.join(" ");
|
|
853
|
+
const result = await client.search({
|
|
854
|
+
query,
|
|
855
|
+
limit: options.limit
|
|
856
|
+
});
|
|
857
|
+
const kbids = result.items.map((hit) => hit.kbid);
|
|
858
|
+
if (kbids.length === 0) {
|
|
859
|
+
return { type: "text/markdown", data: "", total: 0 };
|
|
860
|
+
}
|
|
861
|
+
return client.content(kbids);
|
|
862
|
+
}
|
|
739
863
|
|
|
740
864
|
// src/shared/cli/functions/run-check.function.ts
|
|
741
865
|
function parseDivergentContent(encoded) {
|
|
@@ -750,14 +874,21 @@ function parseDivergentContent(encoded) {
|
|
|
750
874
|
async function runCheck(client, _options) {
|
|
751
875
|
log("running check", 0 /* DEBUG */);
|
|
752
876
|
const raw = await client.integrityCheck();
|
|
877
|
+
const divergent = parseDivergentContent(raw.divergent_content);
|
|
878
|
+
const divergentErrors = divergent.map((d) => ({
|
|
879
|
+
type: "divergent_content",
|
|
880
|
+
entity: d.sourceKey,
|
|
881
|
+
detail: `${d.kbids.length.toString()} divergent sections: ${d.kbids.join(", ")}`
|
|
882
|
+
}));
|
|
883
|
+
const errors = [...raw.errors, ...divergentErrors];
|
|
753
884
|
return {
|
|
754
|
-
ok: raw.ok,
|
|
755
|
-
errors
|
|
885
|
+
ok: raw.ok && errors.length === 0,
|
|
886
|
+
errors,
|
|
756
887
|
sections_checked: raw.sections_checked,
|
|
757
888
|
documents_checked: raw.documents_checked,
|
|
758
889
|
references_checked: raw.references_checked,
|
|
759
890
|
elapsed_ms: raw.elapsed_ms,
|
|
760
|
-
divergent_content:
|
|
891
|
+
divergent_content: divergent
|
|
761
892
|
};
|
|
762
893
|
}
|
|
763
894
|
|
|
@@ -1055,7 +1186,15 @@ async function runSkillLearn(client, options) {
|
|
|
1055
1186
|
description: options.description
|
|
1056
1187
|
});
|
|
1057
1188
|
return {
|
|
1058
|
-
output: JSON.stringify(
|
|
1189
|
+
output: JSON.stringify(
|
|
1190
|
+
{
|
|
1191
|
+
kbid: result.items[0],
|
|
1192
|
+
name,
|
|
1193
|
+
arguments: args.length > 0 ? args : []
|
|
1194
|
+
},
|
|
1195
|
+
null,
|
|
1196
|
+
2
|
|
1197
|
+
),
|
|
1059
1198
|
exitCode: 0
|
|
1060
1199
|
};
|
|
1061
1200
|
}
|
|
@@ -1116,10 +1255,12 @@ async function runSkillGet(client, options) {
|
|
|
1116
1255
|
};
|
|
1117
1256
|
}
|
|
1118
1257
|
let content;
|
|
1119
|
-
|
|
1258
|
+
let kbid;
|
|
1259
|
+
if (/^[a-z2-7]{26}$/.test(identifier)) {
|
|
1120
1260
|
const sections = await client.readSections([identifier]);
|
|
1121
1261
|
if (sections.length > 0) {
|
|
1122
1262
|
content = sections[0]?.content;
|
|
1263
|
+
kbid = identifier;
|
|
1123
1264
|
}
|
|
1124
1265
|
}
|
|
1125
1266
|
if (content === void 0) {
|
|
@@ -1127,9 +1268,10 @@ async function runSkillGet(client, options) {
|
|
|
1127
1268
|
const match = records.filter((r) => r.title === identifier).pop();
|
|
1128
1269
|
if (match) {
|
|
1129
1270
|
content = match.content;
|
|
1271
|
+
kbid = match.kbid;
|
|
1130
1272
|
}
|
|
1131
1273
|
}
|
|
1132
|
-
if (content === void 0) {
|
|
1274
|
+
if (content === void 0 || kbid === void 0) {
|
|
1133
1275
|
return {
|
|
1134
1276
|
error: `skill not found: ${identifier}`,
|
|
1135
1277
|
exitCode: 1
|
|
@@ -1137,7 +1279,7 @@ async function runSkillGet(client, options) {
|
|
|
1137
1279
|
}
|
|
1138
1280
|
const skill = parseSkillContent(content);
|
|
1139
1281
|
return {
|
|
1140
|
-
output: JSON.stringify(skill, null, 2),
|
|
1282
|
+
output: JSON.stringify({ kbid, ...skill }, null, 2),
|
|
1141
1283
|
exitCode: 0
|
|
1142
1284
|
};
|
|
1143
1285
|
}
|
|
@@ -1152,7 +1294,7 @@ async function runSkillDelete(client, options) {
|
|
|
1152
1294
|
const result = await client.removeSection(kbid);
|
|
1153
1295
|
return {
|
|
1154
1296
|
output: JSON.stringify(
|
|
1155
|
-
{
|
|
1297
|
+
{ removed: result.removed ? [kbid] : [] },
|
|
1156
1298
|
null,
|
|
1157
1299
|
2
|
|
1158
1300
|
),
|
|
@@ -1194,7 +1336,7 @@ async function runAgentCreate(client, options) {
|
|
|
1194
1336
|
title: name,
|
|
1195
1337
|
description: options.description
|
|
1196
1338
|
});
|
|
1197
|
-
const allKbids = [metaResult.
|
|
1339
|
+
const allKbids = [metaResult.items[0], ...skills];
|
|
1198
1340
|
const docid = await client.groupSections(name, allKbids, "agent");
|
|
1199
1341
|
return {
|
|
1200
1342
|
output: JSON.stringify(
|
|
@@ -1294,11 +1436,33 @@ async function runAgentDelete(client, options) {
|
|
|
1294
1436
|
}
|
|
1295
1437
|
await client.removeGrouping(docid);
|
|
1296
1438
|
return {
|
|
1297
|
-
output: JSON.stringify({
|
|
1439
|
+
output: JSON.stringify({ removed: [docid] }, null, 2),
|
|
1298
1440
|
exitCode: 0
|
|
1299
1441
|
};
|
|
1300
1442
|
}
|
|
1301
1443
|
|
|
1444
|
+
// src/shared/cli/functions/run-skill-search.function.ts
|
|
1445
|
+
async function runSkillSearch(client, options) {
|
|
1446
|
+
const paged = await runSearch(client, options);
|
|
1447
|
+
const filtered = paged.items.filter((item) => item.type === "skill");
|
|
1448
|
+
return {
|
|
1449
|
+
...paged,
|
|
1450
|
+
items: filtered,
|
|
1451
|
+
total: filtered.length
|
|
1452
|
+
};
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// src/shared/cli/functions/run-agent-search.function.ts
|
|
1456
|
+
async function runAgentSearch(client, options) {
|
|
1457
|
+
const paged = await runSearch(client, options);
|
|
1458
|
+
const filtered = paged.items.filter((item) => item.type === "agent");
|
|
1459
|
+
return {
|
|
1460
|
+
...paged,
|
|
1461
|
+
items: filtered,
|
|
1462
|
+
total: filtered.length
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1302
1466
|
// src/shared/cli/functions/run-import.function.ts
|
|
1303
1467
|
var import_node_path6 = require("node:path");
|
|
1304
1468
|
async function runImport(client, options) {
|
|
@@ -1389,6 +1553,10 @@ async function dispatchCommand(client, options, io) {
|
|
|
1389
1553
|
const result = await runAgentDelete(client, options);
|
|
1390
1554
|
return result;
|
|
1391
1555
|
}
|
|
1556
|
+
case "skill-search":
|
|
1557
|
+
return handleTypedSearch(client, options, "skill");
|
|
1558
|
+
case "agent-search":
|
|
1559
|
+
return handleTypedSearch(client, options, "agent");
|
|
1392
1560
|
default:
|
|
1393
1561
|
log("unknown command: " + options.command, 2 /* WARNING */);
|
|
1394
1562
|
return {
|
|
@@ -1400,8 +1568,33 @@ async function dispatchCommand(client, options, io) {
|
|
|
1400
1568
|
async function handleLearn(client, options, io) {
|
|
1401
1569
|
try {
|
|
1402
1570
|
const results = await runLearn(client, options, io);
|
|
1571
|
+
const items = results.map((r) => r.kbid);
|
|
1572
|
+
const base = {
|
|
1573
|
+
items,
|
|
1574
|
+
total: results.length,
|
|
1575
|
+
offset: 0
|
|
1576
|
+
};
|
|
1577
|
+
if (results.length === 0) {
|
|
1578
|
+
const empty = {
|
|
1579
|
+
...base,
|
|
1580
|
+
superseded: null,
|
|
1581
|
+
warnings: [],
|
|
1582
|
+
near_duplicates: []
|
|
1583
|
+
};
|
|
1584
|
+
return {
|
|
1585
|
+
output: formatCommandOutput(empty, options.format, "learn"),
|
|
1586
|
+
exitCode: 0
|
|
1587
|
+
};
|
|
1588
|
+
}
|
|
1589
|
+
const last = results[results.length - 1];
|
|
1590
|
+
const data = {
|
|
1591
|
+
...base,
|
|
1592
|
+
superseded: last.superseded,
|
|
1593
|
+
warnings: last.warnings,
|
|
1594
|
+
near_duplicates: last.near_duplicates
|
|
1595
|
+
};
|
|
1403
1596
|
return {
|
|
1404
|
-
output: formatCommandOutput(
|
|
1597
|
+
output: formatCommandOutput(data, options.format, "learn"),
|
|
1405
1598
|
exitCode: 0
|
|
1406
1599
|
};
|
|
1407
1600
|
} catch (err) {
|
|
@@ -1414,9 +1607,10 @@ async function handleLearn(client, options, io) {
|
|
|
1414
1607
|
async function handleUnlearn(client, options) {
|
|
1415
1608
|
try {
|
|
1416
1609
|
const results = await runUnlearn(client, options);
|
|
1610
|
+
const removed = results.filter((r) => r.removed).map((r) => r.kbid);
|
|
1417
1611
|
return {
|
|
1418
1612
|
output: formatCommandOutput(
|
|
1419
|
-
|
|
1613
|
+
{ removed },
|
|
1420
1614
|
options.format,
|
|
1421
1615
|
"unlearn"
|
|
1422
1616
|
),
|
|
@@ -1436,7 +1630,7 @@ async function handleSearch(client, options) {
|
|
|
1436
1630
|
await hydrateSearchPreviews(client, results);
|
|
1437
1631
|
}
|
|
1438
1632
|
return {
|
|
1439
|
-
output: formatOutput(results, options.format),
|
|
1633
|
+
output: formatOutput(results, options.format, options.content),
|
|
1440
1634
|
exitCode: 0
|
|
1441
1635
|
};
|
|
1442
1636
|
} catch (err) {
|
|
@@ -1497,11 +1691,38 @@ async function handleImport(client, options) {
|
|
|
1497
1691
|
async function handleContent(client, options) {
|
|
1498
1692
|
try {
|
|
1499
1693
|
const result = await runContent(client, options);
|
|
1500
|
-
if (options.format === "
|
|
1694
|
+
if (options.format === "text") {
|
|
1501
1695
|
return { output: result.data, exitCode: 0 };
|
|
1502
1696
|
}
|
|
1697
|
+
if (options.format === "rec") {
|
|
1698
|
+
const header = `type: ${result.type}
|
|
1699
|
+
total: ${String(result.total)}
|
|
1700
|
+
|
|
1701
|
+
`;
|
|
1702
|
+
return {
|
|
1703
|
+
output: header + result.data,
|
|
1704
|
+
exitCode: 0
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
if (options.format === "mcp") {
|
|
1708
|
+
const text = result.data || "(empty)";
|
|
1709
|
+
return {
|
|
1710
|
+
output: JSON.stringify(
|
|
1711
|
+
{
|
|
1712
|
+
jsonrpc: "2.0",
|
|
1713
|
+
result: {
|
|
1714
|
+
content: [{ type: "text", text }]
|
|
1715
|
+
}
|
|
1716
|
+
},
|
|
1717
|
+
null,
|
|
1718
|
+
2
|
|
1719
|
+
),
|
|
1720
|
+
exitCode: 0
|
|
1721
|
+
};
|
|
1722
|
+
}
|
|
1723
|
+
const envelope = !options.search && options.args.length === 1 ? { kbid: options.args[0], ...result } : result;
|
|
1503
1724
|
return {
|
|
1504
|
-
output: JSON.stringify(
|
|
1725
|
+
output: JSON.stringify(envelope, null, 2),
|
|
1505
1726
|
exitCode: 0
|
|
1506
1727
|
};
|
|
1507
1728
|
} catch (err) {
|
|
@@ -1588,9 +1809,24 @@ async function handleDbMigrate(client, options) {
|
|
|
1588
1809
|
};
|
|
1589
1810
|
}
|
|
1590
1811
|
}
|
|
1812
|
+
async function handleTypedSearch(client, options, type) {
|
|
1813
|
+
try {
|
|
1814
|
+
const runner = type === "skill" ? runSkillSearch : runAgentSearch;
|
|
1815
|
+
const results = await runner(client, options);
|
|
1816
|
+
return {
|
|
1817
|
+
output: formatOutput(results, options.format),
|
|
1818
|
+
exitCode: 0
|
|
1819
|
+
};
|
|
1820
|
+
} catch (err) {
|
|
1821
|
+
return {
|
|
1822
|
+
error: `${type} search failed: ${errorToMessage(err)}`,
|
|
1823
|
+
exitCode: 1
|
|
1824
|
+
};
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1591
1827
|
|
|
1592
1828
|
// src/shared/version/constants/version.constant.ts
|
|
1593
|
-
var VERSION = "0.6.
|
|
1829
|
+
var VERSION = "0.6.3";
|
|
1594
1830
|
|
|
1595
1831
|
// src/shared/cli/functions/generate-help.function.ts
|
|
1596
1832
|
var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
|
|
@@ -3215,8 +3451,15 @@ function handleInit(options, deps2) {
|
|
|
3215
3451
|
exitCode: 0
|
|
3216
3452
|
};
|
|
3217
3453
|
}
|
|
3454
|
+
const msg = result.errorMessage ?? "init failed";
|
|
3455
|
+
if (/already exists/i.test(msg)) {
|
|
3456
|
+
return {
|
|
3457
|
+
output: `${result.targetPath} (already initialized)`,
|
|
3458
|
+
exitCode: 0
|
|
3459
|
+
};
|
|
3460
|
+
}
|
|
3218
3461
|
return {
|
|
3219
|
-
error: `error: ${
|
|
3462
|
+
error: `error: ${msg}`,
|
|
3220
3463
|
exitCode: 1
|
|
3221
3464
|
};
|
|
3222
3465
|
}
|
|
@@ -3476,7 +3719,7 @@ function createToolDefinitions() {
|
|
|
3476
3719
|
properties: {
|
|
3477
3720
|
content: {
|
|
3478
3721
|
type: "string",
|
|
3479
|
-
description: "
|
|
3722
|
+
description: "Raw text or Markdown content to index. Do not wrap in JSON."
|
|
3480
3723
|
},
|
|
3481
3724
|
type: {
|
|
3482
3725
|
type: "string",
|
|
@@ -3706,7 +3949,7 @@ function createToolDefinitions() {
|
|
|
3706
3949
|
},
|
|
3707
3950
|
body: {
|
|
3708
3951
|
type: "string",
|
|
3709
|
-
description: "Skill body template. Use {{argName}} for placeholders."
|
|
3952
|
+
description: "Skill body template as raw text. Use {{argName}} for placeholders. Do not wrap in JSON."
|
|
3710
3953
|
}
|
|
3711
3954
|
},
|
|
3712
3955
|
required: ["name", "body"]
|
|
@@ -3795,7 +4038,7 @@ function createToolDefinitions() {
|
|
|
3795
4038
|
},
|
|
3796
4039
|
persona: {
|
|
3797
4040
|
type: "string",
|
|
3798
|
-
description: "Agent persona
|
|
4041
|
+
description: "Agent persona as raw text. Do not wrap in JSON."
|
|
3799
4042
|
},
|
|
3800
4043
|
skills: {
|
|
3801
4044
|
type: "array",
|
|
@@ -3870,6 +4113,56 @@ function createToolDefinitions() {
|
|
|
3870
4113
|
openWorldHint: false
|
|
3871
4114
|
}
|
|
3872
4115
|
},
|
|
4116
|
+
{
|
|
4117
|
+
name: "skill-search",
|
|
4118
|
+
description: "Search for skills by keyword. Returns ranked skill definitions matching the query.",
|
|
4119
|
+
inputSchema: {
|
|
4120
|
+
type: "object",
|
|
4121
|
+
properties: {
|
|
4122
|
+
query: {
|
|
4123
|
+
type: "string",
|
|
4124
|
+
description: "Search query text"
|
|
4125
|
+
},
|
|
4126
|
+
limit: {
|
|
4127
|
+
type: "number",
|
|
4128
|
+
description: "Maximum results (default: 20)"
|
|
4129
|
+
}
|
|
4130
|
+
},
|
|
4131
|
+
required: ["query"]
|
|
4132
|
+
},
|
|
4133
|
+
annotations: {
|
|
4134
|
+
title: "Search Skills",
|
|
4135
|
+
readOnlyHint: true,
|
|
4136
|
+
destructiveHint: false,
|
|
4137
|
+
idempotentHint: true,
|
|
4138
|
+
openWorldHint: false
|
|
4139
|
+
}
|
|
4140
|
+
},
|
|
4141
|
+
{
|
|
4142
|
+
name: "agent-search",
|
|
4143
|
+
description: "Search for agents by keyword. Returns ranked agent profiles matching the query.",
|
|
4144
|
+
inputSchema: {
|
|
4145
|
+
type: "object",
|
|
4146
|
+
properties: {
|
|
4147
|
+
query: {
|
|
4148
|
+
type: "string",
|
|
4149
|
+
description: "Search query text"
|
|
4150
|
+
},
|
|
4151
|
+
limit: {
|
|
4152
|
+
type: "number",
|
|
4153
|
+
description: "Maximum results (default: 20)"
|
|
4154
|
+
}
|
|
4155
|
+
},
|
|
4156
|
+
required: ["query"]
|
|
4157
|
+
},
|
|
4158
|
+
annotations: {
|
|
4159
|
+
title: "Search Agents",
|
|
4160
|
+
readOnlyHint: true,
|
|
4161
|
+
destructiveHint: false,
|
|
4162
|
+
idempotentHint: true,
|
|
4163
|
+
openWorldHint: false
|
|
4164
|
+
}
|
|
4165
|
+
},
|
|
3873
4166
|
{
|
|
3874
4167
|
name: "auto-capture-review",
|
|
3875
4168
|
description: "Review and approve pending auto-captured knowledge before storage.",
|
|
@@ -3912,6 +4205,33 @@ function createResourceTemplates() {
|
|
|
3912
4205
|
];
|
|
3913
4206
|
}
|
|
3914
4207
|
|
|
4208
|
+
// src/shared/mcp/functions/format-search-results.function.ts
|
|
4209
|
+
function formatSearchResults(query, results) {
|
|
4210
|
+
if (results.items.length === 0) {
|
|
4211
|
+
return `No results found for "${query}"`;
|
|
4212
|
+
}
|
|
4213
|
+
const lines = results.items.map(
|
|
4214
|
+
(item, index) => formatItem(item, results.offset + index + 1)
|
|
4215
|
+
);
|
|
4216
|
+
const start = results.offset + 1;
|
|
4217
|
+
const end = results.offset + results.items.length;
|
|
4218
|
+
const total = String(results.total);
|
|
4219
|
+
return [
|
|
4220
|
+
`Found ${total} results for "${query}"`,
|
|
4221
|
+
"",
|
|
4222
|
+
...lines,
|
|
4223
|
+
"",
|
|
4224
|
+
`Showing ${String(start)}-${String(end)} of ${total} results`
|
|
4225
|
+
].join("\n");
|
|
4226
|
+
}
|
|
4227
|
+
function formatItem(item, position) {
|
|
4228
|
+
const heading = item.heading ?? "(untitled)";
|
|
4229
|
+
const terms = item.matched_terms.join(", ");
|
|
4230
|
+
return `${String(position)}. [${item.kbid}] ${heading}
|
|
4231
|
+
${item.snippet}
|
|
4232
|
+
type: ${item.type} terms: ${terms}`;
|
|
4233
|
+
}
|
|
4234
|
+
|
|
3915
4235
|
// src/shared/mcp/functions/handle-agent-create.function.ts
|
|
3916
4236
|
function asString(value, fallback) {
|
|
3917
4237
|
return typeof value === "string" ? value : fallback;
|
|
@@ -3962,35 +4282,52 @@ async function handleAgentCreate(client, args) {
|
|
|
3962
4282
|
title: name,
|
|
3963
4283
|
description
|
|
3964
4284
|
});
|
|
3965
|
-
const allKbids = [metaResult.
|
|
4285
|
+
const allKbids = [metaResult.items[0], ...skills];
|
|
3966
4286
|
const docid = await client.groupSections(name, allKbids, "agent");
|
|
3967
4287
|
return {
|
|
3968
4288
|
content: [
|
|
3969
4289
|
{
|
|
3970
4290
|
type: "text",
|
|
3971
|
-
text:
|
|
3972
|
-
|
|
3973
|
-
name,
|
|
3974
|
-
skillCount: skills.length
|
|
3975
|
-
})
|
|
4291
|
+
text: `Created agent "${name}" (docid: ${docid})
|
|
4292
|
+
Skills: ${String(skills.length)} attached`
|
|
3976
4293
|
}
|
|
3977
4294
|
]
|
|
3978
4295
|
};
|
|
3979
4296
|
}
|
|
3980
4297
|
|
|
3981
4298
|
// src/shared/mcp/functions/handle-agent-list.function.ts
|
|
4299
|
+
async function readAgentDescription(client, sections) {
|
|
4300
|
+
const metaKbid = sections[0]?.kbid;
|
|
4301
|
+
if (!metaKbid) return "";
|
|
4302
|
+
const metaSections = await client.readSections([metaKbid]);
|
|
4303
|
+
const first = metaSections.at(0);
|
|
4304
|
+
if (!first) return "";
|
|
4305
|
+
try {
|
|
4306
|
+
const meta = JSON.parse(first.content);
|
|
4307
|
+
return typeof meta["description"] === "string" ? meta["description"] : "";
|
|
4308
|
+
} catch {
|
|
4309
|
+
return "";
|
|
4310
|
+
}
|
|
4311
|
+
}
|
|
3982
4312
|
async function handleAgentList(client) {
|
|
3983
4313
|
const docs = await client.listDocumentsByType("agent");
|
|
3984
|
-
const items =
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
4314
|
+
const items = await Promise.all(
|
|
4315
|
+
docs.map(async (d) => ({
|
|
4316
|
+
name: d.title,
|
|
4317
|
+
description: await readAgentDescription(client, d.sections)
|
|
4318
|
+
}))
|
|
4319
|
+
);
|
|
4320
|
+
const lines = items.map(
|
|
4321
|
+
(item, index) => `${String(index + 1)}. ${item.name}` + (item.description ? ` -- ${item.description}` : "")
|
|
4322
|
+
);
|
|
4323
|
+
const text = [`${String(items.length)} agents:`, ...lines].join(
|
|
4324
|
+
"\n"
|
|
4325
|
+
);
|
|
3989
4326
|
return {
|
|
3990
4327
|
content: [
|
|
3991
4328
|
{
|
|
3992
4329
|
type: "text",
|
|
3993
|
-
text
|
|
4330
|
+
text
|
|
3994
4331
|
}
|
|
3995
4332
|
]
|
|
3996
4333
|
};
|
|
@@ -4039,6 +4376,19 @@ async function resolveSkillRefs(client, skillRefs) {
|
|
|
4039
4376
|
}
|
|
4040
4377
|
});
|
|
4041
4378
|
}
|
|
4379
|
+
function formatAgent(agent) {
|
|
4380
|
+
const skillLines = agent.skills.length > 0 ? agent.skills.map(
|
|
4381
|
+
(s, index) => `${String(index + 1)}. ${s.name ?? `(missing: ${s.kbid})`}`
|
|
4382
|
+
).join("\n") : "none";
|
|
4383
|
+
return [
|
|
4384
|
+
`Agent: ${agent.name} (docid: ${agent.docid})`,
|
|
4385
|
+
`Description: ${agent.description}`,
|
|
4386
|
+
`Persona: ${agent.persona}`,
|
|
4387
|
+
"",
|
|
4388
|
+
"Skills:",
|
|
4389
|
+
skillLines
|
|
4390
|
+
].join("\n");
|
|
4391
|
+
}
|
|
4042
4392
|
async function handleAgentGet(client, args) {
|
|
4043
4393
|
const docid = typeof args["docid"] === "string" ? args["docid"] : "";
|
|
4044
4394
|
if (!docid) {
|
|
@@ -4063,7 +4413,7 @@ async function handleAgentGet(client, args) {
|
|
|
4063
4413
|
content: [
|
|
4064
4414
|
{
|
|
4065
4415
|
type: "text",
|
|
4066
|
-
text:
|
|
4416
|
+
text: formatAgent(agent)
|
|
4067
4417
|
}
|
|
4068
4418
|
]
|
|
4069
4419
|
};
|
|
@@ -4083,17 +4433,74 @@ async function handleAgentDelete(client, args) {
|
|
|
4083
4433
|
content: [
|
|
4084
4434
|
{
|
|
4085
4435
|
type: "text",
|
|
4086
|
-
text:
|
|
4436
|
+
text: `Deleted agent (docid: ${docid})`
|
|
4087
4437
|
}
|
|
4088
4438
|
]
|
|
4089
4439
|
};
|
|
4090
4440
|
}
|
|
4091
4441
|
|
|
4092
4442
|
// src/shared/mcp/functions/handle-recall.function.ts
|
|
4443
|
+
function asRecord(value) {
|
|
4444
|
+
return typeof value === "object" && value !== null ? value : void 0;
|
|
4445
|
+
}
|
|
4446
|
+
function strField(record, key, fallback) {
|
|
4447
|
+
const value = record[key];
|
|
4448
|
+
return typeof value === "string" ? value : fallback;
|
|
4449
|
+
}
|
|
4450
|
+
function formatList(label, items, line) {
|
|
4451
|
+
if (items === void 0 || items === null) {
|
|
4452
|
+
return "";
|
|
4453
|
+
}
|
|
4454
|
+
const list = Array.isArray(items) ? items : [];
|
|
4455
|
+
const rows = list.map((raw) => asRecord(raw)).filter((r) => r !== void 0).map((r) => ` - ${line(r)}`);
|
|
4456
|
+
if (rows.length > 0) {
|
|
4457
|
+
return `
|
|
4458
|
+
|
|
4459
|
+
${label}:
|
|
4460
|
+
${rows.join("\n")}`;
|
|
4461
|
+
}
|
|
4462
|
+
return `
|
|
4463
|
+
|
|
4464
|
+
${label}: (none)`;
|
|
4465
|
+
}
|
|
4466
|
+
function formatRecallItem(raw) {
|
|
4467
|
+
const item = asRecord(raw) ?? {};
|
|
4468
|
+
const kbid = strField(item, "kbid", "?");
|
|
4469
|
+
const heading = strField(item, "heading", "(untitled)");
|
|
4470
|
+
const type = strField(item, "type", "unknown");
|
|
4471
|
+
const content = strField(item, "content", "");
|
|
4472
|
+
const refLine = (r) => `${strField(r, "heading", strField(r, "kbid", "?"))} (${strField(r, "kbid", "?")})`;
|
|
4473
|
+
const text = `${heading} [${type}] (${kbid})
|
|
4474
|
+
|
|
4475
|
+
${content}` + formatList(
|
|
4476
|
+
"Documents",
|
|
4477
|
+
item["documents"],
|
|
4478
|
+
(d) => `${strField(d, "title", "?")} (${strField(d, "docid", "?")})`
|
|
4479
|
+
) + formatList("Back references", item["back_references"], refLine) + formatList("Siblings", item["siblings"], refLine) + formatList("References", item["references"], refLine);
|
|
4480
|
+
return text;
|
|
4481
|
+
}
|
|
4482
|
+
function buildNotFoundResult(id, depth) {
|
|
4483
|
+
const base = {
|
|
4484
|
+
kbid: id,
|
|
4485
|
+
heading: "(not found)",
|
|
4486
|
+
type: "unknown",
|
|
4487
|
+
content: "",
|
|
4488
|
+
docids: []
|
|
4489
|
+
};
|
|
4490
|
+
if (depth >= 1) {
|
|
4491
|
+
base["documents"] = [];
|
|
4492
|
+
base["back_references"] = [];
|
|
4493
|
+
}
|
|
4494
|
+
if (depth >= 2) {
|
|
4495
|
+
base["siblings"] = [];
|
|
4496
|
+
base["references"] = [];
|
|
4497
|
+
}
|
|
4498
|
+
return base;
|
|
4499
|
+
}
|
|
4093
4500
|
async function handleRecall2(client, args) {
|
|
4094
4501
|
const kbid = typeof args["kbid"] === "string" ? args["kbid"] : void 0;
|
|
4095
4502
|
const kbids = Array.isArray(args["kbids"]) && args["kbids"].every((item) => typeof item === "string") ? args["kbids"] : void 0;
|
|
4096
|
-
if (!kbid && !kbids) {
|
|
4503
|
+
if (!kbid && (!kbids || kbids.length === 0)) {
|
|
4097
4504
|
return {
|
|
4098
4505
|
content: [
|
|
4099
4506
|
{
|
|
@@ -4105,17 +4512,63 @@ async function handleRecall2(client, args) {
|
|
|
4105
4512
|
};
|
|
4106
4513
|
}
|
|
4107
4514
|
const depth = typeof args["depth"] === "number" ? args["depth"] : 0;
|
|
4108
|
-
|
|
4515
|
+
let result;
|
|
4516
|
+
try {
|
|
4517
|
+
result = await client.recall({ kbid, kbids, depth });
|
|
4518
|
+
} catch {
|
|
4519
|
+
const ids = kbid ? [kbid] : kbids ?? [];
|
|
4520
|
+
const items = ids.map((id) => buildNotFoundResult(id, depth));
|
|
4521
|
+
result = items.length === 1 ? items[0] : items;
|
|
4522
|
+
}
|
|
4523
|
+
const text = Array.isArray(result) ? result.map(formatRecallItem).join("\n\n---\n\n") : formatRecallItem(result);
|
|
4109
4524
|
return {
|
|
4110
4525
|
content: [
|
|
4111
4526
|
{
|
|
4112
4527
|
type: "text",
|
|
4113
|
-
text
|
|
4528
|
+
text
|
|
4114
4529
|
}
|
|
4115
4530
|
]
|
|
4116
4531
|
};
|
|
4117
4532
|
}
|
|
4118
4533
|
|
|
4534
|
+
// src/shared/mcp/functions/handle-skill-search.function.ts
|
|
4535
|
+
async function handleSkillSearch(client, args) {
|
|
4536
|
+
const query = typeof args["query"] === "string" ? args["query"] : "";
|
|
4537
|
+
const results = await client.search({
|
|
4538
|
+
query,
|
|
4539
|
+
limit: args["limit"]
|
|
4540
|
+
});
|
|
4541
|
+
const filtered = {
|
|
4542
|
+
...results,
|
|
4543
|
+
items: results.items.filter(
|
|
4544
|
+
(item) => item.type === "skill"
|
|
4545
|
+
),
|
|
4546
|
+
total: 0
|
|
4547
|
+
};
|
|
4548
|
+
filtered.total = filtered.items.length;
|
|
4549
|
+
const text = formatSearchResults(query, filtered);
|
|
4550
|
+
return { content: [{ type: "text", text }] };
|
|
4551
|
+
}
|
|
4552
|
+
|
|
4553
|
+
// src/shared/mcp/functions/handle-agent-search.function.ts
|
|
4554
|
+
async function handleAgentSearch(client, args) {
|
|
4555
|
+
const query = typeof args["query"] === "string" ? args["query"] : "";
|
|
4556
|
+
const results = await client.search({
|
|
4557
|
+
query,
|
|
4558
|
+
limit: args["limit"]
|
|
4559
|
+
});
|
|
4560
|
+
const filtered = {
|
|
4561
|
+
...results,
|
|
4562
|
+
items: results.items.filter(
|
|
4563
|
+
(item) => item.type === "agent"
|
|
4564
|
+
),
|
|
4565
|
+
total: 0
|
|
4566
|
+
};
|
|
4567
|
+
filtered.total = filtered.items.length;
|
|
4568
|
+
const text = formatSearchResults(query, filtered);
|
|
4569
|
+
return { content: [{ type: "text", text }] };
|
|
4570
|
+
}
|
|
4571
|
+
|
|
4119
4572
|
// src/shared/mcp/functions/handle-tool-call.function.ts
|
|
4120
4573
|
function asString2(value, fallback) {
|
|
4121
4574
|
return typeof value === "string" ? value : fallback;
|
|
@@ -4135,6 +4588,18 @@ function asStringArray2(value) {
|
|
|
4135
4588
|
}
|
|
4136
4589
|
return [];
|
|
4137
4590
|
}
|
|
4591
|
+
function unwrapJsonContent(raw) {
|
|
4592
|
+
const trimmed = raw.trim();
|
|
4593
|
+
if (!trimmed.startsWith("{")) return raw;
|
|
4594
|
+
try {
|
|
4595
|
+
const parsed = JSON.parse(trimmed);
|
|
4596
|
+
if (typeof parsed["content"] === "string")
|
|
4597
|
+
return parsed["content"];
|
|
4598
|
+
if (typeof parsed["text"] === "string") return parsed["text"];
|
|
4599
|
+
} catch {
|
|
4600
|
+
}
|
|
4601
|
+
return raw;
|
|
4602
|
+
}
|
|
4138
4603
|
async function handleToolCall(client, name, args) {
|
|
4139
4604
|
log("tool call: " + name, 0 /* DEBUG */);
|
|
4140
4605
|
try {
|
|
@@ -4177,6 +4642,10 @@ async function handleToolCall(client, name, args) {
|
|
|
4177
4642
|
return await handleAgentGet(client, args);
|
|
4178
4643
|
case "agent-delete":
|
|
4179
4644
|
return await handleAgentDelete(client, args);
|
|
4645
|
+
case "skill-search":
|
|
4646
|
+
return await handleSkillSearch(client, args);
|
|
4647
|
+
case "agent-search":
|
|
4648
|
+
return await handleAgentSearch(client, args);
|
|
4180
4649
|
case "auto-capture-review":
|
|
4181
4650
|
return handleAutoCaptureReview();
|
|
4182
4651
|
default:
|
|
@@ -4208,30 +4677,18 @@ async function handleToolCall(client, name, args) {
|
|
|
4208
4677
|
}
|
|
4209
4678
|
}
|
|
4210
4679
|
async function handleSearch2(client, args) {
|
|
4680
|
+
const query = asString2(args["query"], "");
|
|
4211
4681
|
const results = await client.search({
|
|
4212
|
-
query
|
|
4682
|
+
query,
|
|
4213
4683
|
mode: args["mode"],
|
|
4214
4684
|
limit: args["limit"],
|
|
4215
4685
|
offset: args["offset"],
|
|
4216
4686
|
algo: args["algo"],
|
|
4217
4687
|
relaxed: args["relaxed"]
|
|
4218
4688
|
});
|
|
4219
|
-
const stripped = {
|
|
4220
|
-
...results,
|
|
4221
|
-
items: results.items.map(
|
|
4222
|
-
({
|
|
4223
|
-
score: _score,
|
|
4224
|
-
confidence: _confidence,
|
|
4225
|
-
...rest
|
|
4226
|
-
}) => rest
|
|
4227
|
-
)
|
|
4228
|
-
};
|
|
4229
4689
|
return {
|
|
4230
4690
|
content: [
|
|
4231
|
-
{
|
|
4232
|
-
type: "text",
|
|
4233
|
-
text: JSON.stringify(stripped, null, 2)
|
|
4234
|
-
}
|
|
4691
|
+
{ type: "text", text: formatSearchResults(query, results) }
|
|
4235
4692
|
]
|
|
4236
4693
|
};
|
|
4237
4694
|
}
|
|
@@ -4253,70 +4710,47 @@ async function handleLearn2(client, args) {
|
|
|
4253
4710
|
isError: true
|
|
4254
4711
|
};
|
|
4255
4712
|
}
|
|
4713
|
+
const rawContent = asString2(args["content"], "");
|
|
4714
|
+
const content = unwrapJsonContent(rawContent);
|
|
4256
4715
|
const result = await client.addSection({
|
|
4257
4716
|
sectionType,
|
|
4258
|
-
content
|
|
4717
|
+
content,
|
|
4259
4718
|
title,
|
|
4260
4719
|
description,
|
|
4261
4720
|
docid,
|
|
4262
4721
|
tags,
|
|
4263
4722
|
replace
|
|
4264
4723
|
});
|
|
4265
|
-
const
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4724
|
+
const payload = {
|
|
4725
|
+
items: result.items,
|
|
4726
|
+
total: result.total,
|
|
4727
|
+
offset: result.offset,
|
|
4269
4728
|
superseded: result.superseded ?? null,
|
|
4270
4729
|
warnings: result.warnings ?? [],
|
|
4271
|
-
near_duplicates:
|
|
4272
|
-
kbid: d.kbid,
|
|
4273
|
-
similarity: d.similarity,
|
|
4274
|
-
...d.method !== void 0 ? { method: d.method } : {}
|
|
4275
|
-
}))
|
|
4730
|
+
near_duplicates: result.near_duplicates ?? []
|
|
4276
4731
|
};
|
|
4277
4732
|
return {
|
|
4278
|
-
content: [
|
|
4279
|
-
{
|
|
4280
|
-
type: "text",
|
|
4281
|
-
text: JSON.stringify(normalized)
|
|
4282
|
-
}
|
|
4283
|
-
]
|
|
4733
|
+
content: [{ type: "text", text: JSON.stringify(payload) }]
|
|
4284
4734
|
};
|
|
4285
4735
|
}
|
|
4286
4736
|
async function handleUnlearn2(client, args) {
|
|
4287
|
-
const
|
|
4288
|
-
|
|
4289
|
-
);
|
|
4737
|
+
const kbid = asString2(args["kbid"], "");
|
|
4738
|
+
await client.removeSection(kbid);
|
|
4290
4739
|
return {
|
|
4291
|
-
content: [
|
|
4292
|
-
{
|
|
4293
|
-
type: "text",
|
|
4294
|
-
text: JSON.stringify(result)
|
|
4295
|
-
}
|
|
4296
|
-
]
|
|
4740
|
+
content: [{ type: "text", text: `Removed section ${kbid}` }]
|
|
4297
4741
|
};
|
|
4298
4742
|
}
|
|
4299
4743
|
async function handleRetrieve(client, args) {
|
|
4300
4744
|
if (typeof args["kbid"] === "string") {
|
|
4301
4745
|
const sections = await client.readSections([args["kbid"]]);
|
|
4302
4746
|
return {
|
|
4303
|
-
content: [
|
|
4304
|
-
{
|
|
4305
|
-
type: "text",
|
|
4306
|
-
text: JSON.stringify(sections, null, 2)
|
|
4307
|
-
}
|
|
4308
|
-
]
|
|
4747
|
+
content: [{ type: "text", text: formatSections(sections) }]
|
|
4309
4748
|
};
|
|
4310
4749
|
}
|
|
4311
4750
|
if (typeof args["docid"] === "string") {
|
|
4312
4751
|
const doc = await client.retrieveDocument(args["docid"]);
|
|
4313
4752
|
return {
|
|
4314
|
-
content: [
|
|
4315
|
-
{
|
|
4316
|
-
type: "text",
|
|
4317
|
-
text: JSON.stringify(doc, null, 2)
|
|
4318
|
-
}
|
|
4319
|
-
]
|
|
4753
|
+
content: [{ type: "text", text: formatDocument(doc) }]
|
|
4320
4754
|
};
|
|
4321
4755
|
}
|
|
4322
4756
|
return {
|
|
@@ -4329,61 +4763,81 @@ async function handleRetrieve(client, args) {
|
|
|
4329
4763
|
isError: true
|
|
4330
4764
|
};
|
|
4331
4765
|
}
|
|
4766
|
+
function formatSections(sections) {
|
|
4767
|
+
if (sections.length === 0) {
|
|
4768
|
+
return "No sections found";
|
|
4769
|
+
}
|
|
4770
|
+
return sections.map((s) => `${s.kbid} (${s.sectionType})
|
|
4771
|
+
${s.content}`).join("\n\n");
|
|
4772
|
+
}
|
|
4773
|
+
function formatDocument(doc) {
|
|
4774
|
+
if (typeof doc !== "object" || doc === null) {
|
|
4775
|
+
return String(doc);
|
|
4776
|
+
}
|
|
4777
|
+
return Object.entries(doc).map(([key, value]) => {
|
|
4778
|
+
if (Array.isArray(value)) {
|
|
4779
|
+
const items = value.map((item) => formatDocValue(item)).map((s) => ` - ${s}`);
|
|
4780
|
+
return items.length > 0 ? `${key}:
|
|
4781
|
+
${items.join("\n")}` : `${key}: (none)`;
|
|
4782
|
+
}
|
|
4783
|
+
return `${key}: ${formatDocValue(value)}`;
|
|
4784
|
+
}).join("\n");
|
|
4785
|
+
}
|
|
4786
|
+
function formatDocValue(value) {
|
|
4787
|
+
if (typeof value !== "object" || value === null) {
|
|
4788
|
+
return String(value);
|
|
4789
|
+
}
|
|
4790
|
+
const rec = value;
|
|
4791
|
+
return Object.entries(rec).map(([k, v]) => `${k}=${String(v)}`).join(", ");
|
|
4792
|
+
}
|
|
4332
4793
|
async function handleStatus2(client) {
|
|
4333
4794
|
const status = await client.dbStatus();
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4795
|
+
const cs = status.cacheStats;
|
|
4796
|
+
const lines = [
|
|
4797
|
+
`Database: ${status.contextPath}`,
|
|
4798
|
+
`Initialized: ${status.initialized ? "yes" : "no"}`
|
|
4799
|
+
];
|
|
4800
|
+
if (cs) {
|
|
4801
|
+
lines.push(
|
|
4802
|
+
`Cached content entries: ${String(cs.contentCount)}`,
|
|
4803
|
+
`Cached index entries: ${String(cs.indexCount)}`
|
|
4804
|
+
);
|
|
4805
|
+
}
|
|
4806
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4342
4807
|
}
|
|
4343
4808
|
async function handleContent2(client, args) {
|
|
4344
4809
|
const ids = asStringArray2(args["ids"]);
|
|
4345
4810
|
const result = await client.content(ids);
|
|
4811
|
+
const text = result.data || "(no content found)";
|
|
4346
4812
|
return {
|
|
4347
|
-
content: [
|
|
4348
|
-
{
|
|
4349
|
-
type: "text",
|
|
4350
|
-
text: JSON.stringify(result)
|
|
4351
|
-
}
|
|
4352
|
-
]
|
|
4813
|
+
content: [{ type: "text", text }]
|
|
4353
4814
|
};
|
|
4354
4815
|
}
|
|
4355
4816
|
async function handleCheck2(client) {
|
|
4356
4817
|
const report = await client.integrityCheck();
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
};
|
|
4818
|
+
const status = report.ok ? "OK" : "FAIL";
|
|
4819
|
+
const lines = [
|
|
4820
|
+
`Integrity check: ${status}. ${String(report.sections_checked)} sections checked.`
|
|
4821
|
+
];
|
|
4822
|
+
for (const error of report.errors) {
|
|
4823
|
+
lines.push(`- ${error.type}: ${error.entity} (${error.detail})`);
|
|
4824
|
+
}
|
|
4825
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4365
4826
|
}
|
|
4366
4827
|
async function handleGc2(client) {
|
|
4367
4828
|
const report = await client.gc();
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
};
|
|
4829
|
+
const lines = [
|
|
4830
|
+
`GC complete: removed ${String(report.removed_sections)} sections, freed ${String(report.removed_bytes)} bytes.`
|
|
4831
|
+
];
|
|
4832
|
+
if (report.stale_sources !== void 0) {
|
|
4833
|
+
lines.push(`stale sources: ${String(report.stale_sources)}`);
|
|
4834
|
+
}
|
|
4835
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4376
4836
|
}
|
|
4377
4837
|
async function handleRebuild2(client) {
|
|
4378
4838
|
const report = await client.rebuildIndexes();
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
{
|
|
4382
|
-
type: "text",
|
|
4383
|
-
text: JSON.stringify(report, null, 2)
|
|
4384
|
-
}
|
|
4385
|
-
]
|
|
4386
|
-
};
|
|
4839
|
+
const text = `Rebuild complete: ${String(report.sections_reindexed)} sections reindexed, ${String(report.terms_indexed)} terms indexed.`;
|
|
4840
|
+
return { content: [{ type: "text", text }] };
|
|
4387
4841
|
}
|
|
4388
4842
|
async function handleSkillLearn(client, args) {
|
|
4389
4843
|
const name = asString2(args["name"], "");
|
|
@@ -4419,37 +4873,22 @@ async function handleSkillLearn(client, args) {
|
|
|
4419
4873
|
content: [
|
|
4420
4874
|
{
|
|
4421
4875
|
type: "text",
|
|
4422
|
-
text:
|
|
4876
|
+
text: `Created skill "${name}" (kbid: ${result.items[0]})`
|
|
4423
4877
|
}
|
|
4424
4878
|
]
|
|
4425
4879
|
};
|
|
4426
4880
|
}
|
|
4427
4881
|
async function handleSkillList(client) {
|
|
4428
4882
|
const records = await client.listByType("skill");
|
|
4429
|
-
const
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
if (Array.isArray(parsed["arguments"])) {
|
|
4434
|
-
argumentCount = parsed["arguments"].length;
|
|
4435
|
-
}
|
|
4436
|
-
} catch {
|
|
4437
|
-
}
|
|
4438
|
-
return {
|
|
4439
|
-
kbid: r.kbid,
|
|
4440
|
-
name: r.title,
|
|
4441
|
-
description: r.description,
|
|
4442
|
-
argumentCount
|
|
4443
|
-
};
|
|
4883
|
+
const lines = records.map((r, index) => {
|
|
4884
|
+
const desc = r.description ? ` -- ${r.description}` : "";
|
|
4885
|
+
const label = r.title ?? "(untitled)";
|
|
4886
|
+
return `${String(index + 1)}. ${label} (${r.kbid})${desc}`;
|
|
4444
4887
|
});
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
text: JSON.stringify(items, null, 2)
|
|
4450
|
-
}
|
|
4451
|
-
]
|
|
4452
|
-
};
|
|
4888
|
+
const text = [`${String(records.length)} skills:`, ...lines].join(
|
|
4889
|
+
"\n"
|
|
4890
|
+
);
|
|
4891
|
+
return { content: [{ type: "text", text }] };
|
|
4453
4892
|
}
|
|
4454
4893
|
async function handleSkillGet(client, args) {
|
|
4455
4894
|
const kbid = typeof args["kbid"] === "string" ? args["kbid"] : void 0;
|
|
@@ -4493,14 +4932,29 @@ async function handleSkillGet(client, args) {
|
|
|
4493
4932
|
}
|
|
4494
4933
|
const skill = parseSkillContent(content);
|
|
4495
4934
|
return {
|
|
4496
|
-
content: [
|
|
4497
|
-
{
|
|
4498
|
-
type: "text",
|
|
4499
|
-
text: JSON.stringify(skill, null, 2)
|
|
4500
|
-
}
|
|
4501
|
-
]
|
|
4935
|
+
content: [{ type: "text", text: formatSkill(skill) }]
|
|
4502
4936
|
};
|
|
4503
4937
|
}
|
|
4938
|
+
function formatSkill(skill) {
|
|
4939
|
+
const lines = [`name: ${skill.name}`];
|
|
4940
|
+
if (skill.description) {
|
|
4941
|
+
lines.push(`description: ${skill.description}`);
|
|
4942
|
+
}
|
|
4943
|
+
if (skill.arguments && skill.arguments.length > 0) {
|
|
4944
|
+
lines.push("arguments:");
|
|
4945
|
+
for (const arg of skill.arguments) {
|
|
4946
|
+
const details = [
|
|
4947
|
+
...arg.type ? [arg.type] : [],
|
|
4948
|
+
...arg.required ? ["required"] : []
|
|
4949
|
+
];
|
|
4950
|
+
lines.push(
|
|
4951
|
+
details.length > 0 ? `- ${arg.name}: ${details.join(", ")}` : `- ${arg.name}`
|
|
4952
|
+
);
|
|
4953
|
+
}
|
|
4954
|
+
}
|
|
4955
|
+
lines.push("body:", skill.body);
|
|
4956
|
+
return lines.join("\n");
|
|
4957
|
+
}
|
|
4504
4958
|
async function handleSkillDelete(client, args) {
|
|
4505
4959
|
const kbid = asString2(args["kbid"], "");
|
|
4506
4960
|
if (!kbid) {
|
|
@@ -4509,14 +4963,9 @@ async function handleSkillDelete(client, args) {
|
|
|
4509
4963
|
isError: true
|
|
4510
4964
|
};
|
|
4511
4965
|
}
|
|
4512
|
-
|
|
4966
|
+
await client.removeSection(kbid);
|
|
4513
4967
|
return {
|
|
4514
|
-
content: [
|
|
4515
|
-
{
|
|
4516
|
-
type: "text",
|
|
4517
|
-
text: JSON.stringify({ kbid, removed: result.removed })
|
|
4518
|
-
}
|
|
4519
|
-
]
|
|
4968
|
+
content: [{ type: "text", text: `Deleted skill ${kbid}` }]
|
|
4520
4969
|
};
|
|
4521
4970
|
}
|
|
4522
4971
|
function handleAutoCaptureReview() {
|
|
@@ -4524,10 +4973,7 @@ function handleAutoCaptureReview() {
|
|
|
4524
4973
|
content: [
|
|
4525
4974
|
{
|
|
4526
4975
|
type: "text",
|
|
4527
|
-
text:
|
|
4528
|
-
pending: [],
|
|
4529
|
-
message: "No pending auto-captured knowledge entries."
|
|
4530
|
-
})
|
|
4976
|
+
text: "No pending auto-captured knowledge entries."
|
|
4531
4977
|
}
|
|
4532
4978
|
]
|
|
4533
4979
|
};
|
|
@@ -4537,14 +4983,13 @@ async function handleExport2(client, args) {
|
|
|
4537
4983
|
const result = await client.export(
|
|
4538
4984
|
path !== void 0 ? { path } : {}
|
|
4539
4985
|
);
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
};
|
|
4986
|
+
const lines = [
|
|
4987
|
+
`Exported to ${result.path}`,
|
|
4988
|
+
`sections: ${String(result.sections_exported)}`,
|
|
4989
|
+
`documents: ${String(result.documents_exported)}`,
|
|
4990
|
+
`elapsed: ${String(result.elapsed_ms)}ms`
|
|
4991
|
+
];
|
|
4992
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4548
4993
|
}
|
|
4549
4994
|
|
|
4550
4995
|
// src/shared/mcp/functions/handle-resource-read.function.ts
|