@cortexkit/pi-magic-context 0.49.20 → 0.49.22

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 (48) hide show
  1. package/dist/auto-search-worker.js +6 -6
  2. package/dist/chunk-embedding-write-worker.js +9 -9
  3. package/dist/{compaction-marker-candidates-fnm47jat.js → compaction-marker-candidates-p1kqkqhq.js} +2 -2
  4. package/dist/compaction-marker-candidates-worker.js +2 -2
  5. package/dist/{compartment-chunk-embedding-81qesfjs.js → compartment-chunk-embedding-y01m95c2.js} +5 -5
  6. package/dist/{embedding-backfill-56e871c6.js → embedding-backfill-2vh6m3bg.js} +11 -11
  7. package/dist/embedding-worker-process.js +1 -1
  8. package/dist/embedding-worker.js +4 -4
  9. package/dist/{index-dzem6gn9.js → index-29nw7n1r.js} +1 -1
  10. package/dist/{index-jt0g3hn0.js → index-2bx7ge3x.js} +60 -18
  11. package/dist/{index-hws5f0z9.js → index-2qtx0q6h.js} +213 -4
  12. package/dist/{index-5vgt1zeh.js → index-3c3ztwgc.js} +2 -2
  13. package/dist/{index-rgfb753z.js → index-579m1751.js} +2 -2
  14. package/dist/{index-kqb3d8bs.js → index-5j6vwg4z.js} +148 -11
  15. package/dist/{index-6kb2xpw7.js → index-6wdwv3a6.js} +1 -1
  16. package/dist/{index-rfyvax95.js → index-at6py2k3.js} +1 -1
  17. package/dist/{index-bxmf4dhr.js → index-ccanzg8p.js} +2367 -1243
  18. package/dist/{index-mtvvhcw4.js → index-dbgg6hsf.js} +24 -10
  19. package/dist/{index-af9t637y.js → index-ftvm2acc.js} +121 -38
  20. package/dist/{index-zhwwp8zz.js → index-gqjxy2p7.js} +14 -4
  21. package/dist/{index-jxjr7kz9.js → index-gwxaz0z5.js} +2 -4
  22. package/dist/{index-p63nwn5v.js → index-hxp6q5f8.js} +1 -1
  23. package/dist/{index-qerzchrs.js → index-j3pz3a1b.js} +1 -1
  24. package/dist/{index-bttctq07.js → index-n8e5e9fp.js} +6 -3
  25. package/dist/{index-b8am7tns.js → index-pe5gz5c4.js} +4 -4
  26. package/dist/{index-tb3d9trm.js → index-st4gwt64.js} +1 -1
  27. package/dist/{index-5n5zxs8e.js → index-vx6f7wff.js} +2 -2
  28. package/dist/{index-v2epyzbm.js → index-w1twp2kp.js} +9 -7
  29. package/dist/{index-vdy273xw.js → index-wgmhk91m.js} +10 -4
  30. package/dist/{index-e19qtjj0.js → index-wqpjhx1p.js} +35 -4
  31. package/dist/index.js +239 -209
  32. package/dist/{message-fts-rowid-map-bpexnsdj.js → message-fts-rowid-map-59y476bk.js} +3 -3
  33. package/dist/{message-index-mvag9crh.js → message-index-3snxf11x.js} +9 -9
  34. package/dist/{message-index-bounded-d4r3weh0.js → message-index-bounded-4ngt600v.js} +9 -9
  35. package/dist/{message-time-backfill-kc10yrcj.js → message-time-backfill-e3r8ddh1.js} +1 -1
  36. package/dist/migration-worker.js +6 -6
  37. package/dist/{project-embedding-registry-cfrg952x.js → project-embedding-registry-hfyzs654.js} +10 -10
  38. package/dist/raw-ordinal-warmup-worker.js +8 -8
  39. package/dist/{read-session-chunk-7g4zvpd8.js → read-session-chunk-5dmc77q2.js} +5 -5
  40. package/dist/{read-session-raw-0fsjh10f.js → read-session-raw-yxv2fv34.js} +2 -2
  41. package/dist/{search-archive-qbhp7e89.js → search-archive-3daj5ttc.js} +6 -6
  42. package/dist/{search-hp4g3g9v.js → search-jhfh3tsj.js} +17 -17
  43. package/dist/{sqlite-d67n6dtr.js → sqlite-v89bj0yy.js} +7 -1
  44. package/dist/{storage-memory-9g882j7a.js → storage-memory-0ndn65fm.js} +2 -2
  45. package/dist/{storage-tags-m2qcp1g2.js → storage-tags-r48vxthe.js} +2 -2
  46. package/dist/subagent-entry.js +22 -21
  47. package/dist/tag-snapshot-worker-pi.js +8 -8
  48. package/package.json +5 -2
