sensemaking 0.20.0 → 0.21.0

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 (138) hide show
  1. package/README.md +0 -1
  2. package/dist/cjs/config/access.d.cts +0 -1
  3. package/dist/cjs/config/access.d.ts +0 -1
  4. package/dist/cjs/config/access.js +10 -17
  5. package/dist/cjs/config/access.js.map +1 -1
  6. package/dist/cjs/config/index.d.cts +1 -1
  7. package/dist/cjs/config/index.d.ts +1 -1
  8. package/dist/cjs/config/index.js +0 -3
  9. package/dist/cjs/config/index.js.map +1 -1
  10. package/dist/cjs/config/types.d.cts +0 -3
  11. package/dist/cjs/config/types.d.ts +0 -3
  12. package/dist/cjs/config/types.js.map +1 -1
  13. package/dist/cjs/config/validate.js +6 -24
  14. package/dist/cjs/config/validate.js.map +1 -1
  15. package/dist/cjs/errors.d.cts +1 -1
  16. package/dist/cjs/errors.d.ts +1 -1
  17. package/dist/cjs/errors.js.map +1 -1
  18. package/dist/cjs/features/links.js +4 -5
  19. package/dist/cjs/features/links.js.map +1 -1
  20. package/dist/cjs/features/sections.js +4 -1
  21. package/dist/cjs/features/sections.js.map +1 -1
  22. package/dist/cjs/store/builder.d.cts +9 -1
  23. package/dist/cjs/store/builder.d.ts +9 -1
  24. package/dist/cjs/store/builder.js +593 -2
  25. package/dist/cjs/store/builder.js.map +1 -1
  26. package/dist/cjs/store/duckdb/open.js +7 -1
  27. package/dist/cjs/store/duckdb/open.js.map +1 -1
  28. package/dist/cjs/store/duckdb/reconcile.js +30 -5
  29. package/dist/cjs/store/duckdb/reconcile.js.map +1 -1
  30. package/dist/cjs/store/embed-scope.d.cts +2 -0
  31. package/dist/cjs/store/embed-scope.d.ts +2 -0
  32. package/dist/cjs/store/embed-scope.js +85 -0
  33. package/dist/cjs/store/embed-scope.js.map +1 -0
  34. package/dist/cjs/store/feature-scope.d.cts +8 -0
  35. package/dist/cjs/store/feature-scope.d.ts +8 -0
  36. package/dist/cjs/store/feature-scope.js +107 -0
  37. package/dist/cjs/store/feature-scope.js.map +1 -0
  38. package/dist/cjs/store/open.js +193 -101
  39. package/dist/cjs/store/open.js.map +1 -1
  40. package/dist/cjs/store/preset-scope.d.cts +3 -0
  41. package/dist/cjs/store/preset-scope.d.ts +3 -0
  42. package/dist/cjs/store/preset-scope.js +293 -0
  43. package/dist/cjs/store/preset-scope.js.map +1 -0
  44. package/dist/cjs/store/reconcile.d.cts +1 -1
  45. package/dist/cjs/store/reconcile.d.ts +1 -1
  46. package/dist/cjs/store/reconcile.js +172 -178
  47. package/dist/cjs/store/reconcile.js.map +1 -1
  48. package/dist/cjs/store/signature.js +7 -5
  49. package/dist/cjs/store/signature.js.map +1 -1
  50. package/dist/cjs/store/sqlite/lexical.d.cts +1 -1
  51. package/dist/cjs/store/sqlite/lexical.d.ts +1 -1
  52. package/dist/cjs/store/sqlite/lexical.js +2 -2
  53. package/dist/cjs/store/sqlite/lexical.js.map +1 -1
  54. package/dist/cjs/store/sqlite/open.d.cts +0 -1
  55. package/dist/cjs/store/sqlite/open.d.ts +0 -1
  56. package/dist/cjs/store/sqlite/open.js +14 -231
  57. package/dist/cjs/store/sqlite/open.js.map +1 -1
  58. package/dist/cjs/store/sqlite/reconcile.d.cts +1 -1
  59. package/dist/cjs/store/sqlite/reconcile.d.ts +1 -1
  60. package/dist/cjs/store/sqlite/reconcile.js +78 -16
  61. package/dist/cjs/store/sqlite/reconcile.js.map +1 -1
  62. package/dist/cjs/store/sqlite/sql-functions.d.cts +1 -1
  63. package/dist/cjs/store/sqlite/sql-functions.d.ts +1 -1
  64. package/dist/cjs/store/sqlite/sql-functions.js +3 -3
  65. package/dist/cjs/store/sqlite/sql-functions.js.map +1 -1
  66. package/dist/cjs/store/sqlite/store.d.cts +1 -2
  67. package/dist/cjs/store/sqlite/store.d.ts +1 -2
  68. package/dist/cjs/store/sqlite/store.js +2 -3
  69. package/dist/cjs/store/sqlite/store.js.map +1 -1
  70. package/dist/cjs/store/turso/open.js +6 -0
  71. package/dist/cjs/store/turso/open.js.map +1 -1
  72. package/dist/cjs/store/turso/reconcile.js +72 -3
  73. package/dist/cjs/store/turso/reconcile.js.map +1 -1
  74. package/dist/cjs/store/types.d.cts +2 -4
  75. package/dist/cjs/store/types.d.ts +2 -4
  76. package/dist/cjs/store/types.js.map +1 -1
  77. package/dist/esm/config/access.d.ts +0 -1
  78. package/dist/esm/config/access.js +12 -17
  79. package/dist/esm/config/access.js.map +1 -1
  80. package/dist/esm/config/index.d.ts +1 -1
  81. package/dist/esm/config/index.js +1 -1
  82. package/dist/esm/config/index.js.map +1 -1
  83. package/dist/esm/config/types.d.ts +0 -3
  84. package/dist/esm/config/types.js.map +1 -1
  85. package/dist/esm/config/validate.js +6 -22
  86. package/dist/esm/config/validate.js.map +1 -1
  87. package/dist/esm/errors.d.ts +1 -1
  88. package/dist/esm/errors.js.map +1 -1
  89. package/dist/esm/features/links.js +3 -4
  90. package/dist/esm/features/links.js.map +1 -1
  91. package/dist/esm/features/sections.js +4 -1
  92. package/dist/esm/features/sections.js.map +1 -1
  93. package/dist/esm/store/builder.d.ts +9 -1
  94. package/dist/esm/store/builder.js +152 -3
  95. package/dist/esm/store/builder.js.map +1 -1
  96. package/dist/esm/store/duckdb/open.js +5 -1
  97. package/dist/esm/store/duckdb/open.js.map +1 -1
  98. package/dist/esm/store/duckdb/reconcile.js +11 -3
  99. package/dist/esm/store/duckdb/reconcile.js.map +1 -1
  100. package/dist/esm/store/embed-scope.d.ts +2 -0
  101. package/dist/esm/store/embed-scope.js +28 -0
  102. package/dist/esm/store/embed-scope.js.map +1 -0
  103. package/dist/esm/store/feature-scope.d.ts +8 -0
  104. package/dist/esm/store/feature-scope.js +49 -0
  105. package/dist/esm/store/feature-scope.js.map +1 -0
  106. package/dist/esm/store/open.js +78 -28
  107. package/dist/esm/store/open.js.map +1 -1
  108. package/dist/esm/store/preset-scope.d.ts +3 -0
  109. package/dist/esm/store/preset-scope.js +77 -0
  110. package/dist/esm/store/preset-scope.js.map +1 -0
  111. package/dist/esm/store/reconcile.d.ts +1 -1
  112. package/dist/esm/store/reconcile.js +30 -5
  113. package/dist/esm/store/reconcile.js.map +1 -1
  114. package/dist/esm/store/signature.js +7 -5
  115. package/dist/esm/store/signature.js.map +1 -1
  116. package/dist/esm/store/sqlite/lexical.d.ts +1 -1
  117. package/dist/esm/store/sqlite/lexical.js +4 -4
  118. package/dist/esm/store/sqlite/lexical.js.map +1 -1
  119. package/dist/esm/store/sqlite/open.d.ts +0 -1
  120. package/dist/esm/store/sqlite/open.js +14 -88
  121. package/dist/esm/store/sqlite/open.js.map +1 -1
  122. package/dist/esm/store/sqlite/reconcile.d.ts +1 -1
  123. package/dist/esm/store/sqlite/reconcile.js +14 -14
  124. package/dist/esm/store/sqlite/reconcile.js.map +1 -1
  125. package/dist/esm/store/sqlite/sql-functions.d.ts +1 -1
  126. package/dist/esm/store/sqlite/sql-functions.js +3 -3
  127. package/dist/esm/store/sqlite/sql-functions.js.map +1 -1
  128. package/dist/esm/store/sqlite/store.d.ts +1 -2
  129. package/dist/esm/store/sqlite/store.js +2 -3
  130. package/dist/esm/store/sqlite/store.js.map +1 -1
  131. package/dist/esm/store/turso/open.js +4 -0
  132. package/dist/esm/store/turso/open.js.map +1 -1
  133. package/dist/esm/store/turso/reconcile.js +6 -2
  134. package/dist/esm/store/turso/reconcile.js.map +1 -1
  135. package/dist/esm/store/types.d.ts +2 -4
  136. package/dist/esm/store/types.js.map +1 -1
  137. package/package.json +3 -2
  138. package/schema.json +0 -11
