@dikolab/kbdb 0.6.3 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/cli.cjs +681 -249
  2. package/dist/cli.cjs.map +4 -4
  3. package/dist/cli.mjs +638 -206
  4. package/dist/cli.mjs.map +4 -4
  5. package/dist/kbdb-worker.cjs +49 -7
  6. package/dist/kbdb-worker.cjs.map +4 -4
  7. package/dist/mod.cjs +1 -1
  8. package/dist/mod.cjs.map +1 -1
  9. package/dist/mod.mjs +1 -1
  10. package/dist/mod.mjs.map +1 -1
  11. package/dist/src/shared/cli/constants/defaults.constant.d.ts +1 -1
  12. package/dist/src/shared/cli/functions/learn-markdown-document.function.d.ts +22 -0
  13. package/dist/src/shared/cli/functions/learn-structured-document.function.d.ts +10 -0
  14. package/dist/src/shared/cli/functions/learn-target-content.function.d.ts +12 -0
  15. package/dist/src/shared/cli/functions/map-add-section-result.function.d.ts +12 -0
  16. package/dist/src/shared/cli/functions/run-agent-list.function.d.ts +13 -9
  17. package/dist/src/shared/cli/functions/run-learn.function.d.ts +10 -59
  18. package/dist/src/shared/cli/functions/run-skill-list.function.d.ts +11 -7
  19. package/dist/src/shared/cli/functions/split-markdown-sections.function.d.ts +16 -0
  20. package/dist/src/shared/cli/typings/learn-client.interface.d.ts +16 -28
  21. package/dist/src/shared/cli/typings/learn-result.model.d.ts +2 -0
  22. package/dist/src/shared/cli/typings/markdown-section.interface.d.ts +23 -0
  23. package/dist/src/shared/content-splitter/classes/heading-parent-tracker.class.d.ts +20 -0
  24. package/dist/src/shared/content-splitter/constants/content-type-maps.constant.d.ts +5 -0
  25. package/dist/src/shared/content-splitter/constants/split-strategy-map.constant.d.ts +4 -0
  26. package/dist/src/shared/content-splitter/functions/detect-content-type.function.d.ts +13 -0
  27. package/dist/src/shared/content-splitter/functions/flush-markdown-draft.function.d.ts +14 -0
  28. package/dist/src/shared/content-splitter/functions/flush-toml-draft.function.d.ts +15 -0
  29. package/dist/src/shared/content-splitter/functions/push-content-section.function.d.ts +16 -0
  30. package/dist/src/shared/content-splitter/functions/resolve-parent-ids.function.d.ts +14 -0
  31. package/dist/src/shared/content-splitter/functions/split-content.function.d.ts +11 -0
  32. package/dist/src/shared/content-splitter/functions/split-html.function.d.ts +12 -0
  33. package/dist/src/shared/content-splitter/functions/split-markdown.function.d.ts +13 -0
  34. package/dist/src/shared/content-splitter/functions/split-plain-text.function.d.ts +8 -0
  35. package/dist/src/shared/content-splitter/functions/split-toml.function.d.ts +12 -0
  36. package/dist/src/shared/content-splitter/index.d.ts +11 -0
  37. package/dist/src/shared/content-splitter/typings/content-format.type.d.ts +2 -0
  38. package/dist/src/shared/content-splitter/typings/content-section.interface.d.ts +17 -0
  39. package/dist/src/shared/content-splitter/typings/markdown-draft.interface.d.ts +12 -0
  40. package/dist/src/shared/content-splitter/typings/split-result.interface.d.ts +8 -0
  41. package/dist/src/shared/content-splitter/typings/split-strategy.interface.d.ts +3 -0
  42. package/dist/src/shared/content-splitter/typings/toml-draft.interface.d.ts +15 -0
  43. package/dist/src/shared/mcp/functions/build-learn-payload.function.d.ts +24 -0
  44. package/dist/src/shared/mcp/functions/determine-learn-split.function.d.ts +18 -0
  45. package/dist/src/shared/mcp/functions/handle-agent-list.function.d.ts +11 -21
  46. package/dist/src/shared/mcp/functions/handle-tool-call.function.d.ts +1 -15
  47. package/dist/src/shared/mcp/functions/handle-tool-learn.function.d.ts +3 -1
  48. package/dist/src/shared/mcp/functions/handle-tool-skill-list.function.d.ts +13 -3
  49. package/dist/src/shared/mcp/functions/learn-with-splitting.function.d.ts +22 -0
  50. package/dist/src/shared/mcp/functions/parse-learn-args.function.d.ts +24 -0
  51. package/dist/src/shared/mcp/functions/store-split-learn-sections.function.d.ts +16 -0
  52. package/dist/src/shared/mcp/functions/unwrap-json-content.function.d.ts +9 -0
  53. package/dist/src/shared/mcp/typings/learn-section-params.interface.d.ts +20 -0
  54. package/dist/src/shared/mcp/typings/mcp-client.interface.d.ts +4 -0
  55. package/dist/src/shared/mcp/typings/mcp-worker-client.interface.d.ts +4 -0
  56. package/dist/src/shared/query-filter/functions/matches-query.function.d.ts +17 -0
  57. package/dist/src/shared/version/constants/version.constant.d.ts +1 -1
  58. package/dist/src/shared/wasm-codec/functions/decode-one-recall-result.function.d.ts +2 -1
  59. package/dist/src/shared/wasm-codec/functions/decode-recall-document.function.d.ts +2 -1
  60. package/dist/src/shared/wasm-codec/functions/decode-recall-result.function.d.ts +2 -0
  61. package/dist/src/shared/wasm-codec/functions/decode-recall-sibling.function.d.ts +2 -1
  62. package/dist/src/shared/wasm-codec/functions/decode-scored-results.function.d.ts +6 -0
  63. package/dist/src/shared/wasm-codec/functions/decode-section-match.function.d.ts +2 -1
  64. package/dist/src/shared/wasm-codec/functions/decode-section-records.function.d.ts +4 -0
  65. package/dist/src/shared/wasm-codec/functions/encode-add-section-params.function.d.ts +1 -0
  66. package/dist/src/shared/wasm-codec/typings/add-section-input.model.d.ts +2 -0
  67. package/dist/src/shared/wasm-codec/typings/section-match.model.d.ts +4 -0
  68. package/dist/src/shared/wasm-codec/typings/section-record-trailing.model.d.ts +2 -0
  69. package/dist/src/shared/wasm-codec/typings/section-record.model.d.ts +2 -0
  70. package/dist/src/shared/worker-client/typings/recall-result.model.d.ts +12 -0
  71. package/dist/src/shared/worker-client/typings/search-result.model.d.ts +4 -0
  72. package/dist/src/shared/worker-client/typings/section.model.d.ts +2 -0
  73. package/dist/wasm/default-embedding/kbdb_default_embedding_bg.wasm +0 -0
  74. package/dist/wasm/fs-database/kbdb_fs_database_bg.wasm +0 -0
  75. package/dist/wasm/kb-worker/kbdb_worker_bg.wasm +0 -0
  76. package/dist/wasm/query-parser/kbdb_query_parser_bg.wasm +0 -0
  77. package/dist/worker.mjs +49 -7
  78. package/dist/worker.mjs.map +4 -4
  79. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  // src/cli.ts
5
5
  var import_node_fs10 = require("node:fs");
6
- var import_node_path14 = require("node:path");
6
+ var import_node_path15 = require("node:path");
7
7
 
8
8
  // src/shared/runtime/functions/detect-runtime.ts
