@cortexkit/pi-magic-context 0.48.0 → 0.49.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/auto-search-worker.js +3 -3
  2. package/dist/embedding-backfill-scywarbn.js +20 -0
  3. package/dist/embedding-worker-process.js +29 -0
  4. package/dist/embedding-worker.js +6 -6
  5. package/dist/historian-calibration-extension.js +30 -5
  6. package/dist/index-0j0zqb4t.js +712 -0
  7. package/dist/{index-pvm4pd5d.js → index-0rasmwm8.js} +811 -76
  8. package/dist/{index-fp37he9a.js → index-0vrkp1jq.js} +1 -1
  9. package/dist/{index-419bndtm.js → index-21v1kfs7.js} +2 -2
  10. package/dist/{index-fm3ksh5e.js → index-27jh224p.js} +4 -4
  11. package/dist/{index-98z1c1r0.js → index-28vnkyy7.js} +1231 -3018
  12. package/dist/{index-wrm4nbj7.js → index-290tzwp1.js} +1 -1
  13. package/dist/{index-603mt6nm.js → index-4gfq5t09.js} +17 -2
  14. package/dist/{index-vf38qhee.js → index-81nthk8j.js} +44 -1
  15. package/dist/{index-5jp1h0bz.js → index-b2anqqad.js} +467 -14
  16. package/dist/{index-6pgq5ns2.js → index-cyrnv16r.js} +314 -1072
  17. package/dist/index-fqb1bddn.js +4947 -0
  18. package/dist/{index-dkx0b1kt.js → index-g7hndmqm.js} +20 -29
  19. package/dist/index-gc2749rx.js +1168 -0
  20. package/dist/{index-5hd7h4rr.js → index-kjd1fj55.js} +39 -31
  21. package/dist/{index-8y5knskr.js → index-mcgehvgw.js} +93 -9
  22. package/dist/{index-r7xg4hvw.js → index-p5zesr4e.js} +26 -722
  23. package/dist/{index-9xb0axhc.js → index-r56xgha8.js} +1 -1
  24. package/dist/{index-544c0e0x.js → index-r874cgmv.js} +42 -40
  25. package/dist/{index-72bdc1bd.js → index-rd53pk0h.js} +4 -4
  26. package/dist/{index-0am8a7k1.js → index-rdtgp48t.js} +8 -6
  27. package/dist/{index-rt5jgzp1.js → index-vakawmbc.js} +160 -25
  28. package/dist/{index-f956htf3.js → index-x3dcnxh0.js} +6 -2
  29. package/dist/{index-zrr5t5a7.js → index-zh1jw8qp.js} +106 -1
  30. package/dist/index.js +2271 -1769
  31. package/dist/{logger-v3dsxdnm.js → logger-j6tecd1h.js} +1 -1
  32. package/dist/{message-index-bounded-t7vvty76.js → message-index-bounded-110sb4fm.js} +13 -12
  33. package/dist/{message-time-backfill-4ndf7hrq.js → message-time-backfill-05ppypkz.js} +2 -2
  34. package/dist/migration-worker.js +10 -9
  35. package/dist/{project-embedding-registry-jy2hmq28.js → project-embedding-registry-64t0mw8y.js} +10 -10
  36. package/dist/raw-ordinal-warmup-worker.js +4 -4
  37. package/dist/{read-session-chunk-47pjn7fz.js → read-session-chunk-rvmc25n5.js} +10 -7
  38. package/dist/{read-session-raw-yn8nawav.js → read-session-raw-npx3920c.js} +5 -3
  39. package/dist/{safe-notification-target-3c1ns931.js → safe-notification-target-vn9kpmv4.js} +2 -2
  40. package/dist/{search-42szfhwp.js → search-7z3w8pmz.js} +19 -18
  41. package/dist/{storage-tags-jym5z6yk.js → storage-tags-kjnsqbdb.js} +6 -6
  42. package/dist/subagent-entry.js +25 -23
  43. package/package.json +3 -3
  44. package/dist/embedding-backfill-bnnytehy.js +0 -20
  45. package/dist/index-bgmv2kaf.js +0 -290
  46. package/dist/index-hrf13mn3.js +0 -2388
  47. /package/dist/{index-5prbx026.js → index-2pp04pmg.js} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  log2
3
- } from "./index-f956htf3.js";
3
+ } from "./index-x3dcnxh0.js";
4
4
 
5
5
  // ../plugin/src/shared/safe-notification-target.ts
6
6
  var DEFAULT_TITLE_RE = /^(New session - |Child session - )\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
@@ -4,7 +4,22 @@ import {
4
4
  } from "./index-3cgbv47m.js";
