@dikolab/kbdb 0.4.0 → 0.4.1

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 (99) hide show
  1. package/README.md +13 -5
  2. package/dist/{chunk-BJPSPNGX.mjs → chunk-BJXEVALU.mjs} +115 -1
  3. package/dist/chunk-BJXEVALU.mjs.map +7 -0
  4. package/dist/cli.cjs +462 -79
  5. package/dist/cli.cjs.map +4 -4
  6. package/dist/cli.mjs +356 -79
  7. package/dist/cli.mjs.map +4 -4
  8. package/dist/kbdb-worker.cjs +413 -53
  9. package/dist/kbdb-worker.cjs.map +4 -4
  10. package/dist/mod.cjs +230 -54
  11. package/dist/mod.cjs.map +4 -4
  12. package/dist/mod.mjs +229 -53
  13. package/dist/mod.mjs.map +4 -4
  14. package/dist/src/shared/cli/typings/cli-options.interface.d.ts +5 -0
  15. package/dist/src/shared/embedding/classes/tfidf-embedding-provider.class.d.ts +28 -0
  16. package/dist/src/shared/embedding/constants/tfidf-defaults.constant.d.ts +4 -0
  17. package/dist/src/shared/embedding/functions/create-embedding-provider.function.d.ts +5 -2
  18. package/dist/src/shared/embedding/index.d.ts +2 -0
  19. package/dist/src/shared/log/constants/log-colors.constant.d.ts +5 -0
  20. package/dist/src/shared/log/constants/log-defaults.constant.d.ts +3 -0
  21. package/dist/src/shared/log/constants/log-icons.constant.d.ts +3 -0
  22. package/dist/src/shared/log/functions/configure-log.function.d.ts +12 -0
  23. package/dist/src/shared/log/functions/log.function.d.ts +28 -0
  24. package/dist/src/shared/log/functions/parse-log-level.function.d.ts +10 -0
  25. package/dist/src/shared/log/functions/resolve-log-level.function.d.ts +12 -0
  26. package/dist/src/shared/log/functions/write-stderr.function.d.ts +10 -0
  27. package/dist/src/shared/log/index.d.ts +10 -0
  28. package/dist/src/shared/log/typings/log-config.interface.d.ts +7 -0
  29. package/dist/src/shared/log/typings/log-level.type.d.ts +7 -0
  30. package/dist/src/shared/log/typings/log-output.interface.d.ts +4 -0
  31. package/dist/src/shared/version/constants/version.constant.d.ts +1 -1
  32. package/dist/src/shared/worker-client/classes/worker-client.class.d.ts +7 -0
  33. package/dist/src/shared/worker-client/functions/retry-on-timeout.function.d.ts +1 -0
  34. package/dist/src/shared/worker-daemon/classes/worker-daemon.class.d.ts +1 -0
  35. package/dist/src/shared/worker-daemon/functions/run-worker.function.d.ts +6 -1
  36. package/dist/src/shared/worker-daemon/typings/wasm-modules.interface.d.ts +5 -0
  37. package/dist/wasm/default-embedding/kbdb_default_embedding.d.ts +55 -0
  38. package/dist/wasm/default-embedding/kbdb_default_embedding.js +156 -0
  39. package/dist/wasm/default-embedding/kbdb_default_embedding_bg.wasm +0 -0
  40. package/dist/wasm/default-embedding/kbdb_default_embedding_bg.wasm.d.ts +12 -0
  41. package/dist/wasm/default-embedding/package.json +13 -0
  42. package/dist/wasm/fs-database/kbdb_fs_database_bg.wasm +0 -0
  43. package/dist/wasm/fs-migration/kbdb_fs_migration.d.ts +38 -0
  44. package/dist/wasm/fs-migration/kbdb_fs_migration.js +130 -0
  45. package/dist/wasm/fs-migration/kbdb_fs_migration_bg.wasm +0 -0
  46. package/dist/wasm/fs-migration/kbdb_fs_migration_bg.wasm.d.ts +9 -0
  47. package/dist/wasm/fs-migration/package.json +13 -0
  48. package/dist/wasm/kb-worker/kbdb_worker_bg.wasm +0 -0
  49. package/dist/wasm/query-parser/kbdb_query_parser_bg.wasm +0 -0
  50. package/dist/worker.mjs +306 -54
  51. package/dist/worker.mjs.map +4 -4
  52. package/docs/details/agent-tooling.md +10 -0
  53. package/docs/details/cli.md +29 -13
  54. package/docs/details/knowledge-base.md +15 -8
  55. package/docs/details/mcp-server.md +16 -1
  56. package/docs/details/search-and-ranking.md +6 -2
  57. package/docs/goals/cli.md +33 -4
  58. package/docs/goals/content-parser.md +1 -1
  59. package/docs/goals/hybrid-search.md +71 -42
  60. package/docs/goals/mcp.md +3 -1
  61. package/docs/goals/overview.md +1 -1
  62. package/docs/goals/query-parser.md +1 -1
  63. package/docs/goals/semantic-dedup.md +7 -3
  64. package/docs/goals/worker-daemon.md +31 -20
  65. package/docs/modules/overview.md +43 -22
  66. package/docs/modules/rust/embedding/module.md +91 -0
  67. package/docs/modules/rust/overview.md +56 -21
  68. package/docs/modules/rust/query-parser/functions/module.md +7 -5
  69. package/docs/modules/rust/query-parser/functions/pipeline.md +6 -138
  70. package/docs/modules/rust/query-parser/module.md +16 -22
  71. package/docs/modules/rust/query-parser/types/module.md +5 -4
  72. package/docs/modules/rust/query-parser/types/token.md +5 -1
  73. package/docs/modules/rust/shared/content-parser/functions.md +1 -1
  74. package/docs/modules/rust/shared/memory/module.md +1 -1
  75. package/docs/modules/rust/shared/module.md +33 -5
  76. package/docs/modules/rust/shared/pipeline/functions.md +141 -0
  77. package/docs/modules/rust/shared/pipeline/module.md +62 -0
  78. package/docs/modules/rust/shared/pipeline/types.md +43 -0
  79. package/docs/modules/rust/shared/section/module.md +1 -1
  80. package/docs/modules/rust/shared/section/types.md +1 -1
  81. package/docs/modules/typescript/cli.md +4 -2
  82. package/docs/modules/typescript/kbdb-worker.md +20 -5
  83. package/docs/modules/typescript/overview.md +28 -6
  84. package/docs/modules/typescript/shared/cli/functions.md +15 -4
  85. package/docs/modules/typescript/shared/cli/typings.md +21 -0
  86. package/docs/modules/typescript/shared/embedding/functions.md +30 -3
  87. package/docs/modules/typescript/shared/embedding/module.md +10 -4
  88. package/docs/modules/typescript/shared/embedding/typings.md +7 -5
  89. package/docs/modules/typescript/shared/log/constants.md +82 -0
  90. package/docs/modules/typescript/shared/log/functions.md +131 -0
  91. package/docs/modules/typescript/shared/log/module.md +153 -0
  92. package/docs/modules/typescript/shared/log/typings.md +82 -0
  93. package/docs/modules/typescript/shared/module.md +22 -6
  94. package/docs/modules/typescript/shared/worker-daemon/functions.md +19 -6
  95. package/docs/modules/typescript/shared/worker-daemon/module.md +5 -2
  96. package/docs/modules/typescript/shared/worker-daemon/typings.md +13 -7
  97. package/docs/release-notes/0.4.1.md +149 -0
  98. package/package.json +2 -2
  99. package/dist/chunk-BJPSPNGX.mjs.map +0 -7