9
9
  function detectRuntime() {
@@ -31,7 +31,10 @@ var SUPPORTED_EXTENSIONS = [
31
31
  ".md",
32
32
  ".txt",
33
33
  ".rst",
34
- ".adoc"
34
+ ".adoc",
35
+ ".html",
36
+ ".htm",
37
+ ".toml"
35
38
  ];
36
39
 
37
40
  // src/shared/log/typings/log-level.type.ts
@@ -745,6 +748,319 @@ function computeDirectoryLevel(filePath, basePath) {
745
748
  return Math.min(depth + 1, MAX_LEVEL);
746
749
  }
747
750
 
751
+ // src/shared/content-splitter/constants/content-type-maps.constant.ts
752
+ var HINT_FORMAT_MAP = {
753
+ markdown: "markdown",
754
+ "text/markdown": "markdown",
755
+ md: "markdown",
756
+ html: "html",
757
+ "text/html": "html",
758
+ toml: "toml",
759
+ "application/toml": "toml",
760
+ "text/toml": "toml",
761
+ "text/x-toml": "toml"
762
+ };
763
+ var EXTENSION_FORMAT_MAP = {
764
+ md: "markdown",
765
+ markdown: "markdown",
766
+ html: "html",
767
+ htm: "html",
768
+ toml: "toml"
769
+ };
770
+
771
+ // src/shared/content-splitter/functions/detect-content-type.function.ts
772
+ function detectContentType(content, typeHint, filePath) {
773
+ const hinted = typeHint && HINT_FORMAT_MAP[typeHint.toLowerCase()];
774
+ if (hinted) return hinted;
775
+ const extension = filePath?.split(".").pop()?.toLowerCase();
776
+ const extMatch = extension && EXTENSION_FORMAT_MAP[extension];
777
+ if (extMatch) return extMatch;
778
+ return sniffContentType(content);
779
+ }
780
+ function sniffContentType(content) {
781
+ const trimmed = content.trimStart();
782
+ if (/^<!DOCTYPE/i.test(trimmed) || /^<html/i.test(trimmed)) {
783
+ return "html";
784
+ }
785
+ if (trimmed.startsWith("[") && trimmed.includes("=")) {
786
+ return "toml";
787
+ }
788
+ return "plain-text";
789
+ }
790
+
791
+ // src/shared/content-splitter/classes/heading-parent-tracker.class.ts
792
+ var HeadingParentTracker = class {
793
+ stack = [];
794
+ /**
795
+ * Resolves the parent index for a heading at `level`
796
+ * appearing at output position `index`, then records the
797
+ * heading so subsequent, deeper headings can nest under it.
798
+ *
799
+ * @param level - heading depth, shallower is smaller
800
+ * @param index - position of this heading in the output
801
+ * sections array
802
+ * @returns the parent's output index, or `null` when the
803
+ * heading is at the root
804
+ */
805
+ resolve(level, index) {
806
+ while (this.stack.length > 0 && this.stack[this.stack.length - 1].level >= level) {
807
+ this.stack.pop();
808
+ }
809
+ const parentIndex = this.stack.length > 0 ? this.stack[this.stack.length - 1].index : null;
810
+ this.stack.push({ level, index });
811
+ return parentIndex;
812
+ }
813
+ };
814
+
815
+ // src/shared/content-splitter/functions/push-content-section.function.ts
816
+ function pushContentSection(sections, tracker, content, title, level) {
817
+ if (level === void 0) {
818
+ sections.push({ content, parentIndex: null });
819
+ return;
820
+ }
821
+ sections.push({
822
+ title,
823
+ level,
824
+ content,
825
+ parentIndex: tracker.resolve(level, sections.length)
826
+ });
827
+ }
828
+
829
+ // src/shared/content-splitter/functions/flush-markdown-draft.function.ts
830
+ function flushMarkdownDraft(draft, sections, tracker) {
831
+ const body = draft.lines.join("\n").trimEnd();
832
+ if (draft.title === void 0 && body.length === 0) return;
833
+ pushContentSection(
834
+ sections,
835
+ tracker,
836
+ body,
837
+ draft.title,
838
+ draft.level
839
+ );
840
+ }
841
+
842
+ // src/shared/content-splitter/functions/split-markdown.function.ts
843
+ var HEADING_PATTERN = /^(#{1,6})\s+(.+)$/;
844
+ function splitMarkdown(content) {
845
+ const sections = [];
846
+ const tracker = new HeadingParentTracker();
847
+ let draft = { lines: [] };
848
+ let inCodeBlock = false;
849
+ for (const line of content.split("\n")) {
850
+ if (line.startsWith("```") || line.startsWith("~~~")) {
851
+ inCodeBlock = !inCodeBlock;
852
+ draft.lines.push(line);
853
+ continue;
854
+ }
855
+ const heading = inCodeBlock ? null : HEADING_PATTERN.exec(line);
856
+ if (heading) {
857
+ flushMarkdownDraft(draft, sections, tracker);
858
+ draft = {
859
+ title: heading[2].trim(),
860
+ level: heading[1].length,
861
+ lines: []
862
+ };
863
+ continue;
864
+ }
865
+ draft.lines.push(line);
866
+ }
867
+ flushMarkdownDraft(draft, sections, tracker);
868
+ return sections.length > 0 ? sections : [{ content: content.trimEnd(), parentIndex: null }];
869
+ }
870
+
871
+ // src/shared/content-splitter/functions/split-html.function.ts
872
+ var HEADING_PATTERN2 = /<h([1-6])[^>]*>(.*?)<\/h\1>/gi;
873
+ function splitHtml(content) {
874
+ const matches = [...content.matchAll(HEADING_PATTERN2)];
875
+ if (matches.length === 0) {
876
+ return [{ content: content.trimEnd(), parentIndex: null }];
877
+ }
878
+ const sections = [];
879
+ const tracker = new HeadingParentTracker();
880
+ const firstIndex = matches[0].index;
881
+ const preamble = content.slice(0, firstIndex).trimEnd();
882
+ if (preamble.length > 0) {
883
+ pushContentSection(sections, tracker, preamble);
884
+ }
885
+ matches.forEach((match, i) => {
886
+ const start = match.index + match[0].length;
887
+ const end = matches[i + 1]?.index ?? content.length;
888
+ pushContentSection(
889
+ sections,
890
+ tracker,
891
+ content.slice(start, end).trimEnd(),
892
+ match[2].trim(),
893
+ Number(match[1])
894
+ );
895
+ });
896
+ return sections;
897
+ }
898
+
899
+ // src/shared/content-splitter/functions/flush-toml-draft.function.ts
900
+ function flushTomlDraft(draft, sections, pathIndex) {
901
+ const body = draft.lines.join("\n").trimEnd();
902
+ if (draft.title === void 0 && body.length === 0) return;
903
+ if (draft.title === void 0) {
904
+ sections.push({ content: body, parentIndex: null });
905
+ return;
906
+ }
907
+ const path = draft.path ?? draft.title;
908
+ sections.push({
909
+ title: draft.title,
910
+ content: body,
911
+ parentIndex: resolveParentIndex(path, pathIndex)
912
+ });
913
+ pathIndex.set(path, sections.length - 1);
914
+ }
915
+ function resolveParentIndex(path, pathIndex) {
916
+ if (/^["']/.test(path)) return null;
917
+ const segments = path.split(".");
918
+ segments.pop();
919
+ if (segments.length === 0) return null;
920
+ return pathIndex.get(segments.join(".")) ?? null;
921
+ }
922
+
923
+ // src/shared/content-splitter/functions/split-toml.function.ts
924
+ var HEADER_PATTERN = /^\[([^\]]+)\]\s*$/;
925
+ var QUOTED_PATTERN = /^(["'])(.*)\1$/;
926
+ function splitToml(content) {
927
+ const sections = [];
928
+ const pathIndex = /* @__PURE__ */ new Map();
929
+ let draft = { lines: [] };
930
+ for (const line of content.split("\n")) {
931
+ const header = HEADER_PATTERN.exec(line);
932
+ if (header) {
933
+ flushTomlDraft(draft, sections, pathIndex);
934
+ draft = { ...parseHeader(header[1]), lines: [] };
935
+ continue;
936
+ }
937
+ draft.lines.push(line);
938
+ }
939
+ flushTomlDraft(draft, sections, pathIndex);
940
+ return sections.length > 0 ? sections : [{ content: content.trimEnd(), parentIndex: null }];
941
+ }
942
+ function parseHeader(inner) {
943
+ const trimmed = inner.trim();
944
+ const quoted = QUOTED_PATTERN.exec(trimmed);
945
+ return quoted ? { title: quoted[2], path: trimmed } : { title: trimmed, path: trimmed };
946
+ }
947
+
948
+ // src/shared/content-splitter/functions/split-plain-text.function.ts
949
+ function splitPlainText(content) {
950
+ return [{ content, parentIndex: null }];
951
+ }
952
+
953
+ // src/shared/content-splitter/constants/split-strategy-map.constant.ts
954
+ var SPLIT_STRATEGY_MAP = {
955
+ markdown: splitMarkdown,
956
+ html: splitHtml,
957
+ toml: splitToml,
958
+ "plain-text": splitPlainText
959
+ };
960
+
961
+ // src/shared/content-splitter/functions/split-content.function.ts
962
+ function splitContent(content, typeHint, filePath) {
963
+ const format = detectContentType(content, typeHint, filePath);
964
+ return {
965
+ format,
966
+ sections: SPLIT_STRATEGY_MAP[format](content)
967
+ };
968
+ }
969
+
970
+ // src/shared/content-splitter/functions/resolve-parent-ids.function.ts
971
+ function resolveParentIds(sections, kbids) {
972
+ return sections.map(
973
+ (section) => section.parentIndex === null ? null : kbids[section.parentIndex]
974
+ );
975
+ }
976
+
977
+ // src/shared/cli/functions/map-add-section-result.function.ts
978
+ function mapAddSectionResult(result, path, size, sectionType) {
979
+ return {
980
+ kbid: result.items[0] ?? "",
981
+ indexed_terms_count: 0,
982
+ type: sectionType,
983
+ path,
984
+ size,
985
+ skipped: false,
986
+ superseded: result.superseded ?? null,
987
+ warnings: result.warnings ?? [],
988
+ near_duplicates: result.near_duplicates ?? []
989
+ };
990
+ }
991
+
992
+ // src/shared/cli/functions/learn-structured-document.function.ts
993
+ var import_node_path3 = require("node:path");
994
+ async function learnStructuredDocument(client, options, path, splitResult, sourcePath) {
995
+ const { sections } = splitResult;
996
+ const firstTitled = sections.find((s) => s.title !== void 0);
997
+ const docTitle = firstTitled?.title ?? (0, import_node_path3.basename)(path);
998
+ const kbids = [];
999
+ const results = [];
1000
+ for (const section of sections) {
1001
+ const [parent] = resolveParentIds([section], kbids);
1002
+ const added = await client.addSection({
1003
+ sectionType: "text",
1004
+ content: section.content,
1005
+ title: section.title,
1006
+ description: options.description,
1007
+ docid: path,
1008
+ tags: options.tags,
1009
+ replace: options.replace,
1010
+ sourcePath,
1011
+ level: section.level,
1012
+ parent: parent ?? void 0
1013
+ });
1014
+ kbids.push(added.items[0] ?? "");
1015
+ results.push(
1016
+ mapAddSectionResult(
1017
+ added,
1018
+ path,
1019
+ section.content.length,
1020
+ "text"
1021
+ )
1022
+ );
1023
+ }
1024
+ await client.groupSections(docTitle, kbids);
1025
+ return results;
1026
+ }
1027
+
1028
+ // src/shared/cli/functions/learn-target-content.function.ts
1029
+ async function learnTargetContent(client, options, path, content, sourcePath, level) {
1030
+ if (!options.title) {
1031
+ const isStdin = path === "-";
1032
+ const split = splitContent(
1033
+ content,
1034
+ isStdin ? "markdown" : void 0,
1035
+ isStdin ? void 0 : path
1036
+ );
1037
+ const hasTitled = split.sections.some(
1038
+ (s) => s.title !== void 0
1039
+ );
1040
+ if (split.sections.length >= 2 && hasTitled) {
1041
+ return learnStructuredDocument(
1042
+ client,
1043
+ options,
1044
+ path,
1045
+ split,
1046
+ sourcePath
1047
+ );
1048
+ }
1049
+ }
1050
+ const result = await client.addSection({
1051
+ sectionType: "text",
1052
+ content,
1053
+ title: options.title,
1054
+ description: options.description,
1055
+ docid: options.docid,
1056
+ tags: options.tags,
1057
+ replace: options.replace,
1058
+ sourcePath,
1059
+ level
1060
+ });
1061
+ return [mapAddSectionResult(result, path, content.length, "text")];
1062
+ }
1063
+
748
1064
  // src/shared/cli/functions/run-learn.function.ts
749
1065
  async function runLearn(client, options, io) {
750
1066
  log(
@@ -759,37 +1075,30 @@ async function runLearn(client, options, io) {
759
1075
  if (stdinConsumed) continue;
760
1076
  stdinConsumed = true;
761
1077
  const content = await readStdin();
762
- const result = await client.addSection({
763
- sectionType: "text",
764
- content,
765
- title: options.title,
766
- description: options.description,
767
- docid: options.docid,
768
- tags: options.tags,
769
- replace: options.replace,
770
- level: options.level
771
- });
772
1078
  results.push(
773
- mapAddSectionResult(result, "-", content.length, "text")
1079
+ ...await learnTargetContent(
1080
+ client,
1081
+ options,
1082
+ "-",
1083
+ content,
1084
+ void 0,
1085
+ options.level
1086
+ )
774
1087
  );
775
1088
  continue;
776
1089
  }
777
1090
  const files = collectFiles(target);
778
1091
  for (const file of files) {
779
1092
  const content = (0, import_node_fs2.readFileSync)(file, "utf-8");
780
- const result = await client.addSection({
781
- sectionType: "text",
782
- content,
783
- title: options.title,
784
- description: options.description,
785
- docid: options.docid,
786
- tags: options.tags,
787
- replace: options.replace,
788
- sourcePath: file,
789
- level: options.level ?? computeDirectoryLevel(file, target)
790
- });
791
1093
  results.push(
792
- mapAddSectionResult(result, file, content.length, "text")
1094
+ ...await learnTargetContent(
1095
+ client,
1096
+ options,
1097
+ file,
1098
+ content,
1099
+ file,
1100
+ options.level ?? computeDirectoryLevel(file, target)
1101
+ )
793
1102
  );
794
1103
  }
795
1104
  }
@@ -799,19 +1108,6 @@ async function runLearn(client, options, io) {
799
1108
  );
800
1109
  return results;
801
1110
  }
802
- function mapAddSectionResult(result, path, size, sectionType) {
803
- return {
804
- kbid: result.items[0] ?? "",
805
- indexed_terms_count: 0,
806
- type: sectionType,
807
- path,
808
- size,
809
- skipped: false,
810
- superseded: result.superseded ?? null,
811
- warnings: result.warnings ?? [],
812
- near_duplicates: result.near_duplicates ?? []
813
- };
814
- }
815
1111
  function readProcessStdin() {
816
1112
  return new Promise((resolve7) => {
817
1113
  const chunks = [];
@@ -906,32 +1202,32 @@ async function runRebuild(client, _options) {
906
1202
 
907
1203
  // src/shared/cli/functions/find-db.function.ts
908
1204
  var import_node_fs3 = require("node:fs");
909
- var import_node_path3 = require("node:path");
1205
+ var import_node_path4 = require("node:path");
910
1206
  function findDb(dbPath) {
911
1207
  if (dbPath) {
912
- const target = (0, import_node_path3.join)((0, import_node_path3.resolve)(dbPath), ".kbdb");
1208
+ const target = (0, import_node_path4.join)((0, import_node_path4.resolve)(dbPath), ".kbdb");
913
1209
  return (0, import_node_fs3.existsSync)(target) ? target : null;
914
1210
  }
915
1211
  let current = process.cwd();
916
- let parent = (0, import_node_path3.dirname)(current);
1212
+ let parent = (0, import_node_path4.dirname)(current);
917
1213
  while (parent !== current) {
918
- const candidate2 = (0, import_node_path3.join)(current, ".kbdb");
1214
+ const candidate2 = (0, import_node_path4.join)(current, ".kbdb");
919
1215
  if ((0, import_node_fs3.existsSync)(candidate2)) return candidate2;
920
1216
  current = parent;
921
- parent = (0, import_node_path3.dirname)(current);
1217
+ parent = (0, import_node_path4.dirname)(current);
922
1218
  }
923
- const candidate = (0, import_node_path3.join)(current, ".kbdb");
1219
+ const candidate = (0, import_node_path4.join)(current, ".kbdb");
924
1220
  return (0, import_node_fs3.existsSync)(candidate) ? candidate : null;
925
1221
  }
926
1222
 
927
1223
  // src/shared/cli/functions/run-init.function.ts
928
1224
  var import_node_fs5 = require("node:fs");
929
- var import_node_path5 = require("node:path");
1225
+ var import_node_path6 = require("node:path");
930
1226
 
931
1227
  // src/shared/cli/functions/install-default-skills.function.ts
932
1228
  var import_node_crypto = require("node:crypto");
933
1229
  var import_node_fs4 = require("node:fs");
934
- var import_node_path4 = require("node:path");
1230
+ var import_node_path5 = require("node:path");
935
1231
  var BASE32_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
936
1232
  function base32Encode(bytes) {
937
1233
  let result = "";
@@ -992,8 +1288,8 @@ function installSkill(sectionsDir, skill) {
992
1288
  });
993
1289
  const kbid = computeSectionKbid("text/markdown", content);
994
1290
  const prefix = kbid.slice(0, 2);
995
- const shardDir = (0, import_node_path4.join)(sectionsDir, prefix);
996
- const filePath = (0, import_node_path4.join)(shardDir, `${kbid}.section`);
1291
+ const shardDir = (0, import_node_path5.join)(sectionsDir, prefix);
1292
+ const filePath = (0, import_node_path5.join)(shardDir, `${kbid}.section`);
997
1293
  if ((0, import_node_fs4.existsSync)(filePath)) {
998
1294
  return;
999
1295
  }
@@ -1021,7 +1317,7 @@ var DEFAULT_SKILLS = [
1021
1317
  }
1022
1318
  ];
1023
1319
  function installDefaultSkills(dbDir) {
1024
- const sectionsDir = (0, import_node_path4.join)(dbDir, "sections");
1320
+ const sectionsDir = (0, import_node_path5.join)(dbDir, "sections");
1025
1321
  for (const skill of DEFAULT_SKILLS) {
1026
1322
  installSkill(sectionsDir, skill);
1027
1323
  }
@@ -1046,19 +1342,19 @@ var GITIGNORE = [
1046
1342
  ].join("\n");
1047
1343
  function createScaffold(dbDir) {
1048
1344
  (0, import_node_fs5.mkdirSync)(dbDir, { recursive: true });
1049
- (0, import_node_fs5.mkdirSync)((0, import_node_path5.join)(dbDir, "sections"));
1050
- (0, import_node_fs5.mkdirSync)((0, import_node_path5.join)(dbDir, "documents"));
1051
- (0, import_node_fs5.writeFileSync)((0, import_node_path5.join)(dbDir, "catalog.toml"), CATALOG_TOML);
1052
- (0, import_node_fs5.writeFileSync)((0, import_node_path5.join)(dbDir, "corpus.bin"), "");
1053
- (0, import_node_fs5.writeFileSync)((0, import_node_path5.join)(dbDir, "inverted.idx"), "");
1054
- (0, import_node_fs5.writeFileSync)((0, import_node_path5.join)(dbDir, "positional.idx"), "");
1055
- (0, import_node_fs5.writeFileSync)((0, import_node_path5.join)(dbDir, "worker.toml"), WORKER_TOML);
1056
- (0, import_node_fs5.writeFileSync)((0, import_node_path5.join)(dbDir, ".gitignore"), GITIGNORE);
1345
+ (0, import_node_fs5.mkdirSync)((0, import_node_path6.join)(dbDir, "sections"));
1346
+ (0, import_node_fs5.mkdirSync)((0, import_node_path6.join)(dbDir, "documents"));
1347
+ (0, import_node_fs5.writeFileSync)((0, import_node_path6.join)(dbDir, "catalog.toml"), CATALOG_TOML);
1348
+ (0, import_node_fs5.writeFileSync)((0, import_node_path6.join)(dbDir, "corpus.bin"), "");
1349
+ (0, import_node_fs5.writeFileSync)((0, import_node_path6.join)(dbDir, "inverted.idx"), "");
1350
+ (0, import_node_fs5.writeFileSync)((0, import_node_path6.join)(dbDir, "positional.idx"), "");
1351
+ (0, import_node_fs5.writeFileSync)((0, import_node_path6.join)(dbDir, "worker.toml"), WORKER_TOML);
1352
+ (0, import_node_fs5.writeFileSync)((0, import_node_path6.join)(dbDir, ".gitignore"), GITIGNORE);
1057
1353
  }
1058
1354
  function runInit(options) {
1059
1355
  log("running init", 0 /* DEBUG */);
1060
- const basePath = options.dbPath ? (0, import_node_path5.resolve)(options.dbPath) : process.cwd();
1061
- const dbDir = (0, import_node_path5.join)(basePath, ".kbdb");
1356
+ const basePath = options.dbPath ? (0, import_node_path6.resolve)(options.dbPath) : process.cwd();
1357
+ const dbDir = (0, import_node_path6.join)(basePath, ".kbdb");
1062
1358
  try {
1063
1359
  if ((0, import_node_fs5.existsSync)(dbDir)) {
1064
1360
  return {
@@ -1199,28 +1495,27 @@ async function runSkillLearn(client, options) {
1199
1495
  };
1200
1496
  }
1201
1497
 
1498
+ // src/shared/query-filter/functions/matches-query.function.ts
1499
+ function matchesQuery(query, ...fields) {
1500
+ if (!query) return true;
1501
+ const needle = query.toLowerCase();
1502
+ return fields.some(
1503
+ (field) => typeof field === "string" && field.toLowerCase().includes(needle)
1504
+ );
1505
+ }
1506
+
1202
1507
  // src/shared/cli/functions/run-skill-list.function.ts
1203
- async function runSkillList(client, _options) {
1508
+ async function runSkillList(client, options) {
1204
1509
  log("running skill-list", 0 /* DEBUG */);
1205
1510
  const records = await client.listByType("skill");
1206
- const items = records.map((r) => {
1207
- let argumentCount = 0;
1208
- try {
1209
- const parsed = JSON.parse(r.content);
1210
- if (Array.isArray(parsed["arguments"])) {
1211
- argumentCount = parsed["arguments"].length;
1212
- }
1213
- } catch {
1214
- }
1215
- return {
1216
- kbid: r.kbid,
1217
- name: r.title,
1218
- description: r.description,
1219
- argumentCount
1220
- };
1221
- });
1511
+ const query = options.args.join(" ").toLowerCase();
1512
+ const filtered = records.filter(
1513
+ (r) => matchesQuery(query, r.title, r.description)
1514
+ );
1515
+ const names = filtered.map((r) => r.title);
1516
+ const data = { items: names, total: names.length, offset: 0 };
1222
1517
  return {
1223
- output: JSON.stringify(items, null, 2),
1518
+ output: JSON.stringify(data, null, 2),
1224
1519
  exitCode: 0
1225
1520
  };
1226
1521
  }
@@ -1349,16 +1644,15 @@ async function runAgentCreate(client, options) {
1349
1644
  }
1350
1645
 
1351
1646
  // src/shared/cli/functions/run-agent-list.function.ts
1352
- async function runAgentList(client, _options) {
1647
+ async function runAgentList(client, options) {
1353
1648
  log("running agent-list", 0 /* DEBUG */);
1354
1649
  const docs = await client.listDocumentsByType("agent");
1355
- const items = docs.map((d) => ({
1356
- docid: d.docid,
1357
- name: d.title,
1358
- skillCount: Math.max(0, d.sections.length - 1)
1359
- }));
1650
+ const query = options.args.join(" ").toLowerCase();
1651
+ const filtered = docs.filter((d) => matchesQuery(query, d.title));
1652
+ const names = filtered.map((d) => d.title);
1653
+ const data = { items: names, total: names.length, offset: 0 };
1360
1654
  return {
1361
- output: JSON.stringify(items, null, 2),
1655
+ output: JSON.stringify(data, null, 2),
1362
1656
  exitCode: 0
1363
1657
  };
1364
1658
  }
@@ -1464,7 +1758,7 @@ async function runAgentSearch(client, options) {
1464
1758
  }
1465
1759
 
1466
1760
  // src/shared/cli/functions/run-import.function.ts
1467
- var import_node_path6 = require("node:path");
1761
+ var import_node_path7 = require("node:path");
1468
1762
  async function runImport(client, options) {
1469
1763
  const from = options.from;
1470
1764
  if (!from) {
@@ -1473,7 +1767,7 @@ async function runImport(client, options) {
1473
1767
  throw new Error(msg);
1474
1768
  }
1475
1769
  return client.import({
1476
- from: (0, import_node_path6.resolve)(process.cwd(), from),
1770
+ from: (0, import_node_path7.resolve)(process.cwd(), from),
1477
1771
  dryRun: options.dryRun === true
1478
1772
  });
1479
1773
  }
@@ -1826,7 +2120,7 @@ async function handleTypedSearch(client, options, type) {
1826
2120
  }
1827
2121
 
1828
2122
  // src/shared/version/constants/version.constant.ts
1829
- var VERSION = "0.6.3";
2123
+ var VERSION = "0.6.5";
1830
2124
 
1831
2125
  // src/shared/cli/functions/generate-help.function.ts
1832
2126
  var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
@@ -1854,13 +2148,13 @@ var GROUP_SUBCOMMANDS = {
1854
2148
  ],
1855
2149
  skill: [
1856
2150
  ["learn", "Create a new skill definition"],
1857
- ["list", "List all skills"],
2151
+ ["list", "List skills (filter by keyword)"],
1858
2152
  ["get", "Retrieve a skill by name or kbid"],
1859
2153
  ["delete", "Remove a skill"]
1860
2154
  ],
1861
2155
  agent: [
1862
2156
  ["create", "Create an agent with skill refs"],
1863
- ["list", "List all agents"],
2157
+ ["list", "List agents (filter by keyword)"],
1864
2158
  ["get", "Retrieve an agent by docid"],
1865
2159
  ["delete", "Remove an agent"]
1866
2160
  ],
@@ -1905,9 +2199,9 @@ Usage: kbdb [options]
1905
2199
  kbdb <command> <subcommand> [options] ...[params]
1906
2200
 
1907
2201
  Knowledge Base:
1908
- learn Import content from files/stdin
2202
+ learn Import content (auto-splits structured formats)
1909
2203
  unlearn Remove sections by kbid
1910
- search Query the knowledge base
2204
+ search Query the knowledge base (sibling boost)
1911
2205
  recall Retrieve section context by kbid
1912
2206
  content Compose rendered content from ids
1913
2207
 
@@ -1926,28 +2220,34 @@ Maintenance:
1926
2220
 
1927
2221
  Skills:
1928
2222
  skill learn Create a new skill definition
1929
- skill list List all skills
2223
+ skill list List skills (filter by keyword)
1930
2224
  skill get Retrieve a skill by name or kbid
1931
2225
  skill delete Remove a skill
2226
+ skill search Search skills by keyword
1932
2227
 
1933
2228
  Agents:
1934
2229
  agent create Create an agent with skill refs
1935
- agent list List all agents
2230
+ agent list List agents (filter by keyword)
1936
2231
  agent get Retrieve an agent by docid
1937
2232
  agent delete Remove an agent
1938
-
1939
- Worker:
1940
- worker stop Stop the worker daemon
1941
- worker restart Restart the worker daemon
2233
+ agent search Search agents by keyword
1942
2234
 
1943
2235
  Server:
1944
2236
  mcp Start MCP server mode (stdio)
1945
2237
 
1946
2238
  Global Options:
1947
2239
  -h, --help Show this help message
1948
- -v, --version Show version information
2240
+ --version Show version information
2241
+ -v, --verbose Log warnings (-vv info, -vvv debug)
1949
2242
  --db <path> Path to .kbdb directory
1950
- --format <fmt> Output format (json|text|mcp)
2243
+ --format <fmt> Output format (rec|json|text|mcp)
2244
+ --timeout-ms <ms> Request timeout (default 30000)
2245
+ --retry <n> Retries on timeout (default 1)
2246
+ --non-interactive Suppress prompts
2247
+
2248
+ Worker:
2249
+ worker stop Stop background daemon
2250
+ worker restart Restart background daemon
1951
2251
 
1952
2252
  Run "kbdb <command> --help" for detailed information.
1953
2253
  `;
@@ -2004,9 +2304,22 @@ Options:
2004
2304
  --replace Supersede existing section by source key
2005
2305
  --db <path> Path to .kbdb directory
2006
2306
 
2307
+ Content splitting:
2308
+ Structured formats are automatically split
2309
+ into independent sections that share a docid.
2310
+ Each section carries a level (heading depth)
2311
+ and parent (kbid of enclosing section).
2312
+ Providing --title imports as a single section
2313
+ (skips splitting).
2314
+
2315
+ Supported formats:
2316
+ Markdown .md, text/markdown ATX headings
2317
+ HTML .html, text/html <h1>-<h6> tags
2318
+ TOML .toml, application/toml [section]
2319
+ Plain .txt, text/plain no splitting
2320
+
2007
2321
  Output:
2008
- JSON array of { kbid, path, size, skipped,
2009
- superseded, warnings, near_duplicates }
2322
+ { items, total, offset } envelope
2010
2323
 
2011
2324
  Examples:
2012
2325
  kbdb learn README.md
@@ -2041,12 +2354,23 @@ Arguments:
2041
2354
  Options:
2042
2355
  --mode <mode> Result granularity (sections|documents|stats)
2043
2356
  --limit <n> Max results (default: 20)
2044
- --format <fmt> Output format (json|text|mcp)
2357
+ --format <fmt> Output format (rec|json|text|mcp)
2045
2358
  --content, -c Hydrate results with section content
2046
2359
  --db <path> Path to .kbdb directory
2047
2360
 
2361
+ Scoring:
2362
+ Results are ranked by BM25F. Sections from
2363
+ the same document (shared docid) receive a
2364
+ sibling score boost when multiple sections
2365
+ match the query.
2366
+
2367
+ Fields:
2368
+ Each result includes level (heading depth,
2369
+ 1-6 or null) and parent (kbid of enclosing
2370
+ section or null).
2371
+
2048
2372
  Output:
2049
- JSON array of { kbid, score, preview, matches }
2373
+ { items, total, offset } envelope
2050
2374
 
2051
2375
  Examples:
2052
2376
  kbdb search "machine learning"
@@ -2066,7 +2390,8 @@ Options:
2066
2390
  --db <path> Path to .kbdb directory
2067
2391
 
2068
2392
  Output:
2069
- JSON RecallResult or RecallResult[]
2393
+ JSON RecallResult or RecallResult[] with
2394
+ level, parent, siblings, and references
2070
2395
 
2071
2396
  Examples:
2072
2397
  kbdb recall abcdef1234567890abcdef1234
@@ -2075,11 +2400,14 @@ Examples:
2075
2400
  content: `kbdb content - Compose rendered content from ids
2076
2401
 
2077
2402
  Usage: kbdb content [options] <id>...
2403
+ kbdb content --search <query>...
2078
2404
 
2079
2405
  Arguments:
2080
2406
  <id> kbid or docid identifier
2407
+ <query> Search terms (with --search)
2081
2408
 
2082
2409
  Options:
2410
+ --search, -s Search for ids by keyword
2083
2411
  --db <path> Path to .kbdb directory
2084
2412
 
2085
2413
  Output:
@@ -2088,6 +2416,7 @@ Output:
2088
2416
  Examples:
2089
2417
  kbdb content abcdef1234567890abcdef1234
2090
2418
  kbdb content id1 id2
2419
+ kbdb content --search machine learning
2091
2420
  `,
2092
2421
  check: `kbdb check - Verify knowledge base integrity
2093
2422
 
@@ -2255,16 +2584,20 @@ Examples:
2255
2584
  `,
2256
2585
  "skill-list": `kbdb skill list - List all skills
2257
2586
 
2258
- Usage: kbdb skill list [options]
2587
+ Usage: kbdb skill list [options] [keywords...]
2588
+
2589
+ Arguments:
2590
+ [keywords...] Case-insensitive substring filter on name or description
2259
2591
 
2260
2592
  Options:
2261
2593
  --db <path> Path to .kbdb directory
2262
2594
 
2263
2595
  Output:
2264
- JSON array of { kbid, name, description, argumentCount }
2596
+ JSON { items, total, offset }
2265
2597
 
2266
2598
  Examples:
2267
2599
  kbdb skill list
2600
+ kbdb skill list summarize
2268
2601
  kbdb skill list --db /path/to/project
2269
2602
  `,
2270
2603
  "skill-get": `kbdb skill get - Retrieve a skill by name or kbid
@@ -2320,16 +2653,20 @@ Examples:
2320
2653
  `,
2321
2654
  "agent-list": `kbdb agent list - List all agents
2322
2655
 
2323
- Usage: kbdb agent list [options]
2656
+ Usage: kbdb agent list [options] [keywords...]
2657
+
2658
+ Arguments:
2659
+ [keywords...] Case-insensitive substring filter on agent name
2324
2660
 
2325
2661
  Options:
2326
2662
  --db <path> Path to .kbdb directory
2327
2663
 
2328
2664
  Output:
2329
- JSON array of { docid, name, description, skillCount }
2665
+ JSON { items, total, offset }
2330
2666
 
2331
2667
  Examples:
2332
2668
  kbdb agent list
2669
+ kbdb agent list reviewer
2333
2670
  kbdb agent list --db /path/to/project
2334
2671
  `,
2335
2672
  "agent-get": `kbdb agent get - Retrieve an agent by docid
@@ -2468,7 +2805,7 @@ var import_node_net = require("node:net");
2468
2805
 
2469
2806
  // src/shared/worker-client/functions/discover-daemon.function.ts
2470
2807
  var import_node_fs6 = require("node:fs");
2471
- var import_node_path7 = require("node:path");
2808
+ var import_node_path8 = require("node:path");
2472
2809
  var import_node_os = require("node:os");
2473
2810
 
2474
2811
  // src/shared/platform/functions/is-process-alive.function.ts
@@ -2484,7 +2821,7 @@ function isProcessAlive(pid) {
2484
2821
  // src/shared/worker-client/functions/discover-daemon.function.ts
2485
2822
  function discoverDaemon(contextId) {
2486
2823
  log("discovering daemon for context: " + contextId, 0 /* DEBUG */);
2487
- const pidPath = (0, import_node_path7.join)((0, import_node_os.tmpdir)(), `kbdb-${contextId}.pid`);
2824
+ const pidPath = (0, import_node_path8.join)((0, import_node_os.tmpdir)(), `kbdb-${contextId}.pid`);
2488
2825
  if (!(0, import_node_fs6.existsSync)(pidPath)) {
2489
2826
  log(
2490
2827
  "no daemon PID file found for context: " + contextId,
@@ -2506,8 +2843,8 @@ function discoverDaemon(contextId) {
2506
2843
  return null;
2507
2844
  }
2508
2845
  log("daemon found: pid=" + pid.toString(), 0 /* DEBUG */);
2509
- const socketPath = (0, import_node_path7.join)((0, import_node_os.tmpdir)(), `kbdb-${contextId}.sock`);
2510
- const crashPath = (0, import_node_path7.join)((0, import_node_os.tmpdir)(), `kbdb-${contextId}.crash`);
2846
+ const socketPath = (0, import_node_path8.join)((0, import_node_os.tmpdir)(), `kbdb-${contextId}.sock`);
2847
+ const crashPath = (0, import_node_path8.join)((0, import_node_os.tmpdir)(), `kbdb-${contextId}.crash`);
2511
2848
  try {
2512
2849
  (0, import_node_fs6.unlinkSync)(crashPath);
2513
2850
  } catch {
@@ -3028,10 +3365,10 @@ var WorkerClient = class {
3028
3365
 
3029
3366
  // src/shared/worker-client/functions/resolve-db-path.function.ts
3030
3367
  var import_node_fs7 = require("node:fs");
3031
- var import_node_path8 = require("node:path");
3368
+ var import_node_path9 = require("node:path");
3032
3369
  function resolveDbPath(targetDir) {
3033
- const base = targetDir ? (0, import_node_path8.resolve)(targetDir) : process.cwd();
3034
- const dbPath = (0, import_node_path8.join)(base, ".kbdb");
3370
+ const base = targetDir ? (0, import_node_path9.resolve)(targetDir) : process.cwd();
3371
+ const dbPath = (0, import_node_path9.join)(base, ".kbdb");
3035
3372
  if (!(0, import_node_fs7.existsSync)(dbPath)) {
3036
3373
  const msg = `database not found: ${dbPath}`;
3037
3374
  log(msg, 3 /* ERROR */);
@@ -3098,13 +3435,13 @@ function spawnDaemon(contextPath, runtime, workerScript) {
3098
3435
 
3099
3436
  // src/shared/worker-client/functions/wait-for-daemon.function.ts
3100
3437
  var import_node_fs8 = require("node:fs");
3101
- var import_node_path9 = require("node:path");
3438
+ var import_node_path10 = require("node:path");
3102
3439
  var import_node_os2 = require("node:os");
3103
3440
  var DEFAULT_TIMEOUT_MS = 1e4;
3104
3441
  var POLL_INTERVAL_MS = 100;
3105
3442
  async function waitForDaemon(contextId, timeoutMs = DEFAULT_TIMEOUT_MS) {
3106
3443
  log("waiting for daemon: contextId=" + contextId, 0 /* DEBUG */);
3107
- const pidPath = (0, import_node_path9.join)((0, import_node_os2.tmpdir)(), `kbdb-${contextId}.pid`);
3444
+ const pidPath = (0, import_node_path10.join)((0, import_node_os2.tmpdir)(), `kbdb-${contextId}.pid`);
3108
3445
  const start = Date.now();
3109
3446
  let iteration = 0;
3110
3447
  while (Date.now() - start < timeoutMs) {
@@ -3132,10 +3469,10 @@ async function waitForDaemon(contextId, timeoutMs = DEFAULT_TIMEOUT_MS) {
3132
3469
 
3133
3470
  // src/shared/worker-client/functions/read-crash-reason.function.ts
3134
3471
  var import_node_fs9 = require("node:fs");
3135
- var import_node_path10 = require("node:path");
3472
+ var import_node_path11 = require("node:path");
3136
3473
  var import_node_os3 = require("node:os");
3137
3474
  function readCrashReason(contextId) {
3138
- const crashPath = (0, import_node_path10.join)((0, import_node_os3.tmpdir)(), `kbdb-${contextId}.crash`);
3475
+ const crashPath = (0, import_node_path11.join)((0, import_node_os3.tmpdir)(), `kbdb-${contextId}.crash`);
3139
3476
  if (!(0, import_node_fs9.existsSync)(crashPath)) {
3140
3477
  return "daemon failed to start (no details available)";
3141
3478
  }
@@ -3150,11 +3487,11 @@ function readCrashReason(contextId) {
3150
3487
  }
3151
3488
 
3152
3489
  // src/shared/worker-client/functions/resolve-spawn-script.function.ts
3153
- var import_node_path12 = require("node:path");
3490
+ var import_node_path13 = require("node:path");
3154
3491
  var import_node_url = require("node:url");
3155
3492
 
3156
3493
  // src/shared/dir-resolver/functions/join-path.function.ts
3157
- var import_node_path11 = require("node:path");
3494
+ var import_node_path12 = require("node:path");
3158
3495
  function isRemoteUrl(path) {
3159
3496
  return path.startsWith("http://") || path.startsWith("https://");
3160
3497
  }
@@ -3163,7 +3500,7 @@ function joinPath(base, ...segments) {
3163
3500
  const trailing = base.endsWith("/") ? "" : "/";
3164
3501
  return base + trailing + segments.join("/");
3165
3502
  }
3166
- return (0, import_node_path11.join)(base, ...segments);
3503
+ return (0, import_node_path12.join)(base, ...segments);
3167
3504
  }
3168
3505
 
3169
3506
  // src/shared/dir-resolver/functions/resolve-worker-script.function.ts
@@ -3181,15 +3518,15 @@ function resolveSpawnScript(runtime) {
3181
3518
  }
3182
3519
  function resolveScriptDir2(runtime) {
3183
3520
  if (typeof __dirname !== "undefined") return __dirname;
3184
- const thisDir = (0, import_node_path12.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
3521
+ const thisDir = (0, import_node_path13.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
3185
3522
  if (runtime === "deno") {
3186
- return (0, import_node_path12.resolve)(thisDir, "..", "..", "..");
3523
+ return (0, import_node_path13.resolve)(thisDir, "..", "..", "..");
3187
3524
  }
3188
3525
  return thisDir;
3189
3526
  }
3190
3527
 
3191
3528
  // src/shared/platform/functions/get-ipc-path.function.ts
3192
- var import_node_path13 = require("node:path");
3529
+ var import_node_path14 = require("node:path");
3193
3530
 
3194
3531
  // src/shared/platform/functions/get-tmpdir.function.ts
3195
3532
  var import_node_os4 = require("node:os");
@@ -3202,7 +3539,7 @@ function getIpcPath(ctx) {
3202
3539
  if (process.platform === "win32") {
3203
3540
  return `\\\\.\\pipe\\kbdb-${ctx}`;
3204
3541
  }
3205
- return (0, import_node_path13.join)(getTmpdir(), `kbdb-${ctx}.sock`);
3542
+ return (0, import_node_path14.join)(getTmpdir(), `kbdb-${ctx}.sock`);
3206
3543
  }
3207
3544
 
3208
3545
  // src/shared/worker-client/functions/create-worker-client.function.ts
@@ -3670,7 +4007,7 @@ function createToolDefinitions() {
3670
4007
  return [
3671
4008
  {
3672
4009
  name: "search",
3673
- description: "Query the knowledge base by keywords. Returns ranked results with heading, snippet, and matched terms. Use multiple short keyword queries for best coverage. Use recall to get full content.",
4010
+ description: "Query the knowledge base by keywords. Returns ranked results with heading, snippet, matched terms, level, and parent. Sections from the same document receive a sibling score boost when multiple sections match. Use multiple short keyword queries for best coverage. Use recall for full content.",
3674
4011
  inputSchema: {
3675
4012
  type: "object",
3676
4013
  properties: {
@@ -3713,7 +4050,7 @@ function createToolDefinitions() {
3713
4050
  },
3714
4051
  {
3715
4052
  name: "learn",
3716
- description: "Import content into the knowledge base. Use for durable facts, decisions, and corrections. Use replace when updating existing knowledge. Attach tags for scoping.",
4053
+ description: "Import content into the knowledge base. Structured content (Markdown, HTML, TOML) is automatically split into sections that share a docid. Each section carries a level (heading depth) and parent reference. Providing title imports as a single section (skips splitting). Use replace when updating existing knowledge. Attach tags for scoping.",
3717
4054
  inputSchema: {
3718
4055
  type: "object",
3719
4056
  properties: {
@@ -3723,11 +4060,11 @@ function createToolDefinitions() {
3723
4060
  },
3724
4061
  type: {
3725
4062
  type: "string",
3726
- description: "MIME type (default: text/markdown). Use image/* for images."
4063
+ description: "MIME type or format hint. Supported: text/markdown, text/html, application/toml (also text/toml, text/x-toml), text/plain, image/*. Default: text/markdown."
3727
4064
  },
3728
4065
  title: {
3729
4066
  type: "string",
3730
- description: "Section title. Required for image/* types."
4067
+ description: "Section title. Skips content splitting when set. Required for image/* types."
3731
4068
  },
3732
4069
  description: {
3733
4070
  type: "string",
@@ -3735,7 +4072,7 @@ function createToolDefinitions() {
3735
4072
  },
3736
4073
  docid: {
3737
4074
  type: "string",
3738
- description: "Document ID to group under"
4075
+ description: "Document ID to group sections under. Set automatically when content splitting is active."
3739
4076
  },
3740
4077
  tags: {
3741
4078
  type: "array",
@@ -3804,7 +4141,7 @@ function createToolDefinitions() {
3804
4141
  },
3805
4142
  {
3806
4143
  name: "recall",
3807
- description: "Retrieve full content and context for sections by identifier. Use after search to read relevant results. Returns section text, metadata, references, and back-references.",
4144
+ description: "Retrieve full content and context for sections by identifier. Use after search to read relevant results. Returns section text, level, parent, metadata, references, and back-references.",
3808
4145
  inputSchema: {
3809
4146
  type: "object",
3810
4147
  properties: {
@@ -3935,7 +4272,7 @@ function createToolDefinitions() {
3935
4272
  },
3936
4273
  {
3937
4274
  name: "skill-learn",
3938
- description: "Create or update a skill definition. Skills are reusable AI agent capabilities with template placeholders.",
4275
+ description: "Create or update a skill definition. Skills are reusable AI agent capabilities with template placeholders. Stored as atomic JSON (not split into sections).",
3939
4276
  inputSchema: {
3940
4277
  type: "object",
3941
4278
  properties: {
@@ -3964,10 +4301,15 @@ function createToolDefinitions() {
3964
4301
  },
3965
4302
  {
3966
4303
  name: "skill-list",
3967
- description: "List all skills in the knowledge base.",
4304
+ description: "List skill definitions stored in the knowledge base, optionally filtered by a substring query.",
3968
4305
  inputSchema: {
3969
4306
  type: "object",
3970
- properties: {}
4307
+ properties: {
4308
+ query: {
4309
+ type: "string",
4310
+ description: "Case-insensitive substring filter on skill name or description."
4311
+ }
4312
+ }
3971
4313
  },
3972
4314
  annotations: {
3973
4315
  title: "List Skills",
@@ -4024,7 +4366,7 @@ function createToolDefinitions() {
4024
4366
  },
4025
4367
  {
4026
4368
  name: "agent-create",
4027
- description: "Create an AI agent with a persona and optional skill references.",
4369
+ description: "Create an AI agent with a persona and optional skill references. Stored as atomic JSON (not split into sections).",
4028
4370
  inputSchema: {
4029
4371
  type: "object",
4030
4372
  properties: {
@@ -4058,10 +4400,15 @@ function createToolDefinitions() {
4058
4400
  },
4059
4401
  {
4060
4402
  name: "agent-list",
4061
- description: "List all agents in the knowledge base.",
4403
+ description: "List agent documents in the knowledge base, optionally filtered by a substring query.",
4062
4404
  inputSchema: {
4063
4405
  type: "object",
4064
- properties: {}
4406
+ properties: {
4407
+ query: {
4408
+ type: "string",
4409
+ description: "Case-insensitive substring filter on agent name or description."
4410
+ }
4411
+ }
4065
4412
  },
4066
4413
  annotations: {
4067
4414
  title: "List Agents",
@@ -4180,7 +4527,7 @@ function createToolDefinitions() {
4180
4527
  title: "Auto-Capture Review",
4181
4528
  readOnlyHint: false,
4182
4529
  destructiveHint: false,
4183
- idempotentHint: true,
4530
+ idempotentHint: false,
4184
4531
  openWorldHint: false
4185
4532
  }
4186
4533
  }
@@ -4309,7 +4656,7 @@ async function readAgentDescription(client, sections) {
4309
4656
  return "";
4310
4657
  }
4311
4658
  }
4312
- async function handleAgentList(client) {
4659
+ async function handleAgentList(client, args = {}) {
4313
4660
  const docs = await client.listDocumentsByType("agent");
4314
4661
  const items = await Promise.all(
4315
4662
  docs.map(async (d) => ({
@@ -4317,17 +4664,17 @@ async function handleAgentList(client) {
4317
4664
  description: await readAgentDescription(client, d.sections)
4318
4665
  }))
4319
4666
  );
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"
4667
+ const query = typeof args["query"] === "string" ? args["query"].toLowerCase() : "";
4668
+ const filtered = items.filter(
4669
+ (item) => matchesQuery(query, item.name, item.description)
4325
4670
  );
4671
+ const names = filtered.map((item) => item.name);
4672
+ const data = { items: names, total: names.length, offset: 0 };
4326
4673
  return {
4327
4674
  content: [
4328
4675
  {
4329
4676
  type: "text",
4330
- text
4677
+ text: JSON.stringify(data, null, 2)
4331
4678
  }
4332
4679
  ]
4333
4680
  };
@@ -4569,25 +4916,38 @@ async function handleAgentSearch(client, args) {
4569
4916
  return { content: [{ type: "text", text }] };
4570
4917
  }
4571
4918
 
4572
- // src/shared/mcp/functions/handle-tool-call.function.ts
4919
+ // src/shared/mcp/functions/as-string.function.ts
4573
4920
  function asString2(value, fallback) {
4574
4921
  return typeof value === "string" ? value : fallback;
4575
4922
  }
4576
- function asBooleanOrUndefined(value) {
4577
- return typeof value === "boolean" ? value : void 0;
4578
- }
4923
+
4924
+ // src/shared/mcp/functions/as-string-array-or-undefined.function.ts
4579
4925
  function asStringArrayOrUndefined(value) {
4580
4926
  if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
4581
4927
  return value;
4582
4928
  }
4583
4929
  return void 0;
4584
4930
  }
4585
- function asStringArray2(value) {
4586
- if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
4587
- return value;
4588
- }
4589
- return [];
4931
+
4932
+ // src/shared/mcp/functions/as-boolean-or-undefined.function.ts
4933
+ function asBooleanOrUndefined(value) {
4934
+ return typeof value === "boolean" ? value : void 0;
4590
4935
  }
4936
+
4937
+ // src/shared/mcp/functions/parse-learn-args.function.ts
4938
+ function parseLearnArgs(args) {
4939
+ return {
4940
+ sectionType: asString2(args["type"], "text/markdown"),
4941
+ title: typeof args["title"] === "string" ? args["title"] : void 0,
4942
+ description: typeof args["description"] === "string" ? args["description"] : void 0,
4943
+ docid: typeof args["docid"] === "string" ? args["docid"] : void 0,
4944
+ tags: asStringArrayOrUndefined(args["tags"]),
4945
+ replace: asBooleanOrUndefined(args["replace"]),
4946
+ level: typeof args["level"] === "number" ? args["level"] : void 0
4947
+ };
4948
+ }
4949
+
4950
+ // src/shared/mcp/functions/unwrap-json-content.function.ts
4591
4951
  function unwrapJsonContent(raw) {
4592
4952
  const trimmed = raw.trim();
4593
4953
  if (!trimmed.startsWith("{")) return raw;
@@ -4600,6 +4960,158 @@ function unwrapJsonContent(raw) {
4600
4960
  }
4601
4961
  return raw;
4602
4962
  }
4963
+
4964
+ // src/shared/mcp/functions/determine-learn-split.function.ts
4965
+ function determineLearnSplit(content, sectionType, title) {
4966
+ const splittable = sectionType.startsWith("text/") || sectionType === "markdown" || sectionType === "application/toml";
4967
+ if (title !== void 0 || !splittable) return void 0;
4968
+ const result = splitContent(content, sectionType);
4969
+ const hasTitledSection = result.sections.some(
4970
+ (section) => section.title !== void 0
4971
+ );
4972
+ return result.sections.length >= 2 && hasTitledSection ? result : void 0;
4973
+ }
4974
+
4975
+ // src/shared/mcp/functions/learn-with-splitting.function.ts
4976
+ async function learnWithSplitting(client, splitResult, params) {
4977
+ const { sections } = splitResult;
4978
+ const firstTitled = sections.find((s) => s.title !== void 0);
4979
+ const docTitle = firstTitled?.title ?? params.docid ?? "Untitled";
4980
+ const docid = params.docid ?? firstTitled?.title;
4981
+ const kbids = [];
4982
+ for (const section of sections) {
4983
+ const [parent] = resolveParentIds([section], kbids);
4984
+ const result = await client.addSection({
4985
+ sectionType: params.sectionType,
4986
+ content: section.content,
4987
+ title: section.title,
4988
+ description: params.description,
4989
+ docid,
4990
+ tags: params.tags,
4991
+ replace: params.replace,
4992
+ level: section.level,
4993
+ parent: parent ?? void 0
4994
+ });
4995
+ kbids.push(result.items[0] ?? "");
4996
+ }
4997
+ return { kbids, docTitle };
4998
+ }
4999
+
5000
+ // src/shared/mcp/functions/store-split-learn-sections.function.ts
5001
+ async function storeSplitLearnSections(client, splitResult, params) {
5002
+ const { kbids, docTitle } = await learnWithSplitting(
5003
+ client,
5004
+ splitResult,
5005
+ params
5006
+ );
5007
+ await client.groupSections(docTitle, kbids);
5008
+ return {
5009
+ items: kbids,
5010
+ total: kbids.length,
5011
+ offset: 0,
5012
+ superseded: null,
5013
+ warnings: [],
5014
+ near_duplicates: []
5015
+ };
5016
+ }
5017
+
5018
+ // src/shared/mcp/functions/build-learn-payload.function.ts
5019
+ function buildLearnPayload(result) {
5020
+ return {
5021
+ items: result.items,
5022
+ total: result.total,
5023
+ offset: result.offset,
5024
+ superseded: result.superseded ?? null,
5025
+ warnings: result.warnings ?? [],
5026
+ near_duplicates: result.near_duplicates ?? []
5027
+ };
5028
+ }
5029
+
5030
+ // src/shared/mcp/functions/handle-tool-learn.function.ts
5031
+ async function handleToolLearn(client, args) {
5032
+ const learnArgs = parseLearnArgs(args);
5033
+ const { sectionType, title, level, ...shared } = learnArgs;
5034
+ if (sectionType.startsWith("image/") && !title) {
5035
+ return {
5036
+ content: [
5037
+ {
5038
+ type: "text",
5039
+ text: "title is required for image/* types"
5040
+ }
5041
+ ],
5042
+ isError: true
5043
+ };
5044
+ }
5045
+ const content = unwrapJsonContent(asString2(args["content"], ""));
5046
+ const splitResult = determineLearnSplit(content, sectionType, title);
5047
+ const result = splitResult ? await storeSplitLearnSections(client, splitResult, {
5048
+ sectionType,
5049
+ ...shared
5050
+ }) : await client.addSection({
5051
+ sectionType,
5052
+ content,
5053
+ title,
5054
+ level,
5055
+ ...shared
5056
+ });
5057
+ return {
5058
+ content: [
5059
+ {
5060
+ type: "text",
5061
+ text: JSON.stringify(buildLearnPayload(result))
5062
+ }
5063
+ ]
5064
+ };
5065
+ }
5066
+
5067
+ // src/shared/mcp/functions/handle-tool-skill-learn.function.ts
5068
+ async function handleToolSkillLearn(client, args) {
5069
+ const name = asString2(args["name"], "");
5070
+ if (!name) {
5071
+ return {
5072
+ content: [{ type: "text", text: "name is required" }],
5073
+ isError: true
5074
+ };
5075
+ }
5076
+ const body = asString2(args["body"], "");
5077
+ if (!body) {
5078
+ return {
5079
+ content: [{ type: "text", text: "body is required" }],
5080
+ isError: true
5081
+ };
5082
+ }
5083
+ const description = typeof args["description"] === "string" ? args["description"] : void 0;
5084
+ const skillArgs = extractSkillArguments(body);
5085
+ const skill = {
5086
+ name,
5087
+ description,
5088
+ arguments: skillArgs.length > 0 ? skillArgs : void 0,
5089
+ body
5090
+ };
5091
+ const json = serializeSkillContent(skill);
5092
+ const result = await client.addSection({
5093
+ sectionType: "skill",
5094
+ content: json,
5095
+ title: name,
5096
+ description
5097
+ });
5098
+ return {
5099
+ content: [
5100
+ {
5101
+ type: "text",
5102
+ text: `Created skill "${name}" (kbid: ${result.items[0]})`
5103
+ }
5104
+ ]
5105
+ };
5106
+ }
5107
+
5108
+ // src/shared/mcp/functions/handle-tool-call.function.ts
5109
+ function asStringArray2(value) {
5110
+ if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
5111
+ return value;
5112
+ }
5113
+ return [];
5114
+ }
4603
5115
  async function handleToolCall(client, name, args) {
4604
5116
  log("tool call: " + name, 0 /* DEBUG */);
4605
5117
  try {
@@ -4607,7 +5119,7 @@ async function handleToolCall(client, name, args) {
4607
5119
  case "search":
4608
5120
  return await handleSearch2(client, args);
4609
5121
  case "learn":
4610
- return await handleLearn2(client, args);
5122
+ return await handleToolLearn(client, args);
4611
5123
  case "unlearn":
4612
5124
  return await handleUnlearn2(client, args);
4613
5125
  case "retrieve":
@@ -4627,9 +5139,9 @@ async function handleToolCall(client, name, args) {
4627
5139
  case "export":
4628
5140
  return await handleExport2(client, args);
4629
5141
  case "skill-learn":
4630
- return await handleSkillLearn(client, args);
5142
+ return await handleToolSkillLearn(client, args);
4631
5143
  case "skill-list":
4632
- return await handleSkillList(client);
5144
+ return await handleSkillList(client, args);
4633
5145
  case "skill-get":
4634
5146
  return await handleSkillGet(client, args);
4635
5147
  case "skill-delete":
@@ -4637,7 +5149,7 @@ async function handleToolCall(client, name, args) {
4637
5149
  case "agent-create":
4638
5150
  return await handleAgentCreate(client, args);
4639
5151
  case "agent-list":
4640
- return await handleAgentList(client);
5152
+ return await handleAgentList(client, args);
4641
5153
  case "agent-get":
4642
5154
  return await handleAgentGet(client, args);
4643
5155
  case "agent-delete":
@@ -4692,47 +5204,6 @@ async function handleSearch2(client, args) {
4692
5204
  ]
4693
5205
  };
4694
5206
  }
4695
- async function handleLearn2(client, args) {
4696
- const sectionType = asString2(args["type"], "text/markdown");
4697
- const title = typeof args["title"] === "string" ? args["title"] : void 0;
4698
- const description = typeof args["description"] === "string" ? args["description"] : void 0;
4699
- const docid = typeof args["docid"] === "string" ? args["docid"] : void 0;
4700
- const tags = asStringArrayOrUndefined(args["tags"]);
4701
- const replace = asBooleanOrUndefined(args["replace"]);
4702
- if (sectionType.startsWith("image/") && !title) {
4703
- return {
4704
- content: [
4705
- {
4706
- type: "text",
4707
- text: "title is required for image/* types"
4708
- }
4709
- ],
4710
- isError: true
4711
- };
4712
- }
4713
- const rawContent = asString2(args["content"], "");
4714
- const content = unwrapJsonContent(rawContent);
4715
- const result = await client.addSection({
4716
- sectionType,
4717
- content,
4718
- title,
4719
- description,
4720
- docid,
4721
- tags,
4722
- replace
4723
- });
4724
- const payload = {
4725
- items: result.items,
4726
- total: result.total,
4727
- offset: result.offset,
4728
- superseded: result.superseded ?? null,
4729
- warnings: result.warnings ?? [],
4730
- near_duplicates: result.near_duplicates ?? []
4731
- };
4732
- return {
4733
- content: [{ type: "text", text: JSON.stringify(payload) }]
4734
- };
4735
- }
4736
5207
  async function handleUnlearn2(client, args) {
4737
5208
  const kbid = asString2(args["kbid"], "");
4738
5209
  await client.removeSection(kbid);
@@ -4839,56 +5310,17 @@ async function handleRebuild2(client) {
4839
5310
  const text = `Rebuild complete: ${String(report.sections_reindexed)} sections reindexed, ${String(report.terms_indexed)} terms indexed.`;
4840
5311
  return { content: [{ type: "text", text }] };
4841
5312
  }
4842
- async function handleSkillLearn(client, args) {
4843
- const name = asString2(args["name"], "");
4844
- if (!name) {
4845
- return {
4846
- content: [{ type: "text", text: "name is required" }],
4847
- isError: true
4848
- };
4849
- }
4850
- const body = asString2(args["body"], "");
4851
- if (!body) {
4852
- return {
4853
- content: [{ type: "text", text: "body is required" }],
4854
- isError: true
4855
- };
4856
- }
4857
- const description = typeof args["description"] === "string" ? args["description"] : void 0;
4858
- const skillArgs = extractSkillArguments(body);
4859
- const skill = {
4860
- name,
4861
- description,
4862
- arguments: skillArgs.length > 0 ? skillArgs : void 0,
4863
- body
4864
- };
4865
- const json = serializeSkillContent(skill);
4866
- const result = await client.addSection({
4867
- sectionType: "skill",
4868
- content: json,
4869
- title: name,
4870
- description
4871
- });
4872
- return {
4873
- content: [
4874
- {
4875
- type: "text",
4876
- text: `Created skill "${name}" (kbid: ${result.items[0]})`
4877
- }
4878
- ]
4879
- };
4880
- }
4881
- async function handleSkillList(client) {
5313
+ async function handleSkillList(client, args) {
4882
5314
  const records = await client.listByType("skill");
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}`;
4887
- });
4888
- const text = [`${String(records.length)} skills:`, ...lines].join(
4889
- "\n"
5315
+ const query = typeof args["query"] === "string" ? args["query"].toLowerCase() : "";
5316
+ const filtered = records.filter(
5317
+ (r) => matchesQuery(query, r.title, r.description)
4890
5318
  );
4891
- return { content: [{ type: "text", text }] };
5319
+ const names = filtered.map((r) => r.title ?? "");
5320
+ const data = { items: names, total: names.length, offset: 0 };
5321
+ return {
5322
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
5323
+ };
4892
5324
  }
4893
5325
  async function handleSkillGet(client, args) {
4894
5326
  const kbid = typeof args["kbid"] === "string" ? args["kbid"] : void 0;
@@ -5924,7 +6356,7 @@ var deps = {
5924
6356
  log("starting MCP server", 1 /* INFO */);
5925
6357
  const client = await createWorkerClient({ contextPath });
5926
6358
  try {
5927
- const tomlPath = (0, import_node_path14.join)(contextPath, "worker.toml");
6359
+ const tomlPath = (0, import_node_path15.join)(contextPath, "worker.toml");
5928
6360
  let autoCaptureConfig;
5929
6361
  try {
5930
6362
  const tomlText = (0, import_node_fs10.readFileSync)(tomlPath, "utf-8");