@@ -23,19 +23,15 @@ var _nodefs = require("node:fs");
23
23
  var _nodepath = require("node:path");
24
24
  var _indexts = require("../config/index.js");
25
25
  var _handoffts = require("../embed/handoff.js");
26
+ var _errorsts = require("../errors.js");
26
27
  var _indexts1 = require("../features/index.js");
27
28
  var _builderts = require("./builder.js");
28
29
  var _cachets = require("./cache.js");
30
+ var _embedscopets = require("./embed-scope.js");
31
+ var _featurescopets = require("./feature-scope.js");
32
+ var _presetscopets = require("./preset-scope.js");
29
33
  var _sharedts = require("./shared.js");
30
34
  var _signaturets = require("./signature.js");
31
- function _array_like_to_array(arr, len) {
32
- if (len == null || len > arr.length) len = arr.length;
33
- for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
34
- return arr2;
35
- }
36
- function _array_without_holes(arr) {
37
- if (Array.isArray(arr)) return _array_like_to_array(arr);
38
- }
39
35
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
40
36
  try {
41
37
  var info = gen[key](arg);
@@ -62,17 +58,6 @@ function _async_to_generator(fn) {
62
58
  });
63
59
  };
64
60
  }
65
- function _iterable_to_array(iter) {
66
- if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
67
- return Array.from(iter);
68
- }
69
- }
70
- function _non_iterable_spread() {
71
- throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
72
- }
73
- function _to_consumable_array(arr) {
74
- return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
75
- }
76
61
  function _ts_generator(thisArg, body) {
77
62
  var f, y, t, _ = {
78
63
  label: 0,
@@ -172,17 +157,70 @@ function _ts_generator(thisArg, body) {
172
157
  };
173
158
  }
174
159
  }