@@ -174,6 +174,177 @@ function topLevelCommaSegments(text) {
174
174
  function getTagIdentityWriteGeneration2() {
175
175
  return tagIdentityWriteGeneration;
176
176
  }
177
+ var busyTimeoutStates = new WeakMap;
178
+ var BUSY_TIMEOUT_QUERY = /^\s*PRAGMA\s+(?:(?:\w+|"[^"]+"|`[^`]+`|\[[^\]]+\])\s*\.\s*)?(?:busy_timeout|"busy_timeout"|`busy_timeout`|\[busy_timeout\])\s*;?\s*$/i;
179
+ var BUSY_TIMEOUT_SETTER = /^\s*PRAGMA\s+(?:(?:\w+|"[^"]+"|`[^`]+`|\[[^\]]+\])\s*\.\s*)?(?:busy_timeout|"busy_timeout"|`busy_timeout`|\[busy_timeout\])\s*(?==|\()/i;
180
+ function literalBusyTimeout(sql) {
181
+ const head = BUSY_TIMEOUT_SETTER.exec(sql);
182
+ if (!head)
183
+ return;
184
+ const match = /^(?:=\s*|\(\s*)(?:'(-?\d+)'|"(-?\d+)"|(-?\d+))\s*\)?\s*;?\s*$/.exec(sql.slice(head[0].length));
185
+ if (!match)
186
+ return;
187
+ const value = Number(match[1] ?? match[2] ?? match[3]);
188
+ return value < 0 ? 0 : value <= 2147483647 ? value : undefined;
189
+ }
190
+ function busyTimeoutStatements(sql) {
191
+ const statements = [];
192
+ let statement = "";
193
+ let quote = "";
194
+ for (let i = 0;i < sql.length; i++) {
195
+ const char = sql[i];
196
+ if (quote) {
197
+ statement += char;
198
+ if (char === quote) {
199
+ if (sql[i + 1] === quote)
200
+ statement += sql[++i];
201
+ else
202
+ quote = "";
203
+ }
204
+ } else if (char === "'" || char === '"' || char === "`" || char === "[") {
205
+ quote = char === "[" ? "]" : char;
206
+ statement += char;
207
+ } else if (char === "-" && sql[i + 1] === "-") {
208
+ while (i + 1 < sql.length && sql[i + 1] !== `
209
+ `)
210
+ i++;
211
+ statement += " ";
212
+ } else if (char === "/" && sql[i + 1] === "*") {
213
+ i += 2;
214
+ while (i < sql.length && !(sql[i] === "*" && sql[i + 1] === "/"))
215
+ i++;
216
+ i++;
217
+ statement += " ";
218
+ } else if (char === ";") {
219
+ statements.push(statement);
220
+ statement = "";
221
+ } else
222
+ statement += char;
223
+ }
224
+ statements.push(statement);
225
+ return statements.filter((part) => part.trim().length > 0);
226
+ }
227
+ function installNativeDeadlineRouting(db) {
228
+ const rawExec = db.exec.bind(db);
229
+ const rawPrepare = db.prepare.bind(db);
230
+ const readTimeout = () => {
231
+ const statement = rawPrepare("PRAGMA busy_timeout");
232
+ try {
233
+ return Object.values(statement.get())[0];
234
+ } finally {
235
+ statement.finalize?.();
236
+ }
237
+ };
238
+ const timeoutState = { current: readTimeout() };
239
+ busyTimeoutStates.set(db, timeoutState);
240
+ const setBusyTimeout = (timeout) => {
241
+ rawExec(`PRAGMA busy_timeout=${timeout}`);
242
+ timeoutState.current = timeout;
243
+ };
244
+ const withinDeadline = (operation) => {
245
+ const deadline = nativeWaitScope?.getStore();
246
+ if (!deadline?.active || !deadline.remainingMs)
247
+ return operation();
248
+ const remaining = deadline.remainingMs();
249
+ if (remaining === Infinity)
250
+ return operation();
251
+ const previous = timeoutState.current;
252
+ const timeout = Math.min(previous, Math.max(0, Math.floor(remaining)));
253
+ if (timeout === previous)
254
+ return operation();
255
+ setBusyTimeout(timeout);
256
+ try {
257
+ return operation();
258
+ } finally {
259
+ setBusyTimeout(previous);
260
+ }
261
+ };
262
+ Object.defineProperty(db, "exec", {
263
+ configurable: true,
264
+ writable: true,
265
+ value: (sql) => {
266
+ const parts = /\bbusy_timeout\b/i.test(sql) ? busyTimeoutStatements(sql) : [];
267
+ if (parts.length === 1 && BUSY_TIMEOUT_QUERY.test(parts[0]))
268
+ return rawExec(sql);
269
+ const singleSetter = parts.length === 1 && BUSY_TIMEOUT_SETTER.test(parts[0]);
270
+ const setting = singleSetter ? literalBusyTimeout(parts[0]) : undefined;
271
+ if (singleSetter) {
272
+ const result = rawExec(sql);
273
+ timeoutState.current = setting ?? readTimeout();
274
+ return result;
275
+ }
276
+ if (!/\bbusy_timeout\b/i.test(sql))
277
+ return withinDeadline(() => rawExec(sql));
278
+ const setters = parts.filter((part) => BUSY_TIMEOUT_SETTER.test(part));
279
+ return withinDeadline(() => {
280
+ try {
281
+ const result = rawExec(sql);
282
+ if (setters.length)
283
+ timeoutState.current = literalBusyTimeout(setters[setters.length - 1]) ?? readTimeout();
284
+ return result;
285
+ } catch (error) {
286
+ if (setters.length)
287
+ timeoutState.current = readTimeout();
288
+ throw error;
289
+ }
290
+ });
291
+ }
292
+ });
293
+ const nativePrepare = (sql) => BUSY_TIMEOUT_QUERY.test(sql) || BUSY_TIMEOUT_SETTER.test(sql) ? rawPrepare(sql) : withinDeadline(() => rawPrepare(sql));
294
+ Object.defineProperty(db, "prepare", {
295
+ configurable: true,
296
+ writable: true,
297
+ value: (sql) => {
298
+ const statement = nativePrepare(sql);
299
+ const normalized = /\bbusy_timeout\b/i.test(sql) ? busyTimeoutStatements(sql)[0] ?? sql : sql;
300
+ const setting = literalBusyTimeout(normalized);
301
+ const timeoutSetter = BUSY_TIMEOUT_SETTER.test(normalized);
302
+ const timeoutQuery = BUSY_TIMEOUT_QUERY.test(normalized);
303
+ if (timeoutSetter)
304
+ timeoutState.current = setting ?? readTimeout();
305
+ for (const method of ["run", "get", "all", "values"]) {
306
+ const execute = statement[method]?.bind(statement);
307
+ if (!execute)
308
+ continue;
309
+ Object.defineProperty(statement, method, {
310
+ configurable: true,
311
+ value: (...args) => {
312
+ if (timeoutQuery)
313
+ return execute(...args);
314
+ if (!timeoutSetter)
315
+ return withinDeadline(() => execute(...args));
316
+ const result = execute(...args);
317
+ timeoutState.current = readTimeout();
318
+ return result;
319
+ }
320
+ });
321
+ }
322
+ if (typeof statement.iterate === "function") {
323
+ const iterate = statement.iterate.bind(statement);
324
+ Object.defineProperty(statement, "iterate", {
325
+ configurable: true,
326
+ value: (...args) => {
327
+ const iterator = !timeoutSetter && !timeoutQuery ? withinDeadline(() => iterate(...args)) : iterate(...args);
328
+ const next = iterator.next.bind(iterator);
329
+ if (timeoutSetter)
330
+ timeoutState.current = readTimeout();
331
+ iterator.next = () => {
332
+ if (timeoutQuery)
333
+ return next();
334
+ if (!timeoutSetter)
335
+ return withinDeadline(next);
336
+ const result = next();
337
+ timeoutState.current = readTimeout();
338
+ return result;
339
+ };
340
+ return iterator;
341
+ }
342
+ });
343
+ }
344
+ return statement;
345
+ }
346
+ });
347
+ }
177
348
  function installTransactionRouting(db, readonly) {
178
349
  const nativeExec = db.exec.bind(db);
179
350
  Object.defineProperty(db, "exec", {
@@ -311,7 +482,7 @@ function wrapRemainingTagWriteForms(statement) {
311
482
  });
312
483
  }
313
484
  }
314
- function trackSqliteConnection(db, filename, options) {
485
+ function trackSqliteConnection(db, filename, options, turnDeadlines = false) {
315
486
  const originalClose = db.close.bind(db);
316
487
  const sequence = nextSqliteConnectionSequence++;
317
488
  const metadata = {
@@ -319,6 +490,8 @@ function trackSqliteConnection(db, filename, options) {
319
490
  filename: typeof filename === "string" ? filename : Buffer.isBuffer(filename) ? "<buffer>" : ":memory:",
320
491
  readonly: Boolean(options) && typeof options === "object" && (options.readonly === true || options.readOnly === true)
321
492
  };
493
+ if (turnDeadlines)
494
+ installNativeDeadlineRouting(db);
322
495
  installTransactionRouting(db, metadata.readonly);
323
496
  Object.defineProperty(db, "close", {
324
497
  configurable: true,
@@ -371,6 +544,12 @@ function buildNodeSqliteDatabaseClass(DatabaseSync) {
371
544
  return NodeSqliteDatabase;
372
545
  }
373
546
  var Database2 = TrackedDatabase;
547
+ function createSqliteTurnDatabase2(filename, options) {
548
+ return trackSqliteConnection(new DatabaseImpl(filename, options), filename, options, true);
549
+ }
550
+ function hasSqliteTurnDeadlineRouting2(db) {
551
+ return busyTimeoutStates.has(db);
552
+ }
374
553
  function getSqliteDatabasePath2(db) {
375
554
  for (const connection of trackedSqliteConnections.values()) {
376
555
  if (connection.reference.deref() === db) {
@@ -390,6 +569,11 @@ function pragmaValue(db, name) {
390
569
  return row[name] ?? Object.values(row)[0];
391
570
  }
392
571
  function pragmaNumber(db, name) {
572
+ if (name === "busy_timeout") {
573
+ const state = busyTimeoutStates.get(db);
574
+ if (state)
575
+ return state.current;
576
+ }
393
577
  try {
394
578
  const value = pragmaValue(db, name);
395
579
  return typeof value === "number" && Number.isFinite(value) ? value : null;
@@ -455,11 +639,34 @@ function prepareCachedStatement2(db, sql) {
455
639
  return ownPreparedStatement(db, db.prepare(sql));
456
640
  }
457
641
  var privilegeDepth = new WeakMap;
642
+ var nativeWaitScope;
643
+ function releaseNativeWaitLease(lease) {
644
+ lease.active = false;
645
+ lease.remainingMs = undefined;
646
+ }
647
+ function withSqliteTurnDeadline2(remainingMs, operation) {
648
+ const scope = nativeWaitScope ??= new AsyncLocalStorage;
649
+ const lease = { active: true, remainingMs };
650
+ return scope.run(lease, () => {
651
+ try {
652
+ const result = operation();
653
+ if (result && typeof result.then === "function")
654
+ return Promise.resolve(result).finally(releaseNativeWaitLease.bind(null, lease));
655
+ releaseNativeWaitLease(lease);
656
+ return result;
657
+ } catch (error) {
658
+ releaseNativeWaitLease(lease);
659
+ throw error;
660
+ }
661
+ });
662
+ }
458
663
  var transformPassScope = new AsyncLocalStorage;
459
664
  var admissionScope = new AsyncLocalStorage;
460
665
  var backgroundWriterScope = new AsyncLocalStorage;
461
666
  function withSqliteBackgroundWriter2(operation) {
462
- return backgroundWriterScope.run(true, operation);
667
+ if (!nativeWaitScope?.getStore())
668
+ return backgroundWriterScope.run(true, operation);
669
+ return nativeWaitScope.run(undefined, () => backgroundWriterScope.run(true, operation));
463
670
  }
464
671
  function withSqliteTransformPass2(operation) {
465
672
  const existing = transformPassScope.getStore();
@@ -490,7 +697,9 @@ function withSqliteTransformPass2(operation) {
490
697
  return typeof reservation === "function" ? run(reservation) : reservation.then(run);
491
698
  }
492
699
  function withoutSqliteTransformPass2(operation) {
493
- return transformPassScope.run(undefined, operation);
700
+ if (!nativeWaitScope?.getStore())
701
+ return transformPassScope.run(undefined, operation);
702
+ return nativeWaitScope.run(undefined, () => transformPassScope.run(undefined, operation));
494
703
  }
495
704
  function guardSqliteTransformPass2(guard) {
496
705
  const lease = transformPassScope.getStore();
@@ -829,4 +1038,4 @@ async function yieldIndexChunk2() {
829
1038
  await yieldIndexTurn();
830
1039
  }
831
1040
 
832
- export { inRootAsyncContext2, registerSlowWriteReporter2, registerSqliteDiagnosticSink2, detectSqliteRuntime2, getTagIdentityWriteGeneration2, Database2, getSqliteDatabasePath2, prepareCachedStatement2, withSqliteBackgroundWriter2, withSqliteTransformPass2, withoutSqliteTransformPass2, guardSqliteTransformPass2, assertTransformWrite2, isTransientSqliteError2, beginSqliteWriterAsync2, withAsyncPrivilegedWriter2, withPrivilegedWriter2, indexCoordinationInput2, releaseIndexOwner2, withIndexChunk2, yieldIndexChunk2 };
1041
+ export { inRootAsyncContext2, registerSlowWriteReporter2, registerSqliteDiagnosticSink2, detectSqliteRuntime2, getTagIdentityWriteGeneration2, Database2, createSqliteTurnDatabase2, hasSqliteTurnDeadlineRouting2, getSqliteDatabasePath2, prepareCachedStatement2, withSqliteTurnDeadline2, withSqliteBackgroundWriter2, withSqliteTransformPass2, withoutSqliteTransformPass2, guardSqliteTransformPass2, assertTransformWrite2, isTransientSqliteError2, beginSqliteWriterAsync2, withAsyncPrivilegedWriter2, withPrivilegedWriter2, indexCoordinationInput2, releaseIndexOwner2, withIndexChunk2, yieldIndexChunk2 };
@@ -16,11 +16,11 @@ import {
16
16
  } from "./index-8976mezv.js";
17
17
  import {
18
18
  Database2
19
- } from "./index-hws5f0z9.js";
19
+ } from "./index-2qtx0q6h.js";
20
20
  import {
21
21
  normalizeStoredProjectPath,
22
22
  storedPathBelongsToIdentity
23
- } from "./index-p63nwn5v.js";
23
+ } from "./index-hxp6q5f8.js";
24
24
  import {
25
25
  logSlowWriteTransaction
26
26
  } from "./index-hqw0rt9k.js";
@@ -2,10 +2,10 @@ import {
2
2
  getSqliteDatabasePath2,
3
3
  withSqliteBackgroundWriter2,
4
4
  withoutSqliteTransformPass2
5
- } from "./index-hws5f0z9.js";
5
+ } from "./index-2qtx0q6h.js";
6
6
  import {
7
7
  runSessionWarmupWorker
8
- } from "./index-rfyvax95.js";
8
+ } from "./index-at6py2k3.js";
9
9
  import {
10
10
  logSlowWriteTransaction
11
11
  } from "./index-hqw0rt9k.js";
@@ -7,18 +7,136 @@ import {
7
7
  import {
8
8
  getTagsBySession2,
9
9
  getTagsByNumbers2
10
- } from "./index-bttctq07.js";
10
+ } from "./index-n8e5e9fp.js";
11
11
  import {
12
12
  inRootAsyncContext2,
13
- getSqliteDatabasePath2
14
- } from "./index-hws5f0z9.js";
13
+ getSqliteDatabasePath2,
14
+ withSqliteTurnDeadline2
15
+ } from "./index-2qtx0q6h.js";
15
16
  import {
16
17
  createFailClosedBlockingError
17
- } from "./index-mtvvhcw4.js";
18
+ } from "./index-dbgg6hsf.js";
18
19
  import {
19
20
  createWorkerShutdown
20
21
  } from "./index-54wmg4rj.js";
21
22
 
23
+ // src/pi-context-budget.ts
24
+ var PI_CONTEXT_BUDGET = {
25
+ hostDeadlineMs: 30000,
26
+ hostMarginMs: 5000,
27
+ outcomeMs: 25000,
28
+ fallbackObservedMs: 4,
29
+ workMs: 21000,
30
+ writerMs: 16500,
31
+ completionReserveMs: 2000,
32
+ searchMs: 3000
33
+ };
34
+
35
+ class PiContextDeadlineError extends Error {
36
+ }
37
+
38
+ class PiContextSupersededError extends Error {
39
+ origin;
40
+ constructor(message, origin = "context ownership") {
41
+ super(message);
42
+ this.origin = origin;
43
+ }
44
+ }
45
+
46
+ class PiContextBudget {
47
+ startedAt;
48
+ now;
49
+ sideTurn = false;
50
+ stage = "entry";
51
+ recovery = "not attempted";
52
+ abandoned = false;
53
+ completed = false;
54
+ failureReason;
55
+ signal;
56
+ cancelled = false;
57
+ isCancelled(error) {
58
+ return this.cancelled || this.signal?.aborted === true || !this.signal && typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
59
+ }
60
+ cancel() {
61
+ this.cancelled = true;
62
+ this.abandoned = true;
63
+ this.completed = false;
64
+ this.failureReason = undefined;
65
+ }
66
+ assertOwner = () => {};
67
+ constructor(startedAt = performance.now(), now = () => performance.now()) {
68
+ this.startedAt = startedAt;
69
+ this.now = now;
70
+ }
71
+ elapsed() {
72
+ return this.now() - this.startedAt;
73
+ }
74
+ remainingWork = () => {
75
+ return Math.max(0, PI_CONTEXT_BUDGET.workMs - this.elapsed());
76
+ };
77
+ remainingOutcome = () => Math.max(0, PI_CONTEXT_BUDGET.outcomeMs - this.elapsed());
78
+ writerAllowance() {
79
+ return Math.max(0, Math.min(PI_CONTEXT_BUDGET.writerMs, this.remainingWork() - PI_CONTEXT_BUDGET.completionReserveMs));
80
+ }
81
+ hydrationAllowance() {
82
+ return Math.max(0, Math.min(this.remainingWork() - PI_CONTEXT_BUDGET.completionReserveMs, this.remainingOutcome() - PI_CONTEXT_BUDGET.completionReserveMs));
83
+ }
84
+ assertOutcome = () => {
85
+ this.assertOwner();
86
+ this.signal?.throwIfAborted();
87
+ if (this.abandoned || this.elapsed() >= PI_CONTEXT_BUDGET.outcomeMs)
88
+ throw new PiContextDeadlineError(this.diagnostic());
89
+ };
90
+ assert = () => {
91
+ this.assertOutcome();
92
+ if (this.elapsed() >= PI_CONTEXT_BUDGET.workMs)
93
+ throw new PiContextDeadlineError(this.diagnostic());
94
+ };
95
+ assertDecisionPublication = () => {
96
+ this.signal?.throwIfAborted();
97
+ if (!this.completed)
98
+ this.assertOwner();
99
+ if (this.abandoned || !this.completed && this.elapsed() >= PI_CONTEXT_BUDGET.outcomeMs)
100
+ throw new PiContextDeadlineError(this.diagnostic());
101
+ };
102
+ diagnostic() {
103
+ return `stage=${this.stage} elapsed=${Math.round(this.elapsed())}ms recovery=${this.recovery}`;
104
+ }
105
+ waitUntil = async (pending, assert, remaining) => {
106
+ try {
107
+ assert();
108
+ } catch (error) {
109
+ pending.catch(() => {});
110
+ throw error;
111
+ }
112
+ let timer;
113
+ let onAbort;
114
+ try {
115
+ return await Promise.race([
116
+ pending,
117
+ ...this.signal ? [
118
+ new Promise((_, reject) => {
119
+ onAbort = () => reject(this.signal?.reason);
120
+ this.signal?.addEventListener("abort", onAbort, {
121
+ once: true
122
+ });
123
+ })
124
+ ] : [],
125
+ new Promise((_, reject) => {
126
+ timer = setTimeout(() => reject(new PiContextDeadlineError(this.diagnostic())), remaining());
127
+ })
128
+ ]);
129
+ } finally {
130
+ clearTimeout(timer);
131
+ if (onAbort)
132
+ this.signal?.removeEventListener("abort", onAbort);
133
+ assert();
134
+ }
135
+ };
136
+ wait = (pending) => this.waitUntil(pending, this.assert, () => this.remainingWork());
137
+ waitMandatory = (pending) => this.waitUntil(pending, this.assertOutcome, this.remainingOutcome);
138
+ }
139
+
22
140
  // src/tag-snapshot-worker-client-pi.ts
23
141
  import { setImmediate as yieldImmediate } from "node:timers/promises";
24
142
  import { Worker } from "node:worker_threads";
@@ -310,6 +428,13 @@ function createPiTagSnapshotReader(db) {
310
428
  const existing = readers.get(db);
311
429
  if (existing)
312
430
  return existing;
431
+ const nativeWaiters = new Set;
432
+ const inSnapshotRoot = (operation) => inRootAsyncContext2(() => withSqliteTurnDeadline2(() => {
433
+ let remaining = Infinity;
434
+ for (const waiter of nativeWaiters)
435
+ remaining = Math.min(remaining, waiter());
436
+ return remaining;
437
+ }, operation));
313
438
  db.exec(`
314
439
  CREATE TEMP TABLE IF NOT EXISTS pi_tag_revision (revision INTEGER NOT NULL);
315
440
  INSERT INTO pi_tag_revision SELECT 0 WHERE NOT EXISTS (SELECT 1 FROM pi_tag_revision);
@@ -403,7 +528,8 @@ function createPiTagSnapshotReader(db) {
403
528
  const ownFirstAllocation = db.prepare(`SELECT 1 FROM pi_tag_first_allocation allocation
404
529
  WHERE session_id = ? AND seen = 1 AND incarnation || ':0' = ?
405
530
  AND EXISTS (SELECT 1 FROM pi_tag_watch WHERE session_id = allocation.session_id)
406
- AND EXISTS (SELECT 1 FROM pi_tag_first_rows WHERE session_id = allocation.session_id)
531
+ AND EXISTS (SELECT 1 FROM pi_tag_changes WHERE session_id = allocation.session_id)
532
+ AND (? = 'legacy' OR EXISTS (SELECT 1 FROM pi_tag_first_rows WHERE session_id = allocation.session_id))
407
533
  AND NOT EXISTS (SELECT 1 FROM pi_tag_first_rows first_row WHERE first_row.session_id = allocation.session_id
408
534
  AND NOT EXISTS (SELECT 1 FROM pi_tag_changes change WHERE change.session_id = first_row.session_id AND change.tag_number IS first_row.tag_number))`);
409
535
  const managed = new Set;
@@ -414,6 +540,7 @@ function createPiTagSnapshotReader(db) {
414
540
  let desiredSession;
415
541
  let failedUntil = 0;
416
542
  let lastFailure;
543
+ let failedSession;
417
544
  const totalRevision = db.prepare("SELECT COALESCE(value, '0') AS revision, value IS NOT NULL AS present FROM (SELECT 1) LEFT JOIN schema_migrations_meta ON key = ?");
418
545
  const assertOutsideTransaction = () => {
419
546
  const connection = db;
@@ -458,7 +585,7 @@ function createPiTagSnapshotReader(db) {
458
585
  if (current?.sessionId === sessionId)
459
586
  current.cancel();
460
587
  };
461
- const load = (sessionId) => inRootAsyncContext2(async () => {
588
+ const load = (sessionId) => inSnapshotRoot(async () => {
462
589
  managed.add(sessionId);
463
590
  if (ready(sessionId))
464
591
  return;
@@ -472,7 +599,7 @@ function createPiTagSnapshotReader(db) {
472
599
  throw new PiTagHydrationError("session hydration superseded", "stale");
473
600
  return load(sessionId);
474
601
  }
475
- if (performance.now() < failedUntil)
602
+ if (failedSession === sessionId && performance.now() < failedUntil)
476
603
  throw lastFailure;
477
604
  watch.run(sessionId);
478
605
  const token = stamps(sessionId, ++jobId);
@@ -516,7 +643,7 @@ function createPiTagSnapshotReader(db) {
516
643
  if (current !== destination || desiredSession !== sessionId || !samePiTagSnapshotToken(token, live) || token.totalRevision !== live.totalRevision || generation.revision !== token.totalRevision || generation.durable !== token.durableVersion)
517
644
  throw new PiTagHydrationError("owner generation or lifetime changed", "stale");
518
645
  const snapshot = {
519
- firstAllocationPending: !live.revisionPresent && candidate.tags.length === 0 && !db.prepare("SELECT 1 FROM tags WHERE session_id = ? LIMIT 1").get(sessionId),
646
+ firstAllocationPending: live.revisionPresent ? undefined : candidate.tags.length === 0 && !db.prepare("SELECT 1 FROM tags WHERE session_id = ? LIMIT 1").get(sessionId) ? "empty" : "legacy",
520
647
  revision: legacyFallbackOnly ? previous.revision : live.localRevision,
521
648
  foreignRevision: live.foreignRevision,
522
649
  tags: legacyFallbackOnly ? previous.tags : candidate.tags,
@@ -545,6 +672,7 @@ function createPiTagSnapshotReader(db) {
545
672
  if (error instanceof PiTagHydrationError && error.code === "stale")
546
673
  destination.stale = true;
547
674
  if (current === destination && desiredSession === sessionId && token.sessionEpoch === (sessionEpochs.get(sessionId) ?? 0)) {
675
+ failedSession = sessionId;
548
676
  lastFailure = error;
549
677
  failedUntil = performance.now() + (error instanceof PiTagHydrationError && error.code === "stale" ? 0 : 500);
550
678
  }
@@ -562,6 +690,12 @@ function createPiTagSnapshotReader(db) {
562
690
  owners.set(db, {
563
691
  ready,
564
692
  load,
693
+ addNativeWaiter: (remaining) => {
694
+ nativeWaiters.add(remaining);
695
+ return () => {
696
+ nativeWaiters.delete(remaining);
697
+ };
698
+ },
565
699
  manage: (sessionId) => managed.add(sessionId),
566
700
  cancel
567
701
  });
@@ -578,9 +712,9 @@ function createPiTagSnapshotReader(db) {
578
712
  ];
579
713
  const stamp = versionStamp.get(sessionId, sessionId);
580
714
  let snapshot = cache.get(sessionId);
581
- if (snapshot?.firstAllocationPending && snapshot.foreignRevision !== external && snapshot.revision !== local && stamp.durable - snapshot.durableVersion === stamp.own - snapshot.ownVersion && ownFirstAllocation.get(sessionId, external)) {
715
+ if (snapshot?.firstAllocationPending && snapshot.foreignRevision !== external && snapshot.revision !== local && stamp.durable - snapshot.durableVersion === stamp.own - snapshot.ownVersion && ownFirstAllocation.get(sessionId, external, snapshot.firstAllocationPending)) {
582
716
  snapshot.foreignRevision = external;
583
- snapshot.firstAllocationPending = false;
717
+ snapshot.firstAllocationPending = undefined;
584
718
  db.prepare("DELETE FROM pi_tag_first_watch WHERE session_id = ?").run(sessionId);
585
719
  db.prepare("DELETE FROM pi_tag_first_rows WHERE session_id = ?").run(sessionId);
586
720
  }
@@ -662,6 +796,7 @@ function createPiTagSnapshotReader(db) {
662
796
  writable: true,
663
797
  value: (...args) => {
664
798
  desiredSession = undefined;
799
+ nativeWaiters.clear();
665
800
  current?.cancel();
666
801
  cache.clear();
667
802
  entryReaders.delete(db);
@@ -885,6 +1020,7 @@ function ensurePiTagSnapshotReady(db, sessionId, budget) {
885
1020
  if (allowance <= 0)
886
1021
  throw new PiTagHydrationError("remaining pass budget exhausted waiting for tag snapshot; turn not sent, retry", "deadline");
887
1022
  let timer;
1023
+ const releaseNativeWaiter = owner.addNativeWaiter(() => budget.remainingOutcome() - PI_CONTEXT_BUDGET.completionReserveMs);
888
1024
  try {
889
1025
  await budget.wait(Promise.race([
890
1026
  owner.load(sessionId),
@@ -901,9 +1037,10 @@ function ensurePiTagSnapshotReady(db, sessionId, budget) {
901
1037
  throw error;
902
1038
  } finally {
903
1039
  clearTimeout(timer);
1040
+ releaseNativeWaiter();
904
1041
  }
905
1042
  }
906
1043
  })();
907
1044
  }
908
1045
 
909
- export { encodePiHydrationOperation, PiTagHydrationError, PI_FALLBACK_ROW_COLUMNS, PI_FALLBACK_ROW_PREDICATE, getPiTagSnapshotView, getPiActiveTagSnapshotView, readPiFallbackTagRows, prewarmPiTagSnapshot, cancelPiTagSnapshotSession, drainPiTagSnapshotSession, assertPiTagSnapshotReady, ensurePiTagSnapshotReady };
1046
+ export { PI_CONTEXT_BUDGET, PiContextDeadlineError, PiContextSupersededError, PiContextBudget, encodePiHydrationOperation, PiTagHydrationError, PI_FALLBACK_ROW_COLUMNS, PI_FALLBACK_ROW_PREDICATE, getPiTagSnapshotView, getPiActiveTagSnapshotView, readPiFallbackTagRows, prewarmPiTagSnapshot, cancelPiTagSnapshotSession, drainPiTagSnapshotSession, assertPiTagSnapshotReady, ensurePiTagSnapshotReady };
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  inRootAsyncContext2,
9
9
  getSqliteDatabasePath2
10
- } from "./index-hws5f0z9.js";
10
+ } from "./index-2qtx0q6h.js";
11
11
 
12
12
  // ../plugin/src/features/magic-context/compaction-marker-candidates.ts
13
13
  import { existsSync, realpathSync } from "node:fs";
@@ -2,7 +2,7 @@ import {
2
2
  inRootAsyncContext2,
3
3
  getSqliteDatabasePath2,
4
4
  releaseIndexOwner2
5
- } from "./index-hws5f0z9.js";
5
+ } from "./index-2qtx0q6h.js";
6
6
  import {
7
7
  registerExitAbort
8
8
  } from "./index-399p688g.js";