5
5
  import {
6
6
  logSlowWriteTransaction
7
- } from "./index-fp37he9a.js";
7
+ } from "./index-0vrkp1jq.js";
8
+
9
+ // ../plugin/src/shared/project-directory-key.ts
10
+ import path from "node:path";
11
+ function projectDirectoryKey(directory) {
12
+ const slashed = directory.replaceAll("\\", "/").replace(/^\/\/\?\/UNC\//i, "//").replace(/^\/\/\?\//, "");
13
+ if (/^[a-z]:\//i.test(slashed) || slashed.startsWith("//")) {
14
+ return path.win32.normalize(slashed).replaceAll("\\", "/").replace(/\/$/, "").toLowerCase();
15
+ }
16
+ return path.resolve(directory);
17
+ }
18
+ function sameProjectDirectory(a, b) {
19
+ if (a.length === 0 || b.length === 0)
20
+ return false;
21
+ return projectDirectoryKey(a) === projectDirectoryKey(b);
22
+ }
8
23
 
9
24
  // ../plugin/src/features/magic-context/message-fts-rowid-map.ts
10
25
  import { createHash } from "node:crypto";
@@ -168,4 +183,4 @@ function deleteUnmappedMessageFtsRows(db, sessionIds) {
168
183
  WHERE rowid > ? AND session_id IN (${placeholders})`).run(state.watermarkRowid, ...sessionIds);
169
184
  }
170
185
 
171
- export { recordMessageFtsRowid, recordIndexedMessageTime, startMessageFtsRowidMapBackfill, messageFtsOrdinalRangeIsMapped, deleteUnmappedMessageFtsRows };
186
+ export { projectDirectoryKey, sameProjectDirectory, recordMessageFtsRowid, recordIndexedMessageTime, startMessageFtsRowidMapBackfill, messageFtsOrdinalRangeIsMapped, deleteUnmappedMessageFtsRows };
@@ -4,6 +4,7 @@ import {
4
4
  chmodSync,
5
5
  closeSync,
6
6
  createWriteStream,
7
+ fsyncSync,
7
8
  lstatSync,
8
9
  mkdirSync,
9
10
  openSync,
@@ -32,6 +33,14 @@ function ensureStorageDirectorySync(directory, forcePrivate = false, recursive =
32
33
  ...privateMode ? { mode: 448 } : {}
33
34
  });
34
35
  }
36
+ function ensurePrivateStorageDirectorySync(directory) {
37
+ ensureStorageDirectorySync(directory, true);
38
+ const stat = lstatSync(directory);
39
+ if (!stat.isDirectory() || stat.isSymbolicLink())
40
+ throw new Error("Private storage directory is not a real directory");
41
+ if (process.platform !== "win32")
42
+ chmodSync(directory, 448);
43
+ }
35
44
  function writeStorageFileSync(filePath, content, options = {}) {
36
45
  const { forcePrivate = false, ...writeOptions } = options;
37
46
  const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
@@ -51,6 +60,35 @@ function writeStorageFileAtomicSync(filePath, content, forcePrivate = false) {
51
60
  throw error;
52
61
  }
53
62
  }
63
+ function syncStorageDirectorySync(directory) {
64
+ const fd = openSync(directory, "r");
65
+ try {
66
+ fsyncSync(fd);
67
+ } finally {
68
+ closeSync(fd);
69
+ }
70
+ }
71
+ function writeStorageFileDurableAtomicSync(filePath, content, afterTempSync) {
72
+ const directory = dirname(filePath);
73
+ ensurePrivateStorageDirectorySync(directory);
74
+ const tempPath = `${filePath}.${process.pid}.${randomBytes(12).toString("hex")}.tmp`;
75
+ let fd;
76
+ try {
77
+ fd = openStorageFileSync(tempPath, "wx", true);
78
+ writeFileSync(fd, content, "utf8");
79
+ fsyncSync(fd);
80
+ closeSync(fd);
81
+ fd = undefined;
82
+ afterTempSync?.();
83
+ renameSync(tempPath, filePath);
84
+ syncStorageDirectorySync(directory);
85
+ syncStorageDirectorySync(dirname(directory));
86
+ } finally {
87
+ if (fd !== undefined)
88
+ closeSync(fd);
89
+ rmSync(tempPath, { force: true });
90
+ }
91
+ }
54
92
  function copyStorageFileSync(sourcePath, destinationPath, forcePrivate = false) {
55
93
  ensureStorageDirectorySync(dirname(destinationPath), forcePrivate);
56
94
  const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
@@ -94,6 +132,11 @@ function copyStorageTreeSync(sourcePath, destinationPath, forcePrivate = false)
94
132
  copyStorageTreeSync(join(sourcePath, entry), join(destinationPath, entry), forcePrivate);
95
133
  }
96
134
  }
135
+ function openStorageFileSync(filePath, flags, forcePrivate = false) {
136
+ ensureStorageDirectorySync(dirname(filePath), forcePrivate);
137
+ const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
138
+ return openSync(filePath, flags, privateMode ? 384 : 438);
139
+ }
97
140
  async function writeStorageFileAsync(filePath, content, forcePrivate = false) {
98
141
  const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
99
142
  ensureStorageDirectorySync(dirname(filePath), privateMode);
@@ -147,4 +190,4 @@ function tightenStorageTreeSync(root) {
147
190
  return { tightened, failures };
148
191
  }
149
192
 
150
- export { setStoragePrivatePermissionEnforcement, shouldEnforcePrivateStoragePermissions, ensureStorageDirectorySync, writeStorageFileSync, writeStorageFileAtomicSync, copyStorageFileSync, copyStorageTreeSync, writeStorageFileAsync, writeStorageFileHandleAsync, createStorageFileHandleAsync, tightenStorageTreeSync };
193
+ export { setStoragePrivatePermissionEnforcement, shouldEnforcePrivateStoragePermissions, ensureStorageDirectorySync, ensurePrivateStorageDirectorySync, writeStorageFileSync, writeStorageFileAtomicSync, syncStorageDirectorySync, writeStorageFileDurableAtomicSync, copyStorageFileSync, copyStorageTreeSync, writeStorageFileAsync, writeStorageFileHandleAsync, createStorageFileHandleAsync, tightenStorageTreeSync };
@@ -1,11 +1,18 @@
1
+ import {
2
+ getHarness2
3
+ } from "./index-0h2mkab2.js";
4
+ import {
5
+ getMagicContextStorageDir
6
+ } from "./index-x3dcnxh0.js";
7
+ import {
8
+ isPidAlive,
9
+ readProcessStartTime
10
+ } from "./index-0j0zqb4t.js";
1
11
  import {
2
12
  removeSystemReminders,
3
13
  hasMeaningfulUserText2,
4
14
  extractTexts2
5
- } from "./index-9xb0axhc.js";
6
- import {
7
- getHarness2
8
- } from "./index-0h2mkab2.js";
15
+ } from "./index-r56xgha8.js";
9
16
  import {
10
17
  withSqliteBackgroundWriter2,
11
18
  withoutSqliteTransformPass2
@@ -15,20 +22,432 @@ import {
15
22
  recordIndexedMessageTime,
16
23
  messageFtsOrdinalRangeIsMapped,
17
24
  deleteUnmappedMessageFtsRows
18
- } from "./index-603mt6nm.js";
25
+ } from "./index-4gfq5t09.js";
19
26
  import {
20
27
  deleteChunkEmbedBackoffForSession
21
- } from "./index-fm3ksh5e.js";
28
+ } from "./index-27jh224p.js";
22
29
  import {
23
30
  closeQuietly,
31
+ TAG_TOMBSTONE_OWNER_PREFIX,
32
+ tagTombstoneOwnerRange,
33
+ tagTombstoneOwnerKey,
34
+ tagRevisionKey,
35
+ tagIdentityRevisionKey,
24
36
  deleteTagIdentityRevisions
25
- } from "./index-8y5knskr.js";
37
+ } from "./index-mcgehvgw.js";
26
38
  import {
27
39
  cleanUserText2
28
- } from "./index-hrf13mn3.js";
40
+ } from "./index-fqb1bddn.js";
29
41
  import {
30
42
  logSlowWriteTransaction
31
- } from "./index-fp37he9a.js";
43
+ } from "./index-0vrkp1jq.js";
44
+ import {
45
+ ensurePrivateStorageDirectorySync,
46
+ writeStorageFileSync,
47
+ writeStorageFileAtomicSync,
48
+ syncStorageDirectorySync,
49
+ writeStorageFileDurableAtomicSync
50
+ } from "./index-81nthk8j.js";
51
+
52
+ // ../plugin/src/hooks/magic-context/lkg-recovery-fence.ts
53
+ import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
54
+ import { lstatSync, readdirSync as readdirSync2, readFileSync as readFileSync2, rmSync as rmSync2 } from "node:fs";
55
+ import { basename, dirname, join as join2 } from "node:path";
56
+
57
+ // ../plugin/src/shared/bounded-session-map.ts
58
+ class BoundedSessionMap {
59
+ maxEntries;
60
+ store = new Map;
61
+ constructor(maxEntries) {
62
+ if (!Number.isFinite(maxEntries) || maxEntries < 1) {
63
+ throw new Error(`BoundedSessionMap: maxEntries must be >= 1, got ${maxEntries}`);
64
+ }
65
+ this.maxEntries = maxEntries;
66
+ }
67
+ get(sessionId) {
68
+ const value = this.store.get(sessionId);
69
+ if (value === undefined)
70
+ return;
71
+ this.store.delete(sessionId);
72
+ this.store.set(sessionId, value);
73
+ return value;
74
+ }
75
+ peek(sessionId) {
76
+ return this.store.get(sessionId);
77
+ }
78
+ has(sessionId) {
79
+ return this.store.has(sessionId);
80
+ }
81
+ set(sessionId, value) {
82
+ if (this.store.has(sessionId)) {
83
+ this.store.delete(sessionId);
84
+ } else if (this.store.size >= this.maxEntries) {
85
+ const oldest = this.store.keys().next().value;
86
+ if (oldest !== undefined)
87
+ this.store.delete(oldest);
88
+ }
89
+ this.store.set(sessionId, value);
90
+ }
91
+ delete(sessionId) {
92
+ return this.store.delete(sessionId);
93
+ }
94
+ clear() {
95
+ this.store.clear();
96
+ }
97
+ get size() {
98
+ return this.store.size;
99
+ }
100
+ }
101
+
102
+ // ../plugin/src/shared/storage-file-mutex.ts
103
+ import { execFileSync } from "node:child_process";
104
+ import { createHash, randomUUID } from "node:crypto";
105
+ import { readdirSync, readFileSync, rmSync } from "node:fs";
106
+ import { join } from "node:path";
107
+ var ticketChecksum = (name, ticket) => createHash("sha256").update(JSON.stringify([name, ticket.choosing, ticket.number, ticket.birth])).digest("hex");
108
+ function processBirth(pid) {
109
+ if (process.platform === "linux") {
110
+ try {
111
+ const stat = readFileSync(`/proc/${pid}/stat`, "utf8");
112
+ const ticks = stat.slice(stat.lastIndexOf(")") + 2).trim().split(/\s+/)[19];
113
+ if (!ticks || !/^\d+$/.test(ticks))
114
+ return null;
115
+ return `${readFileSync("/proc/sys/kernel/random/boot_id", "utf8").trim()}:${ticks}`;
116
+ } catch {
117
+ return null;
118
+ }
119
+ }
120
+ if (process.platform === "darwin") {
121
+ try {
122
+ return execFileSync("ps", ["-p", String(pid), "-o", "lstart="], {
123
+ encoding: "utf8",
124
+ timeout: 1000,
125
+ windowsHide: true,
126
+ env: { ...process.env, TZ: "UTC", LC_ALL: "C" },
127
+ stdio: ["ignore", "pipe", "pipe"]
128
+ }).trim() || null;
129
+ } catch {
130
+ return null;
131
+ }
132
+ }
133
+ const start = readProcessStartTime(pid);
134
+ return start === null ? null : String(start);
135
+ }
136
+ var pause = new Int32Array(new SharedArrayBuffer(4));
137
+ function withStorageFileMutex(directory, work, timeoutMs = 1000) {
138
+ ensurePrivateStorageDirectorySync(directory);
139
+ const name = `${process.pid}-${randomUUID()}.lock`;
140
+ const ownPath = join(directory, name);
141
+ const birth = processBirth(process.pid);
142
+ const ticket = { choosing: true, number: 0, birth, checksum: "" };
143
+ const encodedTicket = () => JSON.stringify({ ...ticket, checksum: ticketChecksum(name, ticket) });
144
+ writeStorageFileSync(ownPath, encodedTicket(), { flag: "wx", forcePrivate: true });
145
+ const deadline = performance.now() + timeoutMs;
146
+ const peers = () => {
147
+ const found = [];
148
+ for (const other of readdirSync(directory)) {
149
+ if (other === name || !/^\d+-[\da-f-]+\.lock$/.test(other))
150
+ continue;
151
+ const pid = Number(other.split("-")[0]);
152
+ const otherPath = join(directory, other);
153
+ let value = null;
154
+ try {
155
+ const parsed = JSON.parse(readFileSync(otherPath, "utf8"));
156
+ if (typeof parsed.choosing === "boolean" && Number.isSafeInteger(parsed.number) && parsed.number >= 0 && (parsed.birth === null || typeof parsed.birth === "string") && parsed.checksum === ticketChecksum(other, parsed))
157
+ value = parsed;
158
+ } catch (error) {
159
+ if (error.code === "ENOENT")
160
+ continue;
161
+ }
162
+ const alive = isPidAlive(pid);
163
+ const actualBirth = alive === "alive" && value?.birth ? processBirth(pid) : null;
164
+ if (alive === "dead" || actualBirth !== null && value?.birth && actualBirth !== value.birth) {
165
+ rmSync(otherPath, { force: true });
166
+ continue;
167
+ }
168
+ found.push([other, value]);
169
+ }
170
+ return found;
171
+ };
172
+ try {
173
+ ticket.number = 1 + Math.max(0, ...peers().map(([, value]) => value?.number ?? 0));
174
+ ticket.choosing = false;
175
+ writeStorageFileAtomicSync(ownPath, encodedTicket(), true);
176
+ while (peers().some(([other, value]) => !value || value.choosing || value.number < ticket.number || value.number === ticket.number && other < name)) {
177
+ if (performance.now() >= deadline)
178
+ throw new Error("Storage safety publication lock is unavailable");
179
+ Atomics.wait(pause, 0, 0, 10);
180
+ }
181
+ const result = work();
182
+ if (result && typeof result.then === "function")
183
+ throw new TypeError("Storage publication mutex requires synchronous work");
184
+ return result;
185
+ } finally {
186
+ rmSync(ownPath, { force: true });
187
+ }
188
+ }
189
+
190
+ // ../plugin/src/hooks/magic-context/lkg-recovery-fence.ts
191
+ class LkgRecoveryFenceError extends Error {
192
+ constructor(message) {
193
+ super(message);
194
+ this.name = "LkgRecoveryFenceError";
195
+ }
196
+ }
197
+ var platform = process.platform;
198
+ var observer;
199
+ var knownFences = new BoundedSessionMap(1000);
200
+ var ioObserver;
201
+ var cacheKey = (sessionId) => `${getMagicContextStorageDir()}\x00${getHarness2()}\x00${sessionId}`;
202
+ function remember(sessionId, value) {
203
+ knownFences.set(cacheKey(sessionId), value);
204
+ return value;
205
+ }
206
+ function known(sessionId) {
207
+ const prior = knownFences.get(cacheKey(sessionId));
208
+ if (prior)
209
+ return prior;
210
+ const record = read(sessionId);
211
+ if (record)
212
+ return remember(sessionId, { state: record.state, record });
213
+ try {
214
+ lstatSync(lkgRecoveryFencePath(sessionId));
215
+ } catch (error) {
216
+ if (error.code === "ENOENT")
217
+ return remember(sessionId, { state: "clean", record: null });
218
+ }
219
+ return remember(sessionId, { state: "invalid", record: null });
220
+ }
221
+ function clearLkgFenceProcessState(sessionId) {
222
+ if (sessionId)
223
+ knownFences.delete(cacheKey(sessionId));
224
+ else
225
+ knownFences.clear();
226
+ }
227
+ var durableFencesSupported = () => platform !== "win32";
228
+ var hash = (value) => createHash2("sha256").update(value).digest("hex");
229
+ function lkgRecoveryFencePath(sessionId) {
230
+ return join2(getMagicContextStorageDir(), "lkg-recovery-fences", `${hash(sessionId)}.json`);
231
+ }
232
+ function metadata(slot) {
233
+ return [
234
+ slot.inputIdSeq,
235
+ slot.inputContentDigests,
236
+ slot.inputContentSignatures ?? null,
237
+ slot.piOutputEntryIds ?? null,
238
+ slot.lastInputMessageId,
239
+ slot.modelKey,
240
+ slot.providerKey
241
+ ];
242
+ }
243
+ function representationKey(slot) {
244
+ return createHash2("sha256").update(slot.jsonPrefix).update(JSON.stringify(metadata(slot))).digest("hex");
245
+ }
246
+ function lkgRecoverySlotKey(slot) {
247
+ return hash(JSON.stringify([
248
+ representationKey(slot),
249
+ slot.capturedAt,
250
+ slot.rowVersion ?? null,
251
+ slot.captureSequence ?? null
252
+ ]));
253
+ }
254
+ function payload(record) {
255
+ return [
256
+ record.version,
257
+ record.sessionId,
258
+ record.host,
259
+ record.modelKey,
260
+ record.providerKey,
261
+ record.slotKey,
262
+ record.servedDigest,
263
+ record.revision,
264
+ record.state
265
+ ];
266
+ }
267
+ function publishRecord(record) {
268
+ ioObserver?.("write");
269
+ try {
270
+ if (record.state === "clean")
271
+ observer?.("clean");
272
+ writeStorageFileDurableAtomicSync(lkgRecoveryFencePath(record.sessionId), JSON.stringify({ ...record, checksum: hash(JSON.stringify(payload(record))) }), () => observer?.("temp-synced"));
273
+ if (record.state === "dirty")
274
+ observer?.("dirty");
275
+ remember(record.sessionId, {
276
+ state: record.state,
277
+ record: { ...record, checksum: hash(JSON.stringify(payload(record))) }
278
+ });
279
+ } catch (error) {
280
+ const visible = read(record.sessionId);
281
+ if (record.state === "clean" && visible?.state === "clean" && visible.revision === record.revision && visible.slotKey === record.slotKey) {
282
+ const dirty = { ...record, state: "dirty" };
283
+ writeStorageFileDurableAtomicSync(lkgRecoveryFencePath(record.sessionId), JSON.stringify({ ...dirty, checksum: hash(JSON.stringify(payload(dirty))) }));
284
+ }
285
+ remember(record.sessionId, { state: "invalid", record: null });
286
+ throw error;
287
+ }
288
+ }
289
+ function read(sessionId) {
290
+ ioObserver?.("read");
291
+ try {
292
+ const path = lkgRecoveryFencePath(sessionId);
293
+ const stat = lstatSync(path);
294
+ const directory = lstatSync(dirname(path));
295
+ if (!stat.isFile() || stat.size > 4096 || !directory.isDirectory() || directory.isSymbolicLink() || process.platform !== "win32" && ((stat.mode & 63) !== 0 || (directory.mode & 63) !== 0 || process.getuid && stat.uid !== process.getuid()))
296
+ return null;
297
+ const value = JSON.parse(readFileSync2(path, "utf8"));
298
+ if (value.version !== 1 || value.sessionId !== sessionId || value.host !== getHarness2() || value.modelKey !== null && typeof value.modelKey !== "string" || value.providerKey !== null && typeof value.providerKey !== "string" || !/^[a-f0-9]{64}$/.test(value.slotKey) || !/^[a-f0-9]{64}$/.test(value.servedDigest) || typeof value.revision !== "string" || !["clean", "dirty"].includes(value.state) || value.checksum !== hash(JSON.stringify(payload(value))))
299
+ return null;
300
+ return value;
301
+ } catch {
302
+ return null;
303
+ }
304
+ }
305
+ function publish(sessionId, slot, state, revision) {
306
+ const record = {
307
+ version: 1,
308
+ sessionId,
309
+ host: getHarness2(),
310
+ modelKey: slot.modelKey,
311
+ providerKey: slot.providerKey,
312
+ slotKey: lkgRecoverySlotKey(slot),
313
+ servedDigest: hash(slot.jsonPrefix),
314
+ revision,
315
+ state
316
+ };
317
+ publishRecord(record);
318
+ }
319
+ function locked(sessionId, work) {
320
+ ioObserver?.("mutex");
321
+ return withStorageFileMutex(`${lkgRecoveryFencePath(sessionId)}.locks`, () => {
322
+ const path = lkgRecoveryFencePath(sessionId);
323
+ for (const name of readdirSync2(dirname(path))) {
324
+ if (name.startsWith(`${basename(path)}.`) && name.endsWith(".tmp"))
325
+ rmSync2(join2(dirname(path), name), { force: true });
326
+ }
327
+ return work();
328
+ });
329
+ }
330
+ function hasCleanLkgRecoveryFence(sessionId, _slot) {
331
+ if (!durableFencesSupported())
332
+ return false;
333
+ const state = known(sessionId);
334
+ return state.state === "clean";
335
+ }
336
+ function lkgFenceRequiresRebuild(sessionId, slot, processLocalProof) {
337
+ return !processLocalProof && (durableFencesSupported() ? !hasCleanLkgRecoveryFence(sessionId, slot) : true);
338
+ }
339
+ function lkgRecoveryFenceUnclean(sessionId) {
340
+ return durableFencesSupported() && known(sessionId).state !== "clean";
341
+ }
342
+ function ownsLkgDirtyFence(sessionId, revision) {
343
+ if (!durableFencesSupported())
344
+ return revision === "process-local";
345
+ const record = known(sessionId).record;
346
+ return revision !== undefined && record?.state === "dirty" && record.revision === revision;
347
+ }
348
+ function invalidateCleanLkgRecoveryFence(sessionId, load, ownRevision) {
349
+ if (!durableFencesSupported())
350
+ return "process-local";
351
+ const prior = known(sessionId);
352
+ if (prior.state === "dirty")
353
+ return prior.record?.revision === ownRevision ? ownRevision : undefined;
354
+ return locked(sessionId, () => {
355
+ const slot = load() ?? {
356
+ jsonPrefix: "",
357
+ inputIdSeq: [],
358
+ inputContentDigests: [],
359
+ lastInputMessageId: "",
360
+ modelKey: null,
361
+ providerKey: null,
362
+ capturedAt: 0
363
+ };
364
+ const record = read(sessionId);
365
+ if (record?.state !== "dirty") {
366
+ const revision = randomUUID2();
367
+ publish(sessionId, slot, "dirty", revision);
368
+ return revision;
369
+ }
370
+ return record?.state === "dirty" && record.revision === ownRevision ? ownRevision : undefined;
371
+ });
372
+ }
373
+ function markLkgRecoveryDirty(args) {
374
+ if (!durableFencesSupported()) {
375
+ if (!args.processLocalProof)
376
+ throw new LkgRecoveryFenceError("Restart replay requires a healthy rebuild on Windows");
377
+ return "process-local";
378
+ }
379
+ const state = known(args.sessionId);
380
+ if (state.state === "dirty" && args.processLocalProof && state.record && state.record.revision === args.ownDirtyRevision)
381
+ return state.record.revision;
382
+ if (state.state === "invalid")
383
+ throw new LkgRecoveryFenceError("No clean durable recovery certificate");
384
+ return locked(args.sessionId, () => {
385
+ const slot = args.slot;
386
+ const before = read(args.sessionId);
387
+ if (before?.state === "dirty") {
388
+ if (!args.processLocalProof || before.revision !== args.ownDirtyRevision)
389
+ throw new LkgRecoveryFenceError(`Recovery superseded this process's last-good request (local=${args.processLocalProof}, owned=${before.revision === args.ownDirtyRevision})`);
390
+ return before.revision;
391
+ }
392
+ if (before && before.state !== "clean")
393
+ throw new LkgRecoveryFenceError("No clean durable recovery certificate");
394
+ const revision = randomUUID2();
395
+ publish(args.sessionId, slot, "dirty", revision);
396
+ return revision;
397
+ });
398
+ }
399
+ function commitLkgWithRecoveryFence(args) {
400
+ if (!durableFencesSupported())
401
+ return args.commit();
402
+ const state = known(args.sessionId);
403
+ if (state.state === "clean" && !args.requiredRevision && !args.retainDirtyRevision) {
404
+ const committed = args.commit();
405
+ if (committed) {
406
+ observer?.("committed");
407
+ remember(args.sessionId, { state: "clean", record: null });
408
+ }
409
+ return committed;
410
+ }
411
+ if (state.state === "invalid" && !args.rebuild)
412
+ throw new LkgRecoveryFenceError("Unproven prior request requires a prefix rebuild");
413
+ return locked(args.sessionId, () => {
414
+ const before = read(args.sessionId);
415
+ if (args.requiredRevision && before?.revision !== args.requiredRevision)
416
+ throw new LkgRecoveryFenceError("A later publisher superseded the rollback snapshot");
417
+ const ownsDirty = before?.state === "dirty" && (before.revision === args.retainDirtyRevision || before.revision === args.ownDirtyRevision);
418
+ if (before?.state === "dirty" && !ownsDirty && !args.rebuild)
419
+ throw new LkgRecoveryFenceError("A concurrent recovery requires a declared prefix rebuild");
420
+ if (before?.state !== "dirty" && state.state === "invalid")
421
+ publish(args.sessionId, args.load() ?? args.slot, "dirty", randomUUID2());
422
+ if (!args.commit())
423
+ return false;
424
+ observer?.("committed");
425
+ const saved = args.load();
426
+ if (!saved || representationKey(saved) !== representationKey(args.slot))
427
+ throw new LkgRecoveryFenceError("Last-good commit did not match its certificate");
428
+ if (args.retainDirtyRevision || args.cleanDigest !== undefined && hash(saved.jsonPrefix) !== args.cleanDigest)
429
+ return true;
430
+ const dirty = read(args.sessionId);
431
+ if (dirty?.state === "dirty")
432
+ publish(args.sessionId, saved, "clean", dirty.revision);
433
+ else
434
+ remember(args.sessionId, { state: "clean", record: null });
435
+ return true;
436
+ });
437
+ }
438
+ function clearLkgRecoveryFence(sessionId, remove, shouldClear) {
439
+ if (!durableFencesSupported())
440
+ return remove?.();
441
+ return locked(sessionId, () => {
442
+ const result = remove?.();
443
+ if (shouldClear && !shouldClear(result))
444
+ return result;
445
+ rmSync2(lkgRecoveryFencePath(sessionId), { force: true });
446
+ syncStorageDirectorySync(dirname(lkgRecoveryFencePath(sessionId)));
447
+ clearLkgFenceProcessState(sessionId);
448
+ return result;
449
+ });
450
+ }
32
451
 