@@ -214,6 +214,73 @@ var import_node_fs8 = require("node:fs");
214
214
  var import_node_path9 = require("node:path");
215
215
  var import_node_os2 = require("node:os");
216
216
 
217
+ // src/shared/log/typings/log-level.type.ts
218
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
219
+ LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
220
+ LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
221
+ LogLevel2[LogLevel2["WARNING"] = 2] = "WARNING";
222
+ LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
223
+ return LogLevel2;
224
+ })(LogLevel || {});
225
+
226
+ // src/shared/log/constants/log-colors.constant.ts
227
+ var ANSI_RESET = "\x1B[0m";
228
+ var LOG_COLORS = {
229
+ [0 /* DEBUG */]: "\x1B[37m",
230
+ [1 /* INFO */]: "\x1B[36m",
231
+ [2 /* WARNING */]: "\x1B[33m",
232
+ [3 /* ERROR */]: "\x1B[91m"
233
+ };
234
+
235
+ // src/shared/log/constants/log-icons.constant.ts
236
+ var LOG_ICONS = {
237
+ [0 /* DEBUG */]: "\u25B8",
238
+ [1 /* INFO */]: "\u2139",
239
+ [2 /* WARNING */]: "\u26A0",
240
+ [3 /* ERROR */]: "\u2716"
241
+ };
242
+
243
+ // src/shared/log/constants/log-defaults.constant.ts
244
+ var DEFAULT_LOG_LEVEL = 3 /* ERROR */;
245
+
246
+ // src/shared/log/functions/write-stderr.function.ts
247
+ function writeStderr(message) {
248
+ const g = globalThis;
249
+ const proc = g["process"];
250
+ if (proc?.stderr) {
251
+ proc.stderr.write(message);
252
+ return;
253
+ }
254
+ const deno = g["Deno"];
255
+ deno?.stderr.writeSync(new TextEncoder().encode(message));
256
+ }
257
+
258
+ // src/shared/log/functions/log.function.ts
259
+ var currentLevel = DEFAULT_LOG_LEVEL;
260
+ var outputs = {
261
+ [0 /* DEBUG */]: writeStderr,
262
+ [1 /* INFO */]: writeStderr,
263
+ [2 /* WARNING */]: writeStderr,
264
+ [3 /* ERROR */]: writeStderr
265
+ };
266
+ function setLogLevel(level) {
267
+ currentLevel = level;
268
+ }
269
+ function setLogOutput(level, output) {
270
+ outputs[level] = output;
271
+ }
272
+ function log(message, level = 3 /* ERROR */) {
273
+ if (level < currentLevel) {
274
+ return;
275
+ }
276
+ const color = LOG_COLORS[level];
277
+ const icon = LOG_ICONS[level];
278
+ const name = LogLevel[level];
279
+ const line = `${color}${icon} [${name}] ${message}${ANSI_RESET}
280
+ `;
281
+ outputs[level](line);
282
+ }
283
+
217
284
  // src/shared/worker-daemon/functions/load-wasm-modules.function.ts
218
285
  var import_node_fs3 = require("node:fs");
219
286
 