175
- function _unsupported_iterable_to_array(o, minLen) {
176
- if (!o) return;
177
- if (typeof o === "string") return _array_like_to_array(o, minLen);
178
- var n = Object.prototype.toString.call(o).slice(8, -1);
179
- if (n === "Object" && o.constructor) n = o.constructor.name;
180
- if (n === "Map" || n === "Set") return Array.from(n);
181
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
160
+ // duckdb and turso hold the cache file for their connection's whole life, not for a transaction,
161
+ // so a second command waits on the first command finishing. Bounded rather than open-ended: this
162
+ // clears a warm query's collision (~100ms) and still fails loudly behind a cold build instead of
163
+ // looking hung.
164
+ var LOCK_RETRY_MS = 5000;
165
+ var LOCK_POLL_MS = 50;
166
+ function connectUnlocked(dbPath, cfg, dialect) {
167
+ return _async_to_generator(function() {
168
+ var deadline, err, _dialect_isLocked;
169
+ return _ts_generator(this, function(_state) {
170
+ switch(_state.label){
171
+ case 0:
172
+ deadline = Date.now() + LOCK_RETRY_MS;
173
+ _state.label = 1;
174
+ case 1:
175
+ _state.trys.push([
176
+ 1,
177
+ 3,
178
+ ,
179
+ 5
180
+ ]);
181
+ return [
182
+ 4,
183
+ dialect.connect(dbPath, cfg)
184
+ ];
185
+ case 2:
186
+ return [
187
+ 2,
188
+ _state.sent()
189
+ ];
190
+ case 3:
191
+ err = _state.sent();
192
+ if (!((_dialect_isLocked = dialect.isLocked) === null || _dialect_isLocked === void 0 ? void 0 : _dialect_isLocked.call(dialect, err))) throw err;
193
+ if (Date.now() >= deadline) {
194
+ throw new _errorsts.SenseError('STORE_BUSY', "another sense process is using this tree's ".concat(cfg.store, " cache (").concat(dbPath, ") and did not release it within ").concat(LOCK_RETRY_MS / 1000, 's; wait for that command to finish, or set "store" to "sqlite" in sense.config.json, which serves concurrent commands'));
195
+ }
196
+ return [
197
+ 4,
198
+ new Promise(function(resolve) {
199
+ return setTimeout(resolve, LOCK_POLL_MS);
200
+ })
201
+ ];
202
+ case 4:
203
+ _state.sent();
204
+ return [
205
+ 3,
206
+ 5
207
+ ];
208
+ case 5:
209
+ return [
210
+ 3,
211
+ 1
212
+ ];
213
+ case 6:
214
+ return [
215
+ 2
216
+ ];
217
+ }
218
+ });
219
+ })();
182
220
  }
183
221
  function connectWithDialect(cfg, dialect, keepBuilderOpen) {
184
222
  return _async_to_generator(function() {
185
- var stateDir, dbPath, _ref, handle, conn, closed, builder, version, features, wantFeatures, tokenizeOnlyRebuild, changedKeys, _tmp, changed, extraReason, rebuildWarnings, _ref1, recordedMaxMs, _ref2, parsed, warnings, err;
223
+ var stateDir, dbPath, _ref, handle, conn, closed, builder, version, features, wantFeatures, forcedPaths, embedInvalidate, featureToggles, changedKeys, presetForced, embedKind, toggles, changed, changed1, changed2, _ref1, recordedMaxMs, embedParsed, _tmp, featureParsed, _tmp1, _ref2, parsed, warnings, err;
186
224
  return _ts_generator(this, function(_state) {
187
225
  switch(_state.label){
188
226
  case 0:
@@ -193,7 +231,7 @@ function connectWithDialect(cfg, dialect, keepBuilderOpen) {
193
231
  dbPath = (0, _nodepath.join)(stateDir, dialect.filename);
194
232
  return [
195
233
  4,
196
- dialect.connect(dbPath, cfg)
234
+ connectUnlocked(dbPath, cfg, dialect)
197
235
  ];
198
236
  case 1:
199
237
  _ref = _state.sent(), handle = _ref.handle, conn = _ref.conn;
@@ -207,9 +245,9 @@ function connectWithDialect(cfg, dialect, keepBuilderOpen) {
207
245
  case 2:
208
246
  _state.trys.push([
209
247
  2,
210
- 26,
248
+ 31,
211
249
  ,
212
- 30
250
+ 35
213
251
  ]);
214
252
  return [
215
253
  4,
@@ -230,10 +268,9 @@ function connectWithDialect(cfg, dialect, keepBuilderOpen) {
230
268
  case 5:
231
269
  features = _state.sent();
232
270
  wantFeatures = (0, _indexts.featureSignature)(cfg, _indexts1.FEATURES);
233
- tokenizeOnlyRebuild = false;
234
271
  if (!(version !== null && version !== dialect.schemaVersion || features !== null && features !== wantFeatures)) return [
235
272
  3,
236
- 14
273
+ 17
237
274
  ];
238
275
  if (!(version !== null && version !== dialect.schemaVersion)) return [
239
276
  3,
@@ -255,111 +292,128 @@ function connectWithDialect(cfg, dialect, keepBuilderOpen) {
255
292
  ];
256
293
  case 7:
257
294
  changedKeys = (0, _signaturets.changedSignatureKeys)(features !== null && features !== void 0 ? features : '', wantFeatures);
258
- _tmp = dialect.partialRebuild;
259
- if (!_tmp) return [
295
+ // Null (rather than the empty set) when changedKeys isn't preset-only, or a changed
296
+ // preset's stored segment can't be parsed back into old include/exclude/vectors -- either
297
+ // way the branch below is skipped and the full rebuild stays the fallback.
298
+ presetForced = (0, _presetscopets.isPresetOnlyChange)(changedKeys) ? (0, _presetscopets.forcedPresetPaths)(cfg, cfg.baseDir, features !== null && features !== void 0 ? features : '', changedKeys) : null;
299
+ // Null unless exactly one segment changed and it decomposes into a recognised embed-only
300
+ // case (embed-scope.ts): anything else, including embed toggled on/off, stays null.
301
+ embedKind = changedKeys.size === 1 && changedKeys.has('embed') ? (0, _embedscopets.classifyEmbedChange)(features !== null && features !== void 0 ? features : '', wantFeatures) : null;
302
+ // Null (rather than the empty set) when changedKeys isn't feature-toggle-only, or a changed
303
+ // feature's stored segment can't be parsed back into old/new on-off -- either way the branch
304
+ // below is skipped and the full rebuild stays the fallback.
305
+ toggles = (0, _featurescopets.isFeatureOnlyChange)(changedKeys) ? (0, _featurescopets.classifyFeatureToggles)(features !== null && features !== void 0 ? features : '', wantFeatures, changedKeys) : null;
306
+ if (!(changedKeys.size === 1 && changedKeys.has('embed') && (0, _signaturets.embedIdentityAdopted)(features !== null && features !== void 0 ? features : '', wantFeatures))) return [
260
307
  3,
261
308
  9
262
309
  ];
310
+ // First sight of a resolved weight identity: the model itself hasn't changed, so
311
+ // adopt it into meta with no rebuild and no re-embed.
312
+ console.error("sense: recorded the embedding model's resolved identity; vectors are unaffected");
263
313
  return [
264
314
  4,
265
- dialect.partialRebuild(handle, conn, cfg, changedKeys)
315
+ (0, _sharedts.setMeta)(conn, 'features', wantFeatures)
266
316
  ];
267
317
  case 8:
268
- _tmp = _state.sent();
269
- _state.label = 9;
270
- case 9:
271
- if (!_tmp) return [
272
- 3,
273
- 10
274
- ];
275
- tokenizeOnlyRebuild = true;
318
+ _state.sent();
276
319
  return [
277
320
  3,
278
- 14
321
+ 17
279
322
  ];
280
- case 10:
281
- if (!(changedKeys.size === 1 && changedKeys.has('embed') && (0, _signaturets.embedIdentityAdopted)(features !== null && features !== void 0 ? features : '', wantFeatures))) return [
323
+ case 9:
324
+ if (!(embedKind !== null)) return [
282
325
  3,
283
- 12
326
+ 11
284
327
  ];
285
- // First sight of a resolved weight identity: the model itself hasn't changed, so
286
- // adopt it into meta with no rebuild and no re-embed, mirroring the tokenize precedent.
287
- console.error("sense: recorded the embedding model's resolved identity; vectors are unaffected");
328
+ // Chunk boundaries are file-derived, not model-derived (embed.ts's chunksOf), so neither
329
+ // case needs any file reparsed for any feature but embed itself.
330
+ embedInvalidate = embedKind;
331
+ 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');
288
332
  return [
289
333
  4,
290
334
  (0, _sharedts.setMeta)(conn, 'features', wantFeatures)
291
335
  ];
292
- case 11:
336
+ case 10:
293
337
  _state.sent();
294
338
  return [
295
339
  3,
296
- 14
340
+ 17
297
341
  ];
298
- case 12:
342
+ case 11:
343
+ if (!(presetForced !== null)) return [
344
+ 3,
345
+ 13
346
+ ];
347
+ // Membership only: which files a preset covers moved, not a file's own content, a
348
+ // global feature, or the embed model. reconcile() already knows how to
349
+ // add, update, and remove a file correctly (every cross-feature cascade included); it
350
+ // just needs telling which unchanged files to treat as touched (forcedPaths, above).
351
+ forcedPaths = presetForced;
299
352
  changed = (0, _signaturets.signatureDiff)(features !== null && features !== void 0 ? features : '', wantFeatures);
300
- console.error("sense: config change (".concat(changed, ") rebuilds the index"));
301
- closed = true;
353
+ console.error("sense: config change (".concat(changed, ") reparses only the files it affects"));
302
354
  return [
303
355
  4,
304
- dialect.close(handle)
356
+ (0, _sharedts.setMeta)(conn, 'features', wantFeatures)
305
357
  ];
306
- case 13:
358
+ case 12:
307
359
  _state.sent();
308
- (0, _cachets.clearCache)(cfg);
309
360
  return [
310
- 2,
311
- connectWithDialect(cfg, dialect, keepBuilderOpen)
361
+ 3,
362
+ 17
363
+ ];
364
+ case 13:
365
+ if (!(toggles !== null)) return [
366
+ 3,
367
+ 15
368
+ ];
369
+ // A feature turned off or on: reconcile.ts's activeFeatures skips a disabled feature's
370
+ // hooks entirely, so its rows rot while off -- invalidateFeatures drops them and, for a
371
+ // feature turning back on, fully re-derives across every indexed file rather than
372
+ // trusting rows written before or during that window.
373
+ featureToggles = toggles;
374
+ changed1 = (0, _signaturets.signatureDiff)(features !== null && features !== void 0 ? features : '', wantFeatures);
375
+ console.error("sense: config change (".concat(changed1, ") reparses only the feature it affects"));
376
+ return [
377
+ 4,
378
+ (0, _sharedts.setMeta)(conn, 'features', wantFeatures)
312
379
  ];
313
380
  case 14:
314
- // A rebuild trigger independent of the signature comparison above (sqlite: the content
315
- // table's own DDL no longer matches the resolved tokenizer).
316
- extraReason = dialect.extraRebuildReason ? dialect.extraRebuildReason(handle) : null;
317
- if (!(extraReason !== null)) return [
381
+ _state.sent();
382
+ return [
318
383
  3,
319
- 16
384
+ 17
320
385
  ];
321
- console.error("sense: ".concat(extraReason, "; rebuilding the index"));
386
+ case 15:
387
+ changed2 = (0, _signaturets.signatureDiff)(features !== null && features !== void 0 ? features : '', wantFeatures);
388
+ console.error("sense: config change (".concat(changed2, ") rebuilds the index"));
322
389
  closed = true;
323
390
  return [
324
391
  4,
325
392
  dialect.close(handle)
326
393
  ];
327
- case 15:
394
+ case 16:
328
395
  _state.sent();
329
396
  (0, _cachets.clearCache)(cfg);
330
397
  return [
331
398
  2,
332
399
  connectWithDialect(cfg, dialect, keepBuilderOpen)
333
400
  ];
334
- case 16:
335
- return [
336
- 4,
337
- dialect.ensureSchema(handle, conn, cfg)
338
- ];
339
401
  case 17:
340
- _state.sent();
341
- rebuildWarnings = [];
342
- if (!(tokenizeOnlyRebuild && dialect.postSchemaRebuild)) return [
343
- 3,
344
- 19
345
- ];
346
402
  return [
347
403
  4,
348
- dialect.postSchemaRebuild(handle, conn, cfg, cfg.baseDir, wantFeatures)
404
+ dialect.ensureSchema(handle, conn, cfg)
349
405
  ];
350
406
  case 18:
351
- rebuildWarnings = _state.sent();
352
- _state.label = 19;
353
- case 19:
407
+ _state.sent();
354
408
  if (!dialect.setDerivedBusyTimeout) return [
355
409
  3,
356
- 22
410
+ 21
357
411
  ];
358
412
  return [
359
413
  4,
360
414
  (0, _sharedts.getMeta)(conn, 'reconcile_max_ms')
361
415
  ];
362
- case 20:
416
+ case 19:
363
417
  recordedMaxMs = Number.apply(void 0, [
364
418
  (_ref1 = _state.sent()) !== null && _ref1 !== void 0 ? _ref1 : '0'
365
419
  ]);
@@ -367,28 +421,66 @@ function connectWithDialect(cfg, dialect, keepBuilderOpen) {
367
421
  4,
368
422
  dialect.setDerivedBusyTimeout(handle, conn, Math.min(Math.max(30000, 3 * recordedMaxMs), 600000))
369
423
  ];
370
- case 21:
424
+ case 20:
371
425
  _state.sent();
372
- _state.label = 22;
373
- case 22:
426
+ _state.label = 21;
427
+ case 21:
428
+ if (!embedInvalidate) return [
429
+ 3,
430
+ 23
431
+ ];
374
432
  return [
375
433
  4,
376
- builder.build()
434
+ builder.invalidate(embedInvalidate)
435
+ ];
436
+ case 22:
437
+ _tmp = _state.sent().parsed;
438
+ return [
439
+ 3,
440
+ 24
377
441
  ];
378
442
  case 23:
443
+ _tmp = 0;
444
+ _state.label = 24;
445
+ case 24:
446
+ embedParsed = _tmp;
447
+ if (!featureToggles) return [
448
+ 3,
449
+ 26
450
+ ];
451
+ return [
452
+ 4,
453
+ builder.invalidateFeatures(featureToggles)
454
+ ];
455
+ case 25:
456
+ _tmp1 = _state.sent().parsed;
457
+ return [
458
+ 3,
459
+ 27
460
+ ];
461
+ case 26:
462
+ _tmp1 = 0;
463
+ _state.label = 27;
464
+ case 27:
465
+ featureParsed = _tmp1;
466
+ return [
467
+ 4,
468
+ builder.build(forcedPaths)
469
+ ];
470
+ case 28:
379
471
  _ref2 = _state.sent(), parsed = _ref2.parsed, warnings = _ref2.warnings;
380
472
  if (!!keepBuilderOpen) return [
381
473
  3,
382
- 25
474
+ 30
383
475
  ];
384
476
  return [
385
477
  4,
386
478
  builder.close()
387
479
  ];
388
- case 24:
480
+ case 29:
389
481
  _state.sent();
390
- _state.label = 25;
391
- case 25:
482
+ _state.label = 30;
483
+ case 30:
392
484
  return [
393
485
  2,
394
486
  {
@@ -396,33 +488,33 @@ function connectWithDialect(cfg, dialect, keepBuilderOpen) {
396
488
  conn: conn,
397
489
  cfg: cfg,
398
490
  dbPath: dbPath,
399
- parsed: parsed,
400
- warnings: _to_consumable_array(rebuildWarnings).concat(_to_consumable_array(warnings)),
491
+ parsed: parsed + embedParsed + featureParsed,
492
+ warnings: warnings,
401
493
  builder: builder
402
494
  }
403
495
  ];
404
- case 26:
496
+ case 31:
405
497
  err = _state.sent();
406
498
  return [
407
499
  4,
408
500
  builder.close()
409
501
  ];
410
- case 27:
502
+ case 32:
411
503
  _state.sent();
412
504
  if (!!closed) return [
413
505
  3,
414
- 29
506
+ 34
415
507
  ];
416
508
  return [
417
509
  4,
418
510
  dialect.close(handle)
419
511
  ];
420
- case 28:
512
+ case 33:
421
513
  _state.sent();
422
- _state.label = 29;
423
- case 29:
514
+ _state.label = 34;
515
+ case 34:
424
516
  throw err;
425
- case 30:
517
+ case 35:
426
518
  return [
427
519
  2
428
520
  ];
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/open.ts"],"sourcesContent":["import { 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 { FEATURES } from '../features/index.ts';\nimport type { Builder } from './builder.ts';\nimport { createBuilder } from './builder.ts';\nimport { clearCache } from './cache.ts';\nimport { getMeta, setMeta } from './shared.ts';\nimport { changedSignatureKeys, embedIdentityAdopted, signatureDiff } from './signature.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}\n\ninterface ConnectResult<Handle> {\n handle: Handle;\n conn: Connection;\n cfg: ResolvedConfig;\n dbPath: string;\n parsed: number;\n warnings: string[];\n // Closed already unless `keepBuilderOpen` was set: a one-shot open reconciles once and is done\n // with it, a watcher keeps calling build() on the same instance across its whole run.\n builder: Builder;\n}\n\nasync function connectWithDialect<Handle>(cfg: ResolvedConfig, dialect: OpenDialect<Handle>, keepBuilderOpen: boolean): Promise<ConnectResult<Handle>> {\n const stateDir = join(cfg.baseDir, STATE_DIR);\n mkdirSync(stateDir, { recursive: true });\n const dbPath = join(stateDir, dialect.filename);\n\n const { handle, conn } = await dialect.connect(dbPath, cfg);\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(): its pool must survive across every build() call this\n // connection sees (a watcher's repeated ticks), not just the one below.\n const builder = createBuilder(conn, cfg, 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 let tokenizeOnlyRebuild = false;\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, keepBuilderOpen);\n }\n const changedKeys = changedSignatureKeys(features ?? '', wantFeatures);\n // Only a dialect-owned carve-out (sqlite's tokenizer) skips the rebuild below with its own\n // partial DDL swap; every other single- or multi-segment change takes it.\n if (dialect.partialRebuild && (await dialect.partialRebuild(handle, conn, cfg, changedKeys))) {\n tokenizeOnlyRebuild = true;\n } else 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, mirroring the tokenize precedent.\n console.error(\"sense: recorded the embedding model's resolved identity; vectors are unaffected\");\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, keepBuilderOpen);\n }\n }\n\n // A rebuild trigger independent of the signature comparison above (sqlite: the content\n // table's own DDL no longer matches the resolved tokenizer).\n const extraReason = dialect.extraRebuildReason ? dialect.extraRebuildReason(handle) : null;\n if (extraReason !== null) {\n console.error(`sense: ${extraReason}; rebuilding the index`);\n closed = true;\n await dialect.close(handle);\n clearCache(cfg);\n return connectWithDialect(cfg, dialect, keepBuilderOpen);\n }\n\n await dialect.ensureSchema(handle, conn, cfg);\n\n let rebuildWarnings: string[] = [];\n if (tokenizeOnlyRebuild && dialect.postSchemaRebuild) {\n rebuildWarnings = await dialect.postSchemaRebuild(handle, conn, cfg, cfg.baseDir, wantFeatures);\n }\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 const { parsed, warnings } = await builder.build();\n // A one-shot open is done reconciling for good; a watcher keeps `builder` alive across its run.\n if (!keepBuilderOpen) await builder.close();\n\n return { handle, conn, cfg, dbPath, parsed, warnings: [...rebuildWarnings, ...warnings], builder };\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 const { handle, conn, cfg: resolvedCfg, dbPath, parsed, warnings } = await connectWithDialect(cfg, dialect, false);\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 };\n}\n\n// Same connect+build as openWithDialect, but keeps the builder's pool alive and hands it back\n// alongside the store, for a caller (a watcher) that reconciles repeatedly on this connection.\nexport async function openWithBuilder<Handle>(cfg: ResolvedConfig, dialect: OpenDialect<Handle>): Promise<OpenResult & { builder: Builder }> {\n const { handle, conn, cfg: resolvedCfg, dbPath, parsed, warnings, builder } = await connectWithDialect(cfg, dialect, true);\n const store = dialect.createStore(handle, conn, resolvedCfg);\n rekeyChunkText(conn, store);\n return { store, cfg: resolvedCfg, dbPath, parsed, warnings, builder };\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","openWithBuilder","openWithDialect","connectWithDialect","cfg","dialect","keepBuilderOpen","stateDir","dbPath","handle","conn","closed","builder","version","features","wantFeatures","tokenizeOnlyRebuild","changedKeys","changed","extraReason","rebuildWarnings","recordedMaxMs","parsed","warnings","err","join","baseDir","STATE_DIR","mkdirSync","recursive","filename","connect","createBuilder","reconcileDialect","exec","getMeta","featureSignature","FEATURES","schemaVersion","console","error","close","clearCache","changedSignatureKeys","partialRebuild","size","has","embedIdentityAdopted","setMeta","signatureDiff","extraRebuildReason","ensureSchema","postSchemaRebuild","setDerivedBusyTimeout","Number","Math","min","max","build","resolvedCfg","store","createStore","rekeyChunkText","stmt","prepare","get","n"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/sensemaking/src/store/open.ts"],"sourcesContent":["import { 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 type { Builder } from './builder.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 { forcedPresetPaths, isPresetOnlyChange } from './preset-scope.ts';\nimport { getMeta, setMeta } from './shared.ts';\nimport { changedSignatureKeys, embedIdentityAdopted, signatureDiff } from './signature.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}\n\ninterface ConnectResult<Handle> {\n handle: Handle;\n conn: Connection;\n cfg: ResolvedConfig;\n dbPath: string;\n parsed: number;\n warnings: string[];\n // Closed already unless `keepBuilderOpen` was set: a one-shot open reconciles once and is done\n // with it, a watcher keeps calling build() on the same instance across its whole run.\n builder: Builder;\n}\n\n// duckdb and turso hold the cache file for their connection's whole life, not for a transaction,\n// so a second command waits on the first command finishing. Bounded rather than open-ended: this\n// clears a warm query's collision (~100ms) and still fails loudly behind a cold build instead of\n// looking hung.\nconst LOCK_RETRY_MS = 5_000;\nconst LOCK_POLL_MS = 50;\n\nasync function connectUnlocked<Handle>(dbPath: string, cfg: ResolvedConfig, dialect: OpenDialect<Handle>): Promise<{ handle: Handle; conn: Connection }> {\n const deadline = Date.now() + LOCK_RETRY_MS;\n for (;;) {\n try {\n return await dialect.connect(dbPath, cfg);\n } catch (err) {\n if (!dialect.isLocked?.(err as Error)) throw err;\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 ${LOCK_RETRY_MS / 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>, keepBuilderOpen: boolean): Promise<ConnectResult<Handle>> {\n const stateDir = join(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(): its pool must survive across every build() call this\n // connection sees (a watcher's repeated ticks), not just the one below.\n const builder = createBuilder(conn, cfg, 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, keepBuilderOpen);\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.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, keepBuilderOpen);\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 } = await builder.build(forcedPaths);\n // A one-shot open is done reconciling for good; a watcher keeps `builder` alive across its run.\n if (!keepBuilderOpen) await builder.close();\n\n return { handle, conn, cfg, dbPath, parsed: parsed + embedParsed + featureParsed, warnings, builder };\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 const { handle, conn, cfg: resolvedCfg, dbPath, parsed, warnings } = await connectWithDialect(cfg, dialect, false);\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 };\n}\n\n// Same connect+build as openWithDialect, but keeps the builder's pool alive and hands it back\n// alongside the store, for a caller (a watcher) that reconciles repeatedly on this connection.\nexport async function openWithBuilder<Handle>(cfg: ResolvedConfig, dialect: OpenDialect<Handle>): Promise<OpenResult & { builder: Builder }> {\n const { handle, conn, cfg: resolvedCfg, dbPath, parsed, warnings, builder } = await connectWithDialect(cfg, dialect, true);\n const store = dialect.createStore(handle, conn, resolvedCfg);\n rekeyChunkText(conn, store);\n return { store, cfg: resolvedCfg, dbPath, parsed, warnings, builder };\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","openWithBuilder","openWithDialect","LOCK_RETRY_MS","LOCK_POLL_MS","connectUnlocked","dbPath","cfg","dialect","deadline","err","Date","now","connect","isLocked","SenseError","store","Promise","resolve","setTimeout","connectWithDialect","keepBuilderOpen","stateDir","handle","conn","closed","builder","version","features","wantFeatures","forcedPaths","embedInvalidate","featureToggles","changedKeys","presetForced","embedKind","toggles","changed","recordedMaxMs","embedParsed","featureParsed","parsed","warnings","join","baseDir","STATE_DIR","mkdirSync","recursive","filename","createBuilder","reconcileDialect","exec","getMeta","featureSignature","FEATURES","schemaVersion","console","error","close","clearCache","changedSignatureKeys","isPresetOnlyChange","forcedPresetPaths","size","has","classifyEmbedChange","isFeatureOnlyChange","classifyFeatureToggles","embedIdentityAdopted","setMeta","signatureDiff","ensureSchema","setDerivedBusyTimeout","Number","Math","min","max","invalidate","invalidateFeatures","build","resolvedCfg","createStore","rekeyChunkText","stmt","prepare","get","n"],"mappings":";;;;;;;;;;;QAyMsBA;eAAAA;;QAPAC;eAAAA;;QAVAC;eAAAA;;;sBAxLI;wBACL;uBAEuB;yBACb;wBACJ;wBACF;yBAEK;uBACH;4BAES;8BAEwB;6BACN;wBACrB;2BACyC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4B1E,iGAAiG;AACjG,iGAAiG;AACjG,iGAAiG;AACjG,gBAAgB;AAChB,IAAMC,gBAAgB;AACtB,IAAMC,eAAe;AAErB,SAAeC,gBAAwBC,MAAc,EAAEC,GAAmB,EAAEC,OAA4B;;YAChGC,UAIKC,KACFF;;;;oBALHC,WAAWE,KAAKC,GAAG,KAAKT;;;;;;;;;oBAGnB;;wBAAMK,QAAQK,OAAO,CAACP,QAAQC;;;oBAArC;;wBAAO;;;oBACAG;oBACP,IAAI,GAACF,oBAAAA,QAAQM,QAAQ,cAAhBN,wCAAAA,uBAAAA,SAAmBE,OAAe,MAAMA;oBAC7C,IAAIC,KAAKC,GAAG,MAAMH,UAAU;wBAC1B,MAAM,IAAIM,oBAAU,CAAC,cAAc,AAAC,8CAAiET,OAApBC,IAAIS,KAAK,EAAC,YAAmDb,OAAzCG,QAAO,oCAAuD,OAArBH,gBAAgB,MAAK;oBACrK;oBACA;;wBAAM,IAAIc,QAAQ,SAACC;mCAAYC,WAAWD,SAASd;;;;oBAAnD;;;;;;;;;;;;;;;;IAGN;;AAEA,SAAegB,mBAA2Bb,GAAmB,EAAEC,OAA4B,EAAEa,eAAwB;;YAC7GC,UAEAhB,QAEmB,MAAjBiB,QAAQC,MAGZC,QAGEC,SAMEC,SACAC,UACAC,cAGFC,aAEAC,iBAEAC,gBAYIC,aAIAC,cAGAC,WAIAC,SAkBEC,SASAA,UAIAA,UAcsB,OAAxBC,eAOFC,mBACAC,sBAEuB,OAArBC,QAAQC,UAKThC;;;;oBA5GHY,WAAWqB,IAAAA,cAAI,EAACpC,IAAIqC,OAAO,EAAEC,kBAAS;oBAC5CC,IAAAA,iBAAS,EAACxB,UAAU;wBAAEyB,WAAW;oBAAK;oBAChCzC,SAASqC,IAAAA,cAAI,EAACrB,UAAUd,QAAQwC,QAAQ;oBAErB;;wBAAM3C,gBAAgBC,QAAQC,KAAKC;;;oBAAnC,OAAA,eAAjBe,SAAiB,KAAjBA,QAAQC,OAAS,KAATA;oBAChB,gGAAgG;oBAChG,kGAAkG;oBAC9FC,SAAS;oBACb,6FAA6F;oBAC7F,wEAAwE;oBAClEC,UAAUuB,IAAAA,wBAAa,EAACzB,MAAMjB,KAAKA,IAAIqC,OAAO,EAAEpC,QAAQ0C,gBAAgB;;;;;;;;;oBAE5E;;wBAAM1B,KAAK2B,IAAI,CAAC;;;oBAAhB;oBAIgB;;wBAAMC,IAAAA,iBAAO,EAAC5B,MAAM;;;oBAA9BG,UAAU;oBACC;;wBAAMyB,IAAAA,iBAAO,EAAC5B,MAAM;;;oBAA/BI,WAAW;oBACXC,eAAewB,IAAAA,yBAAgB,EAAC9C,KAAK+C,kBAAQ;yBAQ/C,CAAA,AAAC3B,YAAY,QAAQA,YAAYnB,QAAQ+C,aAAa,IAAM3B,aAAa,QAAQA,aAAaC,YAAY,GAA1G;;;;yBAGEF,CAAAA,YAAY,QAAQA,YAAYnB,QAAQ+C,aAAa,AAAD,GAApD5B;;;;oBACF6B,QAAQC,KAAK,CAAC;oBACd,kFAAkF;oBAClFhC,SAAS;oBACT;;wBAAMjB,QAAQkD,KAAK,CAACnC;;;oBAApB;oBACAoC,IAAAA,mBAAU,EAACpD;oBACX;;wBAAOa,mBAAmBb,KAAKC,SAASa;;;oBAEpCY,cAAc2B,IAAAA,iCAAoB,EAAChC,qBAAAA,sBAAAA,WAAY,IAAIC;oBACzD,oFAAoF;oBACpF,0FAA0F;oBAC1F,2EAA2E;oBACrEK,eAAe2B,IAAAA,iCAAkB,EAAC5B,eAAe6B,IAAAA,gCAAiB,EAACvD,KAAKA,IAAIqC,OAAO,EAAEhB,qBAAAA,sBAAAA,WAAY,IAAIK,eAAe;oBAC1H,yFAAyF;oBACzF,oFAAoF;oBAC9EE,YAAYF,YAAY8B,IAAI,KAAK,KAAK9B,YAAY+B,GAAG,CAAC,WAAWC,IAAAA,iCAAmB,EAACrC,qBAAAA,sBAAAA,WAAY,IAAIC,gBAAgB;oBAC3H,4FAA4F;oBAC5F,6FAA6F;oBAC7F,4DAA4D;oBACtDO,UAAU8B,IAAAA,mCAAmB,EAACjC,eAAekC,IAAAA,sCAAsB,EAACvC,qBAAAA,sBAAAA,WAAY,IAAIC,cAAcI,eAAe;yBACnHA,CAAAA,YAAY8B,IAAI,KAAK,KAAK9B,YAAY+B,GAAG,CAAC,YAAYI,IAAAA,iCAAoB,EAACxC,qBAAAA,sBAAAA,WAAY,IAAIC,aAAY,GAAvGI;;;;oBACF,iFAAiF;oBACjF,sDAAsD;oBACtDuB,QAAQC,KAAK,CAAC;oBACd;;wBAAMY,IAAAA,iBAAO,EAAC7C,MAAM,YAAYK;;;oBAAhC;;;;;;yBACSM,CAAAA,cAAc,IAAG,GAAjBA;;;;oBACT,yFAAyF;oBACzF,iEAAiE;oBACjEJ,kBAAkBI;oBAClBqB,QAAQC,KAAK,CAACtB,cAAc,UAAU,6EAA6E;oBACnH;;wBAAMkC,IAAAA,iBAAO,EAAC7C,MAAM,YAAYK;;;oBAAhC;;;;;;yBACSK,CAAAA,iBAAiB,IAAG,GAApBA;;;;oBACT,kFAAkF;oBAClF,uEAAuE;oBACvE,sFAAsF;oBACtF,qFAAqF;oBACrFJ,cAAcI;oBACRG,UAAUiC,IAAAA,0BAAa,EAAC1C,qBAAAA,sBAAAA,WAAY,IAAIC;oBAC9C2B,QAAQC,KAAK,CAAC,AAAC,yBAAgC,OAARpB,SAAQ;oBAC/C;;wBAAMgC,IAAAA,iBAAO,EAAC7C,MAAM,YAAYK;;;oBAAhC;;;;;;yBACSO,CAAAA,YAAY,IAAG,GAAfA;;;;oBACT,uFAAuF;oBACvF,wFAAwF;oBACxF,kFAAkF;oBAClF,sDAAsD;oBACtDJ,iBAAiBI;oBACXC,WAAUiC,IAAAA,0BAAa,EAAC1C,qBAAAA,sBAAAA,WAAY,IAAIC;oBAC9C2B,QAAQC,KAAK,CAAC,AAAC,yBAAgC,OAARpB,UAAQ;oBAC/C;;wBAAMgC,IAAAA,iBAAO,EAAC7C,MAAM,YAAYK;;;oBAAhC;;;;;;oBAEMQ,WAAUiC,IAAAA,0BAAa,EAAC1C,qBAAAA,sBAAAA,WAAY,IAAIC;oBAC9C2B,QAAQC,KAAK,CAAC,AAAC,yBAAgC,OAARpB,UAAQ;oBAC/CZ,SAAS;oBACT;;wBAAMjB,QAAQkD,KAAK,CAACnC;;;oBAApB;oBACAoC,IAAAA,mBAAU,EAACpD;oBACX;;wBAAOa,mBAAmBb,KAAKC,SAASa;;;oBAI5C;;wBAAMb,QAAQ+D,YAAY,CAAChD,QAAQC,MAAMjB;;;oBAAzC;yBAIIC,QAAQgE,qBAAqB,EAA7BhE;;;;oBAC4B;;wBAAM4C,IAAAA,iBAAO,EAAC5B,MAAM;;;oBAA5Cc,gBAAgBmC;yBAAQ,QAAA,2BAAA,mBAAA,QAA4C;;oBAC1E;;wBAAMjE,QAAQgE,qBAAqB,CAACjD,QAAQC,MAAMkD,KAAKC,GAAG,CAACD,KAAKE,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;oBAEuB;;wBAAMd,QAAQqD,KAAK,CAACjD;;;oBAApB,QAAA,eAArBW,SAAqB,MAArBA,QAAQC,WAAa,MAAbA;yBAEZ,CAACrB,iBAAD;;;;oBAAkB;;wBAAMK,QAAQgC,KAAK;;;oBAAnB;;;oBAEtB;;wBAAO;4BAAEnC,QAAAA;4BAAQC,MAAAA;4BAAMjB,KAAAA;4BAAKD,QAAAA;4BAAQmC,QAAQA,SAASF,cAAcC;4BAAeE,UAAAA;4BAAUhB,SAAAA;wBAAQ;;;oBAC7FhB;oBACP;;wBAAMgB,QAAQgC,KAAK;;;oBAAnB;yBACI,CAACjC,QAAD;;;;oBAAS;;wBAAMjB,QAAQkD,KAAK,CAACnC;;;oBAApB;;;oBACb,MAAMb;;;;;;;IAEV;;AAIO,SAAeR,gBAAwBK,GAAmB,EAAEC,OAA4B;;YACxB,MAA7De,QAAQC,MAAWwD,aAAa1E,QAAQmC,QAAQC,UAClD1B;;;;oBAD+D;;wBAAMI,mBAAmBb,KAAKC,SAAS;;;oBAAvC,OAAA,eAA7De,SAA6D,KAA7DA,QAAQC,OAAqD,KAArDA,MAAWwD,cAA0C,KAA/CzE,KAAkBD,SAA6B,KAA7BA,QAAQmC,SAAqB,KAArBA,QAAQC,WAAa,KAAbA;oBAClD1B,QAAQR,QAAQyE,WAAW,CAAC1D,QAAQC,MAAMwD;oBAChD,0FAA0F;oBAC1FE,IAAAA,yBAAc,EAAC1D,MAAMR;oBACrB;;wBAAO;4BAAEA,OAAAA;4BAAOT,KAAKyE;4BAAa1E,QAAAA;4BAAQmC,QAAAA;4BAAQC,UAAAA;wBAAS;;;;IAC7D;;AAIO,SAAezC,gBAAwBM,GAAmB,EAAEC,OAA4B;;YACf,MAAtEe,QAAQC,MAAWwD,aAAa1E,QAAQmC,QAAQC,UAAUhB,SAC5DV;;;;oBADwE;;wBAAMI,mBAAmBb,KAAKC,SAAS;;;oBAAvC,OAAA,eAAtEe,SAAsE,KAAtEA,QAAQC,OAA8D,KAA9DA,MAAWwD,cAAmD,KAAxDzE,KAAkBD,SAAsC,KAAtCA,QAAQmC,SAA8B,KAA9BA,QAAQC,WAAsB,KAAtBA,UAAUhB,UAAY,KAAZA;oBAC5DV,QAAQR,QAAQyE,WAAW,CAAC1D,QAAQC,MAAMwD;oBAChDE,IAAAA,yBAAc,EAAC1D,MAAMR;oBACrB;;wBAAO;4BAAEA,OAAAA;4BAAOT,KAAKyE;4BAAa1E,QAAAA;4BAAQmC,QAAAA;4BAAQC,UAAAA;4BAAUhB,SAAAA;wBAAQ;;;;IACtE;;AAEO,SAAe1B,SAASgB,KAAY;;YACnCmE;;;;oBAAO;;wBAAMnE,MAAMoE,OAAO,CAAC;;;oBAA3BD,OAAO;oBACJ;;wBAAMA,KAAKE,GAAG;;;oBAAvB;;wBAAS,cAAoCC,CAAC;;;;IAChD"}
@@ -0,0 +1,3 @@
1
+ import type { Config } from '../config/index.js';
2
+ export declare function isPresetOnlyChange(changedKeys: ReadonlySet<string>): boolean;
3
+ export declare function forcedPresetPaths(cfg: Config, baseDir: string, before: string, changedKeys: ReadonlySet<string>): Set<string> | null;
@@ -0,0 +1,3 @@
1
+ import type { Config } from '../config/index.js';
2
+ export declare function isPresetOnlyChange(changedKeys: ReadonlySet<string>): boolean;
3
+ export declare function forcedPresetPaths(cfg: Config, baseDir: string, before: string, changedKeys: ReadonlySet<string>): Set<string> | null;