33
452
  // ../plugin/src/features/magic-context/session-activity.ts
34
453
  var PREFIX = "retrospective_activity:";
@@ -176,6 +595,17 @@ function deleteSessionScopedRows(db, sessionIds, harness, options = {}) {
176
595
  if (deletableSessionIds.length === 0)
177
596
  return 0;
178
597
  const placeholders = deletableSessionIds.map(() => "?").join(", ");
598
+ const harnessTables = SESSION_SCOPED_TABLES.filter((definition) => definition.harnessScoped);
599
+ if (options.preserveTagRevisionTombstones) {
600
+ const owners = db.prepare(harnessTables.map((definition) => `SELECT session_id, harness FROM ${definition.table} WHERE session_id IN (${placeholders})${definition.extraPredicate ? ` AND ${definition.extraPredicate}` : ""}`).join(" UNION ")).all(...harnessTables.flatMap(() => deletableSessionIds));
601
+ const record = db.prepare("INSERT OR IGNORE INTO schema_migrations_meta (key, value) VALUES (?, ?)");
602
+ for (const owner of owners)
603
+ record.run(tagTombstoneOwnerKey(owner.session_id, owner.harness), owner.harness);
604
+ const fallback = db.prepare(`INSERT INTO schema_migrations_meta (key, value)
605
+ SELECT ?, ? WHERE NOT EXISTS (SELECT 1 FROM schema_migrations_meta WHERE key >= ? AND key < ?)`);
606
+ for (const id of deletableSessionIds)
607
+ fallback.run(tagTombstoneOwnerKey(id, getHarness2()), getHarness2(), ...tagTombstoneOwnerRange(id));
608
+ }
179
609
  for (const sessionId of deletableSessionIds)
180
610
  deleteChunkEmbedBackoffForSession(db, sessionId);
181
611
  for (const definition of SESSION_SCOPED_TABLES) {
@@ -202,6 +632,22 @@ function deleteSessionScopedRows(db, sessionIds, harness, options = {}) {
202
632
  statement.run(...deletableSessionIds);
203
633
  }
204
634
  deleteSessionActivity(db, deletableSessionIds);
635
+ if (!options.preserveTagRevisionTombstones) {
636
+ const retireOwner = db.prepare(harness === undefined ? "DELETE FROM schema_migrations_meta WHERE key >= ? AND key < ?" : "DELETE FROM schema_migrations_meta WHERE key = ?");
637
+ const survivingRows = harnessTables.map((definition) => `EXISTS (SELECT 1 FROM ${definition.table} WHERE session_id = ?${definition.extraPredicate ? ` AND ${definition.extraPredicate}` : ""})`).join(" OR ");
638
+ const retire = db.prepare(`DELETE FROM schema_migrations_meta WHERE key IN (?, ?)
639
+ AND NOT (${survivingRows})
640
+ AND NOT EXISTS (SELECT 1 FROM schema_migrations_meta AS owners WHERE owners.key >= ? AND owners.key < ?)`);
641
+ for (const id of deletableSessionIds) {
642
+ if (harness === undefined)
643
+ retireOwner.run(...tagTombstoneOwnerRange(id));
644
+ else
645
+ retireOwner.run(tagTombstoneOwnerKey(id, harness));
646
+ retire.run(tagIdentityRevisionKey(id), tagRevisionKey(id), ...harnessTables.map(() => id), ...tagTombstoneOwnerRange(id));
647
+ }
648
+ }
649
+ for (const sessionId of deletableSessionIds)
650
+ clearLkgRecoveryFence(sessionId);
205
651
  return deletableSessionIds.length;
206
652
  }
207
653
 
@@ -229,7 +675,7 @@ function clearCompressionDepthRange(db, sessionId, startOrdinal, endOrdinal) {
229
675
  }
230
676
 
231
677
  // ../plugin/src/features/magic-context/message-index.ts
232
- import { createHash } from "node:crypto";
678
+ import { createHash as createHash3 } from "node:crypto";
233
679
  var MESSAGE_HISTORY_ORPHAN_SWEEP_BATCH_SIZE = 200;
234
680
  var MESSAGE_HISTORY_ORPHAN_SAFETY_AGE_MS = 24 * 60 * 60 * 1000;
235
681
  var MESSAGE_HISTORY_ORPHAN_SWEEP_COOLDOWN_MS = 10 * 60 * 1000;
@@ -415,7 +861,7 @@ function toMessageIndexSource(message) {
415
861
  role: message.role,
416
862
  createdAt: message.createdAt,
417
863
  sourceVersion: normalizeSourceVersion(message.version),
418
- contentHash: createHash("sha256").update(content).digest("hex"),
864
+ contentHash: createHash3("sha256").update(content).digest("hex"),
419
865
  content
420
866
  };
421
867
  }
