@dikolab/kbdb 0.6.1 → 0.6.2
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 +662 -217
- package/dist/cli.cjs.map +3 -3
- package/dist/cli.mjs +662 -217
- package/dist/cli.mjs.map +3 -3
- package/dist/kbdb-worker.cjs +71 -12
- package/dist/kbdb-worker.cjs.map +3 -3
- 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/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.mjs
CHANGED
|
@@ -152,6 +152,10 @@ function parseArgs(argv) {
|
|
|
152
152
|
case "-c":
|
|
153
153
|
options.content = true;
|
|
154
154
|
break;
|
|
155
|
+
case "--search":
|
|
156
|
+
case "-s":
|
|
157
|
+
options.search = true;
|
|
158
|
+
break;
|
|
155
159
|
case "--relaxed":
|
|
156
160
|
options.relaxed = true;
|
|
157
161
|
break;
|
|
@@ -188,18 +192,19 @@ function parseArgs(argv) {
|
|
|
188
192
|
}
|
|
189
193
|
|
|
190
194
|
// src/shared/cli/functions/format-text-output.function.ts
|
|
191
|
-
function formatTextOutput(paged) {
|
|
195
|
+
function formatTextOutput(paged, content) {
|
|
192
196
|
if (paged.items.length === 0) return "No results found.";
|
|
193
197
|
const start = paged.offset + 1;
|
|
194
198
|
const end = paged.offset + paged.items.length;
|
|
195
199
|
const lines = paged.items.map((r, i) => {
|
|
196
200
|
const num = paged.offset + i + 1;
|
|
197
|
-
const heading = r.heading
|
|
201
|
+
const heading = r.heading || "(untitled)";
|
|
198
202
|
const terms = r.matched_terms.join(", ");
|
|
199
203
|
const fields = r.matched_fields.join(", ");
|
|
200
204
|
const confidencePct = (r.confidence * 100).toFixed(0);
|
|
205
|
+
const body = content ? r.preview || "(no content)" : r.snippet || r.preview || "(no snippet)";
|
|
201
206
|
return `${String(num)}. [${r.kbid}] ${heading} (score: ${r.score.toFixed(4)}, confidence: ${confidencePct}%)
|
|
202
|
-
${
|
|
207
|
+
${body}
|
|
203
208
|
type: ${r.type} terms: ${terms}` + (fields ? ` fields: ${fields}` : "");
|
|
204
209
|
}).join("\n\n");
|
|
205
210
|
const footer = `
|
|
@@ -210,29 +215,21 @@ Use --offset ${String(end)} to see more` : "";
|
|
|
210
215
|
}
|
|
211
216
|
|
|
212
217
|
// src/shared/cli/functions/format-mcp-output.function.ts
|
|
213
|
-
function formatMcpOutput(paged) {
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
docids: r.docids,
|
|
219
|
-
snippet: r.snippet,
|
|
220
|
-
matched_terms: r.matched_terms,
|
|
221
|
-
matched_fields: r.matched_fields,
|
|
222
|
-
created_at: r.created_at
|
|
223
|
-
}));
|
|
218
|
+
function formatMcpOutput(paged, content) {
|
|
219
|
+
const text = paged.items.length === 0 ? "No results found." : paged.items.map((r) => {
|
|
220
|
+
const body = content ? r.preview || "(no content)" : r.snippet || r.preview;
|
|
221
|
+
return `[${r.kbid}] ${r.heading || "(untitled)"} \u2014 ${body}`;
|
|
222
|
+
}).join("\n");
|
|
224
223
|
return JSON.stringify(
|
|
225
224
|
{
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
has_more: paged.has_more,
|
|
235
|
-
relaxed: paged.relaxed
|
|
225
|
+
jsonrpc: "2.0",
|
|
226
|
+
result: {
|
|
227
|
+
content: [{ type: "text", text }],
|
|
228
|
+
total: paged.total,
|
|
229
|
+
offset: paged.offset,
|
|
230
|
+
limit: paged.limit,
|
|
231
|
+
has_more: paged.has_more
|
|
232
|
+
}
|
|
236
233
|
},
|
|
237
234
|
null,
|
|
238
235
|
2
|
|
@@ -302,15 +299,24 @@ var SEARCH_FIELDS = [
|
|
|
302
299
|
["snippet", "snippet"],
|
|
303
300
|
["level", "level"]
|
|
304
301
|
];
|
|
305
|
-
var
|
|
302
|
+
var SEARCH_CONTENT_FIELDS = [
|
|
306
303
|
["kbid", "kbid"],
|
|
307
|
-
["
|
|
308
|
-
["
|
|
309
|
-
["
|
|
310
|
-
["
|
|
311
|
-
["
|
|
304
|
+
["heading", "heading"],
|
|
305
|
+
["score", "score"],
|
|
306
|
+
["confidence", "confidence"],
|
|
307
|
+
["type", "type"],
|
|
308
|
+
["terms", "matched_terms"],
|
|
309
|
+
["fields", "matched_fields"],
|
|
310
|
+
["content", "preview"],
|
|
312
311
|
["level", "level"]
|
|
313
312
|
];
|
|
313
|
+
var LEARN_FIELDS = [
|
|
314
|
+
["items", "items"],
|
|
315
|
+
["total", "total"],
|
|
316
|
+
["offset", "offset"],
|
|
317
|
+
["superseded", "superseded"],
|
|
318
|
+
["warnings", "warnings"]
|
|
319
|
+
];
|
|
314
320
|
var UNLEARN_FIELDS = [
|
|
315
321
|
["removed", "removed"],
|
|
316
322
|
["elapsed_ms", "elapsed_ms"]
|
|
@@ -338,7 +344,9 @@ var IMPORT_FIELDS = [
|
|
|
338
344
|
];
|
|
339
345
|
var STATUS_FIELDS = [
|
|
340
346
|
["initialized", "initialized"],
|
|
341
|
-
["path", "
|
|
347
|
+
["path", "context_path"],
|
|
348
|
+
["documents", "document_count"],
|
|
349
|
+
["sections", "section_count"],
|
|
342
350
|
["content_cached", "cacheStats.contentCount"],
|
|
343
351
|
["index_cached", "cacheStats.indexCount"]
|
|
344
352
|
];
|
|
@@ -361,16 +369,19 @@ var REBUILD_FIELDS = [
|
|
|
361
369
|
];
|
|
362
370
|
|
|
363
371
|
// src/shared/cli/functions/format-output.function.ts
|
|
364
|
-
function formatOutput(paged, format) {
|
|
372
|
+
function formatOutput(paged, format, content) {
|
|
365
373
|
switch (format) {
|
|
366
374
|
case "json":
|
|
367
375
|
return JSON.stringify(paged, null, 2);
|
|
368
376
|
case "text":
|
|
369
|
-
return formatTextOutput(paged);
|
|
377
|
+
return formatTextOutput(paged, content);
|
|
370
378
|
case "rec":
|
|
371
|
-
return formatRecfileOutput(
|
|
379
|
+
return formatRecfileOutput(
|
|
380
|
+
paged.items,
|
|
381
|
+
content ? SEARCH_CONTENT_FIELDS : SEARCH_FIELDS
|
|
382
|
+
);
|
|
372
383
|
case "mcp":
|
|
373
|
-
return formatMcpOutput(paged);
|
|
384
|
+
return formatMcpOutput(paged, content);
|
|
374
385
|
}
|
|
375
386
|
}
|
|
376
387
|
|
|
@@ -387,6 +398,93 @@ var RECFILE_COMMAND_FIELD_MAP = {
|
|
|
387
398
|
rebuild: REBUILD_FIELDS
|
|
388
399
|
};
|
|
389
400
|
|
|
401
|
+
// src/shared/cli/functions/format-command-text.function.ts
|
|
402
|
+
function str(v) {
|
|
403
|
+
if (typeof v === "string") return v;
|
|
404
|
+
if (typeof v === "number") return String(v);
|
|
405
|
+
if (typeof v === "boolean") return String(v);
|
|
406
|
+
if (v == null) return "";
|
|
407
|
+
return JSON.stringify(v);
|
|
408
|
+
}
|
|
409
|
+
function formatCommandText(data, command) {
|
|
410
|
+
const obj = data;
|
|
411
|
+
switch (command) {
|
|
412
|
+
case "status":
|
|
413
|
+
return formatStatus(obj);
|
|
414
|
+
case "check":
|
|
415
|
+
return formatCheck(obj);
|
|
416
|
+
case "gc":
|
|
417
|
+
return formatGc(obj);
|
|
418
|
+
case "rebuild":
|
|
419
|
+
return formatRebuild(obj);
|
|
420
|
+
case "unlearn":
|
|
421
|
+
return formatUnlearn(obj);
|
|
422
|
+
case "learn":
|
|
423
|
+
return formatLearn(data);
|
|
424
|
+
default:
|
|
425
|
+
return JSON.stringify(data, null, 2);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function formatStatus(o) {
|
|
429
|
+
const cs = o["cacheStats"];
|
|
430
|
+
const path = o["context_path"] ?? o["contextPath"] ?? "(unknown)";
|
|
431
|
+
const lines = [
|
|
432
|
+
`Initialized: ${str(o["initialized"] ?? false)}`,
|
|
433
|
+
`Path: ${str(path)}`
|
|
434
|
+
];
|
|
435
|
+
if (o["document_count"] != null)
|
|
436
|
+
lines.push(`Documents: ${str(o["document_count"])}`);
|
|
437
|
+
if (o["section_count"] != null)
|
|
438
|
+
lines.push(`Sections: ${str(o["section_count"])}`);
|
|
439
|
+
if (cs) {
|
|
440
|
+
lines.push(
|
|
441
|
+
`Content cached: ${str(cs["contentCount"] ?? 0)}`,
|
|
442
|
+
`Index cached: ${str(cs["indexCount"] ?? 0)}`
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
return lines.join("\n");
|
|
446
|
+
}
|
|
447
|
+
function formatCheck(o) {
|
|
448
|
+
const ok = o["ok"] ? "OK" : "FAILED";
|
|
449
|
+
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)`;
|
|
450
|
+
}
|
|
451
|
+
function formatGc(o) {
|
|
452
|
+
return `GC: removed ${str(o["removed_sections"] ?? 0)} sections, reclaimed ${str(o["removed_bytes"] ?? 0)} bytes (${str(o["elapsed_ms"] ?? 0)}ms)`;
|
|
453
|
+
}
|
|
454
|
+
function formatRebuild(o) {
|
|
455
|
+
return `Rebuild: ${str(o["sections_reindexed"] ?? 0)} sections reindexed, ${str(o["terms_indexed"] ?? 0)} terms (${str(o["elapsed_ms"] ?? 0)}ms)`;
|
|
456
|
+
}
|
|
457
|
+
function formatUnlearn(o) {
|
|
458
|
+
const removed = o["removed"];
|
|
459
|
+
if (Array.isArray(removed)) {
|
|
460
|
+
return `Removed: ${removed.length.toString()} section(s)`;
|
|
461
|
+
}
|
|
462
|
+
return `Removed: ${str(removed ?? false)} (${str(o["elapsed_ms"] ?? 0)}ms)`;
|
|
463
|
+
}
|
|
464
|
+
function formatLearn(data) {
|
|
465
|
+
const obj = data;
|
|
466
|
+
const items = obj["items"];
|
|
467
|
+
if (Array.isArray(items)) {
|
|
468
|
+
return items.map((id) => `Learned: ${str(id)}`).join("\n");
|
|
469
|
+
}
|
|
470
|
+
return JSON.stringify(data, null, 2);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/shared/cli/functions/wrap-mcp-envelope.function.ts
|
|
474
|
+
function wrapMcpEnvelope(data, command) {
|
|
475
|
+
const text = formatCommandText(data, command);
|
|
476
|
+
return JSON.stringify(
|
|
477
|
+
{
|
|
478
|
+
jsonrpc: "2.0",
|
|
479
|
+
result: {
|
|
480
|
+
content: [{ type: "text", text }]
|
|
481
|
+
}
|
|
482
|
+
},
|
|
483
|
+
null,
|
|
484
|
+
2
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
|
|
390
488
|
// src/shared/cli/functions/format-command-output.function.ts
|
|
391
489
|
function formatCommandOutput(data, format, command) {
|
|
392
490
|
switch (format) {
|
|
@@ -395,9 +493,11 @@ function formatCommandOutput(data, format, command) {
|
|
|
395
493
|
return fields ? formatRecfileOutput(data, fields) : JSON.stringify(data, null, 2);
|
|
396
494
|
}
|
|
397
495
|
case "json":
|
|
496
|
+
return JSON.stringify(data, null, 2);
|
|
398
497
|
case "text":
|
|
498
|
+
return formatCommandText(data, command);
|
|
399
499
|
case "mcp":
|
|
400
|
-
return
|
|
500
|
+
return wrapMcpEnvelope(data, command);
|
|
401
501
|
}
|
|
402
502
|
}
|
|
403
503
|
|
|
@@ -430,7 +530,7 @@ async function runSearch(client, options) {
|
|
|
430
530
|
return {
|
|
431
531
|
items: results.items.map((r) => ({
|
|
432
532
|
kbid: r.kbid,
|
|
433
|
-
heading: r.heading,
|
|
533
|
+
heading: r.heading || "(untitled)",
|
|
434
534
|
type: r.type,
|
|
435
535
|
docids: r.docids,
|
|
436
536
|
score: r.score,
|
|
@@ -456,6 +556,11 @@ async function runSearch(client, options) {
|
|
|
456
556
|
var SECTION_TYPES = ["text", "code", "image"];
|
|
457
557
|
async function resolveKbidPrefix(prefix, client) {
|
|
458
558
|
if (prefix.length >= 26) return prefix;
|
|
559
|
+
if (prefix.length < 2) {
|
|
560
|
+
const msg = `prefix "${prefix}" is too short (minimum 2 characters)`;
|
|
561
|
+
log(msg, 3 /* ERROR */);
|
|
562
|
+
throw new Error(msg);
|
|
563
|
+
}
|
|
459
564
|
const seen = /* @__PURE__ */ new Set();
|
|
460
565
|
for (const type of SECTION_TYPES) {
|
|
461
566
|
const records = await client.listByType(type);
|
|
@@ -464,7 +569,7 @@ async function resolveKbidPrefix(prefix, client) {
|
|
|
464
569
|
}
|
|
465
570
|
}
|
|
466
571
|
if (seen.size === 0) {
|
|
467
|
-
const msg = `no section matches prefix "${prefix}"`;
|
|
572
|
+
const msg = `no section matches prefix "${prefix}". Try "kbdb content --search <query>" to find by keyword`;
|
|
468
573
|
log(msg, 3 /* ERROR */);
|
|
469
574
|
throw new Error(msg);
|
|
470
575
|
}
|
|
@@ -578,7 +683,9 @@ async function runLearn(client, options, io) {
|
|
|
578
683
|
replace: options.replace,
|
|
579
684
|
level: options.level
|
|
580
685
|
});
|
|
581
|
-
results.push(
|
|
686
|
+
results.push(
|
|
687
|
+
mapAddSectionResult(result, "-", content.length, "text")
|
|
688
|
+
);
|
|
582
689
|
continue;
|
|
583
690
|
}
|
|
584
691
|
const files = collectFiles(target);
|
|
@@ -596,7 +703,7 @@ async function runLearn(client, options, io) {
|
|
|
596
703
|
level: options.level ?? computeDirectoryLevel(file, target)
|
|
597
704
|
});
|
|
598
705
|
results.push(
|
|
599
|
-
mapAddSectionResult(result, file, content.length)
|
|
706
|
+
mapAddSectionResult(result, file, content.length, "text")
|
|
600
707
|
);
|
|
601
708
|
}
|
|
602
709
|
}
|
|
@@ -606,9 +713,11 @@ async function runLearn(client, options, io) {
|
|
|
606
713
|
);
|
|
607
714
|
return results;
|
|
608
715
|
}
|
|
609
|
-
function mapAddSectionResult(result, path, size) {
|
|
716
|
+
function mapAddSectionResult(result, path, size, sectionType) {
|
|
610
717
|
return {
|
|
611
|
-
kbid: result.
|
|
718
|
+
kbid: result.items[0] ?? "",
|
|
719
|
+
indexed_terms_count: 0,
|
|
720
|
+
type: sectionType,
|
|
612
721
|
path,
|
|
613
722
|
size,
|
|
614
723
|
skipped: false,
|
|
@@ -645,11 +754,26 @@ async function runUnlearn(client, options) {
|
|
|
645
754
|
// src/shared/cli/functions/run-content.function.ts
|
|
646
755
|
async function runContent(client, options) {
|
|
647
756
|
log("running content", 0 /* DEBUG */);
|
|
757
|
+
if (options.search) {
|
|
758
|
+
return runContentSearch(client, options);
|
|
759
|
+
}
|
|
648
760
|
const resolved = await Promise.all(
|
|
649
761
|
options.args.map((a) => resolveKbidPrefix(a, client))
|
|
650
762
|
);
|
|
651
763
|
return client.content(resolved);
|
|
652
764
|
}
|
|
765
|
+
async function runContentSearch(client, options) {
|
|
766
|
+
const query = options.args.join(" ");
|
|
767
|
+
const result = await client.search({
|
|
768
|
+
query,
|
|
769
|
+
limit: options.limit
|
|
770
|
+
});
|
|
771
|
+
const kbids = result.items.map((hit) => hit.kbid);
|
|
772
|
+
if (kbids.length === 0) {
|
|
773
|
+
return { type: "text/markdown", data: "", total: 0 };
|
|
774
|
+
}
|
|
775
|
+
return client.content(kbids);
|
|
776
|
+
}
|
|
653
777
|
|
|
654
778
|
// src/shared/cli/functions/run-check.function.ts
|
|
655
779
|
function parseDivergentContent(encoded) {
|
|
@@ -664,14 +788,21 @@ function parseDivergentContent(encoded) {
|
|
|
664
788
|
async function runCheck(client, _options) {
|
|
665
789
|
log("running check", 0 /* DEBUG */);
|
|
666
790
|
const raw = await client.integrityCheck();
|
|
791
|
+
const divergent = parseDivergentContent(raw.divergent_content);
|
|
792
|
+
const divergentErrors = divergent.map((d) => ({
|
|
793
|
+
type: "divergent_content",
|
|
794
|
+
entity: d.sourceKey,
|
|
795
|
+
detail: `${d.kbids.length.toString()} divergent sections: ${d.kbids.join(", ")}`
|
|
796
|
+
}));
|
|
797
|
+
const errors = [...raw.errors, ...divergentErrors];
|
|
667
798
|
return {
|
|
668
|
-
ok: raw.ok,
|
|
669
|
-
errors
|
|
799
|
+
ok: raw.ok && errors.length === 0,
|
|
800
|
+
errors,
|
|
670
801
|
sections_checked: raw.sections_checked,
|
|
671
802
|
documents_checked: raw.documents_checked,
|
|
672
803
|
references_checked: raw.references_checked,
|
|
673
804
|
elapsed_ms: raw.elapsed_ms,
|
|
674
|
-
divergent_content:
|
|
805
|
+
divergent_content: divergent
|
|
675
806
|
};
|
|
676
807
|
}
|
|
677
808
|
|
|
@@ -969,7 +1100,15 @@ async function runSkillLearn(client, options) {
|
|
|
969
1100
|
description: options.description
|
|
970
1101
|
});
|
|
971
1102
|
return {
|
|
972
|
-
output: JSON.stringify(
|
|
1103
|
+
output: JSON.stringify(
|
|
1104
|
+
{
|
|
1105
|
+
kbid: result.items[0],
|
|
1106
|
+
name,
|
|
1107
|
+
arguments: args.length > 0 ? args : []
|
|
1108
|
+
},
|
|
1109
|
+
null,
|
|
1110
|
+
2
|
|
1111
|
+
),
|
|
973
1112
|
exitCode: 0
|
|
974
1113
|
};
|
|
975
1114
|
}
|
|
@@ -1030,10 +1169,12 @@ async function runSkillGet(client, options) {
|
|
|
1030
1169
|
};
|
|
1031
1170
|
}
|
|
1032
1171
|
let content;
|
|
1033
|
-
|
|
1172
|
+
let kbid;
|
|
1173
|
+
if (/^[a-z2-7]{26}$/.test(identifier)) {
|
|
1034
1174
|
const sections = await client.readSections([identifier]);
|
|
1035
1175
|
if (sections.length > 0) {
|
|
1036
1176
|
content = sections[0]?.content;
|
|
1177
|
+
kbid = identifier;
|
|
1037
1178
|
}
|
|
1038
1179
|
}
|
|
1039
1180
|
if (content === void 0) {
|
|
@@ -1041,9 +1182,10 @@ async function runSkillGet(client, options) {
|
|
|
1041
1182
|
const match = records.filter((r) => r.title === identifier).pop();
|
|
1042
1183
|
if (match) {
|
|
1043
1184
|
content = match.content;
|
|
1185
|
+
kbid = match.kbid;
|
|
1044
1186
|
}
|
|
1045
1187
|
}
|
|
1046
|
-
if (content === void 0) {
|
|
1188
|
+
if (content === void 0 || kbid === void 0) {
|
|
1047
1189
|
return {
|
|
1048
1190
|
error: `skill not found: ${identifier}`,
|
|
1049
1191
|
exitCode: 1
|
|
@@ -1051,7 +1193,7 @@ async function runSkillGet(client, options) {
|
|
|
1051
1193
|
}
|
|
1052
1194
|
const skill = parseSkillContent(content);
|
|
1053
1195
|
return {
|
|
1054
|
-
output: JSON.stringify(skill, null, 2),
|
|
1196
|
+
output: JSON.stringify({ kbid, ...skill }, null, 2),
|
|
1055
1197
|
exitCode: 0
|
|
1056
1198
|
};
|
|
1057
1199
|
}
|
|
@@ -1066,7 +1208,7 @@ async function runSkillDelete(client, options) {
|
|
|
1066
1208
|
const result = await client.removeSection(kbid);
|
|
1067
1209
|
return {
|
|
1068
1210
|
output: JSON.stringify(
|
|
1069
|
-
{
|
|
1211
|
+
{ removed: result.removed ? [kbid] : [] },
|
|
1070
1212
|
null,
|
|
1071
1213
|
2
|
|
1072
1214
|
),
|
|
@@ -1108,7 +1250,7 @@ async function runAgentCreate(client, options) {
|
|
|
1108
1250
|
title: name,
|
|
1109
1251
|
description: options.description
|
|
1110
1252
|
});
|
|
1111
|
-
const allKbids = [metaResult.
|
|
1253
|
+
const allKbids = [metaResult.items[0], ...skills];
|
|
1112
1254
|
const docid = await client.groupSections(name, allKbids, "agent");
|
|
1113
1255
|
return {
|
|
1114
1256
|
output: JSON.stringify(
|
|
@@ -1208,11 +1350,33 @@ async function runAgentDelete(client, options) {
|
|
|
1208
1350
|
}
|
|
1209
1351
|
await client.removeGrouping(docid);
|
|
1210
1352
|
return {
|
|
1211
|
-
output: JSON.stringify({
|
|
1353
|
+
output: JSON.stringify({ removed: [docid] }, null, 2),
|
|
1212
1354
|
exitCode: 0
|
|
1213
1355
|
};
|
|
1214
1356
|
}
|
|
1215
1357
|
|
|
1358
|
+
// src/shared/cli/functions/run-skill-search.function.ts
|
|
1359
|
+
async function runSkillSearch(client, options) {
|
|
1360
|
+
const paged = await runSearch(client, options);
|
|
1361
|
+
const filtered = paged.items.filter((item) => item.type === "skill");
|
|
1362
|
+
return {
|
|
1363
|
+
...paged,
|
|
1364
|
+
items: filtered,
|
|
1365
|
+
total: filtered.length
|
|
1366
|
+
};
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
// src/shared/cli/functions/run-agent-search.function.ts
|
|
1370
|
+
async function runAgentSearch(client, options) {
|
|
1371
|
+
const paged = await runSearch(client, options);
|
|
1372
|
+
const filtered = paged.items.filter((item) => item.type === "agent");
|
|
1373
|
+
return {
|
|
1374
|
+
...paged,
|
|
1375
|
+
items: filtered,
|
|
1376
|
+
total: filtered.length
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1216
1380
|
// src/shared/cli/functions/run-import.function.ts
|
|
1217
1381
|
import { resolve as resolve4 } from "node:path";
|
|
1218
1382
|
async function runImport(client, options) {
|
|
@@ -1303,6 +1467,10 @@ async function dispatchCommand(client, options, io) {
|
|
|
1303
1467
|
const result = await runAgentDelete(client, options);
|
|
1304
1468
|
return result;
|
|
1305
1469
|
}
|
|
1470
|
+
case "skill-search":
|
|
1471
|
+
return handleTypedSearch(client, options, "skill");
|
|
1472
|
+
case "agent-search":
|
|
1473
|
+
return handleTypedSearch(client, options, "agent");
|
|
1306
1474
|
default:
|
|
1307
1475
|
log("unknown command: " + options.command, 2 /* WARNING */);
|
|
1308
1476
|
return {
|
|
@@ -1314,8 +1482,33 @@ async function dispatchCommand(client, options, io) {
|
|
|
1314
1482
|
async function handleLearn(client, options, io) {
|
|
1315
1483
|
try {
|
|
1316
1484
|
const results = await runLearn(client, options, io);
|
|
1485
|
+
const items = results.map((r) => r.kbid);
|
|
1486
|
+
const base = {
|
|
1487
|
+
items,
|
|
1488
|
+
total: results.length,
|
|
1489
|
+
offset: 0
|
|
1490
|
+
};
|
|
1491
|
+
if (results.length === 0) {
|
|
1492
|
+
const empty = {
|
|
1493
|
+
...base,
|
|
1494
|
+
superseded: null,
|
|
1495
|
+
warnings: [],
|
|
1496
|
+
near_duplicates: []
|
|
1497
|
+
};
|
|
1498
|
+
return {
|
|
1499
|
+
output: formatCommandOutput(empty, options.format, "learn"),
|
|
1500
|
+
exitCode: 0
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1503
|
+
const last = results[results.length - 1];
|
|
1504
|
+
const data = {
|
|
1505
|
+
...base,
|
|
1506
|
+
superseded: last.superseded,
|
|
1507
|
+
warnings: last.warnings,
|
|
1508
|
+
near_duplicates: last.near_duplicates
|
|
1509
|
+
};
|
|
1317
1510
|
return {
|
|
1318
|
-
output: formatCommandOutput(
|
|
1511
|
+
output: formatCommandOutput(data, options.format, "learn"),
|
|
1319
1512
|
exitCode: 0
|
|
1320
1513
|
};
|
|
1321
1514
|
} catch (err) {
|
|
@@ -1328,9 +1521,10 @@ async function handleLearn(client, options, io) {
|
|
|
1328
1521
|
async function handleUnlearn(client, options) {
|
|
1329
1522
|
try {
|
|
1330
1523
|
const results = await runUnlearn(client, options);
|
|
1524
|
+
const removed = results.filter((r) => r.removed).map((r) => r.kbid);
|
|
1331
1525
|
return {
|
|
1332
1526
|
output: formatCommandOutput(
|
|
1333
|
-
|
|
1527
|
+
{ removed },
|
|
1334
1528
|
options.format,
|
|
1335
1529
|
"unlearn"
|
|
1336
1530
|
),
|
|
@@ -1350,7 +1544,7 @@ async function handleSearch(client, options) {
|
|
|
1350
1544
|
await hydrateSearchPreviews(client, results);
|
|
1351
1545
|
}
|
|
1352
1546
|
return {
|
|
1353
|
-
output: formatOutput(results, options.format),
|
|
1547
|
+
output: formatOutput(results, options.format, options.content),
|
|
1354
1548
|
exitCode: 0
|
|
1355
1549
|
};
|
|
1356
1550
|
} catch (err) {
|
|
@@ -1411,11 +1605,38 @@ async function handleImport(client, options) {
|
|
|
1411
1605
|
async function handleContent(client, options) {
|
|
1412
1606
|
try {
|
|
1413
1607
|
const result = await runContent(client, options);
|
|
1414
|
-
if (options.format === "
|
|
1608
|
+
if (options.format === "text") {
|
|
1415
1609
|
return { output: result.data, exitCode: 0 };
|
|
1416
1610
|
}
|
|
1611
|
+
if (options.format === "rec") {
|
|
1612
|
+
const header = `type: ${result.type}
|
|
1613
|
+
total: ${String(result.total)}
|
|
1614
|
+
|
|
1615
|
+
`;
|
|
1616
|
+
return {
|
|
1617
|
+
output: header + result.data,
|
|
1618
|
+
exitCode: 0
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
if (options.format === "mcp") {
|
|
1622
|
+
const text = result.data || "(empty)";
|
|
1623
|
+
return {
|
|
1624
|
+
output: JSON.stringify(
|
|
1625
|
+
{
|
|
1626
|
+
jsonrpc: "2.0",
|
|
1627
|
+
result: {
|
|
1628
|
+
content: [{ type: "text", text }]
|
|
1629
|
+
}
|
|
1630
|
+
},
|
|
1631
|
+
null,
|
|
1632
|
+
2
|
|
1633
|
+
),
|
|
1634
|
+
exitCode: 0
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
const envelope = !options.search && options.args.length === 1 ? { kbid: options.args[0], ...result } : result;
|
|
1417
1638
|
return {
|
|
1418
|
-
output: JSON.stringify(
|
|
1639
|
+
output: JSON.stringify(envelope, null, 2),
|
|
1419
1640
|
exitCode: 0
|
|
1420
1641
|
};
|
|
1421
1642
|
} catch (err) {
|
|
@@ -1502,6 +1723,21 @@ async function handleDbMigrate(client, options) {
|
|
|
1502
1723
|
};
|
|
1503
1724
|
}
|
|
1504
1725
|
}
|
|
1726
|
+
async function handleTypedSearch(client, options, type) {
|
|
1727
|
+
try {
|
|
1728
|
+
const runner = type === "skill" ? runSkillSearch : runAgentSearch;
|
|
1729
|
+
const results = await runner(client, options);
|
|
1730
|
+
return {
|
|
1731
|
+
output: formatOutput(results, options.format),
|
|
1732
|
+
exitCode: 0
|
|
1733
|
+
};
|
|
1734
|
+
} catch (err) {
|
|
1735
|
+
return {
|
|
1736
|
+
error: `${type} search failed: ${errorToMessage(err)}`,
|
|
1737
|
+
exitCode: 1
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1505
1741
|
|
|
1506
1742
|
// src/shared/version/constants/version.constant.ts
|
|
1507
1743
|
var VERSION = "0.6.1";
|
|
@@ -3048,8 +3284,15 @@ function handleInit(options, deps2) {
|
|
|
3048
3284
|
exitCode: 0
|
|
3049
3285
|
};
|
|
3050
3286
|
}
|
|
3287
|
+
const msg = result.errorMessage ?? "init failed";
|
|
3288
|
+
if (/already exists/i.test(msg)) {
|
|
3289
|
+
return {
|
|
3290
|
+
output: `${result.targetPath} (already initialized)`,
|
|
3291
|
+
exitCode: 0
|
|
3292
|
+
};
|
|
3293
|
+
}
|
|
3051
3294
|
return {
|
|
3052
|
-
error: `error: ${
|
|
3295
|
+
error: `error: ${msg}`,
|
|
3053
3296
|
exitCode: 1
|
|
3054
3297
|
};
|
|
3055
3298
|
}
|
|
@@ -3309,7 +3552,7 @@ function createToolDefinitions() {
|
|
|
3309
3552
|
properties: {
|
|
3310
3553
|
content: {
|
|
3311
3554
|
type: "string",
|
|
3312
|
-
description: "
|
|
3555
|
+
description: "Raw text or Markdown content to index. Do not wrap in JSON."
|
|
3313
3556
|
},
|
|
3314
3557
|
type: {
|
|
3315
3558
|
type: "string",
|
|
@@ -3539,7 +3782,7 @@ function createToolDefinitions() {
|
|
|
3539
3782
|
},
|
|
3540
3783
|
body: {
|
|
3541
3784
|
type: "string",
|
|
3542
|
-
description: "Skill body template. Use {{argName}} for placeholders."
|
|
3785
|
+
description: "Skill body template as raw text. Use {{argName}} for placeholders. Do not wrap in JSON."
|
|
3543
3786
|
}
|
|
3544
3787
|
},
|
|
3545
3788
|
required: ["name", "body"]
|
|
@@ -3628,7 +3871,7 @@ function createToolDefinitions() {
|
|
|
3628
3871
|
},
|
|
3629
3872
|
persona: {
|
|
3630
3873
|
type: "string",
|
|
3631
|
-
description: "Agent persona
|
|
3874
|
+
description: "Agent persona as raw text. Do not wrap in JSON."
|
|
3632
3875
|
},
|
|
3633
3876
|
skills: {
|
|
3634
3877
|
type: "array",
|
|
@@ -3703,6 +3946,56 @@ function createToolDefinitions() {
|
|
|
3703
3946
|
openWorldHint: false
|
|
3704
3947
|
}
|
|
3705
3948
|
},
|
|
3949
|
+
{
|
|
3950
|
+
name: "skill-search",
|
|
3951
|
+
description: "Search for skills by keyword. Returns ranked skill definitions matching the query.",
|
|
3952
|
+
inputSchema: {
|
|
3953
|
+
type: "object",
|
|
3954
|
+
properties: {
|
|
3955
|
+
query: {
|
|
3956
|
+
type: "string",
|
|
3957
|
+
description: "Search query text"
|
|
3958
|
+
},
|
|
3959
|
+
limit: {
|
|
3960
|
+
type: "number",
|
|
3961
|
+
description: "Maximum results (default: 20)"
|
|
3962
|
+
}
|
|
3963
|
+
},
|
|
3964
|
+
required: ["query"]
|
|
3965
|
+
},
|
|
3966
|
+
annotations: {
|
|
3967
|
+
title: "Search Skills",
|
|
3968
|
+
readOnlyHint: true,
|
|
3969
|
+
destructiveHint: false,
|
|
3970
|
+
idempotentHint: true,
|
|
3971
|
+
openWorldHint: false
|
|
3972
|
+
}
|
|
3973
|
+
},
|
|
3974
|
+
{
|
|
3975
|
+
name: "agent-search",
|
|
3976
|
+
description: "Search for agents by keyword. Returns ranked agent profiles matching the query.",
|
|
3977
|
+
inputSchema: {
|
|
3978
|
+
type: "object",
|
|
3979
|
+
properties: {
|
|
3980
|
+
query: {
|
|
3981
|
+
type: "string",
|
|
3982
|
+
description: "Search query text"
|
|
3983
|
+
},
|
|
3984
|
+
limit: {
|
|
3985
|
+
type: "number",
|
|
3986
|
+
description: "Maximum results (default: 20)"
|
|
3987
|
+
}
|
|
3988
|
+
},
|
|
3989
|
+
required: ["query"]
|
|
3990
|
+
},
|
|
3991
|
+
annotations: {
|
|
3992
|
+
title: "Search Agents",
|
|
3993
|
+
readOnlyHint: true,
|
|
3994
|
+
destructiveHint: false,
|
|
3995
|
+
idempotentHint: true,
|
|
3996
|
+
openWorldHint: false
|
|
3997
|
+
}
|
|
3998
|
+
},
|
|
3706
3999
|
{
|
|
3707
4000
|
name: "auto-capture-review",
|
|
3708
4001
|
description: "Review and approve pending auto-captured knowledge before storage.",
|
|
@@ -3745,6 +4038,33 @@ function createResourceTemplates() {
|
|
|
3745
4038
|
];
|
|
3746
4039
|
}
|
|
3747
4040
|
|
|
4041
|
+
// src/shared/mcp/functions/format-search-results.function.ts
|
|
4042
|
+
function formatSearchResults(query, results) {
|
|
4043
|
+
if (results.items.length === 0) {
|
|
4044
|
+
return `No results found for "${query}"`;
|
|
4045
|
+
}
|
|
4046
|
+
const lines = results.items.map(
|
|
4047
|
+
(item, index) => formatItem(item, results.offset + index + 1)
|
|
4048
|
+
);
|
|
4049
|
+
const start = results.offset + 1;
|
|
4050
|
+
const end = results.offset + results.items.length;
|
|
4051
|
+
const total = String(results.total);
|
|
4052
|
+
return [
|
|
4053
|
+
`Found ${total} results for "${query}"`,
|
|
4054
|
+
"",
|
|
4055
|
+
...lines,
|
|
4056
|
+
"",
|
|
4057
|
+
`Showing ${String(start)}-${String(end)} of ${total} results`
|
|
4058
|
+
].join("\n");
|
|
4059
|
+
}
|
|
4060
|
+
function formatItem(item, position) {
|
|
4061
|
+
const heading = item.heading ?? "(untitled)";
|
|
4062
|
+
const terms = item.matched_terms.join(", ");
|
|
4063
|
+
return `${String(position)}. [${item.kbid}] ${heading}
|
|
4064
|
+
${item.snippet}
|
|
4065
|
+
type: ${item.type} terms: ${terms}`;
|
|
4066
|
+
}
|
|
4067
|
+
|
|
3748
4068
|
// src/shared/mcp/functions/handle-agent-create.function.ts
|
|
3749
4069
|
function asString(value, fallback) {
|
|
3750
4070
|
return typeof value === "string" ? value : fallback;
|
|
@@ -3795,35 +4115,52 @@ async function handleAgentCreate(client, args) {
|
|
|
3795
4115
|
title: name,
|
|
3796
4116
|
description
|
|
3797
4117
|
});
|
|
3798
|
-
const allKbids = [metaResult.
|
|
4118
|
+
const allKbids = [metaResult.items[0], ...skills];
|
|
3799
4119
|
const docid = await client.groupSections(name, allKbids, "agent");
|
|
3800
4120
|
return {
|
|
3801
4121
|
content: [
|
|
3802
4122
|
{
|
|
3803
4123
|
type: "text",
|
|
3804
|
-
text:
|
|
3805
|
-
|
|
3806
|
-
name,
|
|
3807
|
-
skillCount: skills.length
|
|
3808
|
-
})
|
|
4124
|
+
text: `Created agent "${name}" (docid: ${docid})
|
|
4125
|
+
Skills: ${String(skills.length)} attached`
|
|
3809
4126
|
}
|
|
3810
4127
|
]
|
|
3811
4128
|
};
|
|
3812
4129
|
}
|
|
3813
4130
|
|
|
3814
4131
|
// src/shared/mcp/functions/handle-agent-list.function.ts
|
|
4132
|
+
async function readAgentDescription(client, sections) {
|
|
4133
|
+
const metaKbid = sections[0]?.kbid;
|
|
4134
|
+
if (!metaKbid) return "";
|
|
4135
|
+
const metaSections = await client.readSections([metaKbid]);
|
|
4136
|
+
const first = metaSections.at(0);
|
|
4137
|
+
if (!first) return "";
|
|
4138
|
+
try {
|
|
4139
|
+
const meta = JSON.parse(first.content);
|
|
4140
|
+
return typeof meta["description"] === "string" ? meta["description"] : "";
|
|
4141
|
+
} catch {
|
|
4142
|
+
return "";
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
3815
4145
|
async function handleAgentList(client) {
|
|
3816
4146
|
const docs = await client.listDocumentsByType("agent");
|
|
3817
|
-
const items =
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
4147
|
+
const items = await Promise.all(
|
|
4148
|
+
docs.map(async (d) => ({
|
|
4149
|
+
name: d.title,
|
|
4150
|
+
description: await readAgentDescription(client, d.sections)
|
|
4151
|
+
}))
|
|
4152
|
+
);
|
|
4153
|
+
const lines = items.map(
|
|
4154
|
+
(item, index) => `${String(index + 1)}. ${item.name}` + (item.description ? ` -- ${item.description}` : "")
|
|
4155
|
+
);
|
|
4156
|
+
const text = [`${String(items.length)} agents:`, ...lines].join(
|
|
4157
|
+
"\n"
|
|
4158
|
+
);
|
|
3822
4159
|
return {
|
|
3823
4160
|
content: [
|
|
3824
4161
|
{
|
|
3825
4162
|
type: "text",
|
|
3826
|
-
text
|
|
4163
|
+
text
|
|
3827
4164
|
}
|
|
3828
4165
|
]
|
|
3829
4166
|
};
|
|
@@ -3872,6 +4209,19 @@ async function resolveSkillRefs(client, skillRefs) {
|
|
|
3872
4209
|
}
|
|
3873
4210
|
});
|
|
3874
4211
|
}
|
|
4212
|
+
function formatAgent(agent) {
|
|
4213
|
+
const skillLines = agent.skills.length > 0 ? agent.skills.map(
|
|
4214
|
+
(s, index) => `${String(index + 1)}. ${s.name ?? `(missing: ${s.kbid})`}`
|
|
4215
|
+
).join("\n") : "none";
|
|
4216
|
+
return [
|
|
4217
|
+
`Agent: ${agent.name} (docid: ${agent.docid})`,
|
|
4218
|
+
`Description: ${agent.description}`,
|
|
4219
|
+
`Persona: ${agent.persona}`,
|
|
4220
|
+
"",
|
|
4221
|
+
"Skills:",
|
|
4222
|
+
skillLines
|
|
4223
|
+
].join("\n");
|
|
4224
|
+
}
|
|
3875
4225
|
async function handleAgentGet(client, args) {
|
|
3876
4226
|
const docid = typeof args["docid"] === "string" ? args["docid"] : "";
|
|
3877
4227
|
if (!docid) {
|
|
@@ -3896,7 +4246,7 @@ async function handleAgentGet(client, args) {
|
|
|
3896
4246
|
content: [
|
|
3897
4247
|
{
|
|
3898
4248
|
type: "text",
|
|
3899
|
-
text:
|
|
4249
|
+
text: formatAgent(agent)
|
|
3900
4250
|
}
|
|
3901
4251
|
]
|
|
3902
4252
|
};
|
|
@@ -3916,17 +4266,74 @@ async function handleAgentDelete(client, args) {
|
|
|
3916
4266
|
content: [
|
|
3917
4267
|
{
|
|
3918
4268
|
type: "text",
|
|
3919
|
-
text:
|
|
4269
|
+
text: `Deleted agent (docid: ${docid})`
|
|
3920
4270
|
}
|
|
3921
4271
|
]
|
|
3922
4272
|
};
|
|
3923
4273
|
}
|
|
3924
4274
|
|
|
3925
4275
|
// src/shared/mcp/functions/handle-recall.function.ts
|
|
4276
|
+
function asRecord(value) {
|
|
4277
|
+
return typeof value === "object" && value !== null ? value : void 0;
|
|
4278
|
+
}
|
|
4279
|
+
function strField(record, key, fallback) {
|
|
4280
|
+
const value = record[key];
|
|
4281
|
+
return typeof value === "string" ? value : fallback;
|
|
4282
|
+
}
|
|
4283
|
+
function formatList(label, items, line) {
|
|
4284
|
+
if (items === void 0 || items === null) {
|
|
4285
|
+
return "";
|
|
4286
|
+
}
|
|
4287
|
+
const list = Array.isArray(items) ? items : [];
|
|
4288
|
+
const rows = list.map((raw) => asRecord(raw)).filter((r) => r !== void 0).map((r) => ` - ${line(r)}`);
|
|
4289
|
+
if (rows.length > 0) {
|
|
4290
|
+
return `
|
|
4291
|
+
|
|
4292
|
+
${label}:
|
|
4293
|
+
${rows.join("\n")}`;
|
|
4294
|
+
}
|
|
4295
|
+
return `
|
|
4296
|
+
|
|
4297
|
+
${label}: (none)`;
|
|
4298
|
+
}
|
|
4299
|
+
function formatRecallItem(raw) {
|
|
4300
|
+
const item = asRecord(raw) ?? {};
|
|
4301
|
+
const kbid = strField(item, "kbid", "?");
|
|
4302
|
+
const heading = strField(item, "heading", "(untitled)");
|
|
4303
|
+
const type = strField(item, "type", "unknown");
|
|
4304
|
+
const content = strField(item, "content", "");
|
|
4305
|
+
const refLine = (r) => `${strField(r, "heading", strField(r, "kbid", "?"))} (${strField(r, "kbid", "?")})`;
|
|
4306
|
+
const text = `${heading} [${type}] (${kbid})
|
|
4307
|
+
|
|
4308
|
+
${content}` + formatList(
|
|
4309
|
+
"Documents",
|
|
4310
|
+
item["documents"],
|
|
4311
|
+
(d) => `${strField(d, "title", "?")} (${strField(d, "docid", "?")})`
|
|
4312
|
+
) + formatList("Back references", item["back_references"], refLine) + formatList("Siblings", item["siblings"], refLine) + formatList("References", item["references"], refLine);
|
|
4313
|
+
return text;
|
|
4314
|
+
}
|
|
4315
|
+
function buildNotFoundResult(id, depth) {
|
|
4316
|
+
const base = {
|
|
4317
|
+
kbid: id,
|
|
4318
|
+
heading: "(not found)",
|
|
4319
|
+
type: "unknown",
|
|
4320
|
+
content: "",
|
|
4321
|
+
docids: []
|
|
4322
|
+
};
|
|
4323
|
+
if (depth >= 1) {
|
|
4324
|
+
base["documents"] = [];
|
|
4325
|
+
base["back_references"] = [];
|
|
4326
|
+
}
|
|
4327
|
+
if (depth >= 2) {
|
|
4328
|
+
base["siblings"] = [];
|
|
4329
|
+
base["references"] = [];
|
|
4330
|
+
}
|
|
4331
|
+
return base;
|
|
4332
|
+
}
|
|
3926
4333
|
async function handleRecall2(client, args) {
|
|
3927
4334
|
const kbid = typeof args["kbid"] === "string" ? args["kbid"] : void 0;
|
|
3928
4335
|
const kbids = Array.isArray(args["kbids"]) && args["kbids"].every((item) => typeof item === "string") ? args["kbids"] : void 0;
|
|
3929
|
-
if (!kbid && !kbids) {
|
|
4336
|
+
if (!kbid && (!kbids || kbids.length === 0)) {
|
|
3930
4337
|
return {
|
|
3931
4338
|
content: [
|
|
3932
4339
|
{
|
|
@@ -3938,17 +4345,63 @@ async function handleRecall2(client, args) {
|
|
|
3938
4345
|
};
|
|
3939
4346
|
}
|
|
3940
4347
|
const depth = typeof args["depth"] === "number" ? args["depth"] : 0;
|
|
3941
|
-
|
|
4348
|
+
let result;
|
|
4349
|
+
try {
|
|
4350
|
+
result = await client.recall({ kbid, kbids, depth });
|
|
4351
|
+
} catch {
|
|
4352
|
+
const ids = kbid ? [kbid] : kbids ?? [];
|
|
4353
|
+
const items = ids.map((id) => buildNotFoundResult(id, depth));
|
|
4354
|
+
result = items.length === 1 ? items[0] : items;
|
|
4355
|
+
}
|
|
4356
|
+
const text = Array.isArray(result) ? result.map(formatRecallItem).join("\n\n---\n\n") : formatRecallItem(result);
|
|
3942
4357
|
return {
|
|
3943
4358
|
content: [
|
|
3944
4359
|
{
|
|
3945
4360
|
type: "text",
|
|
3946
|
-
text
|
|
4361
|
+
text
|
|
3947
4362
|
}
|
|
3948
4363
|
]
|
|
3949
4364
|
};
|
|
3950
4365
|
}
|
|
3951
4366
|
|
|
4367
|
+
// src/shared/mcp/functions/handle-skill-search.function.ts
|
|
4368
|
+
async function handleSkillSearch(client, args) {
|
|
4369
|
+
const query = typeof args["query"] === "string" ? args["query"] : "";
|
|
4370
|
+
const results = await client.search({
|
|
4371
|
+
query,
|
|
4372
|
+
limit: args["limit"]
|
|
4373
|
+
});
|
|
4374
|
+
const filtered = {
|
|
4375
|
+
...results,
|
|
4376
|
+
items: results.items.filter(
|
|
4377
|
+
(item) => item.type === "skill"
|
|
4378
|
+
),
|
|
4379
|
+
total: 0
|
|
4380
|
+
};
|
|
4381
|
+
filtered.total = filtered.items.length;
|
|
4382
|
+
const text = formatSearchResults(query, filtered);
|
|
4383
|
+
return { content: [{ type: "text", text }] };
|
|
4384
|
+
}
|
|
4385
|
+
|
|
4386
|
+
// src/shared/mcp/functions/handle-agent-search.function.ts
|
|
4387
|
+
async function handleAgentSearch(client, args) {
|
|
4388
|
+
const query = typeof args["query"] === "string" ? args["query"] : "";
|
|
4389
|
+
const results = await client.search({
|
|
4390
|
+
query,
|
|
4391
|
+
limit: args["limit"]
|
|
4392
|
+
});
|
|
4393
|
+
const filtered = {
|
|
4394
|
+
...results,
|
|
4395
|
+
items: results.items.filter(
|
|
4396
|
+
(item) => item.type === "agent"
|
|
4397
|
+
),
|
|
4398
|
+
total: 0
|
|
4399
|
+
};
|
|
4400
|
+
filtered.total = filtered.items.length;
|
|
4401
|
+
const text = formatSearchResults(query, filtered);
|
|
4402
|
+
return { content: [{ type: "text", text }] };
|
|
4403
|
+
}
|
|
4404
|
+
|
|
3952
4405
|
// src/shared/mcp/functions/handle-tool-call.function.ts
|
|
3953
4406
|
function asString2(value, fallback) {
|
|
3954
4407
|
return typeof value === "string" ? value : fallback;
|
|
@@ -3968,6 +4421,18 @@ function asStringArray2(value) {
|
|
|
3968
4421
|
}
|
|
3969
4422
|
return [];
|
|
3970
4423
|
}
|
|
4424
|
+
function unwrapJsonContent(raw) {
|
|
4425
|
+
const trimmed = raw.trim();
|
|
4426
|
+
if (!trimmed.startsWith("{")) return raw;
|
|
4427
|
+
try {
|
|
4428
|
+
const parsed = JSON.parse(trimmed);
|
|
4429
|
+
if (typeof parsed["content"] === "string")
|
|
4430
|
+
return parsed["content"];
|
|
4431
|
+
if (typeof parsed["text"] === "string") return parsed["text"];
|
|
4432
|
+
} catch {
|
|
4433
|
+
}
|
|
4434
|
+
return raw;
|
|
4435
|
+
}
|
|
3971
4436
|
async function handleToolCall(client, name, args) {
|
|
3972
4437
|
log("tool call: " + name, 0 /* DEBUG */);
|
|
3973
4438
|
try {
|
|
@@ -4010,6 +4475,10 @@ async function handleToolCall(client, name, args) {
|
|
|
4010
4475
|
return await handleAgentGet(client, args);
|
|
4011
4476
|
case "agent-delete":
|
|
4012
4477
|
return await handleAgentDelete(client, args);
|
|
4478
|
+
case "skill-search":
|
|
4479
|
+
return await handleSkillSearch(client, args);
|
|
4480
|
+
case "agent-search":
|
|
4481
|
+
return await handleAgentSearch(client, args);
|
|
4013
4482
|
case "auto-capture-review":
|
|
4014
4483
|
return handleAutoCaptureReview();
|
|
4015
4484
|
default:
|
|
@@ -4041,30 +4510,18 @@ async function handleToolCall(client, name, args) {
|
|
|
4041
4510
|
}
|
|
4042
4511
|
}
|
|
4043
4512
|
async function handleSearch2(client, args) {
|
|
4513
|
+
const query = asString2(args["query"], "");
|
|
4044
4514
|
const results = await client.search({
|
|
4045
|
-
query
|
|
4515
|
+
query,
|
|
4046
4516
|
mode: args["mode"],
|
|
4047
4517
|
limit: args["limit"],
|
|
4048
4518
|
offset: args["offset"],
|
|
4049
4519
|
algo: args["algo"],
|
|
4050
4520
|
relaxed: args["relaxed"]
|
|
4051
4521
|
});
|
|
4052
|
-
const stripped = {
|
|
4053
|
-
...results,
|
|
4054
|
-
items: results.items.map(
|
|
4055
|
-
({
|
|
4056
|
-
score: _score,
|
|
4057
|
-
confidence: _confidence,
|
|
4058
|
-
...rest
|
|
4059
|
-
}) => rest
|
|
4060
|
-
)
|
|
4061
|
-
};
|
|
4062
4522
|
return {
|
|
4063
4523
|
content: [
|
|
4064
|
-
{
|
|
4065
|
-
type: "text",
|
|
4066
|
-
text: JSON.stringify(stripped, null, 2)
|
|
4067
|
-
}
|
|
4524
|
+
{ type: "text", text: formatSearchResults(query, results) }
|
|
4068
4525
|
]
|
|
4069
4526
|
};
|
|
4070
4527
|
}
|
|
@@ -4086,70 +4543,47 @@ async function handleLearn2(client, args) {
|
|
|
4086
4543
|
isError: true
|
|
4087
4544
|
};
|
|
4088
4545
|
}
|
|
4546
|
+
const rawContent = asString2(args["content"], "");
|
|
4547
|
+
const content = unwrapJsonContent(rawContent);
|
|
4089
4548
|
const result = await client.addSection({
|
|
4090
4549
|
sectionType,
|
|
4091
|
-
content
|
|
4550
|
+
content,
|
|
4092
4551
|
title,
|
|
4093
4552
|
description,
|
|
4094
4553
|
docid,
|
|
4095
4554
|
tags,
|
|
4096
4555
|
replace
|
|
4097
4556
|
});
|
|
4098
|
-
const
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4557
|
+
const payload = {
|
|
4558
|
+
items: result.items,
|
|
4559
|
+
total: result.total,
|
|
4560
|
+
offset: result.offset,
|
|
4102
4561
|
superseded: result.superseded ?? null,
|
|
4103
4562
|
warnings: result.warnings ?? [],
|
|
4104
|
-
near_duplicates:
|
|
4105
|
-
kbid: d.kbid,
|
|
4106
|
-
similarity: d.similarity,
|
|
4107
|
-
...d.method !== void 0 ? { method: d.method } : {}
|
|
4108
|
-
}))
|
|
4563
|
+
near_duplicates: result.near_duplicates ?? []
|
|
4109
4564
|
};
|
|
4110
4565
|
return {
|
|
4111
|
-
content: [
|
|
4112
|
-
{
|
|
4113
|
-
type: "text",
|
|
4114
|
-
text: JSON.stringify(normalized)
|
|
4115
|
-
}
|
|
4116
|
-
]
|
|
4566
|
+
content: [{ type: "text", text: JSON.stringify(payload) }]
|
|
4117
4567
|
};
|
|
4118
4568
|
}
|
|
4119
4569
|
async function handleUnlearn2(client, args) {
|
|
4120
|
-
const
|
|
4121
|
-
|
|
4122
|
-
);
|
|
4570
|
+
const kbid = asString2(args["kbid"], "");
|
|
4571
|
+
await client.removeSection(kbid);
|
|
4123
4572
|
return {
|
|
4124
|
-
content: [
|
|
4125
|
-
{
|
|
4126
|
-
type: "text",
|
|
4127
|
-
text: JSON.stringify(result)
|
|
4128
|
-
}
|
|
4129
|
-
]
|
|
4573
|
+
content: [{ type: "text", text: `Removed section ${kbid}` }]
|
|
4130
4574
|
};
|
|
4131
4575
|
}
|
|
4132
4576
|
async function handleRetrieve(client, args) {
|
|
4133
4577
|
if (typeof args["kbid"] === "string") {
|
|
4134
4578
|
const sections = await client.readSections([args["kbid"]]);
|
|
4135
4579
|
return {
|
|
4136
|
-
content: [
|
|
4137
|
-
{
|
|
4138
|
-
type: "text",
|
|
4139
|
-
text: JSON.stringify(sections, null, 2)
|
|
4140
|
-
}
|
|
4141
|
-
]
|
|
4580
|
+
content: [{ type: "text", text: formatSections(sections) }]
|
|
4142
4581
|
};
|
|
4143
4582
|
}
|
|
4144
4583
|
if (typeof args["docid"] === "string") {
|
|
4145
4584
|
const doc = await client.retrieveDocument(args["docid"]);
|
|
4146
4585
|
return {
|
|
4147
|
-
content: [
|
|
4148
|
-
{
|
|
4149
|
-
type: "text",
|
|
4150
|
-
text: JSON.stringify(doc, null, 2)
|
|
4151
|
-
}
|
|
4152
|
-
]
|
|
4586
|
+
content: [{ type: "text", text: formatDocument(doc) }]
|
|
4153
4587
|
};
|
|
4154
4588
|
}
|
|
4155
4589
|
return {
|
|
@@ -4162,61 +4596,81 @@ async function handleRetrieve(client, args) {
|
|
|
4162
4596
|
isError: true
|
|
4163
4597
|
};
|
|
4164
4598
|
}
|
|
4599
|
+
function formatSections(sections) {
|
|
4600
|
+
if (sections.length === 0) {
|
|
4601
|
+
return "No sections found";
|
|
4602
|
+
}
|
|
4603
|
+
return sections.map((s) => `${s.kbid} (${s.sectionType})
|
|
4604
|
+
${s.content}`).join("\n\n");
|
|
4605
|
+
}
|
|
4606
|
+
function formatDocument(doc) {
|
|
4607
|
+
if (typeof doc !== "object" || doc === null) {
|
|
4608
|
+
return String(doc);
|
|
4609
|
+
}
|
|
4610
|
+
return Object.entries(doc).map(([key, value]) => {
|
|
4611
|
+
if (Array.isArray(value)) {
|
|
4612
|
+
const items = value.map((item) => formatDocValue(item)).map((s) => ` - ${s}`);
|
|
4613
|
+
return items.length > 0 ? `${key}:
|
|
4614
|
+
${items.join("\n")}` : `${key}: (none)`;
|
|
4615
|
+
}
|
|
4616
|
+
return `${key}: ${formatDocValue(value)}`;
|
|
4617
|
+
}).join("\n");
|
|
4618
|
+
}
|
|
4619
|
+
function formatDocValue(value) {
|
|
4620
|
+
if (typeof value !== "object" || value === null) {
|
|
4621
|
+
return String(value);
|
|
4622
|
+
}
|
|
4623
|
+
const rec = value;
|
|
4624
|
+
return Object.entries(rec).map(([k, v]) => `${k}=${String(v)}`).join(", ");
|
|
4625
|
+
}
|
|
4165
4626
|
async function handleStatus2(client) {
|
|
4166
4627
|
const status = await client.dbStatus();
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4628
|
+
const cs = status.cacheStats;
|
|
4629
|
+
const lines = [
|
|
4630
|
+
`Database: ${status.contextPath}`,
|
|
4631
|
+
`Initialized: ${status.initialized ? "yes" : "no"}`
|
|
4632
|
+
];
|
|
4633
|
+
if (cs) {
|
|
4634
|
+
lines.push(
|
|
4635
|
+
`Cached content entries: ${String(cs.contentCount)}`,
|
|
4636
|
+
`Cached index entries: ${String(cs.indexCount)}`
|
|
4637
|
+
);
|
|
4638
|
+
}
|
|
4639
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4175
4640
|
}
|
|
4176
4641
|
async function handleContent2(client, args) {
|
|
4177
4642
|
const ids = asStringArray2(args["ids"]);
|
|
4178
4643
|
const result = await client.content(ids);
|
|
4644
|
+
const text = result.data || "(no content found)";
|
|
4179
4645
|
return {
|
|
4180
|
-
content: [
|
|
4181
|
-
{
|
|
4182
|
-
type: "text",
|
|
4183
|
-
text: JSON.stringify(result)
|
|
4184
|
-
}
|
|
4185
|
-
]
|
|
4646
|
+
content: [{ type: "text", text }]
|
|
4186
4647
|
};
|
|
4187
4648
|
}
|
|
4188
4649
|
async function handleCheck2(client) {
|
|
4189
4650
|
const report = await client.integrityCheck();
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
};
|
|
4651
|
+
const status = report.ok ? "OK" : "FAIL";
|
|
4652
|
+
const lines = [
|
|
4653
|
+
`Integrity check: ${status}. ${String(report.sections_checked)} sections checked.`
|
|
4654
|
+
];
|
|
4655
|
+
for (const error of report.errors) {
|
|
4656
|
+
lines.push(`- ${error.type}: ${error.entity} (${error.detail})`);
|
|
4657
|
+
}
|
|
4658
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4198
4659
|
}
|
|
4199
4660
|
async function handleGc2(client) {
|
|
4200
4661
|
const report = await client.gc();
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
};
|
|
4662
|
+
const lines = [
|
|
4663
|
+
`GC complete: removed ${String(report.removed_sections)} sections, freed ${String(report.removed_bytes)} bytes.`
|
|
4664
|
+
];
|
|
4665
|
+
if (report.stale_sources !== void 0) {
|
|
4666
|
+
lines.push(`stale sources: ${String(report.stale_sources)}`);
|
|
4667
|
+
}
|
|
4668
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4209
4669
|
}
|
|
4210
4670
|
async function handleRebuild2(client) {
|
|
4211
4671
|
const report = await client.rebuildIndexes();
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
{
|
|
4215
|
-
type: "text",
|
|
4216
|
-
text: JSON.stringify(report, null, 2)
|
|
4217
|
-
}
|
|
4218
|
-
]
|
|
4219
|
-
};
|
|
4672
|
+
const text = `Rebuild complete: ${String(report.sections_reindexed)} sections reindexed, ${String(report.terms_indexed)} terms indexed.`;
|
|
4673
|
+
return { content: [{ type: "text", text }] };
|
|
4220
4674
|
}
|
|
4221
4675
|
async function handleSkillLearn(client, args) {
|
|
4222
4676
|
const name = asString2(args["name"], "");
|
|
@@ -4252,37 +4706,22 @@ async function handleSkillLearn(client, args) {
|
|
|
4252
4706
|
content: [
|
|
4253
4707
|
{
|
|
4254
4708
|
type: "text",
|
|
4255
|
-
text:
|
|
4709
|
+
text: `Created skill "${name}" (kbid: ${result.items[0]})`
|
|
4256
4710
|
}
|
|
4257
4711
|
]
|
|
4258
4712
|
};
|
|
4259
4713
|
}
|
|
4260
4714
|
async function handleSkillList(client) {
|
|
4261
4715
|
const records = await client.listByType("skill");
|
|
4262
|
-
const
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
if (Array.isArray(parsed["arguments"])) {
|
|
4267
|
-
argumentCount = parsed["arguments"].length;
|
|
4268
|
-
}
|
|
4269
|
-
} catch {
|
|
4270
|
-
}
|
|
4271
|
-
return {
|
|
4272
|
-
kbid: r.kbid,
|
|
4273
|
-
name: r.title,
|
|
4274
|
-
description: r.description,
|
|
4275
|
-
argumentCount
|
|
4276
|
-
};
|
|
4716
|
+
const lines = records.map((r, index) => {
|
|
4717
|
+
const desc = r.description ? ` -- ${r.description}` : "";
|
|
4718
|
+
const label = r.title ?? "(untitled)";
|
|
4719
|
+
return `${String(index + 1)}. ${label} (${r.kbid})${desc}`;
|
|
4277
4720
|
});
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
text: JSON.stringify(items, null, 2)
|
|
4283
|
-
}
|
|
4284
|
-
]
|
|
4285
|
-
};
|
|
4721
|
+
const text = [`${String(records.length)} skills:`, ...lines].join(
|
|
4722
|
+
"\n"
|
|
4723
|
+
);
|
|
4724
|
+
return { content: [{ type: "text", text }] };
|
|
4286
4725
|
}
|
|
4287
4726
|
async function handleSkillGet(client, args) {
|
|
4288
4727
|
const kbid = typeof args["kbid"] === "string" ? args["kbid"] : void 0;
|
|
@@ -4326,14 +4765,29 @@ async function handleSkillGet(client, args) {
|
|
|
4326
4765
|
}
|
|
4327
4766
|
const skill = parseSkillContent(content);
|
|
4328
4767
|
return {
|
|
4329
|
-
content: [
|
|
4330
|
-
{
|
|
4331
|
-
type: "text",
|
|
4332
|
-
text: JSON.stringify(skill, null, 2)
|
|
4333
|
-
}
|
|
4334
|
-
]
|
|
4768
|
+
content: [{ type: "text", text: formatSkill(skill) }]
|
|
4335
4769
|
};
|
|
4336
4770
|
}
|
|
4771
|
+
function formatSkill(skill) {
|
|
4772
|
+
const lines = [`name: ${skill.name}`];
|
|
4773
|
+
if (skill.description) {
|
|
4774
|
+
lines.push(`description: ${skill.description}`);
|
|
4775
|
+
}
|
|
4776
|
+
if (skill.arguments && skill.arguments.length > 0) {
|
|
4777
|
+
lines.push("arguments:");
|
|
4778
|
+
for (const arg of skill.arguments) {
|
|
4779
|
+
const details = [
|
|
4780
|
+
...arg.type ? [arg.type] : [],
|
|
4781
|
+
...arg.required ? ["required"] : []
|
|
4782
|
+
];
|
|
4783
|
+
lines.push(
|
|
4784
|
+
details.length > 0 ? `- ${arg.name}: ${details.join(", ")}` : `- ${arg.name}`
|
|
4785
|
+
);
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
4788
|
+
lines.push("body:", skill.body);
|
|
4789
|
+
return lines.join("\n");
|
|
4790
|
+
}
|
|
4337
4791
|
async function handleSkillDelete(client, args) {
|
|
4338
4792
|
const kbid = asString2(args["kbid"], "");
|
|
4339
4793
|
if (!kbid) {
|
|
@@ -4342,14 +4796,9 @@ async function handleSkillDelete(client, args) {
|
|
|
4342
4796
|
isError: true
|
|
4343
4797
|
};
|
|
4344
4798
|
}
|
|
4345
|
-
|
|
4799
|
+
await client.removeSection(kbid);
|
|
4346
4800
|
return {
|
|
4347
|
-
content: [
|
|
4348
|
-
{
|
|
4349
|
-
type: "text",
|
|
4350
|
-
text: JSON.stringify({ kbid, removed: result.removed })
|
|
4351
|
-
}
|
|
4352
|
-
]
|
|
4801
|
+
content: [{ type: "text", text: `Deleted skill ${kbid}` }]
|
|
4353
4802
|
};
|
|
4354
4803
|
}
|
|
4355
4804
|
function handleAutoCaptureReview() {
|
|
@@ -4357,10 +4806,7 @@ function handleAutoCaptureReview() {
|
|
|
4357
4806
|
content: [
|
|
4358
4807
|
{
|
|
4359
4808
|
type: "text",
|
|
4360
|
-
text:
|
|
4361
|
-
pending: [],
|
|
4362
|
-
message: "No pending auto-captured knowledge entries."
|
|
4363
|
-
})
|
|
4809
|
+
text: "No pending auto-captured knowledge entries."
|
|
4364
4810
|
}
|
|
4365
4811
|
]
|
|
4366
4812
|
};
|
|
@@ -4370,14 +4816,13 @@ async function handleExport2(client, args) {
|
|
|
4370
4816
|
const result = await client.export(
|
|
4371
4817
|
path !== void 0 ? { path } : {}
|
|
4372
4818
|
);
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
};
|
|
4819
|
+
const lines = [
|
|
4820
|
+
`Exported to ${result.path}`,
|
|
4821
|
+
`sections: ${String(result.sections_exported)}`,
|
|
4822
|
+
`documents: ${String(result.documents_exported)}`,
|
|
4823
|
+
`elapsed: ${String(result.elapsed_ms)}ms`
|
|
4824
|
+
];
|
|
4825
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4381
4826
|
}
|
|
4382
4827
|
|
|
4383
4828
|
// src/shared/mcp/functions/handle-resource-read.function.ts
|