sensemaking 0.24.4 → 0.24.6

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 (130) hide show
  1. package/README.md +16 -12
  2. package/dist/cjs/cli/status.js +14 -24
  3. package/dist/cjs/cli/status.js.map +1 -1
  4. package/dist/cjs/commands/search.js +22 -0
  5. package/dist/cjs/commands/search.js.map +1 -1
  6. package/dist/cjs/config/types.js.map +1 -1
  7. package/dist/cjs/errors.d.cts +1 -1
  8. package/dist/cjs/errors.d.ts +1 -1
  9. package/dist/cjs/errors.js.map +1 -1
  10. package/dist/cjs/lib/watch-notification.d.cts +1 -0
  11. package/dist/cjs/lib/watch-notification.d.ts +1 -0
  12. package/dist/cjs/lib/watch-notification.js +15 -0
  13. package/dist/cjs/lib/watch-notification.js.map +1 -0
  14. package/dist/cjs/lib/worker-file.d.cts +1 -0
  15. package/dist/cjs/lib/worker-file.d.ts +1 -0
  16. package/dist/cjs/lib/worker-file.js +34 -0
  17. package/dist/cjs/lib/worker-file.js.map +1 -0
  18. package/dist/cjs/output/search-error.js +38 -0
  19. package/dist/cjs/output/search-error.js.map +1 -1
  20. package/dist/cjs/scan/pool.js +2 -23
  21. package/dist/cjs/scan/pool.js.map +1 -1
  22. package/dist/cjs/store/builder.d.cts +2 -1
  23. package/dist/cjs/store/builder.d.ts +2 -1
  24. package/dist/cjs/store/builder.js +4 -4
  25. package/dist/cjs/store/builder.js.map +1 -1
  26. package/dist/cjs/store/duckdb/lexical.d.cts +1 -0
  27. package/dist/cjs/store/duckdb/lexical.d.ts +1 -0
  28. package/dist/cjs/store/duckdb/lexical.js +28 -9
  29. package/dist/cjs/store/duckdb/lexical.js.map +1 -1
  30. package/dist/cjs/store/duckdb/native.d.cts +2 -0
  31. package/dist/cjs/store/duckdb/native.d.ts +2 -0
  32. package/dist/cjs/store/duckdb/native.js +11 -1
  33. package/dist/cjs/store/duckdb/native.js.map +1 -1
  34. package/dist/cjs/store/duckdb/ordered-bm25.d.cts +17 -0
  35. package/dist/cjs/store/duckdb/ordered-bm25.d.ts +17 -0
  36. package/dist/cjs/store/duckdb/ordered-bm25.js +238 -0
  37. package/dist/cjs/store/duckdb/ordered-bm25.js.map +1 -0
  38. package/dist/cjs/store/lock-wait.d.cts +2 -2
  39. package/dist/cjs/store/lock-wait.d.ts +2 -2
  40. package/dist/cjs/store/lock-wait.js +14 -11
  41. package/dist/cjs/store/lock-wait.js.map +1 -1
  42. package/dist/cjs/store/native.d.cts +4 -0
  43. package/dist/cjs/store/native.d.ts +4 -0
  44. package/dist/cjs/store/native.js +64 -9
  45. package/dist/cjs/store/native.js.map +1 -1
  46. package/dist/cjs/store/open.js +11 -7
  47. package/dist/cjs/store/open.js.map +1 -1
  48. package/dist/cjs/store/reconcile.d.cts +5 -1
  49. package/dist/cjs/store/reconcile.d.ts +5 -1
  50. package/dist/cjs/store/reconcile.js +5 -4
  51. package/dist/cjs/store/reconcile.js.map +1 -1
  52. package/dist/cjs/store/turso/lexical.js +5 -1
  53. package/dist/cjs/store/turso/lexical.js.map +1 -1
  54. package/dist/cjs/text/segment.js +168 -3
  55. package/dist/cjs/text/segment.js.map +1 -1
  56. package/dist/cjs/watch-claim.d.cts +39 -0
  57. package/dist/cjs/watch-claim.d.ts +39 -0
  58. package/dist/cjs/watch-claim.js +446 -0
  59. package/dist/cjs/watch-claim.js.map +1 -0
  60. package/dist/cjs/watch.js +246 -147
  61. package/dist/cjs/watch.js.map +1 -1
  62. package/dist/cjs/workers/watch-heartbeat.d.cts +1 -0
  63. package/dist/cjs/workers/watch-heartbeat.d.ts +1 -0
  64. package/dist/cjs/workers/watch-heartbeat.js +308 -0
  65. package/dist/cjs/workers/watch-heartbeat.js.map +1 -0
  66. package/dist/esm/cli/status.js +6 -5
  67. package/dist/esm/cli/status.js.map +1 -1
  68. package/dist/esm/commands/search.js +21 -0
  69. package/dist/esm/commands/search.js.map +1 -1
  70. package/dist/esm/config/types.js.map +1 -1
  71. package/dist/esm/errors.d.ts +1 -1
  72. package/dist/esm/errors.js.map +1 -1
  73. package/dist/esm/lib/watch-notification.d.ts +1 -0
  74. package/dist/esm/lib/watch-notification.js +4 -0
  75. package/dist/esm/lib/watch-notification.js.map +1 -0
  76. package/dist/esm/lib/worker-file.d.ts +1 -0
  77. package/dist/esm/lib/worker-file.js +24 -0
  78. package/dist/esm/lib/worker-file.js.map +1 -0
  79. package/dist/esm/output/search-error.js +21 -0
  80. package/dist/esm/output/search-error.js.map +1 -1
  81. package/dist/esm/scan/pool.js +2 -22
  82. package/dist/esm/scan/pool.js.map +1 -1
  83. package/dist/esm/store/builder.d.ts +2 -1
  84. package/dist/esm/store/builder.js +4 -4
  85. package/dist/esm/store/builder.js.map +1 -1
  86. package/dist/esm/store/duckdb/lexical.d.ts +1 -0
  87. package/dist/esm/store/duckdb/lexical.js +16 -7
  88. package/dist/esm/store/duckdb/lexical.js.map +1 -1
  89. package/dist/esm/store/duckdb/native.d.ts +2 -0
  90. package/dist/esm/store/duckdb/native.js +5 -1
  91. package/dist/esm/store/duckdb/native.js.map +1 -1
  92. package/dist/esm/store/duckdb/ordered-bm25.d.ts +17 -0
  93. package/dist/esm/store/duckdb/ordered-bm25.js +56 -0
  94. package/dist/esm/store/duckdb/ordered-bm25.js.map +1 -0
  95. package/dist/esm/store/lock-wait.d.ts +2 -2
  96. package/dist/esm/store/lock-wait.js +17 -14
  97. package/dist/esm/store/lock-wait.js.map +1 -1
  98. package/dist/esm/store/native.d.ts +4 -0
  99. package/dist/esm/store/native.js +60 -6
  100. package/dist/esm/store/native.js.map +1 -1
  101. package/dist/esm/store/open.js +9 -6
  102. package/dist/esm/store/open.js.map +1 -1
  103. package/dist/esm/store/reconcile.d.ts +5 -1
  104. package/dist/esm/store/reconcile.js +4 -3
  105. package/dist/esm/store/reconcile.js.map +1 -1
  106. package/dist/esm/store/turso/lexical.js +5 -1
  107. package/dist/esm/store/turso/lexical.js.map +1 -1
  108. package/dist/esm/text/segment.js +130 -4
  109. package/dist/esm/text/segment.js.map +1 -1
  110. package/dist/esm/watch-claim.d.ts +39 -0
  111. package/dist/esm/watch-claim.js +176 -0
  112. package/dist/esm/watch-claim.js.map +1 -0
  113. package/dist/esm/watch.js +169 -118
  114. package/dist/esm/watch.js.map +1 -1
  115. package/dist/esm/workers/watch-heartbeat.d.ts +1 -0
  116. package/dist/esm/workers/watch-heartbeat.js +106 -0
  117. package/dist/esm/workers/watch-heartbeat.js.map +1 -0
  118. package/package.json +2 -2
  119. package/skills/sense/SKILL.md +105 -104
  120. package/skills/sense/references/search.md +47 -0
  121. package/skills/sense/references/sql.md +120 -0
  122. package/skills/sense/references/stores/duckdb.md +35 -0
  123. package/skills/sense/references/stores/sqlite.md +66 -0
  124. package/skills/sense/references/stores/turso.md +36 -0
  125. package/skills/sense-setup/SKILL.md +93 -34
  126. package/skills/sense-setup/references/embeddings.md +51 -0
  127. package/skills/sense-setup/references/store-benchmarks.md +16 -0
  128. package/skills/sense-setup/references/stores/duckdb.md +28 -0
  129. package/skills/sense-setup/references/stores/sqlite.md +21 -0
  130. package/skills/sense-setup/references/stores/turso.md +25 -0
@@ -24,28 +24,31 @@ var _indexts = require("../config/index.js");
24
24
  var SIDECAR_FILENAME = 'lock-wait.json';
25
25
  var FLOOR_MS = 5000;
26
26
  var CEILING_MS = 600000;