@@ -641,12 +1087,19 @@ function persistMessageHistoryOrphanSweepState(db, cursor, lastSweptAt, harness)
641
1087
  last_swept_at = excluded.last_swept_at`).run(harness, cursor, lastSweptAt);
642
1088
  }
643
1089
  function getOpenCodeSessionScopedCandidateSourceSql(harness) {
644
- return SESSION_SCOPED_TABLES.filter((definition) => definition.harnessScoped === true).map((definition) => {
1090
+ const sources = SESSION_SCOPED_TABLES.filter((definition) => definition.harnessScoped === true).map((definition) => {
645
1091
  const predicates = ["session_id IS NOT NULL", `harness = '${harness}'`];
646
1092
  if (definition.extraPredicate)
647
1093
  predicates.push(definition.extraPredicate);
648
1094
  return `SELECT session_id FROM ${definition.table} WHERE ${predicates.join(" AND ")}`;
649
- }).join(`
1095
+ });
1096
+ const jsonId = `SUBSTR(key, ${TAG_TOMBSTONE_OWNER_PREFIX.length + 1}, LENGTH(key) - ${TAG_TOMBSTONE_OWNER_PREFIX.length + harness.length + 1})`;
1097
+ sources.push(`SELECT CASE WHEN json_valid(${jsonId}) THEN
1098
+ CASE WHEN json_type(${jsonId}) = 'text' THEN json_extract(${jsonId}, '$') END END AS session_id
1099
+ FROM schema_migrations_meta WHERE value = '${harness}'
1100
+ AND key >= '${TAG_TOMBSTONE_OWNER_PREFIX}' AND key < '${TAG_TOMBSTONE_OWNER_PREFIX.slice(0, -1)};'
1101
+ AND SUBSTR(key, -${harness.length + 1}) = ':${harness}'`);
1102
+ return sources.join(`
650
1103
  UNION
651
1104
  `);