@@ -242,6 +309,7 @@ var nullAllocator = { alloc: null };
242
309
  function createHostImports(contextPath, memoryRef = nullMemory, fs = nodeFsAdapter, allocator = nullAllocator) {
243
310
  function getBuffer() {
244
311
  if (!memoryRef.memory) {
312
+ log("WASM memory not initialized", 3 /* ERROR */);
245
313
  throw new Error("WASM memory not initialized");
246
314
  }
247
315
  return memoryRef.memory.buffer;
@@ -410,6 +478,7 @@ async function loadWasmModules(config, wasmDir2) {
410
478
  void 0,
411
479
  allocator
412
480
  );
481
+ log("loading WASM module: kb-worker", 0 /* DEBUG */);
413
482
  const wkPath = joinPath(wasmDir2, "kb-worker", "kbdb_worker_bg.wasm");
414
483
  const wkBytes = await readWasmFile(wkPath, "kb-worker");
415
484
  let wkModule;
@@ -433,7 +502,20 @@ async function loadWasmModules(config, wasmDir2) {
433
502
  if (typeof fn_ !== "function") return 0;
434
503
  return fn_(size);
435
504
  };
436
- return { memory, kbWorker };
505
+ const embPath = joinPath(
506
+ wasmDir2,
507
+ "default-embedding",
508
+ "kbdb_default_embedding_bg.wasm"
509
+ );
510
+ let embedding;
511
+ try {
512
+ const embBytes = await readWasmFile(embPath, "default-embedding");
513
+ const embModule = await WebAssembly.compile(embBytes);
514
+ embedding = await WebAssembly.instantiate(embModule, {});
515
+ } catch {
516
+ }
517
+ log("all WASM modules loaded", 1 /* INFO */);
518
+ return { memory, kbWorker, embedding };
437
519
  }
438
520
  async function readWasmFile(path, label) {
439
521
  try {
@@ -459,7 +541,7 @@ function rethrow(stage, label, err, path) {
459
541
  const detail = err instanceof Error ? err.message : String(err);
460
542
  const suffix = path ? ` (path: ${path})` : "";
461
543
  const message = `failed to ${stage} ${label} WASM: ${detail}${suffix}`;
462
- console.error(`kbdb-worker: ${message}`);
544
+ log(`kbdb-worker: ${message}`, 3 /* ERROR */);
463
545
  throw new Error(message, { cause: err });
464
546
  }
465
547
 
@@ -470,9 +552,14 @@ var KEEPALIVE_MS = 3e4;
470
552
  function createIpcServer(socketPath, handler) {
471
553
  const server = (0, import_node_net.createServer)((socket) => {
472
554
  socket.setKeepAlive(true, KEEPALIVE_MS);
555
+ log("ipc: connection accepted", 0 /* DEBUG */);
473
556
  let buffer = "";
474
557
  let processingQueue = Promise.resolve();
475
558
  socket.on("data", (chunk) => {
559
+ log(
560
+ "ipc: data received bytes=" + String(chunk.length),
561
+ 0 /* DEBUG */
562
+ );
476
563
  buffer += chunk.toString();
477
564
  const lines = buffer.split("\n");
478
565
  buffer = lines.pop() ?? "";
@@ -484,8 +571,9 @@ function createIpcServer(socketPath, handler) {
484
571
  }
485
572
  });
486
573
  socket.on("error", (err) => {
487
- console.error(
488
- `kbdb-worker: ipc connection error: ${err.message}`
574
+ log(
575
+ `kbdb-worker: ipc connection error: ${err.message}`,
576
+ 2 /* WARNING */
489
577
  );
490
578
  });
491
579
  });
@@ -496,8 +584,9 @@ function createIpcServer(socketPath, handler) {
496
584
  () => {
497
585
  server.removeListener("error", reject);
498
586
  server.on("error", (err) => {
499
- console.error(
500
- `kbdb-worker: ipc server error: ${err.message}`
587
+ log(
588
+ `kbdb-worker: ipc server error: ${err.message}`,
589
+ 3 /* ERROR */
501
590
  );
502
591
  });
503
592
  resolve2(server);
@@ -512,8 +601,13 @@ async function handleLine(line, handler, socket) {
512
601
  let response;
513
602
  try {
514
603
  const request = JSON.parse(line);
604
+ log(
605
+ "ipc: request parsed method=" + request.method + " id=" + String(request.id),
606
+ 0 /* DEBUG */
607
+ );
515
608
  response = await handler(request);
516
609
  } catch {
610
+ log("ipc: parse error on malformed request", 0 /* DEBUG */);
517
611
  response = {
518
612
  jsonrpc: "2.0",
519
613
  id: 0,
@@ -523,7 +617,12 @@ async function handleLine(line, handler, socket) {
523
617
  }
524
618
  };
525
619
  }
526
- socket.write(JSON.stringify(response, bigintReplacer) + "\n");
620
+ const encoded = JSON.stringify(response, bigintReplacer) + "\n";
621
+ log(
622
+ "ipc: response sent bytes=" + String(encoded.length),
623
+ 0 /* DEBUG */
624
+ );
625
+ socket.write(encoded);
527
626
  }
528
627
 
529
628
  // src/shared/platform/functions/get-ipc-path.function.ts
@@ -584,6 +683,7 @@ var OnnxEmbeddingProvider = class {
584
683
  * dependency not yet wired
585
684
  */
586
685
  embed(_texts) {
686
+ log("embed called on OnnxEmbeddingProvider", 0 /* DEBUG */);
587
687
  return Promise.reject(
588
688
  new Error(
589
689
  "ONNX Runtime not available; install onnxruntime-node"
@@ -603,6 +703,7 @@ var OnnxEmbeddingProvider = class {
603
703
  // src/shared/embedding/functions/parse-api-embedding-response.function.ts
604
704
  function parseApiEmbeddingResponse(raw) {
605
705
  if (!isEmbeddingApiResponse(raw)) {
706
+ log("Unexpected embedding API response shape", 3 /* ERROR */);
606
707
  throw new Error("Unexpected embedding API response shape");
607
708
  }
608
709
  return raw.data.map((entry) => new Float32Array(entry.embedding));
@@ -656,9 +757,9 @@ var ApiEmbeddingProvider = class {
656
757
  body: JSON.stringify({ input: texts, model: this.model })
657
758
  });
658
759
  if (!response.ok) {
659
- throw new Error(
660
- `Embedding API error: ${String(response.status)}`
661
- );
760
+ const msg = `Embedding API error: ${String(response.status)}`;
761
+ log(msg, 3 /* ERROR */);
762
+ throw new Error(msg);
662
763
  }
663
764
  const json = await response.json();
664
765
  return parseApiEmbeddingResponse(json);
@@ -673,17 +774,89 @@ var ApiEmbeddingProvider = class {
673
774
  }
674
775
  };
675
776
 
777
+ // src/shared/embedding/constants/tfidf-defaults.constant.ts
778
+ var TFIDF_DIMENSIONS = 256;
779
+ var TFIDF_MODEL_NAME = "tfidf-v1";
780
+
781
+ // src/shared/embedding/classes/tfidf-embedding-provider.class.ts
782
+ var TfidfEmbeddingProvider = class {
783
+ _alloc;
784
+ _batch;
785
+ _retPtr;
786
+ _memory;
787
+ /** @param wasm - instantiated `kbdb-default-embedding` WASM module */
788
+ constructor(wasm) {
789
+ const ex = wasm.exports;
790
+ this._memory = ex["memory"];
791
+ this._alloc = ex["kbdb_alloc"];
792
+ this._batch = ex["embedding_tfidf_batch"];
793
+ this._retPtr = ex["get_return_ptr"];
794
+ }
795
+ /**
796
+ * Embeds a batch of texts using TF-IDF computation in WASM.
797
+ *
798
+ * @param texts - input strings to embed
799
+ * @returns one 256-dimension `Float32Array` per input text
800
+ */
801
+ embed(texts) {
802
+ log(
803
+ "embed called on TfidfEmbeddingProvider: " + texts.length.toString() + " texts",
804
+ 0 /* DEBUG */
805
+ );
806
+ const input = texts.join("\n");
807
+ const encoded = new TextEncoder().encode(input);
808
+ const ptr = this._alloc(encoded.byteLength);
809
+ const view = new Uint8Array(this._memory.buffer);
810
+ view.set(encoded, ptr);
811
+ this._batch(ptr, encoded.byteLength);
812
+ const outPtr = this._retPtr();
813
+ const dv = new DataView(this._memory.buffer);
814
+ const count = dv.getUint32(outPtr, true);
815
+ const results = [];
816
+ let offset = outPtr + 4;
817
+ for (let i = 0; i < count; i++) {
818
+ const vec = new Float32Array(TFIDF_DIMENSIONS);
819
+ for (let d = 0; d < TFIDF_DIMENSIONS; d++) {
820
+ vec[d] = dv.getFloat32(offset, true);
821
+ offset += 4;
822
+ }
823
+ results.push(vec);
824
+ }
825
+ return Promise.resolve(results);
826
+ }
827
+ /** Returns 256 -- the fixed dimension count for TF-IDF vectors. */
828
+ dimensions() {
829
+ return TFIDF_DIMENSIONS;
830
+ }
831
+ /** Returns `'tfidf-v1'`. */
832
+ modelName() {
833
+ return TFIDF_MODEL_NAME;
834
+ }
835
+ };
836
+
676
837
  // src/shared/embedding/functions/create-embedding-provider.function.ts
677
- function createEmbeddingProvider(config) {
678
- if (!config || config.provider === "none") {
838
+ function createEmbeddingProvider(config, wasmInstance) {
839
+ log("creating embedding provider", 0 /* DEBUG */);
840
+ if (!config) {
841
+ if (wasmInstance) {
842
+ log("using TfidfEmbeddingProvider", 0 /* DEBUG */);
843
+ return new TfidfEmbeddingProvider(wasmInstance);
844
+ }
845
+ log("using NullEmbeddingProvider", 0 /* DEBUG */);
846
+ return new NullEmbeddingProvider();
847
+ }
848
+ if (config.provider === "none") {
849
+ log("using NullEmbeddingProvider", 0 /* DEBUG */);
679
850
  return new NullEmbeddingProvider();
680
851
  }
681
852
  if (config.provider === "onnx") {
853
+ log("using OnnxEmbeddingProvider", 0 /* DEBUG */);
682
854
  return new OnnxEmbeddingProvider(
683
855
  config.model ?? "",
684
856
  config.dimensions ?? 0
685
857
  );
686
858
  }
859
+ log("using ApiEmbeddingProvider", 0 /* DEBUG */);
687
860
  return new ApiEmbeddingProvider(
688
861
  config.endpoint ?? "",
689
862
  config.dimensions ?? 0,
@@ -720,6 +893,7 @@ function cosineSimilarity(a, b) {
720
893
  var HEADER_SIZE = 32;
721
894
  var KBID_WIDTH = 64;
722
895
  function searchVectors(filePath, queryVector, topN) {
896
+ log("searching vectors", 0 /* DEBUG */);
723
897
  const buf = (0, import_node_fs4.readFileSync)(filePath);
724
898
  if (buf.length < HEADER_SIZE) {
725
899
  return [];
@@ -775,6 +949,7 @@ var IpcError = class extends Error {
775
949
 
776
950
  // src/shared/worker-daemon/functions/handle-hybrid-search.function.ts
777
951
  async function fuseSearchResults(lexical, algo, query, provider, targetDir) {
952
+ log("handling hybrid search", 0 /* DEBUG */);
778
953
  if (algo === "lexical") {
779
954
  return {
780
955
  ...lexical,
@@ -801,10 +976,9 @@ async function fuseSearchResults(lexical, algo, query, provider, targetDir) {
801
976
  }
802
977
  function assertProvider(provider) {
803
978
  if (!provider || provider.dimensions() === 0) {
804
- throw new IpcError(
805
- -32e3,
806
- "embedding provider not configured; set [embedding] in worker.toml"
807
- );
979
+ const embeddingErrMsg = "embedding provider not configured; set [embedding] in worker.toml";
980
+ log(embeddingErrMsg, 3 /* ERROR */);
981
+ throw new IpcError(-32e3, embeddingErrMsg);
808
982
  }
809
983
  }
810
984
  function buildVectorOnly(vectorResults, lexical) {
@@ -907,6 +1081,7 @@ function writeRecord(buf, offset, entry, dimensions, encoder3) {
907
1081
  }
908
1082
  }
909
1083
  function buildVectorIndex(dirPath, modelName, dimensions, entries) {
1084
+ log("building vector index", 0 /* DEBUG */);
910
1085
  const encoder3 = new TextEncoder();
911
1086
  const modelBytes = encoder3.encode(modelName);
912
1087
  const modelLen = modelBytes.length;
@@ -965,6 +1140,7 @@ function collectSections(sectionsDir) {
965
1140
  return result;
966
1141
  }
967
1142
  async function rebuildVectors(targetDir, provider) {
1143
+ log("rebuilding vectors", 0 /* DEBUG */);
968
1144
  if (provider.dimensions() === 0) {
969
1145
  return 0;
970
1146
  }
@@ -988,6 +1164,10 @@ async function rebuildVectors(targetDir, provider) {
988
1164
  provider.dimensions(),
989
1165
  entries
990
1166
  );
1167
+ log(
1168
+ "rebuilt " + sections.length.toString() + " vectors",
1169
+ 1 /* INFO */
1170
+ );
991
1171
  return sections.length;
992
1172
  }
993
1173
 
@@ -1845,6 +2025,7 @@ var WorkerDaemon = class {
1845
2025
  _idleAt = 0;
1846
2026
  _idleTimer = null;
1847
2027
  _server = null;
2028
+ _sockets = /* @__PURE__ */ new Set();
1848
2029
  _wasmDir;
1849
2030
  /** Queue of waiters for the single-writer lock. */
1850
2031
  _writeQueue = [];
@@ -1881,6 +2062,10 @@ var WorkerDaemon = class {
1881
2062
  */
1882
2063
  checkPreconditions() {
1883
2064
  if (!(0, import_node_fs8.existsSync)(this.targetDir)) {
2065
+ log(
2066
+ `database directory not found: ${this.targetDir}`,
2067
+ 3 /* ERROR */
2068
+ );
1884
2069
  throw new Error(
1885
2070
  `database directory not found: ${this.targetDir}`
1886
2071
  );
@@ -1891,9 +2076,9 @@ var WorkerDaemon = class {
1891
2076
  import_node_fs8.constants.R_OK | import_node_fs8.constants.W_OK
1892
2077
  );
1893
2078
  } catch {
1894
- throw new Error(
1895
- `cannot access database directory: ${this.targetDir} -- permission denied`
1896
- );
2079
+ const msg = `cannot access database directory: ${this.targetDir} -- permission denied`;
2080
+ log(msg, 3 /* ERROR */);
2081
+ throw new Error(msg);
1897
2082
  }
1898
2083
  this.checkCatalogVersion();
1899
2084
  }
@@ -1909,18 +2094,34 @@ var WorkerDaemon = class {
1909
2094
  * be created
1910
2095
  */
1911
2096
  async start() {
2097
+ log(
2098
+ "start: loading wasm modules ctx=" + this.ctx,
2099
+ 0 /* DEBUG */
2100
+ );
1912
2101
  const wasmModules = await loadWasmModules(
1913
2102
  this.config,
1914
2103
  this._wasmDir
1915
2104
  );
1916
2105
  this._wasmModules = wasmModules;
2106
+ log("start: wasm modules loaded", 0 /* DEBUG */);
1917
2107
  this._embeddingProvider = createEmbeddingProvider(
1918
- this.config.embedding
2108
+ this.config.embedding,
2109
+ wasmModules.embedding
2110
+ );
2111
+ log(
2112
+ "start: embedding provider created embedding=" + (this.config.embedding?.provider ?? "none"),
2113
+ 0 /* DEBUG */
1919
2114
  );
1920
2115
  this.initWorkerContext();
2116
+ log("start: worker context initialized", 0 /* DEBUG */);
1921
2117
  this.runStartupIntegrityCheck();
2118
+ log(
2119
+ "start: integrity check done ok=" + String(this._integrityOk),
2120
+ 0 /* DEBUG */
2121
+ );
1922
2122
  const ipcPath = getIpcPath(this.ctx);
1923
2123
  if ((0, import_node_fs8.existsSync)(ipcPath)) {
2124
+ log("start: removing stale socket " + ipcPath, 0 /* DEBUG */);
1924
2125
  try {
1925
2126
  (0, import_node_fs8.unlinkSync)(ipcPath);
1926
2127
  } catch {
@@ -1928,18 +2129,34 @@ var WorkerDaemon = class {
1928
2129
  }
1929
2130
  const handler = (req) => this.handleRequest(req);
1930
2131
  this._server = await createIpcServer(ipcPath, handler);
1931
- this._server.on("connection", () => {
2132
+ log("IPC server listening on " + ipcPath, 1 /* INFO */);
2133
+ this._server.on("connection", (socket) => {
2134
+ this._sockets.add(socket);
1932
2135
  this.incrementConnections();
1933
2136
  this.resetIdleTimer();
1934
- });
1935
- this._server.on("close", () => {
1936
- this.decrementConnections();
1937
- if (this._connectionCount === 0) {
1938
- this.resetIdleTimer();
1939
- }
2137
+ log(
2138
+ "client connected (count: " + String(this._connectionCount) + ")",
2139
+ 0 /* DEBUG */
2140
+ );
2141
+ socket.on("close", () => {
2142
+ this._sockets.delete(socket);
2143
+ this.decrementConnections();
2144
+ log(
2145
+ "client disconnected (count: " + String(this._connectionCount) + ")",
2146
+ 0 /* DEBUG */
2147
+ );
2148
+ if (this._connectionCount === 0) {
2149
+ this.resetIdleTimer();
2150
+ }
2151
+ });
1940
2152
  });
1941
2153
  const pidPath = (0, import_node_path9.join)((0, import_node_os2.tmpdir)(), `kbdb-${this.ctx}.pid`);
1942
2154
  (0, import_node_fs8.writeFileSync)(pidPath, process.pid.toString());
2155
+ log(
2156
+ "start: pid file written pid=" + String(process.pid),
2157
+ 0 /* DEBUG */
2158
+ );
2159
+ log("start: daemon ready ctx=" + this.ctx, 0 /* DEBUG */);
1943
2160
  this.resetIdleTimer();
1944
2161
  }
1945
2162
  /**
@@ -1950,23 +2167,36 @@ var WorkerDaemon = class {
1950
2167
  * the process.
1951
2168
  */
1952
2169
  stop() {
2170
+ log(
2171
+ "stop: entry sockets=" + String(this._sockets.size),
2172
+ 0 /* DEBUG */
2173
+ );
2174
+ log("shutting down", 1 /* INFO */);
1953
2175
  if (this._idleTimer !== null) {
1954
2176
  clearTimeout(this._idleTimer);
1955
2177
  this._idleTimer = null;
1956
2178
  }
2179
+ for (const socket of this._sockets) {
2180
+ socket.destroy();
2181
+ }
2182
+ this._sockets.clear();
1957
2183
  if (this._server !== null) {
1958
2184
  this._server.close();
1959
2185
  this._server = null;
2186
+ log("stop: server closed", 0 /* DEBUG */);
1960
2187
  }
1961
2188
  this._wasmModules = null;
2189
+ log("stop: wasm resources released", 0 /* DEBUG */);
1962
2190
  const pidPath = (0, import_node_path9.join)((0, import_node_os2.tmpdir)(), `kbdb-${this.ctx}.pid`);
1963
2191
  try {
1964
2192
  (0, import_node_fs8.unlinkSync)(pidPath);
2193
+ log("stop: pid file removed", 0 /* DEBUG */);
1965
2194
  } catch {
1966
2195
  }
1967
2196
  const ipcPath = getIpcPath(this.ctx);
1968
2197
  try {
1969
2198
  (0, import_node_fs8.unlinkSync)(ipcPath);
2199
+ log("stop: socket file removed", 0 /* DEBUG */);
1970
2200
  } catch {
1971
2201
  }
1972
2202
  const crashPath = (0, import_node_path9.join)((0, import_node_os2.tmpdir)(), `kbdb-${this.ctx}.crash`);
@@ -1974,6 +2204,7 @@ var WorkerDaemon = class {
1974
2204
  (0, import_node_fs8.unlinkSync)(crashPath);
1975
2205
  } catch {
1976
2206
  }
2207
+ log("stop: daemon exiting", 0 /* DEBUG */);
1977
2208
  process.exit(0);
1978
2209
  }
1979
2210
  /**
@@ -1987,8 +2218,16 @@ var WorkerDaemon = class {
1987
2218
  * @returns the JSON-RPC response
1988
2219
  */
1989
2220
  async handleRequest(request) {
2221
+ log(
2222
+ "handle-request: method=" + request.method + " id=" + String(request.id),
2223
+ 0 /* DEBUG */
2224
+ );
1990
2225
  const params = request.params;
1991
2226
  if (params === void 0 || params.ctx !== this.ctx) {
2227
+ log(
2228
+ "handle-request: context mismatch id=" + String(request.id),
2229
+ 0 /* DEBUG */
2230
+ );
1992
2231
  return this.errorResponse(
1993
2232
  request.id,
1994
2233
  -32001,
@@ -1999,6 +2238,10 @@ var WorkerDaemon = class {
1999
2238
  try {
2000
2239
  const result = await this.dispatch(request.method, params);
2001
2240
  this._idleAt = Math.floor(Date.now() / 1e3);
2241
+ log(
2242
+ "handle-request: success method=" + request.method + " id=" + String(request.id),
2243
+ 0 /* DEBUG */
2244
+ );
2002
2245
  return {
2003
2246
  jsonrpc: "2.0",
2004
2247
  id: request.id,
@@ -2007,6 +2250,10 @@ var WorkerDaemon = class {
2007
2250
  } catch (err) {
2008
2251
  this._idleAt = Math.floor(Date.now() / 1e3);
2009
2252
  if (err instanceof IpcError2) {
2253
+ log(
2254
+ "handle-request: ipc error method=" + request.method + " id=" + String(request.id) + " code=" + String(err.code),
2255
+ 0 /* DEBUG */
2256
+ );
2010
2257
  return this.errorResponse(
2011
2258
  request.id,
2012
2259
  err.code,
@@ -2014,6 +2261,10 @@ var WorkerDaemon = class {
2014
2261
  );
2015
2262
  }
2016
2263
  const message = err instanceof Error ? err.message : String(err);
2264
+ log(
2265
+ "handle-request: error method=" + request.method + " id=" + String(request.id),
2266
+ 0 /* DEBUG */
2267
+ );
2017
2268
  return this.errorResponse(request.id, -32e3, message);
2018
2269
  }
2019
2270
  }
@@ -2057,7 +2308,15 @@ var WorkerDaemon = class {
2057
2308
  clearTimeout(this._idleTimer);
2058
2309
  }
2059
2310
  if (this._connectionCount === 0) {
2311
+ log(
2312
+ "idle timer started (" + String(this.config.timeoutMs) + "ms)",
2313
+ 0 /* DEBUG */
2314
+ );
2060
2315
  this._idleTimer = setTimeout(() => {
2316
+ log(
2317
+ "idle timer fired: shutting down ctx=" + this.ctx,
2318
+ 0 /* DEBUG */
2319
+ );
2061
2320
  this.stop();
2062
2321
  }, this.config.timeoutMs);
2063
2322
  }
@@ -2069,25 +2328,25 @@ var WorkerDaemon = class {
2069
2328
  try {
2070
2329
  text = (0, import_node_fs8.readFileSync)(catalogPath, "utf-8");
2071
2330
  } catch {
2072
- throw new Error(
2073
- `cannot read database directory: ${this.targetDir} -- permission denied`
2074
- );
2331
+ const msg = `cannot read database directory: ${this.targetDir} -- permission denied`;
2332
+ log(msg, 3 /* ERROR */);
2333
+ throw new Error(msg);
2075
2334
  }
2076
2335
  const version = parseCatalogVersion(text);
2077
2336
  if (version === null) {
2078
- throw new Error(
2079
- "database version 0 requires migration to version " + String(DB_FORMAT_VERSION) + " -- run `kbdb --migrate` before starting the daemon"
2080
- );
2337
+ const msg = "database version 0 requires migration to version " + String(DB_FORMAT_VERSION) + " -- run `kbdb --migrate` before starting the daemon";
2338
+ log(msg, 3 /* ERROR */);
2339
+ throw new Error(msg);
2081
2340
  }
2082
2341
  if (version > DB_FORMAT_VERSION) {
2083
- throw new Error(
2084
- "database version " + String(version) + " is newer than kbdb version " + String(DB_FORMAT_VERSION) + " -- upgrade kbdb to open this database"
2085
- );
2342
+ const msg = "database version " + String(version) + " is newer than kbdb version " + String(DB_FORMAT_VERSION) + " -- upgrade kbdb to open this database";
2343
+ log(msg, 3 /* ERROR */);
2344
+ throw new Error(msg);
2086
2345
  }
2087
2346
  if (version < DB_FORMAT_VERSION) {
2088
- throw new Error(
2089
- "database version " + String(version) + " requires migration to version " + String(DB_FORMAT_VERSION) + " -- run `kbdb --migrate` before starting the daemon"
2090
- );
2347
+ const msg = "database version " + String(version) + " requires migration to version " + String(DB_FORMAT_VERSION) + " -- run `kbdb --migrate` before starting the daemon";
2348
+ log(msg, 3 /* ERROR */);
2349
+ throw new Error(msg);
2091
2350
  }
2092
2351
  }
2093
2352
  /** Builds a JSON-RPC error response. */
@@ -2603,8 +2862,13 @@ var WorkerDaemon = class {
2603
2862
  acquireWriteLock() {
2604
2863
  if (!this._writeLocked) {
2605
2864
  this._writeLocked = true;
2865
+ log("write-lock: acquired", 0 /* DEBUG */);
2606
2866
  return Promise.resolve();
2607
2867
  }
2868
+ log(
2869
+ "write-lock: queued depth=" + String(this._writeQueue.length + 1),
2870
+ 0 /* DEBUG */
2871
+ );
2608
2872
  return new Promise((resolve2) => {
2609
2873
  this._writeQueue.push({ resolve: resolve2 });
2610
2874
  });
@@ -2618,9 +2882,14 @@ var WorkerDaemon = class {
2618
2882
  releaseWriteLock() {
2619
2883
  const next = this._writeQueue.shift();
2620
2884
  if (next !== void 0) {
2885
+ log(
2886
+ "write-lock: released to next waiter depth=" + String(this._writeQueue.length),
2887
+ 0 /* DEBUG */
2888
+ );
2621
2889
  next.resolve();
2622
2890
  } else {
2623
2891
  this._writeLocked = false;
2892
+ log("write-lock: released", 0 /* DEBUG */);
2624
2893
  }
2625
2894
  }
2626
2895
  // -- WASM lifecycle --
@@ -2645,26 +2914,29 @@ var WorkerDaemon = class {
2645
2914
  this._integrityOk = kv["ok"] === "true";
2646
2915
  if (!this._integrityOk) {
2647
2916
  this._integrityErrors = Object.entries(kv).filter(([k]) => k !== "ok").map(([k, v]) => `${k}=${v}`);
2648
- console.error(
2649
- "[kbdb-worker] startup integrity check failed:",
2650
- this._integrityErrors.join(", ")
2917
+ log(
2918
+ "[kbdb-worker] startup integrity check failed: " + this._integrityErrors.join(", "),
2919
+ 2 /* WARNING */
2651
2920
  );
2652
2921
  }
2653
2922
  } catch {
2654
2923
  this._integrityOk = false;
2655
2924
  this._integrityErrors = ["integrity_check_failed"];
2656
- console.error(
2657
- "[kbdb-worker] startup integrity check threw an error"
2925
+ log(
2926
+ "[kbdb-worker] startup integrity check threw an error",
2927
+ 2 /* WARNING */
2658
2928
  );
2659
2929
  }
2660
2930
  }
2661
2931
  // -- WASM bridge primitives --
2662
2932
  getExport(name) {
2663
2933
  if (this._wasmModules === null) {
2934
+ log("WASM modules not loaded", 3 /* ERROR */);
2664
2935
  throw new Error("WASM modules not loaded");
2665
2936
  }
2666
2937
  const fn = this._wasmModules.kbWorker.exports[name];
2667
2938
  if (typeof fn !== "function") {
2939
+ log(`WASM export not found: ${name}`, 3 /* ERROR */);
2668
2940
  throw new Error(`WASM export not found: ${name}`);
2669
2941
  }
2670
2942
  return fn;
@@ -2688,6 +2960,7 @@ var WorkerDaemon = class {
2688
2960
  if (!memory) return;
2689
2961
  const memView = new Uint8Array(memory.buffer);
2690
2962
  if (ptr + data.length > memView.length) {
2963
+ log("WASM memory overflow", 3 /* ERROR */);
2691
2964
  throw new Error("WASM memory overflow");
2692
2965
  }
2693
2966
  memView.set(data, ptr);
@@ -2799,9 +3072,18 @@ function parseCatalogVersion(text) {
2799
3072
 
2800
3073
  // src/shared/worker-daemon/functions/start-daemon.function.ts
2801
3074
  async function startDaemon(contextPath, wasmDir2) {
3075
+ log(
3076
+ "start-daemon: entry contextPath=" + contextPath,
3077
+ 0 /* DEBUG */
3078
+ );
2802
3079
  const config = readConfig(contextPath);
3080
+ log(
3081
+ "start-daemon: config loaded timeoutMs=" + String(config.timeoutMs) + " embedding=" + (config.embedding?.provider ?? "none"),
3082
+ 0 /* DEBUG */
3083
+ );
2803
3084
  const hash = await computeSha256(contextPath);
2804
3085
  const contextId = hash.slice(0, 16);
3086
+ log("start-daemon: contextId=" + contextId, 0 /* DEBUG */);
2805
3087
  const daemon = new WorkerDaemon(
2806
3088
  contextId,
2807
3089
  contextPath,
@@ -2812,22 +3094,30 @@ async function startDaemon(contextPath, wasmDir2) {
2812
3094
  daemon.checkPreconditions();
2813
3095
  } catch (err) {
2814
3096
  const message = err instanceof Error ? err.message : String(err);
2815
- console.error(`kbdb-worker: ${message}`);
3097
+ log(`kbdb-worker: ${message}`, 3 /* ERROR */);
2816
3098
  writeCrashLog(contextId, message);
2817
3099
  process.exit(1);
2818
3100
  }
3101
+ log("preconditions passed", 0 /* DEBUG */);
2819
3102
  try {
2820
3103
  await daemon.start();
2821
3104
  } catch (err) {
2822
3105
  const message = err instanceof Error ? err.message : String(err);
2823
- console.error(`kbdb-worker: ${message}`);
3106
+ log(`kbdb-worker: ${message}`, 3 /* ERROR */);
2824
3107
  writeCrashLog(contextId, message);
2825
3108
  process.exit(1);
2826
3109
  }
3110
+ log("daemon started", 1 /* INFO */);
3111
+ log(
3112
+ "start-daemon: registering SIGTERM/SIGINT handlers",
3113
+ 0 /* DEBUG */
3114
+ );
2827
3115
  process.on("SIGTERM", () => {
3116
+ log("start-daemon: SIGTERM received", 0 /* DEBUG */);
2828
3117
  daemon.stop();
2829
3118
  });
2830
3119
  process.on("SIGINT", () => {
3120
+ log("start-daemon: SIGINT received", 0 /* DEBUG */);
2831
3121
  daemon.stop();
2832
3122
  });
2833
3123
  }
@@ -2845,11 +3135,24 @@ function writeCrashLog(contextId, message) {
2845
3135
 
2846
3136
  // src/shared/worker-daemon/functions/run-worker.function.ts
2847
3137
  var import_node_path11 = require("node:path");
2848
- async function runWorker(argv, deps) {
2849
- const contextPath = argv[0];
3138
+
3139
+ // src/shared/log/functions/parse-log-level.function.ts
3140
+ var LOG_LEVEL_MAP = {
3141
+ debug: 0 /* DEBUG */,
3142
+ info: 1 /* INFO */,
3143
+ warning: 2 /* WARNING */,
3144
+ error: 3 /* ERROR */
3145
+ };
3146
+ function parseLogLevel(value) {
3147
+ return LOG_LEVEL_MAP[value.toLowerCase()] ?? 2 /* WARNING */;
3148
+ }
3149
+
3150
+ // src/shared/worker-daemon/functions/run-worker.function.ts
3151
+ async function runWorker(argv2, deps) {
3152
+ const { contextPath, logLevel } = parseWorkerArgs(argv2);
2850
3153
  if (!contextPath) {
2851
3154
  return {
2852
- error: "usage: kbdb-worker <context-path>",
3155
+ error: "usage: kbdb-worker <context-path> [--log-level <level>]",
2853
3156
  exitCode: 1
2854
3157
  };
2855
3158
  }
@@ -2861,28 +3164,85 @@ async function runWorker(argv, deps) {
2861
3164
  };
2862
3165
  }
2863
3166
  await deps.startDaemon(resolved, deps.wasmDir);
2864
- return { exitCode: 0 };
3167
+ return { exitCode: 0, logLevel };
3168
+ }
3169
+ function parseWorkerArgs(argv2) {
3170
+ let contextPath;
3171
+ let logLevel;
3172
+ for (let i = 0; i < argv2.length; i++) {
3173
+ if (argv2[i] === "--log-level" && argv2[i + 1]) {
3174
+ logLevel = parseLogLevel(argv2[++i]);
3175
+ } else if (!contextPath) {
3176
+ contextPath = argv2[i];
3177
+ }
3178
+ }
3179
+ return { contextPath, logLevel };
3180
+ }
3181
+
3182
+ // src/shared/log/functions/resolve-log-level.function.ts
3183
+ function resolveLogLevel(cliLevel) {
3184
+ if (cliLevel !== void 0) {
3185
+ return cliLevel;
3186
+ }
3187
+ const envValue = process.env["KBDB_LOG_LEVEL"];
3188
+ if (envValue !== void 0) {
3189
+ return parseLogLevel(envValue);
3190
+ }
3191
+ return DEFAULT_LOG_LEVEL;
3192
+ }
3193
+
3194
+ // src/shared/log/functions/configure-log.function.ts
3195
+ function configureLog(config) {
3196
+ setLogLevel(config.level);
3197
+ if (config.outputs === void 0) {
3198
+ return;
3199
+ }
3200
+ const levels = [
3201
+ 0 /* DEBUG */,
3202
+ 1 /* INFO */,
3203
+ 2 /* WARNING */,
3204
+ 3 /* ERROR */
3205
+ ];
3206
+ for (const level of levels) {
3207
+ const output = config.outputs[level];
3208
+ if (output !== void 0) {
3209
+ setLogOutput(level, output.write);
3210
+ }
3211
+ }
2865
3212
  }
2866
3213
 
2867
3214
  // src/worker.ts
2868
3215
  var import_meta = {};
2869
3216
  var baseDir = resolveBaseDir(import_meta.url, import_meta.dirname);
2870
3217
  var wasmDir = resolveWasmDir(baseDir.scriptDir);
3218
+ var argv = getArgs();
3219
+ var cliLogLevel = extractLogLevel(argv);
3220
+ configureLog({ level: resolveLogLevel(cliLogLevel) });
3221
+ log("daemon process starting", 0 /* DEBUG */);
2871
3222
  async function main() {
2872
- const result = await runWorker(getArgs(), {
3223
+ const result = await runWorker(argv, {
2873
3224
  existsSync: import_node_fs10.existsSync,
2874
3225
  startDaemon,
2875
3226
  wasmDir
2876
3227
  });
2877
3228
  if (result.error) {
2878
- console.error(result.error);
3229
+ log(result.error, 3 /* ERROR */);
2879
3230
  }
2880
3231
  if (result.exitCode !== 0) {
2881
3232
  process.exitCode = result.exitCode;
2882
3233
  }
2883
3234
  }
2884
3235
  main().catch((err) => {
2885
- console.error(err);
3236
+ const msg = err instanceof Error ? err.message : String(err);
3237
+ log(msg, 3 /* ERROR */);
2886
3238
  process.exitCode = 1;
2887
3239
  });
3240
+ function extractLogLevel(args) {
3241
+ for (let i = 0; i < args.length; i++) {
3242
+ if (args[i] === "--log-level" && args[i + 1]) {
3243
+ return parseLogLevel(args[i + 1]);
3244
+ }
3245
+ }
3246
+ return void 0;
3247
+ }
2888
3248
  //# sourceMappingURL=kbdb-worker.cjs.map