27
- function sidecarPath(baseDir) {
28
- return (0, _nodepath.join)(baseDir, _indexts.STATE_DIR, SIDECAR_FILENAME);
27
+ function sidecarPath(configDir) {
28
+ return (0, _nodepath.join)(configDir, _indexts.STATE_DIR, SIDECAR_FILENAME);
29
29
  }
30
- function readRecordedMs(baseDir) {
30
+ function readRecordedMs(configDir) {
31
31
  try {
32
- var raw = JSON.parse((0, _nodefs.readFileSync)(sidecarPath(baseDir), 'utf8'));
33
- return typeof raw.reconcile_max_ms === 'number' ? raw.reconcile_max_ms : 0;
32
+ var raw = JSON.parse((0, _nodefs.readFileSync)(sidecarPath(configDir), 'utf8'));
33
+ var value = raw.reconcile_max_ms;
34
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;
34
35
  } catch (unused) {
35
- return 0;
36
+ return undefined;
36
37
  }
37
38
  }
38
- function recordLockWaitMs(baseDir, ms) {
39
- if (ms <= readRecordedMs(baseDir)) return;
39
+ function recordLockWaitMs(configDir, ms) {
40
+ var recordedMs = readRecordedMs(configDir);
41
+ if (recordedMs !== undefined && ms <= recordedMs) return;
40
42
  try {
41
- (0, _nodefs.writeFileSync)(sidecarPath(baseDir), JSON.stringify({
43
+ (0, _nodefs.writeFileSync)(sidecarPath(configDir), JSON.stringify({
42
44
  reconcile_max_ms: ms
43
45
  }));
44
46
  } catch (unused) {
45
47
  // Best-effort: a write failure here only narrows the next waiter's budget back to the floor.
46
48
  }
47
49
  }
48
- function lockWaitBudgetMs(baseDir) {
49
- return Math.min(Math.max(FLOOR_MS, 3 * readRecordedMs(baseDir)), CEILING_MS);
50
+ function lockWaitBudgetMs(configDir) {
51
+ var _readRecordedMs;
52
+ return Math.min(Math.max(FLOOR_MS, 3 * ((_readRecordedMs = readRecordedMs(configDir)) !== null && _readRecordedMs !== void 0 ? _readRecordedMs : 0)), CEILING_MS);
50
53
  }
51
54
  /* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/lock-wait.ts"],"sourcesContent":["import { readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { STATE_DIR } from '../config/index.ts';\n\n// duckdb/turso lock the cache file exclusively, so a waiter can't connect and read reconcile_max_ms\n// from meta; this sidecar is plain fs, readable while locked. Same derivation as busy_timeout (open.ts).\nconst SIDECAR_FILENAME = 'lock-wait.json';\nconst FLOOR_MS = 5_000;\nconst CEILING_MS = 600_000;\n\nfunction sidecarPath(baseDir: string): string {\n return join(baseDir, STATE_DIR, SIDECAR_FILENAME);\n}\n\nfunction readRecordedMs(baseDir: string): number {\n try {\n const raw = JSON.parse(readFileSync(sidecarPath(baseDir), 'utf8'));\n return typeof raw.reconcile_max_ms === 'number' ? raw.reconcile_max_ms : 0;\n } catch {\n return 0;\n }\n}\n\n// Called after every reconcile's write transaction, every store alike, so a fresh duckdb/turso\n// tree starts building this the first time anything writes.\nexport function recordLockWaitMs(baseDir: string, ms: number): void {\n if (ms <= readRecordedMs(baseDir)) return;\n try {\n writeFileSync(sidecarPath(baseDir), JSON.stringify({ reconcile_max_ms: ms }));\n } catch {\n // Best-effort: a write failure here only narrows the next waiter's budget back to the floor.\n }\n}\n\n// 3x the largest reconcile this tree has recorded, floored and capped -- a waiter outlasts a\n// real reconcile and still fails behind a hung one.\nexport function lockWaitBudgetMs(baseDir: string): number {\n return Math.min(Math.max(FLOOR_MS, 3 * readRecordedMs(baseDir)), CEILING_MS);\n}\n"],"names":["lockWaitBudgetMs","recordLockWaitMs","SIDECAR_FILENAME","FLOOR_MS","CEILING_MS","sidecarPath","baseDir","join","STATE_DIR","readRecordedMs","raw","JSON","parse","readFileSync","reconcile_max_ms","ms","writeFileSync","stringify","Math","min","max"],"mappings":";;;;;;;;;;;QAoCgBA;eAAAA;;QAXAC;eAAAA;;;sBAzB4B;wBACvB;uBACK;AAE1B,oGAAoG;AACpG,yGAAyG;AACzG,IAAMC,mBAAmB;AACzB,IAAMC,WAAW;AACjB,IAAMC,aAAa;AAEnB,SAASC,YAAYC,OAAe;IAClC,OAAOC,IAAAA,cAAI,EAACD,SAASE,kBAAS,EAAEN;AAClC;AAEA,SAASO,eAAeH,OAAe;IACrC,IAAI;QACF,IAAMI,MAAMC,KAAKC,KAAK,CAACC,IAAAA,oBAAY,EAACR,YAAYC,UAAU;QAC1D,OAAO,OAAOI,IAAII,gBAAgB,KAAK,WAAWJ,IAAII,gBAAgB,GAAG;IAC3E,EAAE,eAAM;QACN,OAAO;IACT;AACF;AAIO,SAASb,iBAAiBK,OAAe,EAAES,EAAU;IAC1D,IAAIA,MAAMN,eAAeH,UAAU;IACnC,IAAI;QACFU,IAAAA,qBAAa,EAACX,YAAYC,UAAUK,KAAKM,SAAS,CAAC;YAAEH,kBAAkBC;QAAG;IAC5E,EAAE,eAAM;IACN,6FAA6F;IAC/F;AACF;AAIO,SAASf,iBAAiBM,OAAe;IAC9C,OAAOY,KAAKC,GAAG,CAACD,KAAKE,GAAG,CAACjB,UAAU,IAAIM,eAAeH,WAAWF;AACnE"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/lock-wait.ts"],"sourcesContent":["import { readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { STATE_DIR } from '../config/index.ts';\n\n// duckdb/turso lock the cache file exclusively, so a waiter can't connect and read reconcile_max_ms\n// from meta; this sidecar is plain fs, readable while locked. Same derivation as busy_timeout (open.ts).\nconst SIDECAR_FILENAME = 'lock-wait.json';\nconst FLOOR_MS = 5_000;\nconst CEILING_MS = 600_000;\n\nfunction sidecarPath(configDir: string): string {\n return join(configDir, STATE_DIR, SIDECAR_FILENAME);\n}\n\nfunction readRecordedMs(configDir: string): number | undefined {\n try {\n const raw = JSON.parse(readFileSync(sidecarPath(configDir), 'utf8'));\n const value = raw.reconcile_max_ms;\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;\n } catch {\n return undefined;\n }\n}\n\n// Called after every reconcile's write transaction, every store alike, so a fresh cache records\n// its first write even when the measured duration is zero.\nexport function recordLockWaitMs(configDir: string, ms: number): void {\n const recordedMs = readRecordedMs(configDir);\n if (recordedMs !== undefined && ms <= recordedMs) return;\n try {\n writeFileSync(sidecarPath(configDir), JSON.stringify({ reconcile_max_ms: ms }));\n } catch {\n // Best-effort: a write failure here only narrows the next waiter's budget back to the floor.\n }\n}\n\n// 3x the largest reconcile this cache has recorded, floored and capped -- a waiter outlasts a\n// real reconcile and still fails behind a hung one.\nexport function lockWaitBudgetMs(configDir: string): number {\n return Math.min(Math.max(FLOOR_MS, 3 * (readRecordedMs(configDir) ?? 0)), CEILING_MS);\n}\n"],"names":["lockWaitBudgetMs","recordLockWaitMs","SIDECAR_FILENAME","FLOOR_MS","CEILING_MS","sidecarPath","configDir","join","STATE_DIR","readRecordedMs","raw","JSON","parse","readFileSync","value","reconcile_max_ms","Number","isFinite","undefined","ms","recordedMs","writeFileSync","stringify","Math","min","max"],"mappings":";;;;;;;;;;;QAsCgBA;eAAAA;;QAZAC;eAAAA;;;sBA1B4B;wBACvB;uBACK;AAE1B,oGAAoG;AACpG,yGAAyG;AACzG,IAAMC,mBAAmB;AACzB,IAAMC,WAAW;AACjB,IAAMC,aAAa;AAEnB,SAASC,YAAYC,SAAiB;IACpC,OAAOC,IAAAA,cAAI,EAACD,WAAWE,kBAAS,EAAEN;AACpC;AAEA,SAASO,eAAeH,SAAiB;IACvC,IAAI;QACF,IAAMI,MAAMC,KAAKC,KAAK,CAACC,IAAAA,oBAAY,EAACR,YAAYC,YAAY;QAC5D,IAAMQ,QAAQJ,IAAIK,gBAAgB;QAClC,OAAO,OAAOD,UAAU,YAAYE,OAAOC,QAAQ,CAACH,UAAUA,SAAS,IAAIA,QAAQI;IACrF,EAAE,eAAM;QACN,OAAOA;IACT;AACF;AAIO,SAASjB,iBAAiBK,SAAiB,EAAEa,EAAU;IAC5D,IAAMC,aAAaX,eAAeH;IAClC,IAAIc,eAAeF,aAAaC,MAAMC,YAAY;IAClD,IAAI;QACFC,IAAAA,qBAAa,EAAChB,YAAYC,YAAYK,KAAKW,SAAS,CAAC;YAAEP,kBAAkBI;QAAG;IAC9E,EAAE,eAAM;IACN,6FAA6F;IAC/F;AACF;AAIO,SAASnB,iBAAiBM,SAAiB;QACRG;IAAxC,OAAOc,KAAKC,GAAG,CAACD,KAAKE,GAAG,CAACtB,UAAU,MAAKM,kBAAAA,eAAeH,wBAAfG,6BAAAA,kBAA6B,KAAKL;AAC5E"}
@@ -2,6 +2,10 @@ export interface NativeDescriptor {
2
2
  store: string;
3
3
  pkg: string;
4
4
  sizeHint: string;
5
+ /** Optional exact package version required by this native binding. */
6
+ version?: string;
7
+ /** npm specifier used only when installation is required (imports stay bare). */
8
+ installSpec?: string;
5
9
  }
6
10
  export declare function packageNodeModules(): string;
7
11
  export declare function loadOrInstall<T>(descriptor: NativeDescriptor, nodeModulesPath: string, importName?: string): Promise<T>;
@@ -2,6 +2,10 @@ export interface NativeDescriptor {
2
2
  store: string;
3
3
  pkg: string;
4
4
  sizeHint: string;
5
+ /** Optional exact package version required by this native binding. */
6
+ version?: string;
7
+ /** npm specifier used only when installation is required (imports stay bare). */
8
+ installSpec?: string;
5
9
  }
6
10
  export declare function packageNodeModules(): string;
7
11
  export declare function loadOrInstall<T>(descriptor: NativeDescriptor, nodeModulesPath: string, importName?: string): Promise<T>;
@@ -253,14 +253,62 @@ function resolveEntrySpecifier(importName, nodeModulesPath) {
253
253
  var entryPath = (0, _nodepath.join)(pkgDir, entry);
254
254
  return typeof require === 'undefined' ? (0, _nodeurl.pathToFileURL)(entryPath).href : entryPath;
255
255
  }
256
+ function readPackageMetadata(pkgDir) {
257
+ try {
258
+ return JSON.parse((0, _nodefs.readFileSync)((0, _nodepath.join)(pkgDir, 'package.json'), 'utf8'));
259
+ } catch (unused) {
260
+ return undefined;
261
+ }
262
+ }
263
+ function targetPackageMetadata(importName, nodeModulesPath) {
264
+ var pkgDir = _nodepath.join.apply(void 0, [
265
+ nodeModulesPath
266
+ ].concat(_to_consumable_array(importName.split('/'))));
267
+ return {
268
+ exists: (0, _nodefs.existsSync)(pkgDir),
269
+ metadata: readPackageMetadata(pkgDir)
270
+ };
271
+ }
272
+ function resolvedPackageMetadata(importName) {
273
+ try {
274
+ var dir = (0, _nodepath.dirname)(_require.resolve(importName));
275
+ for(;;){
276
+ var manifest = (0, _nodepath.join)(dir, 'package.json');
277
+ if ((0, _nodefs.existsSync)(manifest)) {
278
+ var pkg = readPackageMetadata(dir);
279
+ if (!pkg) return undefined;
280
+ if (pkg.name === importName) return pkg;
281
+ }
282
+ var parent = (0, _nodepath.dirname)(dir);
283
+ if (parent === dir) return undefined;
284
+ dir = parent;
285
+ }
286
+ } catch (unused) {
287
+ return undefined;
288
+ }
289
+ }
290
+ function versionContractError(descriptor, installed) {
291
+ var _descriptor_installSpec;
292
+ var installSpec = (_descriptor_installSpec = descriptor.installSpec) !== null && _descriptor_installSpec !== void 0 ? _descriptor_installSpec : descriptor.pkg;
293
+ var detail = installed ? "".concat(descriptor.pkg, "@").concat(installed, " is installed") : "".concat(descriptor.pkg, " has missing or unreadable version metadata");
294
+ return new _errorsts.SenseError('STORE_DEPENDENCY_MISSING', 'store "'.concat(descriptor.store, '" needs ').concat(installSpec, ", but ").concat(detail, "; refusing to overwrite it -- run `npm install ").concat(installSpec, "` yourself and try again"));
295
+ }
296
+ function assertExpectedVersion(descriptor, metadata) {
297
+ if (!descriptor.version) return;
298
+ if (!(metadata === null || metadata === void 0 ? void 0 : metadata.version) || metadata.version !== descriptor.version) throw versionContractError(descriptor, metadata === null || metadata === void 0 ? void 0 : metadata.version);
299
+ }
256
300
  function loadOrInstall(_0, _1) {
257
301
  return _async_to_generator(function(descriptor, nodeModulesPath) {
258
- var importName, unused, installErr, loadErr;
302
+ var importName, target, loaded, unused, _descriptor_installSpec, _descriptor_installSpec1, installSpec, displaySpec, installErr, loaded1, loadErr;
259
303
  var _arguments = arguments;
260
304
  return _ts_generator(this, function(_state) {
261
305
  switch(_state.label){
262
306
  case 0:
263
307
  importName = _arguments.length > 2 && _arguments[2] !== void 0 ? _arguments[2] : descriptor.pkg;
308
+ if (descriptor.version) {
309
+ target = targetPackageMetadata(importName, nodeModulesPath);
310
+ if (target.exists) assertExpectedVersion(descriptor, target.metadata);
311
+ }
264
312
  _state.label = 1;
265
313
  case 1:
266
314
  _state.trys.push([
@@ -276,13 +324,16 @@ function loadOrInstall(_0, _1) {
276
324
  })
277
325
  ];
278
326
  case 2:
327
+ loaded = _state.sent();
279
328
  return [
280
- 2,
281
- _state.sent()
329
+ 3,
330
+ 11
282
331
  ];
283
332
  case 3:
284
333
  unused = _state.sent();
285
- console.error('sense: store "'.concat(descriptor.store, '" needs ').concat(descriptor.pkg, "; installing it now (one-time download, ").concat(descriptor.sizeHint, ")..."));
334
+ installSpec = (_descriptor_installSpec = descriptor.installSpec) !== null && _descriptor_installSpec !== void 0 ? _descriptor_installSpec : importName;
335
+ displaySpec = (_descriptor_installSpec1 = descriptor.installSpec) !== null && _descriptor_installSpec1 !== void 0 ? _descriptor_installSpec1 : descriptor.pkg;
336
+ console.error('sense: store "'.concat(descriptor.store, '" needs ').concat(displaySpec, "; installing it now (one-time download, ").concat(descriptor.sizeHint, ")..."));
286
337
  _state.label = 4;
287
338
  case 4:
288
339
  _state.trys.push([
@@ -293,7 +344,7 @@ function loadOrInstall(_0, _1) {
293
344
  ]);
294
345
  return [
295
346
  4,
296
- installOnce(importName, nodeModulesPath)
347
+ installOnce(installSpec, nodeModulesPath)
297
348
  ];
298
349
  case 5:
299
350
  _state.sent();
@@ -303,7 +354,7 @@ function loadOrInstall(_0, _1) {
303
354
  ];
304
355
  case 6:
305
356
  installErr = _state.sent();
306
- throw new _errorsts.SenseError('STORE_DEPENDENCY_MISSING', 'store "'.concat(descriptor.store, '" needs ').concat(descriptor.pkg, ", and installing it automatically failed (").concat(installErr.message, "); this can happen offline, in a sandboxed environment, or when node_modules is read-only or owned by another user (e.g. under a global install) -- run `npm install ").concat(descriptor.pkg, "` yourself and try again"));
357
+ throw new _errorsts.SenseError('STORE_DEPENDENCY_MISSING', 'store "'.concat(descriptor.store, '" needs ').concat(displaySpec, ", and installing it automatically failed (").concat(installErr.message, "); this can happen offline, in a sandboxed environment, or when node_modules is read-only or owned by another user (e.g. under a global install) -- run `npm install ").concat(displaySpec, "` yourself and try again"));
307
358
  case 7:
308
359
  _state.trys.push([
309
360
  7,
@@ -318,21 +369,25 @@ function loadOrInstall(_0, _1) {
318
369
  })
319
370
  ];
320
371
  case 8:
372
+ loaded1 = _state.sent();
373
+ assertExpectedVersion(descriptor, targetPackageMetadata(importName, nodeModulesPath).metadata);
321
374
  return [
322
375
  2,
323
- _state.sent()
376
+ loaded1
324
377
  ];
325
378
  case 9:
326
379
  loadErr = _state.sent();
327
- throw new _errorsts.SenseError('STORE_DEPENDENCY_MISSING', 'store "'.concat(descriptor.store, '" installed ').concat(descriptor.pkg, " but it could not be loaded (").concat(loadErr.message, "); it may not be available for this platform (").concat(process.platform, "-").concat(process.arch, ") -- run `npm install ").concat(descriptor.pkg, "` to see the underlying error"));
380
+ throw new _errorsts.SenseError('STORE_DEPENDENCY_MISSING', 'store "'.concat(descriptor.store, '" installed ').concat(displaySpec, " but it could not be loaded (").concat(loadErr.message, "); it may not be available for this platform (").concat(process.platform, "-").concat(process.arch, ") -- run `npm install ").concat(displaySpec, "` to see the underlying error"));
328
381
  case 10:
329
382
  return [
330
383
  3,
331
384
  11
332
385
  ];
333
386
  case 11:
387
+ if (descriptor.version) assertExpectedVersion(descriptor, resolvedPackageMetadata(importName));
334
388
  return [
335
- 2
389
+ 2,
390
+ loaded
336
391
  ];
337
392
  }
338
393
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/native.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport Module from 'node:module';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { SenseError } from '../errors.ts';\n\n// A store's optional native package, and the strings its error messages and install notice name.\nexport interface NativeDescriptor {\n store: string;\n pkg: string;\n sizeHint: string;\n}\n\n// install-module-linked is small, but a target native package can be large (@duckdb/node-api's\n// ~110MB), so it is required lazily inside the gated branch below, not for every store/index.ts load.\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\nconst _dirname = dirname(typeof __filename !== 'undefined' ? __filename : fileURLToPath(import.meta.url));\n\n// Walks up from this file's own directory rather than a fixed dot-count: it sits at a\n// different depth under src/ than under built dist/{cjs,esm}/store output.\nexport function packageNodeModules(): string {\n let dir = _dirname;\n for (;;) {\n const candidate = join(dir, 'package.json');\n if (existsSync(candidate)) {\n const pkg = JSON.parse(readFileSync(candidate, 'utf8')) as { name?: string };\n if (pkg.name === 'sensemaking') return join(dir, 'node_modules');\n }\n const parent = dirname(dir);\n if (parent === dir) throw new Error('could not locate the sensemaking package root to install a native dependency into');\n dir = parent;\n }\n}\n\nconst installing = new Map<string, Promise<void>>();\n\n// De-dupes concurrent installs: since the install is async, concurrent callers await the same\n// in-flight promise, keyed by specifier and target. A failed install is not cached, so a later call retries.\nfunction installOnce(specifier: string, nodeModulesPath: string): Promise<void> {\n const key = `${specifier}\\n${nodeModulesPath}`;\n let promise = installing.get(key);\n if (!promise) {\n const installModuleLinked = (_require('install-module-linked') as { default: (specifier: string, nodeModulesPath: string) => Promise<string> }).default;\n promise = installModuleLinked(specifier, nodeModulesPath).then(\n () => {},\n (err) => {\n installing.delete(key);\n throw err;\n }\n );\n installing.set(key, promise);\n }\n return promise;\n}\n\n// Node caches a bare specifier's resolution, including a \"not found\" miss, for the process\n// lifetime; use the installed entry directly, as a URL for ESM and a path for CJS.\nfunction resolveEntrySpecifier(importName: string, nodeModulesPath: string): string {\n const pkgDir = join(nodeModulesPath, ...importName.split('/'));\n const pkg = JSON.parse(readFileSync(join(pkgDir, 'package.json'), 'utf8')) as { main?: string; exports?: string };\n const entry = typeof pkg.exports === 'string' ? pkg.exports : (pkg.main ?? 'index.js');\n const entryPath = join(pkgDir, entry);\n return typeof require === 'undefined' ? pathToFileURL(entryPath).href : entryPath;\n}\n\n// Import-then-install-then-retry, over an injectable importName so the failure path can be\n// exercised in tests without a real native binding. Thrown errors always name descriptor.pkg.\nexport async function loadOrInstall<T>(descriptor: NativeDescriptor, nodeModulesPath: string, importName: string = descriptor.pkg): Promise<T> {\n try {\n return (await import(importName)) as T;\n } catch {\n console.error(`sense: store \"${descriptor.store}\" needs ${descriptor.pkg}; installing it now (one-time download, ${descriptor.sizeHint})...`);\n try {\n await installOnce(importName, nodeModulesPath);\n } catch (installErr) {\n throw new SenseError(\n 'STORE_DEPENDENCY_MISSING',\n `store \"${descriptor.store}\" needs ${descriptor.pkg}, and installing it automatically failed (${(installErr as Error).message}); this can happen offline, in a sandboxed environment, or when node_modules is read-only or owned by another user (e.g. under a global install) -- run \\`npm install ${descriptor.pkg}\\` yourself and try again`\n );\n }\n try {\n return (await import(resolveEntrySpecifier(importName, nodeModulesPath))) as T;\n } catch (loadErr) {\n throw new SenseError(\n 'STORE_DEPENDENCY_MISSING',\n `store \"${descriptor.store}\" installed ${descriptor.pkg} but it could not be loaded (${(loadErr as Error).message}); it may not be available for this platform (${process.platform}-${process.arch}) -- run \\`npm install ${descriptor.pkg}\\` to see the underlying error`\n );\n }\n }\n}\n"],"names":["loadOrInstall","packageNodeModules","_require","require","Module","createRequire","_dirname","dirname","__filename","fileURLToPath","dir","candidate","join","existsSync","pkg","JSON","parse","readFileSync","name","parent","Error","installing","Map","installOnce","specifier","nodeModulesPath","key","promise","get","installModuleLinked","default","then","err","delete","set","resolveEntrySpecifier","importName","pkgDir","split","entry","exports","main","entryPath","pathToFileURL","href","descriptor","installErr","loadErr","console","error","store","sizeHint","SenseError","message","process","platform","arch"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/native.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport Module from 'node:module';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { SenseError } from '../errors.ts';\n\n// A store's optional native package, and the strings its error messages and install notice name.\nexport interface NativeDescriptor {\n store: string;\n pkg: string;\n sizeHint: string;\n /** Optional exact package version required by this native binding. */\n version?: string;\n /** npm specifier used only when installation is required (imports stay bare). */\n installSpec?: string;\n}\n\n// install-module-linked is small, but a target native package can be large (@duckdb/node-api's\n// ~110MB), so it is required lazily inside the gated branch below, not for every store/index.ts load.\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\nconst _dirname = dirname(typeof __filename !== 'undefined' ? __filename : fileURLToPath(import.meta.url));\n\n// Walks up from this file's own directory rather than a fixed dot-count: it sits at a\n// different depth under src/ than under built dist/{cjs,esm}/store output.\nexport function packageNodeModules(): string {\n let dir = _dirname;\n for (;;) {\n const candidate = join(dir, 'package.json');\n if (existsSync(candidate)) {\n const pkg = JSON.parse(readFileSync(candidate, 'utf8')) as { name?: string };\n if (pkg.name === 'sensemaking') return join(dir, 'node_modules');\n }\n const parent = dirname(dir);\n if (parent === dir) throw new Error('could not locate the sensemaking package root to install a native dependency into');\n dir = parent;\n }\n}\n\nconst installing = new Map<string, Promise<void>>();\n\n// De-dupes concurrent installs: since the install is async, concurrent callers await the same\n// in-flight promise, keyed by specifier and target. A failed install is not cached, so a later call retries.\nfunction installOnce(specifier: string, nodeModulesPath: string): Promise<void> {\n const key = `${specifier}\\n${nodeModulesPath}`;\n let promise = installing.get(key);\n if (!promise) {\n const installModuleLinked = (_require('install-module-linked') as { default: (specifier: string, nodeModulesPath: string) => Promise<string> }).default;\n promise = installModuleLinked(specifier, nodeModulesPath).then(\n () => {},\n (err) => {\n installing.delete(key);\n throw err;\n }\n );\n installing.set(key, promise);\n }\n return promise;\n}\n\n// Node caches a bare specifier's resolution, including a \"not found\" miss, for the process\n// lifetime; use the installed entry directly, as a URL for ESM and a path for CJS.\nfunction resolveEntrySpecifier(importName: string, nodeModulesPath: string): string {\n const pkgDir = join(nodeModulesPath, ...importName.split('/'));\n const pkg = JSON.parse(readFileSync(join(pkgDir, 'package.json'), 'utf8')) as { main?: string; exports?: string };\n const entry = typeof pkg.exports === 'string' ? pkg.exports : (pkg.main ?? 'index.js');\n const entryPath = join(pkgDir, entry);\n return typeof require === 'undefined' ? pathToFileURL(entryPath).href : entryPath;\n}\n\ntype PackageMetadata = { name?: string; version?: string };\n\nfunction readPackageMetadata(pkgDir: string): PackageMetadata | undefined {\n try {\n return JSON.parse(readFileSync(join(pkgDir, 'package.json'), 'utf8')) as PackageMetadata;\n } catch {\n return undefined;\n }\n}\n\nfunction targetPackageMetadata(importName: string, nodeModulesPath: string): { exists: boolean; metadata?: PackageMetadata } {\n const pkgDir = join(nodeModulesPath, ...importName.split('/'));\n return { exists: existsSync(pkgDir), metadata: readPackageMetadata(pkgDir) };\n}\n\nfunction resolvedPackageMetadata(importName: string): PackageMetadata | undefined {\n try {\n let dir = dirname(_require.resolve(importName));\n for (;;) {\n const manifest = join(dir, 'package.json');\n if (existsSync(manifest)) {\n const pkg = readPackageMetadata(dir);\n if (!pkg) return undefined;\n if (pkg.name === importName) return pkg;\n }\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n } catch {\n return undefined;\n }\n}\n\nfunction versionContractError(descriptor: NativeDescriptor, installed?: string): SenseError {\n const installSpec = descriptor.installSpec ?? descriptor.pkg;\n const detail = installed ? `${descriptor.pkg}@${installed} is installed` : `${descriptor.pkg} has missing or unreadable version metadata`;\n return new SenseError('STORE_DEPENDENCY_MISSING', `store \"${descriptor.store}\" needs ${installSpec}, but ${detail}; refusing to overwrite it -- run \\`npm install ${installSpec}\\` yourself and try again`);\n}\n\nfunction assertExpectedVersion(descriptor: NativeDescriptor, metadata: PackageMetadata | undefined): void {\n if (!descriptor.version) return;\n if (!metadata?.version || metadata.version !== descriptor.version) throw versionContractError(descriptor, metadata?.version);\n}\n\n// Import-then-install-then-retry, over an injectable importName so the failure path can be\n// exercised in tests without a real native binding. Thrown errors always name descriptor.pkg.\nexport async function loadOrInstall<T>(descriptor: NativeDescriptor, nodeModulesPath: string, importName: string = descriptor.pkg): Promise<T> {\n if (descriptor.version) {\n const target = targetPackageMetadata(importName, nodeModulesPath);\n if (target.exists) assertExpectedVersion(descriptor, target.metadata);\n }\n let loaded: T;\n try {\n loaded = (await import(importName)) as T;\n } catch {\n const installSpec = descriptor.installSpec ?? importName;\n const displaySpec = descriptor.installSpec ?? descriptor.pkg;\n console.error(`sense: store \"${descriptor.store}\" needs ${displaySpec}; installing it now (one-time download, ${descriptor.sizeHint})...`);\n try {\n await installOnce(installSpec, nodeModulesPath);\n } catch (installErr) {\n throw new SenseError(\n 'STORE_DEPENDENCY_MISSING',\n `store \"${descriptor.store}\" needs ${displaySpec}, and installing it automatically failed (${(installErr as Error).message}); this can happen offline, in a sandboxed environment, or when node_modules is read-only or owned by another user (e.g. under a global install) -- run \\`npm install ${displaySpec}\\` yourself and try again`\n );\n }\n try {\n const loaded = (await import(resolveEntrySpecifier(importName, nodeModulesPath))) as T;\n assertExpectedVersion(descriptor, targetPackageMetadata(importName, nodeModulesPath).metadata);\n return loaded;\n } catch (loadErr) {\n throw new SenseError('STORE_DEPENDENCY_MISSING', `store \"${descriptor.store}\" installed ${displaySpec} but it could not be loaded (${(loadErr as Error).message}); it may not be available for this platform (${process.platform}-${process.arch}) -- run \\`npm install ${displaySpec}\\` to see the underlying error`);\n }\n }\n if (descriptor.version) assertExpectedVersion(descriptor, resolvedPackageMetadata(importName));\n return loaded;\n}\n"],"names":["loadOrInstall","packageNodeModules","_require","require","Module","createRequire","_dirname","dirname","__filename","fileURLToPath","dir","candidate","join","existsSync","pkg","JSON","parse","readFileSync","name","parent","Error","installing","Map","installOnce","specifier","nodeModulesPath","key","promise","get","installModuleLinked","default","then","err","delete","set","resolveEntrySpecifier","importName","pkgDir","split","entry","exports","main","entryPath","pathToFileURL","href","readPackageMetadata","undefined","targetPackageMetadata","exists","metadata","resolvedPackageMetadata","resolve","manifest","versionContractError","descriptor","installed","installSpec","detail","SenseError","store","assertExpectedVersion","version","target","loaded","displaySpec","installErr","loadErr","console","error","sizeHint","message","process","platform","arch"],"mappings":"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"}
@@ -160,13 +160,13 @@ function _ts_generator(thisArg, body) {
160
160
  // Bounded by this tree's recorded reconcile time (lock-wait.ts), not a fixed guess.
161
161
  var LOCK_POLL_MS = 50;
162
162
  var lockWait = (0, _nodediagnostics_channel.channel)('sensemaking.store.lock-wait');
163
- function connectUnlocked(dbPath, cfg, dialect) {
163
+ function connectUnlocked(dbPath, cfg, configDir, dialect) {
164
164
  return _async_to_generator(function() {
165
- var _cfg_configDir, budgetMs, deadline, err, _dialect_isLocked;
165
+ var budgetMs, deadline, err, _dialect_isLocked;
166
166
  return _ts_generator(this, function(_state) {
167
167
  switch(_state.label){
168
168
  case 0:
169
- budgetMs = (0, _lockwaitts.lockWaitBudgetMs)((_cfg_configDir = cfg.configDir) !== null && _cfg_configDir !== void 0 ? _cfg_configDir : cfg.baseDir);
169
+ budgetMs = (0, _lockwaitts.lockWaitBudgetMs)(configDir);
170
170
  deadline = Date.now() + budgetMs;
171
171
  _state.label = 1;
172
172
  case 1:
@@ -223,18 +223,19 @@ function connectUnlocked(dbPath, cfg, dialect) {
223
223
  }
224
224
  function connectWithDialect(cfg, dialect) {
225
225
  return _async_to_generator(function() {
226
- var _cfg_configDir, _cfg_rootDir, stateDir, dbPath, _ref, handle, conn, closed, builder, version, features, wantFeatures, forcedPaths, embedInvalidate, featureToggles, _cfg_rootDir1, changedKeys, presetForced, embedKind, toggles, changed, changed1, changed2, _ref1, recordedMaxMs, embedParsed, _tmp, featureParsed, _tmp1, _ref2, parsed, warnings, stages, err;
226
+ var _cfg_configDir, _cfg_rootDir, configDir, stateDir, dbPath, _ref, handle, conn, closed, builder, version, features, wantFeatures, forcedPaths, embedInvalidate, featureToggles, _cfg_rootDir1, changedKeys, presetForced, embedKind, toggles, changed, changed1, changed2, _ref1, recordedMaxMs, embedParsed, _tmp, featureParsed, _tmp1, _ref2, parsed, warnings, stages, err;
227
227
  return _ts_generator(this, function(_state) {
228
228
  switch(_state.label){
229
229
  case 0:
230
- stateDir = (0, _nodepath.join)((_cfg_configDir = cfg.configDir) !== null && _cfg_configDir !== void 0 ? _cfg_configDir : cfg.baseDir, _indexts.STATE_DIR);
230
+ configDir = (_cfg_configDir = cfg.configDir) !== null && _cfg_configDir !== void 0 ? _cfg_configDir : cfg.baseDir;
231
+ stateDir = (0, _nodepath.join)(configDir, _indexts.STATE_DIR);
231
232
  (0, _nodefs.mkdirSync)(stateDir, {
232
233
  recursive: true
233
234
  });
234
235
  dbPath = (0, _nodepath.join)(stateDir, dialect.filename);
235
236
  return [
236
237
  4,
237
- connectUnlocked(dbPath, cfg, dialect)
238
+ connectUnlocked(dbPath, cfg, configDir, dialect)
238
239
  ];
239
240
  case 1:
240
241
  _ref = _state.sent(), handle = _ref.handle, conn = _ref.conn;
@@ -243,7 +244,10 @@ function connectWithDialect(cfg, dialect) {
243
244
  closed = false;
244
245
  // Created here, not inside reconcile(): invalidate()/invalidateFeatures() below share its pool
245
246
  // with the build() call that follows them.
246
- builder = (0, _builderts.createBuilder)(conn, cfg, (_cfg_rootDir = cfg.rootDir) !== null && _cfg_rootDir !== void 0 ? _cfg_rootDir : cfg.baseDir, dialect.reconcileDialect);
247
+ builder = (0, _builderts.createBuilder)(conn, cfg, {
248
+ rootDir: (_cfg_rootDir = cfg.rootDir) !== null && _cfg_rootDir !== void 0 ? _cfg_rootDir : cfg.baseDir,
249
+ configDir: configDir
250
+ }, dialect.reconcileDialect);
247
251
  _state.label = 2;
248
252
  case 2:
249
253
  _state.trys.push([
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/open.ts"],"sourcesContent":["import { channel } from 'node:diagnostics_channel';\nimport { mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { ResolvedConfig } from '../config/index.ts';\nimport { featureSignature, STATE_DIR } from '../config/index.ts';\nimport { rekeyChunkText } from '../embed/handoff.ts';\nimport { SenseError } from '../errors.ts';\nimport { FEATURES } from '../features/index.ts';\nimport { createBuilder } from './builder.ts';\nimport { clearCache } from './cache.ts';\nimport type { EmbedChangeKind } from './embed-scope.ts';\nimport { classifyEmbedChange } from './embed-scope.ts';\nimport type { FeatureToggle } from './feature-scope.ts';\nimport { classifyFeatureToggles, isFeatureOnlyChange } from './feature-scope.ts';\nimport { lockWaitBudgetMs } from './lock-wait.ts';\nimport { forcedPresetPaths, isPresetOnlyChange } from './preset-scope.ts';\nimport { getMeta, setMeta } from './shared.ts';\nimport { changedSignatureKeys, embedIdentityAdopted, signatureDiff } from './signature.ts';\nimport type { Stages } from './stages.ts';\nimport type { Connection, OpenDialect, Store } from './types.ts';\n\n// One open algorithm shared by every store, parameterised by a per-engine OpenDialect (types.ts).\n// Ordering is universal, not a dialect concern: connect, meta table, schema-version and\n// feature-signature comparison (rebuild, adopt, or partial rebuild), any extra rebuild trigger,\n// ensureSchema, the derived busy_timeout PRAGMA, reconcile, then the store itself.\n\nexport interface OpenResult {\n store: Store;\n cfg: ResolvedConfig;\n dbPath: string;\n parsed: number;\n warnings: string[];\n // Per-stage wall time for this open's build pass (stages.ts), not for any narrow embed or\n // feature invalidation that ran beside it -- on a cold build there is none, so it is the whole cost.\n stages: Stages;\n}\n\ninterface ConnectResult<Handle> {\n handle: Handle;\n conn: Connection;\n cfg: ResolvedConfig;\n dbPath: string;\n parsed: number;\n warnings: string[];\n stages: Stages;\n}\n\n// duckdb/turso hold the cache file for their connection's whole life, so a second command waits.\n// Bounded by this tree's recorded reconcile time (lock-wait.ts), not a fixed guess.\nconst LOCK_POLL_MS = 50;\nconst lockWait = channel('sensemaking.store.lock-wait');\n\nasync function connectUnlocked<Handle>(dbPath: string, cfg: ResolvedConfig, dialect: OpenDialect<Handle>): Promise<{ handle: Handle; conn: Connection }> {\n const budgetMs = lockWaitBudgetMs(cfg.configDir ?? cfg.baseDir);\n const deadline = Date.now() + budgetMs;\n for (;;) {\n try {\n return await dialect.connect(dbPath, cfg);\n } catch (err) {\n if (!dialect.isLocked?.(err as Error)) throw err;\n // Observe a real rejected native connection, never merely the start of an async open.\n if (lockWait.hasSubscribers) lockWait.publish({ store: cfg.store, dbPath });\n if (Date.now() >= deadline) {\n throw new SenseError('STORE_BUSY', `another sense process is using this tree's ${cfg.store} cache (${dbPath}) and did not release it within ${Math.round(budgetMs / 1000)}s; wait for that command to finish, or set \"store\" to \"sqlite\" in sense.config.json, which serves concurrent commands`);\n }\n await new Promise((resolve) => setTimeout(resolve, LOCK_POLL_MS));\n }\n }\n}\n\nasync function connectWithDialect<Handle>(cfg: ResolvedConfig, dialect: OpenDialect<Handle>): Promise<ConnectResult<Handle>> {\n const stateDir = join(cfg.configDir ?? cfg.baseDir, STATE_DIR);\n mkdirSync(stateDir, { recursive: true });\n const dbPath = join(stateDir, dialect.filename);\n\n const { handle, conn } = await connectUnlocked(dbPath, cfg, dialect);\n // A throw below must release this handle, or the leaked WAL makes the cache file undeletable on\n // Windows. `closed` keeps the catch from double-closing a handle a rebuild branch already closed.\n let closed = false;\n // Created here, not inside reconcile(): invalidate()/invalidateFeatures() below share its pool\n // with the build() call that follows them.\n const builder = createBuilder(conn, cfg, cfg.rootDir ?? cfg.baseDir, dialect.reconcileDialect);\n try {\n await conn.exec('CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT)');\n\n // Schema-version or feature-set mismatch: reconcile only reparses changed files, so an\n // old cache can't be patched incrementally -- rebuild instead (cheap: nothing expensive lives here).\n const version = await getMeta(conn, 'schema_version');\n const features = await getMeta(conn, 'features');\n const wantFeatures = featureSignature(cfg, FEATURES);\n // Set only by the preset-membership branch below; reconcile treats these paths as touched\n // despite an unchanged stamp, for this one build() call.\n let forcedPaths: Set<string> | undefined;\n // Set only by the embed-narrow branch below; applied via builder.invalidate() after ensureSchema.\n let embedInvalidate: EmbedChangeKind | undefined;\n // Set only by the feature-toggle branch below; applied via builder.invalidateFeatures() after ensureSchema.\n let featureToggles: FeatureToggle[] | undefined;\n if ((version !== null && version !== dialect.schemaVersion) || (features !== null && features !== wantFeatures)) {\n // Indexing derives from presets, so a config edit rebuilding the cache must say so and\n // name what changed -- silent rebuilds make derived indexing look like a hang or a bug.\n if (version !== null && version !== dialect.schemaVersion) {\n console.error('sense: cache format changed (new sensemaking version); rebuilding the index');\n // Close before clearCache deletes the files out from under the still-open handle.\n closed = true;\n await dialect.close(handle);\n clearCache(cfg);\n return connectWithDialect(cfg, dialect);\n }\n const changedKeys = changedSignatureKeys(features ?? '', wantFeatures);\n // Null (rather than the empty set) when changedKeys isn't preset-only, or a changed\n // preset's stored segment can't be parsed back into old include/exclude/vectors -- either\n // way the branch below is skipped and the full rebuild stays the fallback.\n const presetForced = isPresetOnlyChange(changedKeys) ? forcedPresetPaths(cfg, cfg.rootDir ?? cfg.baseDir, features ?? '', changedKeys) : null;\n // Null unless exactly one segment changed and it decomposes into a recognised embed-only\n // case (embed-scope.ts): anything else, including embed toggled on/off, stays null.\n const embedKind = changedKeys.size === 1 && changedKeys.has('embed') ? classifyEmbedChange(features ?? '', wantFeatures) : null;\n // Null (rather than the empty set) when changedKeys isn't feature-toggle-only, or a changed\n // feature's stored segment can't be parsed back into old/new on-off -- either way the branch\n // below is skipped and the full rebuild stays the fallback.\n const toggles = isFeatureOnlyChange(changedKeys) ? classifyFeatureToggles(features ?? '', wantFeatures, changedKeys) : null;\n if (changedKeys.size === 1 && changedKeys.has('embed') && embedIdentityAdopted(features ?? '', wantFeatures)) {\n // First sight of a resolved weight identity: the model itself hasn't changed, so\n // adopt it into meta with no rebuild and no re-embed.\n console.error(\"sense: recorded the embedding model's resolved identity; vectors are unaffected\");\n await setMeta(conn, 'features', wantFeatures);\n } else if (embedKind !== null) {\n // Chunk boundaries are file-derived, not model-derived (embed.ts's chunksOf), so neither\n // case needs any file reparsed for any feature but embed itself.\n embedInvalidate = embedKind;\n console.error(embedKind === 'model' ? 'sense: config change (embed settings) invalidates only the stale vectors' : 'sense: config change (embed settings) rebuilds only the embeddings it affects');\n await setMeta(conn, 'features', wantFeatures);\n } else if (presetForced !== null) {\n // Membership only: which files a preset covers moved, not a file's own content, a\n // global feature, or the embed model. reconcile() already knows how to\n // add, update, and remove a file correctly (every cross-feature cascade included); it\n // just needs telling which unchanged files to treat as touched (forcedPaths, above).\n forcedPaths = presetForced;\n const changed = signatureDiff(features ?? '', wantFeatures);\n console.error(`sense: config change (${changed}) reparses only the files it affects`);\n await setMeta(conn, 'features', wantFeatures);\n } else if (toggles !== null) {\n // A feature turned off or on: reconcile.ts's activeFeatures skips a disabled feature's\n // hooks entirely, so its rows rot while off -- invalidateFeatures drops them and, for a\n // feature turning back on, fully re-derives across every indexed file rather than\n // trusting rows written before or during that window.\n featureToggles = toggles;\n const changed = signatureDiff(features ?? '', wantFeatures);\n console.error(`sense: config change (${changed}) reparses only the feature it affects`);\n await setMeta(conn, 'features', wantFeatures);\n } else {\n const changed = signatureDiff(features ?? '', wantFeatures);\n console.error(`sense: config change (${changed}) rebuilds the index`);\n closed = true;\n await dialect.close(handle);\n clearCache(cfg);\n return connectWithDialect(cfg, dialect);\n }\n }\n\n await dialect.ensureSchema(handle, conn, cfg);\n\n // 3x the largest reconcile this cache has recorded, floored at 30s and capped at 10min.\n // Installed before build() -- that call is the one that races a watcher's transaction.\n if (dialect.setDerivedBusyTimeout) {\n const recordedMaxMs = Number((await getMeta(conn, 'reconcile_max_ms')) ?? '0');\n await dialect.setDerivedBusyTimeout(handle, conn, Math.min(Math.max(30000, 3 * recordedMaxMs), 600_000));\n }\n\n // Runs before build(): forcedPaths, embedInvalidate and featureToggles never target the same\n // call (each comes from its own mutually exclusive branch above: a preset-only, embed-only, or\n // feature-toggle-only changed-key set).\n const embedParsed = embedInvalidate ? (await builder.invalidate(embedInvalidate)).parsed : 0;\n const featureParsed = featureToggles ? (await builder.invalidateFeatures(featureToggles)).parsed : 0;\n\n const { parsed, warnings, stages } = await builder.build(forcedPaths);\n // Every open reconciles once and is done with it -- a watcher opens fresh per event instead of holding this connection (src/watch.ts).\n await builder.close();\n\n return { handle, conn, cfg, dbPath, parsed: parsed + embedParsed + featureParsed, warnings, stages };\n } catch (err) {\n await builder.close();\n if (!closed) await dialect.close(handle);\n throw err;\n }\n}\n\n// A store's open(): connects (see connectWithDialect above), then wraps the resulting connection\n// in the Store interface. The builder's pool closes right after the initial build.\nexport async function openWithDialect<Handle>(cfg: ResolvedConfig, dialect: OpenDialect<Handle>): Promise<OpenResult> {\n // `baseDir` was the original public open() input. Keep direct API callers working while\n // making the two ownership paths explicit for every internal operation.\n if (!cfg.rootDir) {\n if (!cfg.baseDir) throw new SenseError('CONFIG_INVALID', 'open requires rootDir (or legacy baseDir)');\n cfg.rootDir = cfg.baseDir;\n }\n if (!cfg.configDir) cfg.configDir = cfg.rootDir;\n const { handle, conn, cfg: resolvedCfg, dbPath, parsed, warnings, stages } = await connectWithDialect(cfg, dialect);\n const store = dialect.createStore(handle, conn, resolvedCfg);\n // reconcile ran before this object existed, so its chunk text is keyed by the connection.\n rekeyChunkText(conn, store);\n return { store, cfg: resolvedCfg, dbPath, parsed, warnings, stages };\n}\n\nexport async function docCount(store: Store): Promise<number> {\n const stmt = await store.prepare('SELECT COUNT(*) AS n FROM frontmatter');\n return ((await stmt.get()) as { n: number }).n;\n}\n"],"names":["docCount","openWithDialect","LOCK_POLL_MS","lockWait","channel","connectUnlocked","dbPath","cfg","dialect","budgetMs","deadline","err","lockWaitBudgetMs","configDir","baseDir","Date","now","connect","isLocked","hasSubscribers","publish","store","SenseError","Math","round","Promise","resolve","setTimeout","connectWithDialect","stateDir","handle","conn","closed","builder","version","features","wantFeatures","forcedPaths","embedInvalidate","featureToggles","changedKeys","presetForced","embedKind","toggles","changed","recordedMaxMs","embedParsed","featureParsed","parsed","warnings","stages","join","STATE_DIR","mkdirSync","recursive","filename","createBuilder","rootDir","reconcileDialect","exec","getMeta","featureSignature","FEATURES","schemaVersion","console","error","close","clearCache","changedSignatureKeys","isPresetOnlyChange","forcedPresetPaths","size","has","classifyEmbedChange","isFeatureOnlyChange","classifyFeatureToggles","embedIdentityAdopted","setMeta","signatureDiff","ensureSchema","setDerivedBusyTimeout","Number","min","max","invalidate","invalidateFeatures","build","resolvedCfg","createStore","rekeyChunkText","stmt","prepare","get","n"],"mappings":";;;;;;;;;;;QA2MsBA;eAAAA;;QAfAC;eAAAA;;;uCA5LE;sBACE;wBACL;uBAEuB;yBACb;wBACJ;wBACF;yBACK;uBACH;4BAES;8BAEwB;0BAC3B;6BACqB;wBACrB;2BACyC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8B1E,iGAAiG;AACjG,oFAAoF;AACpF,IAAMC,eAAe;AACrB,IAAMC,WAAWC,IAAAA,gCAAO,EAAC;AAEzB,SAAeC,gBAAwBC,MAAc,EAAEC,GAAmB,EAAEC,OAA4B;;YACpED,gBAA5BE,UACAC,UAIKC,KACFH;;;;oBANHC,WAAWG,IAAAA,4BAAgB,GAACL,iBAAAA,IAAIM,SAAS,cAAbN,4BAAAA,iBAAiBA,IAAIO,OAAO;oBACxDJ,WAAWK,KAAKC,GAAG,KAAKP;;;;;;;;;oBAGnB;;wBAAMD,QAAQS,OAAO,CAACX,QAAQC;;;oBAArC;;wBAAO;;;oBACAI;oBACP,IAAI,GAACH,oBAAAA,QAAQU,QAAQ,cAAhBV,wCAAAA,uBAAAA,SAAmBG,OAAe,MAAMA;oBAC7C,sFAAsF;oBACtF,IAAIR,SAASgB,cAAc,EAAEhB,SAASiB,OAAO,CAAC;wBAAEC,OAAOd,IAAIc,KAAK;wBAAEf,QAAAA;oBAAO;oBACzE,IAAIS,KAAKC,GAAG,MAAMN,UAAU;wBAC1B,MAAM,IAAIY,oBAAU,CAAC,cAAc,AAAC,8CAAiEhB,OAApBC,IAAIc,KAAK,EAAC,YAAmDE,OAAzCjB,QAAO,oCAA8D,OAA5BiB,KAAKC,KAAK,CAACf,WAAW,OAAM;oBAC5K;oBACA;;wBAAM,IAAIgB,QAAQ,SAACC;mCAAYC,WAAWD,SAASxB;;;;oBAAnD;;;;;;;;;;;;;;;;IAGN;;AAEA,SAAe0B,mBAA2BrB,GAAmB,EAAEC,OAA4B;;YACnED,gBAUmBA,cAVnCsB,UAEAvB,QAEmB,MAAjBwB,QAAQC,MAGZC,QAGEC,SAMEC,SACAC,UACAC,cAGFC,aAEAC,iBAEAC,gBAgB4EhC,eAJxEiC,aAIAC,cAGAC,WAIAC,SAkBEC,SASAA,UAIAA,UAcsB,OAAxBC,eAOFC,mBACAC,sBAE+B,OAA7BC,QAAQC,UAAUC,QAKnBvC;;;;oBA5GHkB,WAAWsB,IAAAA,cAAI,GAAC5C,iBAAAA,IAAIM,SAAS,cAAbN,4BAAAA,iBAAiBA,IAAIO,OAAO,EAAEsC,kBAAS;oBAC7DC,IAAAA,iBAAS,EAACxB,UAAU;wBAAEyB,WAAW;oBAAK;oBAChChD,SAAS6C,IAAAA,cAAI,EAACtB,UAAUrB,QAAQ+C,QAAQ;oBAErB;;wBAAMlD,gBAAgBC,QAAQC,KAAKC;;;oBAAnC,OAAA,eAAjBsB,SAAiB,KAAjBA,QAAQC,OAAS,KAATA;oBAChB,gGAAgG;oBAChG,kGAAkG;oBAC9FC,SAAS;oBACb,+FAA+F;oBAC/F,2CAA2C;oBACrCC,UAAUuB,IAAAA,wBAAa,EAACzB,MAAMxB,MAAKA,eAAAA,IAAIkD,OAAO,cAAXlD,0BAAAA,eAAeA,IAAIO,OAAO,EAAEN,QAAQkD,gBAAgB;;;;;;;;;oBAE3F;;wBAAM3B,KAAK4B,IAAI,CAAC;;;oBAAhB;oBAIgB;;wBAAMC,IAAAA,iBAAO,EAAC7B,MAAM;;;oBAA9BG,UAAU;oBACC;;wBAAM0B,IAAAA,iBAAO,EAAC7B,MAAM;;;oBAA/BI,WAAW;oBACXC,eAAeyB,IAAAA,yBAAgB,EAACtD,KAAKuD,kBAAQ;yBAQ/C,CAAA,AAAC5B,YAAY,QAAQA,YAAY1B,QAAQuD,aAAa,IAAM5B,aAAa,QAAQA,aAAaC,YAAY,GAA1G;;;;yBAGEF,CAAAA,YAAY,QAAQA,YAAY1B,QAAQuD,aAAa,AAAD,GAApD7B;;;;oBACF8B,QAAQC,KAAK,CAAC;oBACd,kFAAkF;oBAClFjC,SAAS;oBACT;;wBAAMxB,QAAQ0D,KAAK,CAACpC;;;oBAApB;oBACAqC,IAAAA,mBAAU,EAAC5D;oBACX;;wBAAOqB,mBAAmBrB,KAAKC;;;oBAE3BgC,cAAc4B,IAAAA,iCAAoB,EAACjC,qBAAAA,sBAAAA,WAAY,IAAIC;oBACzD,oFAAoF;oBACpF,0FAA0F;oBAC1F,2EAA2E;oBACrEK,eAAe4B,IAAAA,iCAAkB,EAAC7B,eAAe8B,IAAAA,gCAAiB,EAAC/D,MAAKA,gBAAAA,IAAIkD,OAAO,cAAXlD,2BAAAA,gBAAeA,IAAIO,OAAO,EAAEqB,qBAAAA,sBAAAA,WAAY,IAAIK,eAAe;oBACzI,yFAAyF;oBACzF,oFAAoF;oBAC9EE,YAAYF,YAAY+B,IAAI,KAAK,KAAK/B,YAAYgC,GAAG,CAAC,WAAWC,IAAAA,iCAAmB,EAACtC,qBAAAA,sBAAAA,WAAY,IAAIC,gBAAgB;oBAC3H,4FAA4F;oBAC5F,6FAA6F;oBAC7F,4DAA4D;oBACtDO,UAAU+B,IAAAA,mCAAmB,EAAClC,eAAemC,IAAAA,sCAAsB,EAACxC,qBAAAA,sBAAAA,WAAY,IAAIC,cAAcI,eAAe;yBACnHA,CAAAA,YAAY+B,IAAI,KAAK,KAAK/B,YAAYgC,GAAG,CAAC,YAAYI,IAAAA,iCAAoB,EAACzC,qBAAAA,sBAAAA,WAAY,IAAIC,aAAY,GAAvGI;;;;oBACF,iFAAiF;oBACjF,sDAAsD;oBACtDwB,QAAQC,KAAK,CAAC;oBACd;;wBAAMY,IAAAA,iBAAO,EAAC9C,MAAM,YAAYK;;;oBAAhC;;;;;;yBACSM,CAAAA,cAAc,IAAG,GAAjBA;;;;oBACT,yFAAyF;oBACzF,iEAAiE;oBACjEJ,kBAAkBI;oBAClBsB,QAAQC,KAAK,CAACvB,cAAc,UAAU,6EAA6E;oBACnH;;wBAAMmC,IAAAA,iBAAO,EAAC9C,MAAM,YAAYK;;;oBAAhC;;;;;;yBACSK,CAAAA,iBAAiB,IAAG,GAApBA;;;;oBACT,kFAAkF;oBAClF,uEAAuE;oBACvE,sFAAsF;oBACtF,qFAAqF;oBACrFJ,cAAcI;oBACRG,UAAUkC,IAAAA,0BAAa,EAAC3C,qBAAAA,sBAAAA,WAAY,IAAIC;oBAC9C4B,QAAQC,KAAK,CAAC,AAAC,yBAAgC,OAARrB,SAAQ;oBAC/C;;wBAAMiC,IAAAA,iBAAO,EAAC9C,MAAM,YAAYK;;;oBAAhC;;;;;;yBACSO,CAAAA,YAAY,IAAG,GAAfA;;;;oBACT,uFAAuF;oBACvF,wFAAwF;oBACxF,kFAAkF;oBAClF,sDAAsD;oBACtDJ,iBAAiBI;oBACXC,WAAUkC,IAAAA,0BAAa,EAAC3C,qBAAAA,sBAAAA,WAAY,IAAIC;oBAC9C4B,QAAQC,KAAK,CAAC,AAAC,yBAAgC,OAARrB,UAAQ;oBAC/C;;wBAAMiC,IAAAA,iBAAO,EAAC9C,MAAM,YAAYK;;;oBAAhC;;;;;;oBAEMQ,WAAUkC,IAAAA,0BAAa,EAAC3C,qBAAAA,sBAAAA,WAAY,IAAIC;oBAC9C4B,QAAQC,KAAK,CAAC,AAAC,yBAAgC,OAARrB,UAAQ;oBAC/CZ,SAAS;oBACT;;wBAAMxB,QAAQ0D,KAAK,CAACpC;;;oBAApB;oBACAqC,IAAAA,mBAAU,EAAC5D;oBACX;;wBAAOqB,mBAAmBrB,KAAKC;;;oBAInC;;wBAAMA,QAAQuE,YAAY,CAACjD,QAAQC,MAAMxB;;;oBAAzC;yBAIIC,QAAQwE,qBAAqB,EAA7BxE;;;;oBAC4B;;wBAAMoD,IAAAA,iBAAO,EAAC7B,MAAM;;;oBAA5Cc,gBAAgBoC;yBAAQ,QAAA,2BAAA,mBAAA,QAA4C;;oBAC1E;;wBAAMzE,QAAQwE,qBAAqB,CAAClD,QAAQC,MAAMR,KAAK2D,GAAG,CAAC3D,KAAK4D,GAAG,CAAC,OAAO,IAAItC,gBAAgB;;;oBAA/F;;;yBAMkBP,iBAAAA;;;;oBAAmB;;wBAAML,QAAQmD,UAAU,CAAC9C;;;2BAA1B,AAAC,cAA2CU,MAAM;;;;;;2BAAG;;;oBAArFF;yBACgBP,gBAAAA;;;;oBAAkB;;wBAAMN,QAAQoD,kBAAkB,CAAC9C;;;4BAAlC,AAAC,cAAkDS,MAAM;;;;;;4BAAG;;;oBAA7FD;oBAE+B;;wBAAMd,QAAQqD,KAAK,CAACjD;;;oBAApB,QAAA,eAA7BW,SAA6B,MAA7BA,QAAQC,WAAqB,MAArBA,UAAUC,SAAW,MAAXA;oBAC1B,uIAAuI;oBACvI;;wBAAMjB,QAAQiC,KAAK;;;oBAAnB;oBAEA;;wBAAO;4BAAEpC,QAAAA;4BAAQC,MAAAA;4BAAMxB,KAAAA;4BAAKD,QAAAA;4BAAQ0C,QAAQA,SAASF,cAAcC;4BAAeE,UAAAA;4BAAUC,QAAAA;wBAAO;;;oBAC5FvC;oBACP;;wBAAMsB,QAAQiC,KAAK;;;oBAAnB;yBACI,CAAClC,QAAD;;;;oBAAS;;wBAAMxB,QAAQ0D,KAAK,CAACpC;;;oBAApB;;;oBACb,MAAMnB;;;;;;;IAEV;;AAIO,SAAeV,gBAAwBM,GAAmB,EAAEC,OAA4B;;YAQhB,MAArEsB,QAAQC,MAAWwD,aAAajF,QAAQ0C,QAAQC,UAAUC,QAC5D7B;;;;oBARN,wFAAwF;oBACxF,wEAAwE;oBACxE,IAAI,CAACd,IAAIkD,OAAO,EAAE;wBAChB,IAAI,CAAClD,IAAIO,OAAO,EAAE,MAAM,IAAIQ,oBAAU,CAAC,kBAAkB;wBACzDf,IAAIkD,OAAO,GAAGlD,IAAIO,OAAO;oBAC3B;oBACA,IAAI,CAACP,IAAIM,SAAS,EAAEN,IAAIM,SAAS,GAAGN,IAAIkD,OAAO;oBAC8B;;wBAAM7B,mBAAmBrB,KAAKC;;;oBAA9B,OAAA,eAArEsB,SAAqE,KAArEA,QAAQC,OAA6D,KAA7DA,MAAWwD,cAAkD,KAAvDhF,KAAkBD,SAAqC,KAArCA,QAAQ0C,SAA6B,KAA7BA,QAAQC,WAAqB,KAArBA,UAAUC,SAAW,KAAXA;oBAC5D7B,QAAQb,QAAQgF,WAAW,CAAC1D,QAAQC,MAAMwD;oBAChD,0FAA0F;oBAC1FE,IAAAA,yBAAc,EAAC1D,MAAMV;oBACrB;;wBAAO;4BAAEA,OAAAA;4BAAOd,KAAKgF;4BAAajF,QAAAA;4BAAQ0C,QAAAA;4BAAQC,UAAAA;4BAAUC,QAAAA;wBAAO;;;;IACrE;;AAEO,SAAelD,SAASqB,KAAY;;YACnCqE;;;;oBAAO;;wBAAMrE,MAAMsE,OAAO,CAAC;;;oBAA3BD,OAAO;oBACJ;;wBAAMA,KAAKE,GAAG;;;oBAAvB;;wBAAS,cAAoCC,CAAC;;;;IAChD"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/open.ts"],"sourcesContent":["import { channel } from 'node:diagnostics_channel';\nimport { mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { ResolvedConfig } from '../config/index.ts';\nimport { featureSignature, STATE_DIR } from '../config/index.ts';\nimport { rekeyChunkText } from '../embed/handoff.ts';\nimport { SenseError } from '../errors.ts';\nimport { FEATURES } from '../features/index.ts';\nimport { createBuilder } from './builder.ts';\nimport { clearCache } from './cache.ts';\nimport type { EmbedChangeKind } from './embed-scope.ts';\nimport { classifyEmbedChange } from './embed-scope.ts';\nimport type { FeatureToggle } from './feature-scope.ts';\nimport { classifyFeatureToggles, isFeatureOnlyChange } from './feature-scope.ts';\nimport { lockWaitBudgetMs } from './lock-wait.ts';\nimport { forcedPresetPaths, isPresetOnlyChange } from './preset-scope.ts';\nimport { getMeta, setMeta } from './shared.ts';\nimport { changedSignatureKeys, embedIdentityAdopted, signatureDiff } from './signature.ts';\nimport type { Stages } from './stages.ts';\nimport type { Connection, OpenDialect, Store } from './types.ts';\n\n// One open algorithm shared by every store, parameterised by a per-engine OpenDialect (types.ts).\n// Ordering is universal, not a dialect concern: connect, meta table, schema-version and\n// feature-signature comparison (rebuild, adopt, or partial rebuild), any extra rebuild trigger,\n// ensureSchema, the derived busy_timeout PRAGMA, reconcile, then the store itself.\n\nexport interface OpenResult {\n store: Store;\n cfg: ResolvedConfig;\n dbPath: string;\n parsed: number;\n warnings: string[];\n // Per-stage wall time for this open's build pass (stages.ts), not for any narrow embed or\n // feature invalidation that ran beside it -- on a cold build there is none, so it is the whole cost.\n stages: Stages;\n}\n\ninterface ConnectResult<Handle> {\n handle: Handle;\n conn: Connection;\n cfg: ResolvedConfig;\n dbPath: string;\n parsed: number;\n warnings: string[];\n stages: Stages;\n}\n\n// duckdb/turso hold the cache file for their connection's whole life, so a second command waits.\n// Bounded by this tree's recorded reconcile time (lock-wait.ts), not a fixed guess.\nconst LOCK_POLL_MS = 50;\nconst lockWait = channel('sensemaking.store.lock-wait');\n\nasync function connectUnlocked<Handle>(dbPath: string, cfg: ResolvedConfig, configDir: string, dialect: OpenDialect<Handle>): Promise<{ handle: Handle; conn: Connection }> {\n const budgetMs = lockWaitBudgetMs(configDir);\n const deadline = Date.now() + budgetMs;\n for (;;) {\n try {\n return await dialect.connect(dbPath, cfg);\n } catch (err) {\n if (!dialect.isLocked?.(err as Error)) throw err;\n // Observe a real rejected native connection, never merely the start of an async open.\n if (lockWait.hasSubscribers) lockWait.publish({ store: cfg.store, dbPath });\n if (Date.now() >= deadline) {\n throw new SenseError('STORE_BUSY', `another sense process is using this tree's ${cfg.store} cache (${dbPath}) and did not release it within ${Math.round(budgetMs / 1000)}s; wait for that command to finish, or set \"store\" to \"sqlite\" in sense.config.json, which serves concurrent commands`);\n }\n await new Promise((resolve) => setTimeout(resolve, LOCK_POLL_MS));\n }\n }\n}\n\nasync function connectWithDialect<Handle>(cfg: ResolvedConfig, dialect: OpenDialect<Handle>): Promise<ConnectResult<Handle>> {\n const configDir = cfg.configDir ?? cfg.baseDir;\n const stateDir = join(configDir, STATE_DIR);\n mkdirSync(stateDir, { recursive: true });\n const dbPath = join(stateDir, dialect.filename);\n\n const { handle, conn } = await connectUnlocked(dbPath, cfg, configDir, dialect);\n // A throw below must release this handle, or the leaked WAL makes the cache file undeletable on\n // Windows. `closed` keeps the catch from double-closing a handle a rebuild branch already closed.\n let closed = false;\n // Created here, not inside reconcile(): invalidate()/invalidateFeatures() below share its pool\n // with the build() call that follows them.\n const builder = createBuilder(conn, cfg, { rootDir: cfg.rootDir ?? cfg.baseDir, configDir }, dialect.reconcileDialect);\n try {\n await conn.exec('CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT)');\n\n // Schema-version or feature-set mismatch: reconcile only reparses changed files, so an\n // old cache can't be patched incrementally -- rebuild instead (cheap: nothing expensive lives here).\n const version = await getMeta(conn, 'schema_version');\n const features = await getMeta(conn, 'features');\n const wantFeatures = featureSignature(cfg, FEATURES);\n // Set only by the preset-membership branch below; reconcile treats these paths as touched\n // despite an unchanged stamp, for this one build() call.\n let forcedPaths: Set<string> | undefined;\n // Set only by the embed-narrow branch below; applied via builder.invalidate() after ensureSchema.\n let embedInvalidate: EmbedChangeKind | undefined;\n // Set only by the feature-toggle branch below; applied via builder.invalidateFeatures() after ensureSchema.\n let featureToggles: FeatureToggle[] | undefined;\n if ((version !== null && version !== dialect.schemaVersion) || (features !== null && features !== wantFeatures)) {\n // Indexing derives from presets, so a config edit rebuilding the cache must say so and\n // name what changed -- silent rebuilds make derived indexing look like a hang or a bug.\n if (version !== null && version !== dialect.schemaVersion) {\n console.error('sense: cache format changed (new sensemaking version); rebuilding the index');\n // Close before clearCache deletes the files out from under the still-open handle.\n closed = true;\n await dialect.close(handle);\n clearCache(cfg);\n return connectWithDialect(cfg, dialect);\n }\n const changedKeys = changedSignatureKeys(features ?? '', wantFeatures);\n // Null (rather than the empty set) when changedKeys isn't preset-only, or a changed\n // preset's stored segment can't be parsed back into old include/exclude/vectors -- either\n // way the branch below is skipped and the full rebuild stays the fallback.\n const presetForced = isPresetOnlyChange(changedKeys) ? forcedPresetPaths(cfg, cfg.rootDir ?? cfg.baseDir, features ?? '', changedKeys) : null;\n // Null unless exactly one segment changed and it decomposes into a recognised embed-only\n // case (embed-scope.ts): anything else, including embed toggled on/off, stays null.\n const embedKind = changedKeys.size === 1 && changedKeys.has('embed') ? classifyEmbedChange(features ?? '', wantFeatures) : null;\n // Null (rather than the empty set) when changedKeys isn't feature-toggle-only, or a changed\n // feature's stored segment can't be parsed back into old/new on-off -- either way the branch\n // below is skipped and the full rebuild stays the fallback.\n const toggles = isFeatureOnlyChange(changedKeys) ? classifyFeatureToggles(features ?? '', wantFeatures, changedKeys) : null;\n if (changedKeys.size === 1 && changedKeys.has('embed') && embedIdentityAdopted(features ?? '', wantFeatures)) {\n // First sight of a resolved weight identity: the model itself hasn't changed, so\n // adopt it into meta with no rebuild and no re-embed.\n console.error(\"sense: recorded the embedding model's resolved identity; vectors are unaffected\");\n await setMeta(conn, 'features', wantFeatures);\n } else if (embedKind !== null) {\n // Chunk boundaries are file-derived, not model-derived (embed.ts's chunksOf), so neither\n // case needs any file reparsed for any feature but embed itself.\n embedInvalidate = embedKind;\n console.error(embedKind === 'model' ? 'sense: config change (embed settings) invalidates only the stale vectors' : 'sense: config change (embed settings) rebuilds only the embeddings it affects');\n await setMeta(conn, 'features', wantFeatures);\n } else if (presetForced !== null) {\n // Membership only: which files a preset covers moved, not a file's own content, a\n // global feature, or the embed model. reconcile() already knows how to\n // add, update, and remove a file correctly (every cross-feature cascade included); it\n // just needs telling which unchanged files to treat as touched (forcedPaths, above).\n forcedPaths = presetForced;\n const changed = signatureDiff(features ?? '', wantFeatures);\n console.error(`sense: config change (${changed}) reparses only the files it affects`);\n await setMeta(conn, 'features', wantFeatures);\n } else if (toggles !== null) {\n // A feature turned off or on: reconcile.ts's activeFeatures skips a disabled feature's\n // hooks entirely, so its rows rot while off -- invalidateFeatures drops them and, for a\n // feature turning back on, fully re-derives across every indexed file rather than\n // trusting rows written before or during that window.\n featureToggles = toggles;\n const changed = signatureDiff(features ?? '', wantFeatures);\n console.error(`sense: config change (${changed}) reparses only the feature it affects`);\n await setMeta(conn, 'features', wantFeatures);\n } else {\n const changed = signatureDiff(features ?? '', wantFeatures);\n console.error(`sense: config change (${changed}) rebuilds the index`);\n closed = true;\n await dialect.close(handle);\n clearCache(cfg);\n return connectWithDialect(cfg, dialect);\n }\n }\n\n await dialect.ensureSchema(handle, conn, cfg);\n\n // 3x the largest reconcile this cache has recorded, floored at 30s and capped at 10min.\n // Installed before build() -- that call is the one that races a watcher's transaction.\n if (dialect.setDerivedBusyTimeout) {\n const recordedMaxMs = Number((await getMeta(conn, 'reconcile_max_ms')) ?? '0');\n await dialect.setDerivedBusyTimeout(handle, conn, Math.min(Math.max(30000, 3 * recordedMaxMs), 600_000));\n }\n\n // Runs before build(): forcedPaths, embedInvalidate and featureToggles never target the same\n // call (each comes from its own mutually exclusive branch above: a preset-only, embed-only, or\n // feature-toggle-only changed-key set).\n const embedParsed = embedInvalidate ? (await builder.invalidate(embedInvalidate)).parsed : 0;\n const featureParsed = featureToggles ? (await builder.invalidateFeatures(featureToggles)).parsed : 0;\n\n const { parsed, warnings, stages } = await builder.build(forcedPaths);\n // Every open reconciles once and is done with it -- a watcher opens fresh per event instead of holding this connection (src/watch.ts).\n await builder.close();\n\n return { handle, conn, cfg, dbPath, parsed: parsed + embedParsed + featureParsed, warnings, stages };\n } catch (err) {\n await builder.close();\n if (!closed) await dialect.close(handle);\n throw err;\n }\n}\n\n// A store's open(): connects (see connectWithDialect above), then wraps the resulting connection\n// in the Store interface. The builder's pool closes right after the initial build.\nexport async function openWithDialect<Handle>(cfg: ResolvedConfig, dialect: OpenDialect<Handle>): Promise<OpenResult> {\n // `baseDir` was the original public open() input. Keep direct API callers working while\n // making the two ownership paths explicit for every internal operation.\n if (!cfg.rootDir) {\n if (!cfg.baseDir) throw new SenseError('CONFIG_INVALID', 'open requires rootDir (or legacy baseDir)');\n cfg.rootDir = cfg.baseDir;\n }\n if (!cfg.configDir) cfg.configDir = cfg.rootDir;\n const { handle, conn, cfg: resolvedCfg, dbPath, parsed, warnings, stages } = await connectWithDialect(cfg, dialect);\n const store = dialect.createStore(handle, conn, resolvedCfg);\n // reconcile ran before this object existed, so its chunk text is keyed by the connection.\n rekeyChunkText(conn, store);\n return { store, cfg: resolvedCfg, dbPath, parsed, warnings, stages };\n}\n\nexport async function docCount(store: Store): Promise<number> {\n const stmt = await store.prepare('SELECT COUNT(*) AS n FROM frontmatter');\n return ((await stmt.get()) as { n: number }).n;\n}\n"],"names":["docCount","openWithDialect","LOCK_POLL_MS","lockWait","channel","connectUnlocked","dbPath","cfg","configDir","dialect","budgetMs","deadline","err","lockWaitBudgetMs","Date","now","connect","isLocked","hasSubscribers","publish","store","SenseError","Math","round","Promise","resolve","setTimeout","connectWithDialect","stateDir","handle","conn","closed","builder","version","features","wantFeatures","forcedPaths","embedInvalidate","featureToggles","changedKeys","presetForced","embedKind","toggles","changed","recordedMaxMs","embedParsed","featureParsed","parsed","warnings","stages","baseDir","join","STATE_DIR","mkdirSync","recursive","filename","createBuilder","rootDir","reconcileDialect","exec","getMeta","featureSignature","FEATURES","schemaVersion","console","error","close","clearCache","changedSignatureKeys","isPresetOnlyChange","forcedPresetPaths","size","has","classifyEmbedChange","isFeatureOnlyChange","classifyFeatureToggles","embedIdentityAdopted","setMeta","signatureDiff","ensureSchema","setDerivedBusyTimeout","Number","min","max","invalidate","invalidateFeatures","build","resolvedCfg","createStore","rekeyChunkText","stmt","prepare","get","n"],"mappings":"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"}
@@ -3,7 +3,11 @@ import type { ParsePool } from '../scan/pool.js';
3
3
  import { type Stages } from './stages.js';
4
4
  import type { Connection, ReconcileDialect } from './types.js';
5
5
  export declare const CORE_FRONTMATTER_COLUMNS: Set<string>;
6
- export declare function reconcile(conn: Connection, cfg: Config, baseDir: string, dialect: ReconcileDialect, pool?: ParsePool, forcedPaths?: ReadonlySet<string>): Promise<{
6
+ export interface ReconcilePaths {
7
+ rootDir: string;
8
+ configDir: string;
9
+ }
10
+ export declare function reconcile(conn: Connection, cfg: Config, paths: ReconcilePaths, dialect: ReconcileDialect, pool?: ParsePool, forcedPaths?: ReadonlySet<string>): Promise<{
7
11
  parsed: number;
8
12
  warnings: string[];
9
13
  stages: Stages;
@@ -3,7 +3,11 @@ import type { ParsePool } from '../scan/pool.js';
3
3
  import { type Stages } from './stages.js';
4
4
  import type { Connection, ReconcileDialect } from './types.js';
5
5
  export declare const CORE_FRONTMATTER_COLUMNS: Set<string>;
6
- export declare function reconcile(conn: Connection, cfg: Config, baseDir: string, dialect: ReconcileDialect, pool?: ParsePool, forcedPaths?: ReadonlySet<string>): Promise<{
6
+ export interface ReconcilePaths {
7
+ rootDir: string;
8
+ configDir: string;
9
+ }
10
+ export declare function reconcile(conn: Connection, cfg: Config, paths: ReconcilePaths, dialect: ReconcileDialect, pool?: ParsePool, forcedPaths?: ReadonlySet<string>): Promise<{
7
11
  parsed: number;
8
12
  warnings: string[];
9
13
  stages: Stages;
@@ -203,12 +203,13 @@ var CORE_FRONTMATTER_COLUMNS = new Set([
203
203
  '_size',
204
204
  '_parse_error'
205
205
  ]);
206
- function reconcile(conn, cfg, baseDir, dialect, pool, forcedPaths) {
206
+ function reconcile(conn, cfg, paths, dialect, pool, forcedPaths) {
207
207
  return _async_to_generator(function() {
208
- var start, features, stages, elapsed, files, currentSet, existingRows, existing, vanished, toReparse, seenColumns, report, _ref, parsedDocs, warnings, newColumns, workerParseMs, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, col, allColumns, writableColumns, insertSql, added, delta, addedSet, reparsedExisting, touched, txStart, durationMs;
208
+ var rootDir, configDir, start, features, stages, elapsed, files, currentSet, existingRows, existing, vanished, toReparse, seenColumns, report, _ref, parsedDocs, warnings, newColumns, workerParseMs, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, col, allColumns, writableColumns, insertSql, added, delta, addedSet, reparsedExisting, touched, txStart, durationMs;
209
209
  return _ts_generator(this, function(_state) {
210
210
  switch(_state.label){
211
211
  case 0:
212
+ rootDir = paths.rootDir, configDir = paths.configDir;
212
213
  start = process.hrtime.bigint();
213
214
  features = (0, _indexts.activeFeatures)(cfg);
214
215
  stages = (0, _stagests.stageRecorder)(features.map(function(f) {
@@ -220,7 +221,7 @@ function reconcile(conn, cfg, baseDir, dialect, pool, forcedPaths) {
220
221
  return [
221
222
  4,
222
223
  stages.time('list', function() {
223
- return (0, _indexts1.listFiles)(cfg, baseDir);
224
+ return (0, _indexts1.listFiles)(cfg, rootDir);
224
225
  })
225
226
  ];
226
227
  case 1:
@@ -884,7 +885,7 @@ function reconcile(conn, cfg, baseDir, dialect, pool, forcedPaths) {
884
885
  _state.sent();
885
886
  durationMs = Date.now() - txStart;
886
887
  // Every store, not just the ones with a PRAGMA to derive: connectUnlocked's lock-wait budget needs it too.
887
- (0, _lockwaitts.recordLockWaitMs)(baseDir, durationMs);
888
+ (0, _lockwaitts.recordLockWaitMs)(configDir, durationMs);
888
889
  if (!dialect.recordDuration) return [
889
890
  3,
890
891
  7
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/reconcile.ts"],"sourcesContent":["import type { Config } from '../config/index.ts';\nimport { activeFeatures } from '../features/index.ts';\nimport type { ExtractedDoc, ReconcileDelta } from '../features/types.ts';\nimport { progress } from '../output/progress.ts';\nimport { listFiles, RESERVED_COLUMNS } from '../scan/index.ts';\nimport type { ParsePool } from '../scan/pool.ts';\nimport { reparseFiles } from '../scan/reparse.ts';\nimport { recordLockWaitMs } from './lock-wait.ts';\nimport { appendRows, getColumns, quoteIdent } from './shared.ts';\nimport { featureStage, type Stages, stageRecorder } from './stages.ts';\nimport { withTransaction } from './transaction.ts';\nimport type { Connection, ReconcileDialect } from './types.ts';\n\n// One reconcile algorithm shared by every store, parameterised by a per-engine ReconcileDialect\n// (types.ts). Ordering is universal, not a dialect concern: ALTER, then the frontmatter upsert,\n// then reconcileContent, then preset_files, then the vanished-frontmatter delete, then feature hooks\n// -- a vanished path's content delete (inside reconcileContent) must precede its frontmatter\n// delete, since sqlite's delete SQL resolves the row via its frontmatter rowid.\n\n// Feature-owned columns (`_rank`) must stay out of the upsert: a reparse would null the last\n// computed value on every touch, not just the reconciles that recompute it.\nexport const CORE_FRONTMATTER_COLUMNS = new Set(['path', '_mtime', '_ctime', '_size', '_parse_error']);\n\nexport async function reconcile(conn: Connection, cfg: Config, baseDir: string, dialect: ReconcileDialect, pool?: ParsePool, forcedPaths?: ReadonlySet<string>): Promise<{ parsed: number; warnings: string[]; stages: Stages }> {\n const start = process.hrtime.bigint();\n const features = activeFeatures(cfg);\n const stages = stageRecorder(features.map((f) => f.name));\n const elapsed = () => Number(process.hrtime.bigint() - start) / 1e6;\n const files = await stages.time('list', () => listFiles(cfg, baseDir));\n const currentSet = new Set(files.map((f) => f.relPath));\n\n const existingRows = await stages.time('existing', async () => {\n const existingStmt = await conn.prepare('SELECT \"path\", \"_mtime\", \"_size\" FROM frontmatter');\n return (await existingStmt.all()) as Array<{ path: string; _mtime: number; _size: number }>;\n });\n const existing = new Map(existingRows.map((r) => [r.path, r]));\n // A path whose coverage moved between presets (forcedPaths) but is no longer covered at all is\n // already caught below by !currentSet.has, since it can only be forced by having existed under\n // an old preset's match, which means it was reconciled into `existing` already.\n const vanished = existingRows.filter((r) => !currentSet.has(r.path)).map((r) => r.path);\n\n // forcedPaths treats an unchanged file as touched because its preset coverage moved, not its\n // stamp -- reconcile still owns add/update/remove and every cross-feature cascade for it.\n const toReparse = files.filter((f) => {\n const row = existing.get(f.relPath);\n return !row || row._mtime !== f.mtimeMs || row._size !== f.size || (forcedPaths?.has(f.relPath) ?? false);\n });\n\n if (vanished.length === 0 && toReparse.length === 0) return { parsed: 0, warnings: [], stages: stages.take(elapsed(), 0) };\n\n const seenColumns = await getColumns(conn);\n\n // Bulk reparses (a sync, a cold build) are the long silences a query can hit; short\n // reconciles stay silent (progress() has a threshold).\n const report = progress('reparsing files', toReparse.length);\n // Pool wall time, dispatch to drain, so this stage shares a clock with every other one.\n const { docs: parsedDocs, warnings, newColumns, workerParseMs } = await stages.time('parse', () => reparseFiles(toReparse, features, cfg, seenColumns, report.tick, { pool }));\n report.finish();\n for (const col of newColumns) seenColumns.add(col);\n\n const allColumns = [...seenColumns];\n // Fence before ALTERing: a store's own failure past this point is a raw, engine-specific\n // error with no indication of the boundary or the levers -- dialect.checkColumnLimit names both.\n dialect.checkColumnLimit(allColumns.length);\n // Columns the frontmatter upsert actually writes: core + parsed frontmatter keys, never a\n // feature-owned reserved column (see CORE_FRONTMATTER_COLUMNS above).\n const writableColumns = allColumns.filter((c) => CORE_FRONTMATTER_COLUMNS.has(c) || !RESERVED_COLUMNS.has(c));\n // ON CONFLICT DO UPDATE (not OR REPLACE) keeps the row's rowid stable across reparses --\n // sqlite's content rows are coupled to that rowid.\n const insertSql = `INSERT INTO frontmatter (${writableColumns.map(quoteIdent).join(', ')}) VALUES (${writableColumns.map(() => '?').join(', ')}) ON CONFLICT(\"path\") DO UPDATE SET ${writableColumns\n .filter((c) => c !== 'path')\n .map((c) => `${quoteIdent(c)} = excluded.${quoteIdent(c)}`)\n .join(', ')}`;\n\n const added = toReparse.filter((f) => !existing.has(f.relPath)).map((f) => f.relPath);\n const delta: ReconcileDelta = { files, reparsed: parsedDocs.map((d) => d.relPath), added, vanished };\n const addedSet = new Set(added);\n const reparsedExisting = parsedDocs.map((d) => d.relPath).filter((p) => !addedSet.has(p));\n // Paths whose content (and, per feature, other rows) need clearing: gone entirely, or about to\n // be reinserted fresh. Disjoint from `added`, which has nothing to clear.\n const touched = [...vanished, ...reparsedExisting];\n\n const txStart = Date.now();\n await withTransaction(\n conn,\n async () => {\n // Re-read inside the write transaction: newColumns came from a read taken before it opened, so a\n // concurrent reconcile may have added some of them since. ALTER has no IF NOT EXISTS.\n const present = await getColumns(conn);\n const missingColumns = newColumns.filter((col) => !present.has(col));\n if (missingColumns.length > 0) await stages.time('alter', () => dialect.addColumns(conn, missingColumns));\n\n // Revalidated once the lock is held, before this process's own frontmatter upsert below:\n // `added` came from a path read taken before this transaction's lock, so a path still\n // called \"added\" here may already have a content row from a concurrent reconcile that\n // committed while this one waited. One SELECT, not a DELETE per added file -- with no\n // contention it returns the same set `existing` already ruled out, so nothing extra clears.\n let contentTouched = touched;\n if (added.length > 0)\n contentTouched = await stages.time('added-recheck', async () => {\n const currentPathsStmt = await conn.prepare('SELECT \"path\" FROM frontmatter');\n const currentPaths = new Set(((await currentPathsStmt.all()) as Array<{ path: string }>).map((r) => r.path));\n const staleAdded = added.filter((p) => currentPaths.has(p));\n return staleAdded.length > 0 ? [...touched, ...staleAdded] : touched;\n });\n\n if (parsedDocs.length > 0) {\n const toRow = (doc: (typeof parsedDocs)[number]) =>\n writableColumns.map((col) => {\n if (col === 'path') return doc.relPath;\n if (col === '_mtime') return doc.mtimeMs;\n if (col === '_ctime') return doc.ctimeMs;\n if (col === '_size') return doc.size;\n // Written per parse, unlike _rank, which a feature pass owns and the upsert skips.\n if (col === '_parse_error') return doc.parseError;\n return doc.data[col] ?? null;\n });\n // A path in `added` has no existing frontmatter row, so it can never conflict; the rest\n // genuinely can, and keep the upsert.\n await stages.time('fm-upsert', async () => {\n const newDocs = parsedDocs.filter((d) => addedSet.has(d.relPath));\n const updateDocs = parsedDocs.filter((d) => !addedSet.has(d.relPath));\n await appendRows(conn, 'frontmatter', writableColumns, insertSql, newDocs.map(toRow));\n if (updateDocs.length > 0) await conn.runBatch(insertSql, updateDocs.map(toRow));\n });\n }\n\n // After the upsert, so every doc already has the frontmatter row sqlite's content rowid\n // couples to. ON CONFLICT DO UPDATE preserves that rowid, so a reparse keeps its identity.\n await stages.time('text-index', () => dialect.reconcileContent(conn, contentTouched, parsedDocs, delta, cfg));\n\n // A preset edit forces a full rebuild, so an unchanged doc's coverage is already correct;\n // new docs have nothing to clear, which keeps cold builds linear.\n await stages.time('presets', async () => {\n if (touched.length > 0)\n await conn.runBatch(\n 'DELETE FROM preset_files WHERE \"path\" = ?',\n touched.map((p) => [p])\n );\n const presetRows: unknown[][] = [];\n for (const doc of parsedDocs) for (const presetName of doc.presets) presetRows.push([doc.relPath, presetName]);\n // DO NOTHING, not a bare INSERT: the added/touched split above comes from a read taken\n // before this transaction's lock, so a path this process calls \"added\" can already have\n // its (path, preset) row committed by a concurrent reconcile -- the row would be identical either way.\n await appendRows(conn, 'preset_files', ['path', 'preset'], 'INSERT INTO preset_files (\"path\", preset) VALUES (?, ?) ON CONFLICT(\"path\", preset) DO NOTHING', presetRows);\n });\n\n // Before the feature hooks, never after: rank's afterReconcile reads frontmatter as PageRank's\n // node set, so a lingering vanished row would dilute rank mass across every surviving note.\n if (vanished.length > 0)\n await stages.time('vanished', () =>\n conn.runBatch(\n 'DELETE FROM frontmatter WHERE \"path\" = ?',\n vanished.map((p) => [p])\n )\n );\n\n // Timed per feature per hook, so link resolution and PageRank are named stages without\n // links.ts or rank.ts knowing anything about this, and a new feature is visible for free.\n if (touched.length > 0) for (const feature of features) await stages.time(featureStage(feature.name, 'remove'), () => feature.remove?.(conn, touched, delta));\n for (const feature of features) {\n const docsForFeature: ExtractedDoc[] = parsedDocs.map((doc) => ({ path: doc.relPath, extracted: doc.extracted[feature.name] }));\n await stages.time(featureStage(feature.name, 'store'), () => feature.store?.(conn, docsForFeature, delta));\n }\n for (const feature of features) await stages.time(featureStage(feature.name, 'after'), () => feature.afterReconcile?.(conn, delta));\n },\n dialect.beginMode()\n );\n\n const durationMs = Date.now() - txStart;\n // Every store, not just the ones with a PRAGMA to derive: connectUnlocked's lock-wait budget needs it too.\n recordLockWaitMs(baseDir, durationMs);\n if (dialect.recordDuration) await stages.time('meta', () => dialect.recordDuration?.(conn, durationMs));\n\n return { parsed: parsedDocs.length, warnings, stages: stages.take(elapsed(), durationMs, workerParseMs) };\n}\n"],"names":["CORE_FRONTMATTER_COLUMNS","reconcile","Set","conn","cfg","baseDir","dialect","pool","forcedPaths","start","features","stages","elapsed","files","currentSet","existingRows","existing","vanished","toReparse","seenColumns","report","parsedDocs","warnings","newColumns","workerParseMs","col","allColumns","writableColumns","insertSql","added","delta","addedSet","reparsedExisting","touched","txStart","durationMs","process","hrtime","bigint","activeFeatures","stageRecorder","map","f","name","Number","time","listFiles","relPath","existingStmt","prepare","all","Map","r","path","filter","has","row","get","_mtime","mtimeMs","_size","size","length","parsed","take","getColumns","progress","reparseFiles","tick","docs","finish","add","checkColumnLimit","c","RESERVED_COLUMNS","quoteIdent","join","reparsed","d","p","Date","now","withTransaction","present","missingColumns","contentTouched","toRow","addColumns","currentPathsStmt","currentPaths","staleAdded","doc","ctimeMs","parseError","data","newDocs","updateDocs","appendRows","runBatch","reconcileContent","presetRows","presetName","presets","push","feature","featureStage","remove","docsForFeature","extracted","store","afterReconcile","beginMode","recordLockWaitMs","recordDuration"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/reconcile.ts"],"sourcesContent":["import type { Config } from '../config/index.ts';\nimport { activeFeatures } from '../features/index.ts';\nimport type { ExtractedDoc, ReconcileDelta } from '../features/types.ts';\nimport { progress } from '../output/progress.ts';\nimport { listFiles, RESERVED_COLUMNS } from '../scan/index.ts';\nimport type { ParsePool } from '../scan/pool.ts';\nimport { reparseFiles } from '../scan/reparse.ts';\nimport { recordLockWaitMs } from './lock-wait.ts';\nimport { appendRows, getColumns, quoteIdent } from './shared.ts';\nimport { featureStage, type Stages, stageRecorder } from './stages.ts';\nimport { withTransaction } from './transaction.ts';\nimport type { Connection, ReconcileDialect } from './types.ts';\n\n// One reconcile algorithm shared by every store, parameterised by a per-engine ReconcileDialect\n// (types.ts). Ordering is universal, not a dialect concern: ALTER, then the frontmatter upsert,\n// then reconcileContent, then preset_files, then the vanished-frontmatter delete, then feature hooks\n// -- a vanished path's content delete (inside reconcileContent) must precede its frontmatter\n// delete, since sqlite's delete SQL resolves the row via its frontmatter rowid.\n\n// Feature-owned columns (`_rank`) must stay out of the upsert: a reparse would null the last\n// computed value on every touch, not just the reconciles that recompute it.\nexport const CORE_FRONTMATTER_COLUMNS = new Set(['path', '_mtime', '_ctime', '_size', '_parse_error']);\n\nexport interface ReconcilePaths {\n rootDir: string;\n configDir: string;\n}\n\nexport async function reconcile(conn: Connection, cfg: Config, paths: ReconcilePaths, dialect: ReconcileDialect, pool?: ParsePool, forcedPaths?: ReadonlySet<string>): Promise<{ parsed: number; warnings: string[]; stages: Stages }> {\n const { rootDir, configDir } = paths;\n const start = process.hrtime.bigint();\n const features = activeFeatures(cfg);\n const stages = stageRecorder(features.map((f) => f.name));\n const elapsed = () => Number(process.hrtime.bigint() - start) / 1e6;\n const files = await stages.time('list', () => listFiles(cfg, rootDir));\n const currentSet = new Set(files.map((f) => f.relPath));\n\n const existingRows = await stages.time('existing', async () => {\n const existingStmt = await conn.prepare('SELECT \"path\", \"_mtime\", \"_size\" FROM frontmatter');\n return (await existingStmt.all()) as Array<{ path: string; _mtime: number; _size: number }>;\n });\n const existing = new Map(existingRows.map((r) => [r.path, r]));\n // A path whose coverage moved between presets (forcedPaths) but is no longer covered at all is\n // already caught below by !currentSet.has, since it can only be forced by having existed under\n // an old preset's match, which means it was reconciled into `existing` already.\n const vanished = existingRows.filter((r) => !currentSet.has(r.path)).map((r) => r.path);\n\n // forcedPaths treats an unchanged file as touched because its preset coverage moved, not its\n // stamp -- reconcile still owns add/update/remove and every cross-feature cascade for it.\n const toReparse = files.filter((f) => {\n const row = existing.get(f.relPath);\n return !row || row._mtime !== f.mtimeMs || row._size !== f.size || (forcedPaths?.has(f.relPath) ?? false);\n });\n\n if (vanished.length === 0 && toReparse.length === 0) return { parsed: 0, warnings: [], stages: stages.take(elapsed(), 0) };\n\n const seenColumns = await getColumns(conn);\n\n // Bulk reparses (a sync, a cold build) are the long silences a query can hit; short\n // reconciles stay silent (progress() has a threshold).\n const report = progress('reparsing files', toReparse.length);\n // Pool wall time, dispatch to drain, so this stage shares a clock with every other one.\n const { docs: parsedDocs, warnings, newColumns, workerParseMs } = await stages.time('parse', () => reparseFiles(toReparse, features, cfg, seenColumns, report.tick, { pool }));\n report.finish();\n for (const col of newColumns) seenColumns.add(col);\n\n const allColumns = [...seenColumns];\n // Fence before ALTERing: a store's own failure past this point is a raw, engine-specific\n // error with no indication of the boundary or the levers -- dialect.checkColumnLimit names both.\n dialect.checkColumnLimit(allColumns.length);\n // Columns the frontmatter upsert actually writes: core + parsed frontmatter keys, never a\n // feature-owned reserved column (see CORE_FRONTMATTER_COLUMNS above).\n const writableColumns = allColumns.filter((c) => CORE_FRONTMATTER_COLUMNS.has(c) || !RESERVED_COLUMNS.has(c));\n // ON CONFLICT DO UPDATE (not OR REPLACE) keeps the row's rowid stable across reparses --\n // sqlite's content rows are coupled to that rowid.\n const insertSql = `INSERT INTO frontmatter (${writableColumns.map(quoteIdent).join(', ')}) VALUES (${writableColumns.map(() => '?').join(', ')}) ON CONFLICT(\"path\") DO UPDATE SET ${writableColumns\n .filter((c) => c !== 'path')\n .map((c) => `${quoteIdent(c)} = excluded.${quoteIdent(c)}`)\n .join(', ')}`;\n\n const added = toReparse.filter((f) => !existing.has(f.relPath)).map((f) => f.relPath);\n const delta: ReconcileDelta = { files, reparsed: parsedDocs.map((d) => d.relPath), added, vanished };\n const addedSet = new Set(added);\n const reparsedExisting = parsedDocs.map((d) => d.relPath).filter((p) => !addedSet.has(p));\n // Paths whose content (and, per feature, other rows) need clearing: gone entirely, or about to\n // be reinserted fresh. Disjoint from `added`, which has nothing to clear.\n const touched = [...vanished, ...reparsedExisting];\n\n const txStart = Date.now();\n await withTransaction(\n conn,\n async () => {\n // Re-read inside the write transaction: newColumns came from a read taken before it opened, so a\n // concurrent reconcile may have added some of them since. ALTER has no IF NOT EXISTS.\n const present = await getColumns(conn);\n const missingColumns = newColumns.filter((col) => !present.has(col));\n if (missingColumns.length > 0) await stages.time('alter', () => dialect.addColumns(conn, missingColumns));\n\n // Revalidated once the lock is held, before this process's own frontmatter upsert below:\n // `added` came from a path read taken before this transaction's lock, so a path still\n // called \"added\" here may already have a content row from a concurrent reconcile that\n // committed while this one waited. One SELECT, not a DELETE per added file -- with no\n // contention it returns the same set `existing` already ruled out, so nothing extra clears.\n let contentTouched = touched;\n if (added.length > 0)\n contentTouched = await stages.time('added-recheck', async () => {\n const currentPathsStmt = await conn.prepare('SELECT \"path\" FROM frontmatter');\n const currentPaths = new Set(((await currentPathsStmt.all()) as Array<{ path: string }>).map((r) => r.path));\n const staleAdded = added.filter((p) => currentPaths.has(p));\n return staleAdded.length > 0 ? [...touched, ...staleAdded] : touched;\n });\n\n if (parsedDocs.length > 0) {\n const toRow = (doc: (typeof parsedDocs)[number]) =>\n writableColumns.map((col) => {\n if (col === 'path') return doc.relPath;\n if (col === '_mtime') return doc.mtimeMs;\n if (col === '_ctime') return doc.ctimeMs;\n if (col === '_size') return doc.size;\n // Written per parse, unlike _rank, which a feature pass owns and the upsert skips.\n if (col === '_parse_error') return doc.parseError;\n return doc.data[col] ?? null;\n });\n // A path in `added` has no existing frontmatter row, so it can never conflict; the rest\n // genuinely can, and keep the upsert.\n await stages.time('fm-upsert', async () => {\n const newDocs = parsedDocs.filter((d) => addedSet.has(d.relPath));\n const updateDocs = parsedDocs.filter((d) => !addedSet.has(d.relPath));\n await appendRows(conn, 'frontmatter', writableColumns, insertSql, newDocs.map(toRow));\n if (updateDocs.length > 0) await conn.runBatch(insertSql, updateDocs.map(toRow));\n });\n }\n\n // After the upsert, so every doc already has the frontmatter row sqlite's content rowid\n // couples to. ON CONFLICT DO UPDATE preserves that rowid, so a reparse keeps its identity.\n await stages.time('text-index', () => dialect.reconcileContent(conn, contentTouched, parsedDocs, delta, cfg));\n\n // A preset edit forces a full rebuild, so an unchanged doc's coverage is already correct;\n // new docs have nothing to clear, which keeps cold builds linear.\n await stages.time('presets', async () => {\n if (touched.length > 0)\n await conn.runBatch(\n 'DELETE FROM preset_files WHERE \"path\" = ?',\n touched.map((p) => [p])\n );\n const presetRows: unknown[][] = [];\n for (const doc of parsedDocs) for (const presetName of doc.presets) presetRows.push([doc.relPath, presetName]);\n // DO NOTHING, not a bare INSERT: the added/touched split above comes from a read taken\n // before this transaction's lock, so a path this process calls \"added\" can already have\n // its (path, preset) row committed by a concurrent reconcile -- the row would be identical either way.\n await appendRows(conn, 'preset_files', ['path', 'preset'], 'INSERT INTO preset_files (\"path\", preset) VALUES (?, ?) ON CONFLICT(\"path\", preset) DO NOTHING', presetRows);\n });\n\n // Before the feature hooks, never after: rank's afterReconcile reads frontmatter as PageRank's\n // node set, so a lingering vanished row would dilute rank mass across every surviving note.\n if (vanished.length > 0)\n await stages.time('vanished', () =>\n conn.runBatch(\n 'DELETE FROM frontmatter WHERE \"path\" = ?',\n vanished.map((p) => [p])\n )\n );\n\n // Timed per feature per hook, so link resolution and PageRank are named stages without\n // links.ts or rank.ts knowing anything about this, and a new feature is visible for free.\n if (touched.length > 0) for (const feature of features) await stages.time(featureStage(feature.name, 'remove'), () => feature.remove?.(conn, touched, delta));\n for (const feature of features) {\n const docsForFeature: ExtractedDoc[] = parsedDocs.map((doc) => ({ path: doc.relPath, extracted: doc.extracted[feature.name] }));\n await stages.time(featureStage(feature.name, 'store'), () => feature.store?.(conn, docsForFeature, delta));\n }\n for (const feature of features) await stages.time(featureStage(feature.name, 'after'), () => feature.afterReconcile?.(conn, delta));\n },\n dialect.beginMode()\n );\n\n const durationMs = Date.now() - txStart;\n // Every store, not just the ones with a PRAGMA to derive: connectUnlocked's lock-wait budget needs it too.\n recordLockWaitMs(configDir, durationMs);\n if (dialect.recordDuration) await stages.time('meta', () => dialect.recordDuration?.(conn, durationMs));\n\n return { parsed: parsedDocs.length, warnings, stages: stages.take(elapsed(), durationMs, workerParseMs) };\n}\n"],"names":["CORE_FRONTMATTER_COLUMNS","reconcile","Set","conn","cfg","paths","dialect","pool","forcedPaths","rootDir","configDir","start","features","stages","elapsed","files","currentSet","existingRows","existing","vanished","toReparse","seenColumns","report","parsedDocs","warnings","newColumns","workerParseMs","col","allColumns","writableColumns","insertSql","added","delta","addedSet","reparsedExisting","touched","txStart","durationMs","process","hrtime","bigint","activeFeatures","stageRecorder","map","f","name","Number","time","listFiles","relPath","existingStmt","prepare","all","Map","r","path","filter","has","row","get","_mtime","mtimeMs","_size","size","length","parsed","take","getColumns","progress","reparseFiles","tick","docs","finish","add","checkColumnLimit","c","RESERVED_COLUMNS","quoteIdent","join","reparsed","d","p","Date","now","withTransaction","present","missingColumns","contentTouched","toRow","addColumns","currentPathsStmt","currentPaths","staleAdded","doc","ctimeMs","parseError","data","newDocs","updateDocs","appendRows","runBatch","reconcileContent","presetRows","presetName","presets","push","feature","featureStage","remove","docsForFeature","extracted","store","afterReconcile","beginMode","recordLockWaitMs","recordDuration"],"mappings":"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"}