652
1105
  }
@@ -747,4 +1200,4 @@ function sweepOrphanedOpenCodeMessageIndexes(db, openReadableOpenCodeDb, options
747
1200
  return withoutSqliteTransformPass2(() => withSqliteBackgroundWriter2(() => sweepOrphanedOpenCodeMessageIndexesInBackground(db, openReadableOpenCodeDb, options)));
748
1201
  }
749
1202
 
750
- export { readSessionActivity, observeSessionActivity, backfillSessionActivity, deleteSessionScopedRows, clearCompressionDepth, clearCompressionDepthRange, MESSAGE_INDEX_MAX_FTS_BYTES, messageIndexSkipKey, getMessageIndexSourceIdentity, isMessageIndexSourceCurrent, getLastIndexedOrdinal, getIndexedMessageCorpusSize, markMessageIndexDirty, getMessageIndexReconciliationStartOrdinal, isMessageIndexReconciledThrough, getIndexableContent, indexSingleMessage, indexMessagesAfterOrdinal, sweepOrphanedOpenCodeMessageIndexes };
1203
+ export { BoundedSessionMap, LkgRecoveryFenceError, clearLkgFenceProcessState, lkgFenceRequiresRebuild, lkgRecoveryFenceUnclean, ownsLkgDirtyFence, invalidateCleanLkgRecoveryFence, markLkgRecoveryDirty, commitLkgWithRecoveryFence, clearLkgRecoveryFence, readSessionActivity, observeSessionActivity, backfillSessionActivity, deleteSessionScopedRows, clearCompressionDepth, clearCompressionDepthRange, MESSAGE_INDEX_MAX_FTS_BYTES, messageIndexSkipKey, getMessageIndexSourceIdentity, isMessageIndexSourceCurrent, getLastIndexedOrdinal, getIndexedMessageCorpusSize, markMessageIndexDirty, getMessageIndexReconciliationStartOrdinal, isMessageIndexReconciledThrough, getIndexableContent, indexSingleMessage, indexMessagesAfterOrdinal, sweepOrphanedOpenCodeMessageIndexes };