@cortexkit/opencode-magic-context 0.35.0 → 0.36.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 (91) hide show
  1. package/README.md +9 -5
  2. package/dist/agents/hidden-agent-registrations.d.ts +10 -2
  3. package/dist/agents/hidden-agent-registrations.d.ts.map +1 -1
  4. package/dist/agents/permissions.d.ts +21 -3
  5. package/dist/agents/permissions.d.ts.map +1 -1
  6. package/dist/{announcement-gms2nhya.js → announcement-6c1g4es4.js} +2 -2
  7. package/dist/config/schema/agent-overrides.d.ts +1 -1
  8. package/dist/config/schema/magic-context.d.ts +19 -9
  9. package/dist/config/schema/magic-context.d.ts.map +1 -1
  10. package/dist/{conflict-warning-hook-p2pmhvn7.js → conflict-warning-hook-dw9fs934.js} +4 -4
  11. package/dist/{derive-budgets-9crp0cvd.js → derive-budgets-88mxk2w1.js} +3 -3
  12. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts +2 -0
  13. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  14. package/dist/features/magic-context/dreamer/task-executor.d.ts +1 -0
  15. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  16. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  17. package/dist/features/magic-context/smart-notes/condition-compiler.d.ts +37 -0
  18. package/dist/features/magic-context/smart-notes/condition-compiler.d.ts.map +1 -0
  19. package/dist/features/magic-context/smart-notes/runner.d.ts +1 -0
  20. package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -1
  21. package/dist/features/magic-context/smart-notes/storage.d.ts +3 -3
  22. package/dist/features/magic-context/smart-notes/storage.d.ts.map +1 -1
  23. package/dist/features/magic-context/storage-db.d.ts +1 -1
  24. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  25. package/dist/features/magic-context/storage-notes.d.ts +13 -0
  26. package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
  27. package/dist/features/magic-context/storage.d.ts +1 -1
  28. package/dist/features/magic-context/storage.d.ts.map +1 -1
  29. package/dist/hooks/magic-context/compartment-prompt.d.ts +6 -6
  30. package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
  31. package/dist/hooks/magic-context/hook.d.ts +3 -0
  32. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/lkg-slot.d.ts +15 -1
  34. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  35. package/dist/hooks/magic-context/module-state-sync.d.ts +6 -0
  36. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/module-transport.d.ts +9 -0
  38. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  39. package/dist/hooks/magic-context/raw-fallback-context-limit.d.ts +10 -0
  40. package/dist/hooks/magic-context/raw-fallback-context-limit.d.ts.map +1 -0
  41. package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
  42. package/dist/hooks/magic-context/rust-mode-transform.d.ts +7 -2
  43. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  44. package/dist/{index-8aaadh98.js → index-37rt2bka.js} +2 -2
  45. package/dist/{index-4anesz49.js → index-3nfgbsp4.js} +103 -56
  46. package/dist/{index-fcyvznch.js → index-3tnkymva.js} +47 -4
  47. package/dist/{index-k1esqfwk.js → index-f1tnb3vm.js} +1 -1
  48. package/dist/{index-kvrcg31b.js → index-mmrhhk9a.js} +8 -1
  49. package/dist/{index-cn960ffd.js → index-nsx2n9eg.js} +3 -3
  50. package/dist/{index-dmr999a2.js → index-qf20mv7e.js} +1 -1
  51. package/dist/{index-73xz0247.js → index-tsgs7td8.js} +1 -1
  52. package/dist/{index-ry8rh8cv.js → index-wgvxkqpx.js} +5 -4
  53. package/dist/index-z8v31d85.js +2892 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +822 -119
  56. package/dist/plugin/dream-timer.d.ts +1 -0
  57. package/dist/plugin/dream-timer.d.ts.map +1 -1
  58. package/dist/plugin/hooks/create-session-hooks.d.ts +3 -0
  59. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  60. package/dist/plugin/messages-transform.d.ts +5 -5
  61. package/dist/plugin/messages-transform.d.ts.map +1 -1
  62. package/dist/{recomp-orchestrator-zc915ceq.js → recomp-orchestrator-7wbbvf87.js} +7 -7
  63. package/dist/{safe-notification-target-q9jk5n44.js → safe-notification-target-c11fdda2.js} +3 -3
  64. package/dist/{send-session-notification-6njqewzk.js → send-session-notification-bgtf4853.js} +4 -4
  65. package/dist/shared/data-path.d.ts +27 -0
  66. package/dist/shared/data-path.d.ts.map +1 -1
  67. package/dist/shared/harness-provider-map.d.ts +23 -20
  68. package/dist/shared/harness-provider-map.d.ts.map +1 -1
  69. package/dist/shared/prompt-surface-a1-golden.d.ts +28 -0
  70. package/dist/shared/prompt-surface-a1-golden.d.ts.map +1 -0
  71. package/dist/shared/prompt-surface-runtime.d.ts +15 -2
  72. package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
  73. package/dist/shared/sqlite.d.ts +13 -0
  74. package/dist/shared/sqlite.d.ts.map +1 -1
  75. package/dist/{storage-meta-session-53cjs6mr.js → storage-meta-session-kh5egr11.js} +4 -4
  76. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  77. package/package.json +3 -3
  78. package/src/agents/hidden-agent-registrations.ts +49 -1
  79. package/src/agents/permissions.ts +91 -3
  80. package/src/config/compaction-accessor-guard.test.ts +9 -4
  81. package/src/config/schema/magic-context.test.ts +2 -0
  82. package/src/config/schema/magic-context.ts +15 -0
  83. package/src/shared/data-path.test.ts +65 -9
  84. package/src/shared/data-path.ts +66 -1
  85. package/src/shared/harness-provider-map.test.ts +42 -1
  86. package/src/shared/harness-provider-map.ts +48 -26
  87. package/src/shared/prompt-surface-a1-golden.ts +41 -0
  88. package/src/shared/prompt-surface-runtime.ts +13 -5
  89. package/src/shared/sqlite.test.ts +32 -0
  90. package/src/shared/sqlite.ts +85 -9
  91. package/dist/index-h8mk7vpa.js +0 -135318
@@ -0,0 +1,2892 @@
1
+ import {
2
+ closeQuietly,
3
+ getRawSessionMessageCountFromDb,
4
+ openCodeDbExists,
5
+ withReadOnlySessionDb
6
+ } from "./index-3tnkymva.js";
7
+ import {
8
+ log
9
+ } from "./index-f1tnb3vm.js";
10
+ import {
11
+ getHarness
12
+ } from "./index-mmrhhk9a.js";
13
+
14
+ // src/features/magic-context/storage-meta-session.ts
15
+ import { Buffer as Buffer2 } from "node:buffer";
16
+
17
+ // src/features/magic-context/compression-depth-storage.ts
18
+ var incrementDepthStatements = new WeakMap;
19
+ var totalDepthStatements = new WeakMap;
20
+ var maxDepthStatements = new WeakMap;
21
+ var clearDepthStatements = new WeakMap;
22
+ function getClearDepthStatement(db) {
23
+ let stmt = clearDepthStatements.get(db);
24
+ if (!stmt) {
25
+ stmt = db.prepare("DELETE FROM compression_depth WHERE session_id = ?");
26
+ clearDepthStatements.set(db, stmt);
27
+ }
28
+ return stmt;
29
+ }
30
+ function clearCompressionDepth(db, sessionId) {
31
+ getClearDepthStatement(db).run(sessionId);
32
+ }
33
+ function clearCompressionDepthRange(db, sessionId, startOrdinal, endOrdinal) {
34
+ if (endOrdinal < startOrdinal) {
35
+ return;
36
+ }
37
+ db.prepare("DELETE FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?").run(sessionId, startOrdinal, endOrdinal);
38
+ }
39
+
40
+ // src/features/magic-context/message-index.ts
41
+ import { createHash } from "node:crypto";
42
+
43
+ // src/shared/internal-initiator-marker.ts
44
+ var OMO_INTERNAL_INITIATOR_MARKER = "<!-- OMO_INTERNAL_INITIATOR -->";
45
+
46
+ // src/shared/system-directive.ts
47
+ var SYSTEM_DIRECTIVE_PREFIX = "[SYSTEM DIRECTIVE: MAGIC-CONTEXT";
48
+ function isSystemDirective(text) {
49
+ return text.trimStart().startsWith(SYSTEM_DIRECTIVE_PREFIX);
50
+ }
51
+ function removeSystemReminders(text) {
52
+ return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi, "").trim();
53
+ }
54
+
55
+ // src/hooks/magic-context/read-session-formatting.ts
56
+ import { createRequire } from "node:module";
57
+
58
+ // src/shared/commit-detection.ts
59
+ var HASH_HEX = "[0-9a-f]{7,12}";
60
+ var COMMIT_HASH_TEST_PATTERN = new RegExp(`\\b${HASH_HEX}\\b`, "i");
61
+ var COMMIT_VERB_PATTERN = /\b(?:commit(?:ted|ting|s)?|cherry-?pick(?:ed|ing|s)?|merge[ds]?|merging|rebas(?:e|ed|es|ing))\b/i;
62
+ function textMentionsRecentCommit(text) {
63
+ return COMMIT_HASH_TEST_PATTERN.test(text) && COMMIT_VERB_PATTERN.test(text);
64
+ }
65
+ function createCommitHashExtractPattern() {
66
+ return new RegExp(`\`?\\b(${HASH_HEX})\\b\`?`, "gi");
67
+ }
68
+
69
+ // src/hooks/magic-context/read-session-formatting.ts
70
+ var MAX_COMMITS_PER_BLOCK = 5;
71
+ function hasMeaningfulUserText(parts) {
72
+ for (const part of parts) {
73
+ if (part === null || typeof part !== "object")
74
+ continue;
75
+ const candidate = part;
76
+ if (candidate.type !== "text" || typeof candidate.text !== "string")
77
+ continue;
78
+ if (candidate.ignored === true)
79
+ continue;
80
+ const cleaned = removeSystemReminders(candidate.text).replace(OMO_INTERNAL_INITIATOR_MARKER, "").trim();
81
+ if (!cleaned)
82
+ continue;
83
+ if (isSystemDirective(cleaned))
84
+ continue;
85
+ return true;
86
+ }
87
+ return false;
88
+ }
89
+ function extractTexts(parts) {
90
+ const texts = [];
91
+ for (const part of parts) {
92
+ if (part === null || typeof part !== "object")
93
+ continue;
94
+ const p = part;
95
+ if (p.type === "text" && typeof p.text === "string" && p.text.trim().length > 0) {
96
+ texts.push(p.text.trim());
97
+ }
98
+ }
99
+ return texts;
100
+ }
101
+ function extractToolCallSummaries(parts) {
102
+ const summaries = [];
103
+ for (const part of parts) {
104
+ if (part === null || typeof part !== "object")
105
+ continue;
106
+ const p = part;
107
+ if (p.type !== "tool" || typeof p.tool !== "string")
108
+ continue;
109
+ const state = p.state;
110
+ if (!state || typeof state !== "object")
111
+ continue;
112
+ const input = state.input;
113
+ const metadata = state.metadata;
114
+ const description = input && typeof input.description === "string" && input.description || metadata && typeof metadata.description === "string" && metadata.description;
115
+ if (description) {
116
+ summaries.push(`TC: ${description}`);
117
+ continue;
118
+ }
119
+ const toolName = p.tool;
120
+ const keyArg = extractKeyArg(toolName, input);
121
+ summaries.push(keyArg ? `TC: ${toolName}(${keyArg})` : `TC: ${toolName}`);
122
+ }
123
+ return summaries;
124
+ }
125
+ function extractKeyArg(_toolName, input) {
126
+ if (!input)
127
+ return null;
128
+ if (typeof input.filePath === "string")
129
+ return truncateArg(input.filePath);
130
+ if (typeof input.path === "string")
131
+ return truncateArg(input.path);
132
+ if (typeof input.pattern === "string")
133
+ return truncateArg(input.pattern);
134
+ if (typeof input.query === "string")
135
+ return truncateArg(input.query);
136
+ if (typeof input.symbol === "string")
137
+ return input.symbol;
138
+ if (typeof input.module === "string")
139
+ return input.module;
140
+ if (typeof input.action === "string")
141
+ return input.action;
142
+ return null;
143
+ }
144
+ function truncateArg(value, maxLen = 60) {
145
+ if (value.length <= maxLen)
146
+ return value;
147
+ return `${value.slice(0, maxLen)}…`;
148
+ }
149
+ var requireFromThisModule = createRequire(import.meta.url);
150
+ var tokenizer;
151
+ function getTokenizer() {
152
+ if (tokenizer)
153
+ return tokenizer;
154
+ const tokenizerModule = requireFromThisModule("ai-" + "tokenizer");
155
+ const Tokenizer = tokenizerModule.default ?? tokenizerModule.Tokenizer;
156
+ if (!Tokenizer)
157
+ throw new Error("ai-tokenizer does not expose a Tokenizer constructor");
158
+ const claudeEncoding = requireFromThisModule("ai-tokenizer/encoding/" + "claude");
159
+ tokenizer = new Tokenizer(claudeEncoding);
160
+ return tokenizer;
161
+ }
162
+ function estimateTokens(text) {
163
+ if (!text)
164
+ return 0;
165
+ return getTokenizer().encode(text, "all").length;
166
+ }
167
+ function normalizeText(text) {
168
+ return text.replace(/\s+/g, " ").trim();
169
+ }
170
+ function compactRole(role) {
171
+ if (role === "assistant")
172
+ return "A";
173
+ if (role === "user")
174
+ return "U";
175
+ return role.slice(0, 1).toUpperCase() || "M";
176
+ }
177
+ function formatBlock(block) {
178
+ const range = block.startOrdinal === block.endOrdinal ? `[${block.startOrdinal}]` : `[${block.startOrdinal}-${block.endOrdinal}]`;
179
+ const commitSuffix = block.commitHashes.length > 0 ? ` commits: ${block.commitHashes.join(", ")}` : "";
180
+ return `${range} ${block.role}:${commitSuffix} ${block.parts.join(" / ")}`;
181
+ }
182
+ function extractCommitHashes(text) {
183
+ const hashes = [];
184
+ const seen = new Set;
185
+ for (const match of text.matchAll(createCommitHashExtractPattern())) {
186
+ const hash = match[1]?.toLowerCase();
187
+ if (!hash || seen.has(hash))
188
+ continue;
189
+ seen.add(hash);
190
+ hashes.push(hash);
191
+ if (hashes.length >= MAX_COMMITS_PER_BLOCK)
192
+ break;
193
+ }
194
+ return hashes;
195
+ }
196
+ function compactTextForSummary(text, role) {
197
+ const commitHashes = role === "assistant" ? extractCommitHashes(text) : [];
198
+ if (commitHashes.length === 0 || !COMMIT_VERB_PATTERN.test(text)) {
199
+ return { text, commitHashes };
200
+ }
201
+ const withoutHashes = text.replace(createCommitHashExtractPattern(), "").replace(/\(\s*\)/g, "").replace(/\s+,/g, ",").replace(/,\s*,+/g, ", ").replace(/\s{2,}/g, " ").replace(/\s+([,.;:])/g, "$1").trim();
202
+ return {
203
+ text: withoutHashes.length > 0 ? withoutHashes : text,
204
+ commitHashes
205
+ };
206
+ }
207
+ function mergeCommitHashes(existing, next) {
208
+ if (next.length === 0)
209
+ return existing;
210
+ const merged = [...existing];
211
+ for (const hash of next) {
212
+ if (merged.includes(hash))
213
+ continue;
214
+ merged.push(hash);
215
+ if (merged.length >= MAX_COMMITS_PER_BLOCK)
216
+ break;
217
+ }
218
+ return merged;
219
+ }
220
+
221
+ // src/hooks/magic-context/read-session-raw.ts
222
+ function isRawMessageRow(row) {
223
+ if (row === null || typeof row !== "object")
224
+ return false;
225
+ const candidate = row;
226
+ return typeof candidate.id === "string" && typeof candidate.data === "string";
227
+ }
228
+ function isRawPartRow(row) {
229
+ if (row === null || typeof row !== "object")
230
+ return false;
231
+ const candidate = row;
232
+ return typeof candidate.message_id === "string" && typeof candidate.data === "string";
233
+ }
234
+ function parseJsonRecord(value) {
235
+ try {
236
+ const parsed = JSON.parse(value);
237
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
238
+ return null;
239
+ }
240
+ return parsed;
241
+ } catch {
242
+ return null;
243
+ }
244
+ }
245
+ function isRawCompactionSummaryInfo(info) {
246
+ if (info === null || typeof info !== "object" || Array.isArray(info))
247
+ return false;
248
+ const candidate = info;
249
+ return candidate.summary === true && candidate.finish === "stop";
250
+ }
251
+ function parseJsonUnknown(value) {
252
+ try {
253
+ return JSON.parse(value);
254
+ } catch {
255
+ return null;
256
+ }
257
+ }
258
+ function attachRawPartVersion(value, timeUpdated) {
259
+ if (value === null || typeof value !== "object" || Array.isArray(value))
260
+ return value;
261
+ if (typeof timeUpdated !== "number")
262
+ return value;
263
+ try {
264
+ Object.defineProperty(value, "__magicContextPartUpdatedAt", {
265
+ value: timeUpdated,
266
+ enumerable: false,
267
+ configurable: true
268
+ });
269
+ } catch {}
270
+ return value;
271
+ }
272
+ function readRawSessionMessagesFromDb(db, sessionId) {
273
+ const messageRows = db.prepare("SELECT id, data, time_created, time_updated FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawMessageRow);
274
+ const partRows = db.prepare("SELECT message_id, data, time_updated FROM part WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawPartRow);
275
+ const partsByMessageId = new Map;
276
+ for (const part of partRows) {
277
+ const list = partsByMessageId.get(part.message_id) ?? [];
278
+ list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
279
+ partsByMessageId.set(part.message_id, list);
280
+ }
281
+ const filtered = messageRows.filter((row) => !isRawCompactionSummaryInfo(parseJsonRecord(row.data)));
282
+ return filtered.flatMap((row, index) => {
283
+ const info = parseJsonRecord(row.data);
284
+ if (!info)
285
+ return [];
286
+ const role = typeof info.role === "string" ? info.role : "unknown";
287
+ return {
288
+ ordinal: index + 1,
289
+ id: row.id,
290
+ role,
291
+ parts: partsByMessageId.get(row.id) ?? [],
292
+ createdAt: row.time_created ?? null,
293
+ version: row.time_updated ?? null
294
+ };
295
+ });
296
+ }
297
+ function readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, finalWatermark = Number.MAX_SAFE_INTEGER) {
298
+ const remaining = Math.max(0, Math.floor(finalWatermark) - Math.floor(afterOrdinal));
299
+ const pageSize = Math.min(Math.max(1, Math.floor(limit)), remaining);
300
+ if (pageSize === 0)
301
+ return [];
302
+ const messageRows = db.prepare(`SELECT id, data, time_created, time_updated
303
+ FROM message
304
+ WHERE session_id = ?
305
+ AND NOT (
306
+ CASE WHEN json_valid(data) = 1
307
+ THEN COALESCE(json_extract(data, '$.summary'), 0)
308
+ ELSE 0 END = 1
309
+ AND CASE WHEN json_valid(data) = 1
310
+ THEN COALESCE(json_extract(data, '$.finish'), '')
311
+ ELSE '' END = 'stop'
312
+ )
313
+ ORDER BY time_created ASC, id ASC
314
+ LIMIT ? OFFSET ?`).all(sessionId, pageSize, Math.max(0, Math.floor(afterOrdinal))).filter(isRawMessageRow).map((row, index) => ({
315
+ ...row,
316
+ ordinal: Math.floor(afterOrdinal) + index + 1
317
+ }));
318
+ if (messageRows.length === 0)
319
+ return [];
320
+ const placeholders = messageRows.map(() => "?").join(", ");
321
+ const partRows = db.prepare(`SELECT message_id, data, time_updated
322
+ FROM part
323
+ WHERE session_id = ? AND message_id IN (${placeholders})
324
+ ORDER BY time_created ASC, id ASC`).all(sessionId, ...messageRows.map((row) => row.id)).filter(isRawPartRow);
325
+ const partsByMessageId = new Map;
326
+ for (const part of partRows) {
327
+ const list = partsByMessageId.get(part.message_id) ?? [];
328
+ list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
329
+ partsByMessageId.set(part.message_id, list);
330
+ }
331
+ return messageRows.map((row) => {
332
+ const info = parseJsonRecord(row.data);
333
+ return {
334
+ ordinal: row.ordinal,
335
+ id: row.id,
336
+ role: typeof info?.role === "string" ? info.role : "unknown",
337
+ parts: partsByMessageId.get(row.id) ?? [],
338
+ createdAt: row.time_created ?? null,
339
+ version: row.time_updated ?? null
340
+ };
341
+ });
342
+ }
343
+ function countRawSessionMessageOrdinalsFromDb(db, sessionId) {
344
+ const row = db.prepare(`SELECT COUNT(*) AS count
345
+ FROM message
346
+ WHERE session_id = ?
347
+ AND NOT (
348
+ CASE WHEN json_valid(data) = 1
349
+ THEN COALESCE(json_extract(data, '$.summary'), 0)
350
+ ELSE 0 END = 1
351
+ AND CASE WHEN json_valid(data) = 1
352
+ THEN COALESCE(json_extract(data, '$.finish'), '')
353
+ ELSE '' END = 'stop'
354
+ )`).get(sessionId);
355
+ return typeof row?.count === "number" ? row.count : 0;
356
+ }
357
+ function readRawSessionMessageOrdinalPageFromDb(db, sessionId, after, limit) {
358
+ const pageSize = Math.max(1, Math.floor(limit));
359
+ const rows = (after ? db.prepare(`SELECT id, data, time_created
360
+ FROM message
361
+ WHERE session_id = ?
362
+ AND (time_created, id) > (?, ?)
363
+ ORDER BY time_created ASC, id ASC
364
+ LIMIT ?`).all(sessionId, after.timeCreated, after.id, pageSize) : db.prepare(`SELECT id, data, time_created
365
+ FROM message
366
+ WHERE session_id = ?
367
+ ORDER BY time_created ASC, id ASC
368
+ LIMIT ?`).all(sessionId, pageSize)).filter(isRawMessageRow);
369
+ return rows.flatMap((row) => {
370
+ if (typeof row.time_created !== "number")
371
+ return [];
372
+ const info = parseJsonRecord(row.data);
373
+ return {
374
+ id: row.id,
375
+ timeCreated: row.time_created,
376
+ contributesOrdinal: !isRawCompactionSummaryInfo(info),
377
+ hasValidInfo: info !== null
378
+ };
379
+ });
380
+ }
381
+ function countStoredRawSessionMessagesFromDb(db, sessionId) {
382
+ const row = db.prepare("SELECT COUNT(*) AS count FROM message WHERE session_id = ?").get(sessionId);
383
+ return typeof row?.count === "number" ? row.count : 0;
384
+ }
385
+ function isAnchorRow(row) {
386
+ return row !== null && typeof row === "object" && typeof row.time_created === "number" && typeof row.id === "string";
387
+ }
388
+ function readRawSessionTailFromDb(db, sessionId, baseOrdinal, anchorMessageId) {
389
+ const anchorRow = db.prepare("SELECT time_created, id, data FROM message WHERE id = ? AND session_id = ?").get(anchorMessageId, sessionId);
390
+ if (!isAnchorRow(anchorRow))
391
+ return null;
392
+ const anchorInfo = parseJsonRecord(anchorRow.data ?? "");
393
+ if (anchorInfo?.summary === true && anchorInfo?.finish === "stop")
394
+ return null;
395
+ const messageRows = db.prepare(`SELECT id, data, time_created, time_updated FROM message
396
+ WHERE session_id = ?
397
+ AND (time_created > ? OR (time_created = ? AND id >= ?))
398
+ ORDER BY time_created ASC, id ASC`).all(sessionId, anchorRow.time_created, anchorRow.time_created, anchorRow.id).filter(isRawMessageRow);
399
+ const filtered = messageRows.filter((row) => {
400
+ const info = parseJsonRecord(row.data);
401
+ return !(info?.summary === true && info?.finish === "stop");
402
+ });
403
+ const ids = filtered.map((row) => row.id);
404
+ const partsByMessageId = new Map;
405
+ if (ids.length > 0) {
406
+ const CHUNK = 800;
407
+ for (let i = 0;i < ids.length; i += CHUNK) {
408
+ const slice = ids.slice(i, i + CHUNK);
409
+ const placeholders = slice.map(() => "?").join(",");
410
+ const partRows = db.prepare(`SELECT message_id, data, time_updated FROM part WHERE session_id = ? AND message_id IN (${placeholders}) ORDER BY time_created ASC, id ASC`).all(sessionId, ...slice).filter(isRawPartRow);
411
+ for (const part of partRows) {
412
+ const list = partsByMessageId.get(part.message_id) ?? [];
413
+ list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
414
+ partsByMessageId.set(part.message_id, list);
415
+ }
416
+ }
417
+ }
418
+ const messages = [];
419
+ let ord = baseOrdinal;
420
+ for (const row of filtered) {
421
+ const info = parseJsonRecord(row.data);
422
+ if (!info) {
423
+ ord += 1;
424
+ continue;
425
+ }
426
+ messages.push({
427
+ ordinal: ord,
428
+ id: row.id,
429
+ role: typeof info.role === "string" ? info.role : "unknown",
430
+ parts: partsByMessageId.get(row.id) ?? [],
431
+ createdAt: row.time_created ?? null,
432
+ version: row.time_updated ?? null
433
+ });
434
+ ord += 1;
435
+ }
436
+ return { messages, absoluteMessageCount: Math.max(0, ord - 1) };
437
+ }
438
+ function extractInMemoryMessageViews(messages) {
439
+ return messages.map((m) => {
440
+ const info = m.info ?? {};
441
+ return {
442
+ id: typeof info.id === "string" ? info.id : "",
443
+ role: typeof info.role === "string" ? info.role : "unknown",
444
+ parts: Array.isArray(m.parts) ? m.parts : [],
445
+ summary: info.summary === true ? true : undefined,
446
+ finish: typeof info.finish === "string" ? info.finish : undefined
447
+ };
448
+ });
449
+ }
450
+ function buildInMemoryTailRawMessages(args) {
451
+ const { messages, lastCompartmentEnd, anchorMessageId } = args;
452
+ const filtered = messages.filter((m) => !(m.summary === true && m.finish === "stop"));
453
+ if (filtered.length === 0)
454
+ return null;
455
+ let startIndex = 0;
456
+ let baseOrdinal;
457
+ let anchorFound = false;
458
+ if (anchorMessageId) {
459
+ const anchorIndex = filtered.findIndex((m) => m.id === anchorMessageId);
460
+ if (anchorIndex >= 0) {
461
+ anchorFound = true;
462
+ startIndex = anchorIndex;
463
+ baseOrdinal = lastCompartmentEnd;
464
+ } else {
465
+ baseOrdinal = Math.max(1, lastCompartmentEnd + 1);
466
+ }
467
+ } else {
468
+ baseOrdinal = Math.max(1, lastCompartmentEnd + 1);
469
+ }
470
+ const out = [];
471
+ let ord = baseOrdinal;
472
+ for (let i = startIndex;i < filtered.length; i += 1) {
473
+ const m = filtered[i];
474
+ if (!m.id || typeof m.id !== "string") {
475
+ ord += 1;
476
+ continue;
477
+ }
478
+ out.push({
479
+ ordinal: ord,
480
+ id: m.id,
481
+ role: typeof m.role === "string" ? m.role : "unknown",
482
+ parts: m.parts ?? [],
483
+ version: null
484
+ });
485
+ ord += 1;
486
+ }
487
+ return { messages: out, absoluteMessageCount: Math.max(0, ord - 1), anchorFound };
488
+ }
489
+ function readRawSessionMessagePartsByIdFromDb(db, sessionId, messageId) {
490
+ const row = db.prepare("SELECT id, data, time_created, time_updated FROM message WHERE session_id = ? AND id = ?").get(sessionId, messageId);
491
+ if (!row || !isRawMessageRow(row) || typeof row.time_created !== "number")
492
+ return null;
493
+ const info = parseJsonRecord(row.data);
494
+ if (!info || isRawCompactionSummaryInfo(info))
495
+ return null;
496
+ const partRows = db.prepare("SELECT message_id, data, time_updated FROM part WHERE session_id = ? AND message_id = ? ORDER BY time_created ASC, id ASC").all(sessionId, messageId).filter(isRawPartRow);
497
+ return {
498
+ id: row.id,
499
+ role: typeof info.role === "string" ? info.role : "unknown",
500
+ parts: partRows.map((part) => attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated)),
501
+ createdAt: row.time_created,
502
+ version: row.time_updated ?? null
503
+ };
504
+ }
505
+ function readRawSessionMessageOrdinalByIdFromDb(db, sessionId, messageId) {
506
+ const row = db.prepare(`SELECT COUNT(candidate.id) AS ordinal
507
+ FROM message AS target
508
+ JOIN message AS candidate
509
+ ON candidate.session_id = target.session_id
510
+ AND NOT (
511
+ CASE WHEN json_valid(candidate.data) = 1
512
+ THEN COALESCE(json_extract(candidate.data, '$.summary'), 0)
513
+ ELSE 0 END = 1
514
+ AND CASE WHEN json_valid(candidate.data) = 1
515
+ THEN COALESCE(json_extract(candidate.data, '$.finish'), '')
516
+ ELSE '' END = 'stop'
517
+ )
518
+ AND (candidate.time_created < target.time_created
519
+ OR (candidate.time_created = target.time_created AND candidate.id <= target.id))
520
+ WHERE target.session_id = ?
521
+ AND target.id = ?
522
+ AND NOT (
523
+ CASE WHEN json_valid(target.data) = 1
524
+ THEN COALESCE(json_extract(target.data, '$.summary'), 0)
525
+ ELSE 0 END = 1
526
+ AND CASE WHEN json_valid(target.data) = 1
527
+ THEN COALESCE(json_extract(target.data, '$.finish'), '')
528
+ ELSE '' END = 'stop'
529
+ )`).get(sessionId, messageId);
530
+ const ordinal = row?.ordinal;
531
+ return typeof ordinal === "number" && ordinal > 0 ? ordinal : null;
532
+ }
533
+ function readRawSessionMessageByIdFromDb(db, sessionId, messageId) {
534
+ const row = db.prepare("SELECT id, data, time_created, time_updated FROM message WHERE session_id = ? AND id = ?").get(sessionId, messageId);
535
+ if (!row || !isRawMessageRow(row) || typeof row.time_created !== "number") {
536
+ return null;
537
+ }
538
+ const info = parseJsonRecord(row.data);
539
+ if (!info || isRawCompactionSummaryInfo(info)) {
540
+ return null;
541
+ }
542
+ const ordinalRow = db.prepare(`SELECT COUNT(*) AS ordinal FROM message
543
+ WHERE session_id = ?
544
+ AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
545
+ AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')
546
+ AND (time_created < ? OR (time_created = ? AND id <= ?))`).get(sessionId, row.time_created, row.time_created, messageId);
547
+ const ordinal = typeof ordinalRow?.ordinal === "number" ? ordinalRow.ordinal : 0;
548
+ if (ordinal <= 0) {
549
+ return null;
550
+ }
551
+ const partRows = db.prepare("SELECT message_id, data, time_updated FROM part WHERE session_id = ? AND message_id = ? ORDER BY time_created ASC, id ASC").all(sessionId, messageId).filter(isRawPartRow);
552
+ const role = typeof info.role === "string" ? info.role : "unknown";
553
+ return {
554
+ ordinal,
555
+ id: row.id,
556
+ role,
557
+ parts: partRows.map((part) => attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated)),
558
+ createdAt: row.time_created,
559
+ version: row.time_updated ?? null
560
+ };
561
+ }
562
+
563
+ // src/shared/record-type-guard.ts
564
+ function isRecord(value) {
565
+ return typeof value === "object" && value !== null && !Array.isArray(value);
566
+ }
567
+
568
+ // src/shared/stable-json.ts
569
+ function stableStringify(value, seen = new WeakSet) {
570
+ if (value === undefined)
571
+ return "undefined";
572
+ if (value === null || typeof value !== "object")
573
+ return JSON.stringify(value) ?? String(value);
574
+ if (seen.has(value))
575
+ return '"[Circular]"';
576
+ seen.add(value);
577
+ if (Array.isArray(value)) {
578
+ return `[${value.map((item) => stableStringify(item, seen)).join(",")}]`;
579
+ }
580
+ const entries = Object.entries(value).sort(([a], [b]) => {
581
+ if (a < b)
582
+ return -1;
583
+ if (a > b)
584
+ return 1;
585
+ return 0;
586
+ });
587
+ return `{${entries.map(([key, child]) => `${JSON.stringify(key)}:${stableStringify(child, seen)}`).join(",")}}`;
588
+ }
589
+
590
+ // src/hooks/magic-context/read-session-true-raw-tokens.ts
591
+ function completedToolArcCrossesBoundary(invOrdinal, resOrdinal, boundary) {
592
+ return invOrdinal < boundary && boundary <= resOrdinal;
593
+ }
594
+ var MAX_MESSAGE_CACHE_ENTRIES = 1e5;
595
+ var MAX_MESSAGE_CACHE_KEY_BYTES = 64 * 1024 * 1024;
596
+ var FNV1A_32_OFFSET = 2166136261;
597
+ var FNV1A_32_PRIME = 16777619;
598
+ var messageEstimateCache = new Map;
599
+ var messageEstimateCacheBytes = 0;
600
+ var EMPTY_BREAKDOWN = {
601
+ text: 0,
602
+ reasoning: 0,
603
+ toolInput: 0,
604
+ toolOutput: 0,
605
+ image: 0,
606
+ other: 0,
607
+ total: 0
608
+ };
609
+ function addBreakdown(target, kind, value) {
610
+ if (kind === "total")
611
+ return;
612
+ const safeValue = Number.isFinite(value) && value > 0 ? Math.round(value) : 0;
613
+ target[kind] += safeValue;
614
+ target.total += safeValue;
615
+ }
616
+ function estimateStructured(value) {
617
+ if (typeof value === "string")
618
+ return estimateTokens(value);
619
+ if (value === undefined || value === null)
620
+ return 0;
621
+ return estimateTokens(stableStringify(value));
622
+ }
623
+ function firstStringField(record, fields) {
624
+ for (const field of fields) {
625
+ const value = record[field];
626
+ if (typeof value === "string" && value.length > 0)
627
+ return value;
628
+ }
629
+ return null;
630
+ }
631
+ function stringValue(value) {
632
+ if (typeof value === "string")
633
+ return value;
634
+ if (value === undefined || value === null)
635
+ return "";
636
+ return stableStringify(value);
637
+ }
638
+ function textFromToolResultContent(content) {
639
+ if (typeof content === "string")
640
+ return content;
641
+ if (Array.isArray(content)) {
642
+ const pieces = [];
643
+ for (const entry of content) {
644
+ if (typeof entry === "string") {
645
+ pieces.push(entry);
646
+ } else if (isRecord(entry)) {
647
+ const text = firstStringField(entry, ["text", "content", "value"]);
648
+ pieces.push(text ?? stableStringify(entry));
649
+ } else if (entry !== null && entry !== undefined) {
650
+ pieces.push(String(entry));
651
+ }
652
+ }
653
+ return pieces.join(`
654
+ `);
655
+ }
656
+ return stringValue(content);
657
+ }
658
+ function looksImageLike(part) {
659
+ const type = typeof part.type === "string" ? part.type.toLowerCase() : "";
660
+ const mime = typeof part.mime === "string" ? part.mime.toLowerCase() : "";
661
+ const mediaType = typeof part.mediaType === "string" ? part.mediaType.toLowerCase() : "";
662
+ return type.includes("image") || mime.startsWith("image/") || mediaType.startsWith("image/") || part.image_url !== undefined || part.imageUrl !== undefined || part.image !== undefined;
663
+ }
664
+ function defaultImageTokenHeuristic(part) {
665
+ if (isRecord(part)) {
666
+ const width = part.width;
667
+ const height = part.height;
668
+ if (typeof width === "number" && typeof height === "number" && width > 0 && height > 0) {
669
+ return Math.max(256, Math.min(4096, Math.ceil(width * height / 750)));
670
+ }
671
+ }
672
+ return 1024;
673
+ }
674
+ function partType(part) {
675
+ return typeof part.type === "string" ? part.type : "";
676
+ }
677
+ function hasOwn(record, key) {
678
+ return Object.hasOwn(record, key);
679
+ }
680
+ function recursiveByteLength(value) {
681
+ if (value === null || value === undefined)
682
+ return 0;
683
+ if (typeof value === "string")
684
+ return value.length;
685
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
686
+ return String(value).length;
687
+ }
688
+ if (Array.isArray(value)) {
689
+ return value.reduce((sum, item) => sum + recursiveByteLength(item), value.length);
690
+ }
691
+ if (isRecord(value)) {
692
+ let total = Object.keys(value).length;
693
+ for (const [key, child] of Object.entries(value)) {
694
+ total += key.length + recursiveByteLength(child);
695
+ }
696
+ return total;
697
+ }
698
+ return String(value).length;
699
+ }
700
+ function updateFnv1a32(hash, text) {
701
+ let next = hash;
702
+ for (let index = 0;index < text.length; index += 1) {
703
+ next ^= text.charCodeAt(index);
704
+ next = Math.imul(next, FNV1A_32_PRIME) >>> 0;
705
+ }
706
+ return next;
707
+ }
708
+ function contentStringsHash(fields) {
709
+ let hash = FNV1A_32_OFFSET;
710
+ for (const field of fields) {
711
+ hash = updateFnv1a32(hash, `${field.length}:`);
712
+ hash = updateFnv1a32(hash, field);
713
+ hash = updateFnv1a32(hash, "\x00");
714
+ }
715
+ return hash.toString(16).padStart(8, "0");
716
+ }
717
+ function rawPartVersion(part) {
718
+ return part.__magicContextPartUpdatedAt ?? part.updated_at ?? part.updatedAt ?? part.version ?? part.revision ?? "";
719
+ }
720
+ function callIdFromPart(part) {
721
+ const direct = firstStringField(part, ["callID", "callId", "toolCallId", "tool_call_id", "id"]);
722
+ if (direct)
723
+ return direct;
724
+ const state = isRecord(part.state) ? part.state : null;
725
+ return state ? firstStringField(state, ["callID", "callId", "toolCallId", "tool_call_id", "id"]) ?? "" : "";
726
+ }
727
+ function toolSignalFromPart(part) {
728
+ if (!isRecord(part))
729
+ return null;
730
+ const type = partType(part);
731
+ const state = isRecord(part.state) ? part.state : null;
732
+ const callId = callIdFromPart(part);
733
+ if (!callId && type !== "tool")
734
+ return null;
735
+ if (type === "tool") {
736
+ const hasInput = state !== null && hasOwn(state, "input");
737
+ const outputKey = state ? hasOwn(state, "output") ? "output" : hasOwn(state, "error") ? "error" : hasOwn(state, "result") ? "result" : null : null;
738
+ const hasOutput = outputKey !== null;
739
+ const outputValue = outputKey && state ? state[outputKey] : undefined;
740
+ const providerExecuted = part.providerExecuted === true;
741
+ const openInvocation = !providerExecuted && !hasOutput;
742
+ return {
743
+ callId,
744
+ hasInput: hasInput || openInvocation,
745
+ hasOutput,
746
+ inputText: hasInput && state ? stringValue(state.input) : "",
747
+ outputText: hasOutput ? stringValue(outputValue) : ""
748
+ };
749
+ }
750
+ if (type === "tool-invocation") {
751
+ const args = part.args ?? part.input;
752
+ return {
753
+ callId,
754
+ hasInput: args !== undefined,
755
+ hasOutput: false,
756
+ inputText: args !== undefined ? stringValue(args) : "",
757
+ outputText: ""
758
+ };
759
+ }
760
+ if (type === "tool_use") {
761
+ const input = part.input;
762
+ return {
763
+ callId,
764
+ hasInput: input !== undefined,
765
+ hasOutput: false,
766
+ inputText: input !== undefined ? stringValue(input) : "",
767
+ outputText: ""
768
+ };
769
+ }
770
+ if (type === "tool_result") {
771
+ const content = part.content ?? part.output ?? part.result;
772
+ return {
773
+ callId,
774
+ hasInput: false,
775
+ hasOutput: content !== undefined,
776
+ inputText: "",
777
+ outputText: content !== undefined ? textFromToolResultContent(content) : ""
778
+ };
779
+ }
780
+ return null;
781
+ }
782
+ function partCheapFingerprint(part) {
783
+ if (!isRecord(part))
784
+ return `${typeof part}:${recursiveByteLength(part)}`;
785
+ const version = rawPartVersion(part);
786
+ const type = typeof part.type === "string" ? part.type : "";
787
+ return `${type}:${String(version)}:${recursiveByteLength(part)}`;
788
+ }
789
+ function messageCacheKey(message, options) {
790
+ const namespace = "cacheNamespace" in options ? options.cacheNamespace : "estimate";
791
+ const cheapFingerprint = message.parts.map(partCheapFingerprint).join("|");
792
+ return [
793
+ namespace,
794
+ options.providerShapeVersion,
795
+ message.id || `ordinal:${message.ordinal}`,
796
+ message.role,
797
+ message.parts.length,
798
+ cheapFingerprint
799
+ ].join("\x00");
800
+ }
801
+ function setCachedEstimate(key, breakdown) {
802
+ const keyEstimateBytes = key.length * 2 + 64;
803
+ const existing = messageEstimateCache.get(key);
804
+ if (existing)
805
+ messageEstimateCacheBytes -= existing.keyEstimateBytes;
806
+ messageEstimateCache.set(key, { breakdown, keyEstimateBytes });
807
+ messageEstimateCacheBytes += keyEstimateBytes;
808
+ while (messageEstimateCache.size > MAX_MESSAGE_CACHE_ENTRIES || messageEstimateCacheBytes > MAX_MESSAGE_CACHE_KEY_BYTES) {
809
+ const first = messageEstimateCache.keys().next().value;
810
+ if (typeof first !== "string")
811
+ break;
812
+ const removed = messageEstimateCache.get(first);
813
+ if (removed)
814
+ messageEstimateCacheBytes -= removed.keyEstimateBytes;
815
+ messageEstimateCache.delete(first);
816
+ }
817
+ }
818
+ function cloneBreakdown(value) {
819
+ return { ...value };
820
+ }
821
+ function estimateNonToolPart(part, options, breakdown) {
822
+ if (!isRecord(part)) {
823
+ if (part !== null && part !== undefined)
824
+ addBreakdown(breakdown, "other", estimateStructured(part));
825
+ return true;
826
+ }
827
+ const type = partType(part);
828
+ if (type === "step-start" || type === "step-finish" || type === "meta" && Object.keys(part).length <= 1) {
829
+ return true;
830
+ }
831
+ if (type === "text") {
832
+ const text = firstStringField(part, ["text", "content"]);
833
+ if (text)
834
+ addBreakdown(breakdown, "text", estimateTokens(text));
835
+ return true;
836
+ }
837
+ if (type === "reasoning" || type === "thinking" || type === "redacted_thinking") {
838
+ const text = firstStringField(part, ["thinking", "text", "content", "reasoning"]);
839
+ if (text) {
840
+ addBreakdown(breakdown, "reasoning", estimateTokens(text));
841
+ } else {
842
+ addBreakdown(breakdown, "other", estimateStructured(part));
843
+ }
844
+ return true;
845
+ }
846
+ const reasoningText = firstStringField(part, ["thinking", "reasoning"]);
847
+ if (reasoningText && type.length === 0) {
848
+ addBreakdown(breakdown, "reasoning", estimateTokens(reasoningText));
849
+ return true;
850
+ }
851
+ if (looksImageLike(part)) {
852
+ addBreakdown(breakdown, "image", options.imageTokenHeuristic?.(part) ?? defaultImageTokenHeuristic(part));
853
+ const altText = firstStringField(part, ["alt", "text", "description"]);
854
+ if (altText)
855
+ addBreakdown(breakdown, "text", estimateTokens(altText));
856
+ return true;
857
+ }
858
+ if (type.includes("file") || type === "source") {
859
+ const content = firstStringField(part, ["content", "text", "source"]);
860
+ if (content)
861
+ addBreakdown(breakdown, "text", estimateTokens(content));
862
+ else
863
+ addBreakdown(breakdown, "other", estimateStructured(part));
864
+ return true;
865
+ }
866
+ return false;
867
+ }
868
+ function estimateTrueRawMessageTokens(message, options) {
869
+ const breakdown = cloneBreakdown(EMPTY_BREAKDOWN);
870
+ const countedInput = new Set;
871
+ const countedOutput = new Set;
872
+ let ordinalToolIndex = 0;
873
+ for (const part of message.parts) {
874
+ const signal = toolSignalFromPart(part);
875
+ if (signal) {
876
+ const localKey = `${signal.callId || "tool"}:${message.ordinal}:${ordinalToolIndex}`;
877
+ ordinalToolIndex += 1;
878
+ if (signal.hasInput) {
879
+ const key = `${signal.callId}:input:${message.ordinal}`;
880
+ if (!countedInput.has(key)) {
881
+ countedInput.add(key);
882
+ addBreakdown(breakdown, "toolInput", estimateTokens(signal.inputText));
883
+ }
884
+ }
885
+ if (signal.hasOutput) {
886
+ const key = `${signal.callId}:output:${message.ordinal}:${localKey}`;
887
+ if (!countedOutput.has(key)) {
888
+ countedOutput.add(key);
889
+ addBreakdown(breakdown, "toolOutput", estimateTokens(signal.outputText));
890
+ }
891
+ }
892
+ continue;
893
+ }
894
+ if (!estimateNonToolPart(part, options, breakdown)) {
895
+ addBreakdown(breakdown, "other", estimateStructured(part));
896
+ }
897
+ }
898
+ return breakdown;
899
+ }
900
+ function buildToolArcs(messages) {
901
+ const openQueues = new Map;
902
+ const arcs = [];
903
+ for (const message of messages) {
904
+ for (const part of message.parts) {
905
+ const signal = toolSignalFromPart(part);
906
+ if (!signal || signal.callId.length === 0)
907
+ continue;
908
+ if (signal.hasInput && signal.hasOutput) {
909
+ arcs.push({
910
+ callId: signal.callId,
911
+ invOrdinal: message.ordinal,
912
+ resOrdinal: message.ordinal
913
+ });
914
+ continue;
915
+ }
916
+ if (signal.hasInput) {
917
+ const queue = openQueues.get(signal.callId) ?? [];
918
+ queue.push(message.ordinal);
919
+ openQueues.set(signal.callId, queue);
920
+ continue;
921
+ }
922
+ if (signal.hasOutput) {
923
+ const queue = openQueues.get(signal.callId) ?? [];
924
+ const invOrdinal = queue.shift();
925
+ if (queue.length === 0)
926
+ openQueues.delete(signal.callId);
927
+ else
928
+ openQueues.set(signal.callId, queue);
929
+ if (invOrdinal !== undefined) {
930
+ arcs.push({ callId: signal.callId, invOrdinal, resOrdinal: message.ordinal });
931
+ }
932
+ }
933
+ }
934
+ }
935
+ for (const [callId, queue] of openQueues) {
936
+ for (const invOrdinal of queue) {
937
+ arcs.push({ callId, invOrdinal, resOrdinal: null });
938
+ }
939
+ }
940
+ return arcs.sort((a, b) => a.invOrdinal - b.invOrdinal || (a.resOrdinal ?? Number.MAX_SAFE_INTEGER) - (b.resOrdinal ?? Number.MAX_SAFE_INTEGER));
941
+ }
942
+ function fenceBoundaryForToolArcs(candidate, arcs, lastCompartmentEndOrdinal, recentOpenArcCutoff) {
943
+ let boundary = candidate;
944
+ for (const arc of arcs) {
945
+ if (arc.resOrdinal !== null) {
946
+ if (completedToolArcCrossesBoundary(arc.invOrdinal, arc.resOrdinal, boundary)) {
947
+ boundary = arc.resOrdinal + 1;
948
+ }
949
+ continue;
950
+ }
951
+ if (arc.invOrdinal < recentOpenArcCutoff)
952
+ continue;
953
+ if (arc.invOrdinal >= lastCompartmentEndOrdinal + 1 && arc.invOrdinal < boundary) {
954
+ return arc.invOrdinal;
955
+ }
956
+ if (arc.invOrdinal >= boundary) {
957
+ return arc.invOrdinal;
958
+ }
959
+ }
960
+ return boundary;
961
+ }
962
+ function tokenForMessage(message, options) {
963
+ const key = messageCacheKey(message, options);
964
+ const cached = messageEstimateCache.get(key);
965
+ if (cached)
966
+ return cloneBreakdown(cached.breakdown);
967
+ const breakdown = estimateTrueRawMessageTokens(message, options);
968
+ setCachedEstimate(key, breakdown);
969
+ return cloneBreakdown(breakdown);
970
+ }
971
+ function buildTrueRawTokenIndex(sessionId, messages, options) {
972
+ const ordered = [...messages].sort((a, b) => a.ordinal - b.ordinal);
973
+ const sliceCount = ordered.length;
974
+ const firstOrdinal = ordered.length > 0 ? ordered[0].ordinal : 1;
975
+ const terminalOrdinal = ordered.length > 0 ? ordered[ordered.length - 1].ordinal : 0;
976
+ const rawMessageCount = Math.max(sliceCount, terminalOrdinal, options.absoluteMessageCount ?? sliceCount);
977
+ const ordinalSpan = terminalOrdinal >= firstOrdinal ? terminalOrdinal - firstOrdinal + 1 : 0;
978
+ const tokensByOrdinal = new Map;
979
+ const idsByOrdinal = new Map;
980
+ const prefix = new Array(ordinalSpan + 1).fill(0);
981
+ for (const message of ordered) {
982
+ const stored = options.storedTotalForMessage?.(message);
983
+ const total = stored !== undefined && stored !== null ? stored : tokenForMessage(message, options).total;
984
+ tokensByOrdinal.set(message.ordinal, total);
985
+ idsByOrdinal.set(message.ordinal, message.id);
986
+ const relative = message.ordinal - firstOrdinal + 1;
987
+ if (relative >= 1 && relative <= ordinalSpan) {
988
+ prefix[relative] = total;
989
+ }
990
+ }
991
+ for (let k = 1;k <= ordinalSpan; k += 1) {
992
+ prefix[k] += prefix[k - 1];
993
+ }
994
+ const ordinalToIndex = (ordinal) => Math.max(0, Math.min(ordinalSpan, ordinal - firstOrdinal));
995
+ return {
996
+ sessionId,
997
+ providerShapeVersion: options.providerShapeVersion,
998
+ rawMessageCount,
999
+ tokenForOrdinal(ordinal) {
1000
+ return tokensByOrdinal.get(ordinal) ?? 0;
1001
+ },
1002
+ messageIdAtOrdinal(ordinal) {
1003
+ return idsByOrdinal.get(ordinal) ?? null;
1004
+ },
1005
+ suffixTokensFromOrdinal(ordinal) {
1006
+ if (ordinal <= firstOrdinal)
1007
+ return prefix[ordinalSpan];
1008
+ if (ordinal > terminalOrdinal)
1009
+ return 0;
1010
+ return prefix[ordinalSpan] - prefix[ordinalToIndex(ordinal)];
1011
+ },
1012
+ rangeTokens(startInclusive, endExclusive) {
1013
+ const start = Math.max(firstOrdinal, startInclusive);
1014
+ const end = Math.max(start, Math.min(terminalOrdinal + 1, endExclusive));
1015
+ return prefix[end - firstOrdinal] - prefix[start - firstOrdinal];
1016
+ },
1017
+ findSuffixStartForTokens(tokens) {
1018
+ if (!Number.isFinite(tokens) || tokens <= 0)
1019
+ return terminalOrdinal + 1;
1020
+ const target = Math.max(0, Math.floor(tokens));
1021
+ const total = prefix[ordinalSpan];
1022
+ if (total < target)
1023
+ return firstOrdinal;
1024
+ const cut = total - target;
1025
+ let lo = 0;
1026
+ let hi = ordinalSpan;
1027
+ let best = 0;
1028
+ while (lo <= hi) {
1029
+ const mid = lo + hi >> 1;
1030
+ if (prefix[mid] <= cut) {
1031
+ best = mid;
1032
+ lo = mid + 1;
1033
+ } else {
1034
+ hi = mid - 1;
1035
+ }
1036
+ }
1037
+ return firstOrdinal + best;
1038
+ },
1039
+ findHeadEndForCap(startInclusive, endExclusive, capTokens) {
1040
+ const start = Math.max(firstOrdinal, Math.min(terminalOrdinal + 1, startInclusive));
1041
+ const end = Math.max(start, Math.min(terminalOrdinal + 1, endExclusive));
1042
+ if (!Number.isFinite(capTokens) || capTokens <= 0)
1043
+ return start;
1044
+ const startIndex = start - firstOrdinal;
1045
+ const endIndex = end - firstOrdinal;
1046
+ const cut = prefix[startIndex] + Math.floor(capTokens);
1047
+ let lo = startIndex + 1;
1048
+ let hi = endIndex;
1049
+ let bestEndIndex = startIndex;
1050
+ while (lo <= hi) {
1051
+ const mid = lo + hi >> 1;
1052
+ if (prefix[mid] <= cut) {
1053
+ bestEndIndex = mid;
1054
+ lo = mid + 1;
1055
+ } else {
1056
+ hi = mid - 1;
1057
+ }
1058
+ }
1059
+ let bestEnd = firstOrdinal + bestEndIndex;
1060
+ if (bestEnd === start && start < end)
1061
+ bestEnd = start + 1;
1062
+ return Math.min(bestEnd, end);
1063
+ }
1064
+ };
1065
+ }
1066
+ function partContentFingerprint(part) {
1067
+ if (!isRecord(part))
1068
+ return `${typeof part}:${recursiveByteLength(part)}`;
1069
+ const tool = toolSignalFromPart(part);
1070
+ if (tool) {
1071
+ return contentStringsHash([tool.inputText, tool.outputText]);
1072
+ }
1073
+ const text = firstStringField(part, ["text", "thinking", "reasoning", "content", "url"]) ?? "";
1074
+ return contentStringsHash([text]);
1075
+ }
1076
+ function computeRawRangeFingerprint(messages, startInclusive, endExclusive) {
1077
+ const pieces = [];
1078
+ for (const message of messages) {
1079
+ if (message.ordinal < startInclusive || message.ordinal >= endExclusive)
1080
+ continue;
1081
+ const partFingerprint = message.parts.map(partContentFingerprint).join(",");
1082
+ pieces.push(`${message.ordinal}:${message.id}:${message.parts.length}:${partFingerprint}`);
1083
+ }
1084
+ return pieces.join("|");
1085
+ }
1086
+ function invalidateTrueRawTokenCache(args) {
1087
+ const sessionNeedle = args.sessionId ? `${args.sessionId}` : null;
1088
+ const messageNeedle = args.messageId ? `\x00${args.messageId}\x00` : null;
1089
+ for (const [key, value] of messageEstimateCache) {
1090
+ const sessionMatches = sessionNeedle === null || key.includes(sessionNeedle);
1091
+ const messageMatches = messageNeedle === null || key.includes(messageNeedle);
1092
+ if (sessionMatches && messageMatches) {
1093
+ messageEstimateCache.delete(key);
1094
+ messageEstimateCacheBytes -= value.keyEstimateBytes;
1095
+ }
1096
+ }
1097
+ args.reason;
1098
+ }
1099
+
1100
+ // src/hooks/magic-context/tag-content-primitives.ts
1101
+ var encoder = new TextEncoder;
1102
+ var TAG_PREFIX_REGEX = /^(?:§\d+§\s*)+/;
1103
+ var MALFORMED_TAG_PREFIX_REGEX = /^(?:§\d+">§(?:\d+§)?\s*)+/;
1104
+ var DANGLING_TAG_GLOBAL_REGEX = /\u00a7\d+(?!\.\d)[^\s\u00a7\w.]?/g;
1105
+ var DANGLING_TAG_PREFIX_REGEX = /^(?:\u00a7\d+(?!\.\d)[^\s\u00a7\w.]?\s*)+/;
1106
+ var COMPLETE_TAG_PAIR_GLOBAL_REGEX = /\u00a7\d+\u00a7/g;
1107
+ var MALFORMED_TAG_GLOBAL_REGEX = /\u00a7\d+">(?:\u00a7(?:\d+\u00a7)?)?/g;
1108
+ var STRAY_SECTION_CHAR_REGEX = /\u00a7/g;
1109
+ function stripWellFormedLeadingTagPrefix(value) {
1110
+ return value.replace(/^(\u00a7\d+\u00a7\s*)+/, "");
1111
+ }
1112
+ function stripCompleteTagPairsGlobally(value) {
1113
+ return value.replace(COMPLETE_TAG_PAIR_GLOBAL_REGEX, "");
1114
+ }
1115
+ function stripMalformedTagNotationGlobally(value) {
1116
+ return value.replace(MALFORMED_TAG_GLOBAL_REGEX, "");
1117
+ }
1118
+ function stripDanglingTagNotationGlobally(value) {
1119
+ return value.replace(DANGLING_TAG_GLOBAL_REGEX, "");
1120
+ }
1121
+ function stripTagSectionCharacters(value) {
1122
+ return value.replace(STRAY_SECTION_CHAR_REGEX, "");
1123
+ }
1124
+ function stripPersistedAssistantText(value) {
1125
+ let text = stripWellFormedLeadingTagPrefix(value);
1126
+ text = stripCompleteTagPairsGlobally(text);
1127
+ text = stripMalformedTagNotationGlobally(text);
1128
+ text = stripDanglingTagNotationGlobally(text);
1129
+ text = stripTagSectionCharacters(text);
1130
+ return text.trim();
1131
+ }
1132
+ function byteSize(value) {
1133
+ return encoder.encode(value).length;
1134
+ }
1135
+ function stripTagPrefix(value) {
1136
+ let stripped = value;
1137
+ for (let pass = 0;pass < 8; pass++) {
1138
+ const prev = stripped;
1139
+ stripped = stripped.replace(MALFORMED_TAG_PREFIX_REGEX, "");
1140
+ stripped = stripped.replace(TAG_PREFIX_REGEX, "");
1141
+ stripped = stripped.replace(DANGLING_TAG_PREFIX_REGEX, "");
1142
+ if (stripped === prev)
1143
+ break;
1144
+ }
1145
+ return stripped;
1146
+ }
1147
+ function peelLeadingMcTagNotation(value) {
1148
+ const body = stripTagPrefix(value);
1149
+ if (body === value)
1150
+ return { tagPrefix: "", body };
1151
+ return { tagPrefix: value.slice(0, value.length - body.length), body };
1152
+ }
1153
+ function prependTag(tagId, value) {
1154
+ const stripped = stripTagPrefix(value);
1155
+ return `§${tagId}§ ${stripped}`;
1156
+ }
1157
+ function isThinkingPart(part) {
1158
+ if (part === null || typeof part !== "object")
1159
+ return false;
1160
+ const candidate = part;
1161
+ return candidate.type === "thinking" || candidate.type === "reasoning";
1162
+ }
1163
+
1164
+ // src/hooks/magic-context/tag-part-guards.ts
1165
+ function isTextPart(part) {
1166
+ if (part === null || typeof part !== "object")
1167
+ return false;
1168
+ const p = part;
1169
+ return p.type === "text" && typeof p.text === "string";
1170
+ }
1171
+ function isToolPartWithOutput(part) {
1172
+ if (part === null || typeof part !== "object")
1173
+ return false;
1174
+ const p = part;
1175
+ if (p.type !== "tool" || typeof p.callID !== "string")
1176
+ return false;
1177
+ if (p.state === null || typeof p.state !== "object")
1178
+ return false;
1179
+ return typeof p.state.output === "string";
1180
+ }
1181
+ function isFilePart(part) {
1182
+ if (part === null || typeof part !== "object")
1183
+ return false;
1184
+ const p = part;
1185
+ return p.type === "file" && typeof p.url === "string";
1186
+ }
1187
+ function buildFileSourceContent(parts) {
1188
+ const content = parts.filter(isTextPart).map((part) => stripTagPrefix(part.text)).join(`
1189
+ `).trim();
1190
+ return content.length > 0 ? content : null;
1191
+ }
1192
+
1193
+ // src/hooks/magic-context/edit-marker.ts
1194
+ var TRUNCATION_SENTINEL = "...[truncated]";
1195
+ var EDIT_REGION_HINT_LEN = 40;
1196
+ var PATH_KEYS = new Set(["filePath", "file_path", "path"]);
1197
+ var DIFF_KEYS = new Set(["oldString", "newString", "content", "old_string", "new_string"]);
1198
+ function safeSlice(str, maxLen) {
1199
+ if (str.length <= maxLen)
1200
+ return str;
1201
+ const lastCharCode = str.charCodeAt(maxLen - 1);
1202
+ if (lastCharCode >= 55296 && lastCharCode <= 56319) {
1203
+ return str.slice(0, maxLen - 1);
1204
+ }
1205
+ return str.slice(0, maxLen);
1206
+ }
1207
+ function isEditTool(name) {
1208
+ return name === "edit" || name === "write";
1209
+ }
1210
+ function applyEditMarkerToInput(input) {
1211
+ for (const key of Object.keys(input)) {
1212
+ if (PATH_KEYS.has(key))
1213
+ continue;
1214
+ const value = input[key];
1215
+ if (typeof value !== "string" || !DIFF_KEYS.has(key))
1216
+ continue;
1217
+ if (value.endsWith(TRUNCATION_SENTINEL))
1218
+ continue;
1219
+ input[key] = value.length > EDIT_REGION_HINT_LEN ? `${safeSlice(value, EDIT_REGION_HINT_LEN)}${TRUNCATION_SENTINEL}` : value;
1220
+ }
1221
+ }
1222
+
1223
+ // src/hooks/magic-context/tool-drop-target.ts
1224
+ var DROP_PREFIX = "[dropped";
1225
+ var IGNORE_PART_TYPES = new Set([
1226
+ "thinking",
1227
+ "reasoning",
1228
+ "redacted_thinking",
1229
+ "meta",
1230
+ "step-start",
1231
+ "step-finish"
1232
+ ]);
1233
+ function isToolCallId(value) {
1234
+ return typeof value === "string" && value.length > 0;
1235
+ }
1236
+ function getToolContent(part) {
1237
+ if (!isRecord(part))
1238
+ return;
1239
+ if (part.type === "tool" && isRecord(part.state)) {
1240
+ return typeof part.state.output === "string" ? part.state.output : undefined;
1241
+ }
1242
+ if (part.type === "tool_result") {
1243
+ return typeof part.content === "string" ? part.content : undefined;
1244
+ }
1245
+ return;
1246
+ }
1247
+ function setToolContent(part, content) {
1248
+ if (!isRecord(part))
1249
+ return;
1250
+ if (part.type === "tool" && isRecord(part.state)) {
1251
+ part.state.output = content;
1252
+ return;
1253
+ }
1254
+ if (part.type === "tool_result") {
1255
+ part.content = content;
1256
+ }
1257
+ }
1258
+ function clonePart(part) {
1259
+ if (part === null || typeof part !== "object")
1260
+ return part;
1261
+ try {
1262
+ return structuredClone(part);
1263
+ } catch {
1264
+ try {
1265
+ return JSON.parse(JSON.stringify(part));
1266
+ } catch {
1267
+ return part;
1268
+ }
1269
+ }
1270
+ }
1271
+ function clampCloneInPlace(occurrence, clamp) {
1272
+ const clone = clonePart(occurrence.part);
1273
+ clamp(clone);
1274
+ const parts = occurrence.message.parts;
1275
+ const index = parts.indexOf(occurrence.part);
1276
+ if (index >= 0)
1277
+ parts[index] = clone;
1278
+ }
1279
+ function truncateToolPart(part, tagId) {
1280
+ if (!isRecord(part))
1281
+ return;
1282
+ const sentinel = `[dropped §${tagId}§]`;
1283
+ if (part.type === "tool" && isRecord(part.state)) {
1284
+ const state = part.state;
1285
+ state.output = sentinel;
1286
+ if (isRecord(state.input)) {
1287
+ const inputSize = estimateInputSize(state.input);
1288
+ if (inputSize > 500) {
1289
+ truncateInputValues(state.input);
1290
+ }
1291
+ }
1292
+ return;
1293
+ }
1294
+ if (part.type === "tool_result") {
1295
+ part.content = sentinel;
1296
+ return;
1297
+ }
1298
+ if (part.type === "tool-invocation" && isRecord(part.args)) {
1299
+ const inputSize = estimateInputSize(part.args);
1300
+ if (inputSize > 500) {
1301
+ truncateInputValues(part.args);
1302
+ }
1303
+ return;
1304
+ }
1305
+ if (part.type === "tool_use" && isRecord(part.input)) {
1306
+ const inputSize = estimateInputSize(part.input);
1307
+ if (inputSize > 500) {
1308
+ truncateInputValues(part.input);
1309
+ }
1310
+ }
1311
+ }
1312
+ function estimateInputSize(input) {
1313
+ try {
1314
+ return JSON.stringify(input).length;
1315
+ } catch {
1316
+ return 0;
1317
+ }
1318
+ }
1319
+ function editMarkerToolPart(part, tagId) {
1320
+ if (!isRecord(part))
1321
+ return;
1322
+ const sentinel = `[dropped §${tagId}§]`;
1323
+ if (part.type === "tool" && isRecord(part.state)) {
1324
+ part.state.output = sentinel;
1325
+ if (isRecord(part.state.input))
1326
+ applyEditMarkerToInput(part.state.input);
1327
+ return;
1328
+ }
1329
+ if (part.type === "tool_result") {
1330
+ part.content = sentinel;
1331
+ return;
1332
+ }
1333
+ if (part.type === "tool-invocation" && isRecord(part.args)) {
1334
+ applyEditMarkerToInput(part.args);
1335
+ return;
1336
+ }
1337
+ if (part.type === "tool_use" && isRecord(part.input)) {
1338
+ applyEditMarkerToInput(part.input);
1339
+ }
1340
+ }
1341
+ function readToolPartInput(part) {
1342
+ if (!isRecord(part))
1343
+ return null;
1344
+ if (part.type === "tool" && isRecord(part.state) && isRecord(part.state.input)) {
1345
+ return part.state.input;
1346
+ }
1347
+ if (part.type === "tool-invocation" && isRecord(part.args))
1348
+ return part.args;
1349
+ if (part.type === "tool_use" && isRecord(part.input))
1350
+ return part.input;
1351
+ return null;
1352
+ }
1353
+ var TRUNCATION_SENTINEL2 = "...[truncated]";
1354
+ function safeSlice2(str, maxLen) {
1355
+ if (str.length <= maxLen)
1356
+ return str;
1357
+ const lastCharCode = str.charCodeAt(maxLen - 1);
1358
+ if (lastCharCode >= 55296 && lastCharCode <= 56319) {
1359
+ return str.slice(0, maxLen - 1);
1360
+ }
1361
+ return str.slice(0, maxLen);
1362
+ }
1363
+ function truncateInputValues(input) {
1364
+ for (const key of Object.keys(input)) {
1365
+ const value = input[key];
1366
+ if (typeof value === "string") {
1367
+ if (value.endsWith(TRUNCATION_SENTINEL2) || value === "[object]" || /^\[\d+ items\]$/.test(value))
1368
+ continue;
1369
+ input[key] = value.length > 5 ? `${safeSlice2(value, 5)}${TRUNCATION_SENTINEL2}` : value;
1370
+ } else if (Array.isArray(value)) {
1371
+ input[key] = `[${value.length} items]`;
1372
+ } else if (value !== null && typeof value === "object") {
1373
+ input[key] = "[object]";
1374
+ }
1375
+ }
1376
+ }
1377
+ function hasMeaningfulPart(part) {
1378
+ if (!isRecord(part))
1379
+ return false;
1380
+ const type = part.type;
1381
+ if (type === "text") {
1382
+ if (typeof part.text !== "string")
1383
+ return false;
1384
+ return stripTagPrefix(part.text).trim().length > 0;
1385
+ }
1386
+ if (typeof type !== "string")
1387
+ return false;
1388
+ if (IGNORE_PART_TYPES.has(type))
1389
+ return false;
1390
+ return true;
1391
+ }
1392
+ function clearThinkingParts(thinkingParts) {
1393
+ for (const part of thinkingParts) {
1394
+ if (part.thinking !== undefined)
1395
+ part.thinking = "[cleared]";
1396
+ if (part.text !== undefined)
1397
+ part.text = "[cleared]";
1398
+ }
1399
+ }
1400
+ function partHasCompletedResult(part) {
1401
+ if (!isRecord(part))
1402
+ return false;
1403
+ if (part.type === "tool") {
1404
+ if (!isRecord(part.state))
1405
+ return false;
1406
+ return typeof part.state.output === "string" || part.state.status === "error";
1407
+ }
1408
+ return part.type === "tool_result";
1409
+ }
1410
+ function extractToolCallObservation(part) {
1411
+ if (!isRecord(part))
1412
+ return null;
1413
+ if (part.type === "tool" && isToolCallId(part.callID)) {
1414
+ return { callId: part.callID, kind: "result" };
1415
+ }
1416
+ if (part.type === "tool-invocation" && isToolCallId(part.callID)) {
1417
+ return { callId: part.callID, kind: "invocation" };
1418
+ }
1419
+ if (part.type === "tool_use" && isToolCallId(part.id)) {
1420
+ return { callId: part.id, kind: "invocation" };
1421
+ }
1422
+ if (part.type === "tool_result" && isToolCallId(part.tool_use_id)) {
1423
+ return { callId: part.tool_use_id, kind: "result" };
1424
+ }
1425
+ return null;
1426
+ }
1427
+ function isDropContent(content) {
1428
+ return content.startsWith(DROP_PREFIX);
1429
+ }
1430
+
1431
+ class ToolMutationBatch {
1432
+ partsToRemove = new Set;
1433
+ affectedMessages = new Set;
1434
+ messages;
1435
+ constructor(messages) {
1436
+ this.messages = messages;
1437
+ }
1438
+ markForRemoval(occurrence) {
1439
+ this.partsToRemove.add(occurrence.part);
1440
+ this.affectedMessages.add(occurrence.message);
1441
+ }
1442
+ finalize() {
1443
+ if (this.partsToRemove.size === 0)
1444
+ return;
1445
+ for (const message of this.affectedMessages) {
1446
+ message.parts = message.parts.filter((p) => !this.partsToRemove.has(p));
1447
+ }
1448
+ for (let i = this.messages.length - 1;i >= 0; i -= 1) {
1449
+ if (!this.messages[i].parts.some(hasMeaningfulPart)) {
1450
+ this.messages.splice(i, 1);
1451
+ }
1452
+ }
1453
+ this.partsToRemove.clear();
1454
+ this.affectedMessages.clear();
1455
+ }
1456
+ }
1457
+ function createToolDropTarget(compositeKey, thinkingParts, index, batch, tagId) {
1458
+ const drop = () => {
1459
+ const entry = index.get(compositeKey);
1460
+ if (!entry || entry.occurrences.length === 0)
1461
+ return "absent";
1462
+ if (!entry.hasResult)
1463
+ return "incomplete";
1464
+ for (const occurrence of entry.occurrences) {
1465
+ batch.markForRemoval(occurrence);
1466
+ }
1467
+ clearThinkingParts(thinkingParts);
1468
+ index.delete(compositeKey);
1469
+ return "removed";
1470
+ };
1471
+ const truncate = () => {
1472
+ const entry = index.get(compositeKey);
1473
+ if (!entry || entry.occurrences.length === 0)
1474
+ return "absent";
1475
+ if (!entry.hasResult)
1476
+ return "incomplete";
1477
+ for (const occurrence of entry.occurrences) {
1478
+ clampCloneInPlace(occurrence, (part) => truncateToolPart(part, tagId));
1479
+ }
1480
+ clearThinkingParts(thinkingParts);
1481
+ return "truncated";
1482
+ };
1483
+ const editMarker = () => {
1484
+ const entry = index.get(compositeKey);
1485
+ if (!entry || entry.occurrences.length === 0)
1486
+ return "absent";
1487
+ if (!entry.hasResult)
1488
+ return "incomplete";
1489
+ for (const occurrence of entry.occurrences) {
1490
+ clampCloneInPlace(occurrence, (part) => editMarkerToolPart(part, tagId));
1491
+ }
1492
+ clearThinkingParts(thinkingParts);
1493
+ return "truncated";
1494
+ };
1495
+ return {
1496
+ setContent: (content) => {
1497
+ if (isDropContent(content)) {
1498
+ drop();
1499
+ return true;
1500
+ }
1501
+ const entry = index.get(compositeKey);
1502
+ if (!entry)
1503
+ return false;
1504
+ let changed = false;
1505
+ for (const occurrence of entry.occurrences) {
1506
+ if (occurrence.kind !== "result")
1507
+ continue;
1508
+ const prevContent = getToolContent(occurrence.part);
1509
+ if (prevContent !== content) {
1510
+ setToolContent(occurrence.part, content);
1511
+ changed = true;
1512
+ }
1513
+ }
1514
+ return changed;
1515
+ },
1516
+ drop,
1517
+ truncate,
1518
+ editMarker,
1519
+ canDrop: () => {
1520
+ const entry = index.get(compositeKey);
1521
+ return !!entry && entry.occurrences.length > 0 && entry.hasResult;
1522
+ },
1523
+ readInput: () => {
1524
+ const entry = index.get(compositeKey);
1525
+ if (!entry)
1526
+ return null;
1527
+ for (const occurrence of entry.occurrences) {
1528
+ if (occurrence.kind !== "invocation")
1529
+ continue;
1530
+ const input = readToolPartInput(occurrence.part);
1531
+ if (input)
1532
+ return input;
1533
+ }
1534
+ for (const occurrence of entry.occurrences) {
1535
+ const input = readToolPartInput(occurrence.part);
1536
+ if (input)
1537
+ return input;
1538
+ }
1539
+ return null;
1540
+ }
1541
+ };
1542
+ }
1543
+
1544
+ // src/hooks/magic-context/read-session-chunk.ts
1545
+ var BLOCK_TOKEN_MEMO_MAX = 2048;
1546
+ var blockTokenMemo = new Map;
1547
+ function estimateBlockTokens(blockText) {
1548
+ const cached = blockTokenMemo.get(blockText);
1549
+ if (cached !== undefined) {
1550
+ blockTokenMemo.delete(blockText);
1551
+ blockTokenMemo.set(blockText, cached);
1552
+ return cached;
1553
+ }
1554
+ const count = estimateTokens(blockText);
1555
+ if (blockTokenMemo.size >= BLOCK_TOKEN_MEMO_MAX) {
1556
+ const oldest = blockTokenMemo.keys().next().value;
1557
+ if (oldest !== undefined)
1558
+ blockTokenMemo.delete(oldest);
1559
+ }
1560
+ blockTokenMemo.set(blockText, count);
1561
+ return count;
1562
+ }
1563
+ var activeRawMessageCache = null;
1564
+ var activeAbsoluteCountCache = null;
1565
+ var sessionProviders = new Map;
1566
+ function setRawMessageProvider(sessionId, provider) {
1567
+ sessionProviders.set(sessionId, provider);
1568
+ return () => {
1569
+ const current = sessionProviders.get(sessionId);
1570
+ if (current === provider)
1571
+ sessionProviders.delete(sessionId);
1572
+ };
1573
+ }
1574
+ function cleanUserText(text) {
1575
+ return removeSystemReminders(text).replace(OMO_INTERNAL_INITIATOR_MARKER, "").trim();
1576
+ }
1577
+ function withRawSessionMessageCache(fn) {
1578
+ const outerCache = activeRawMessageCache;
1579
+ if (!outerCache) {
1580
+ activeRawMessageCache = new Map;
1581
+ activeAbsoluteCountCache = new Map;
1582
+ }
1583
+ try {
1584
+ return fn();
1585
+ } finally {
1586
+ if (!outerCache) {
1587
+ activeRawMessageCache = null;
1588
+ activeAbsoluteCountCache = null;
1589
+ }
1590
+ }
1591
+ }
1592
+ function readRawSessionMessages(sessionId) {
1593
+ if (activeRawMessageCache) {
1594
+ const cached = activeRawMessageCache.get(sessionId);
1595
+ if (cached) {
1596
+ return cached;
1597
+ }
1598
+ const messages = readRawSessionMessagesFromSource(sessionId);
1599
+ activeRawMessageCache.set(sessionId, messages);
1600
+ return messages;
1601
+ }
1602
+ return readRawSessionMessagesFromSource(sessionId);
1603
+ }
1604
+ function readRawSessionMessagePage(sessionId, afterOrdinal, limit, finalWatermark) {
1605
+ const provider = sessionProviders.get(sessionId);
1606
+ if (provider?.readMessagePage) {
1607
+ return provider.readMessagePage(afterOrdinal, limit, finalWatermark);
1608
+ }
1609
+ if (provider) {
1610
+ return provider.readMessages().filter((message) => message.ordinal > afterOrdinal && message.ordinal <= finalWatermark).slice(0, limit);
1611
+ }
1612
+ if (!openCodeDbExists())
1613
+ return [];
1614
+ return withReadOnlySessionDb((db) => readRawSessionMessagePageFromDb(db, sessionId, afterOrdinal, limit, finalWatermark));
1615
+ }
1616
+ function getRawSessionMessageOrdinalCount(sessionId) {
1617
+ const provider = sessionProviders.get(sessionId);
1618
+ if (provider) {
1619
+ if (provider.getMessageCount)
1620
+ return provider.getMessageCount();
1621
+ return provider.readMessages().length;
1622
+ }
1623
+ if (!openCodeDbExists())
1624
+ return 0;
1625
+ return withReadOnlySessionDb((db) => countRawSessionMessageOrdinalsFromDb(db, sessionId));
1626
+ }
1627
+ readRawSessionMessages.readPage = readRawSessionMessagePage;
1628
+ readRawSessionMessages.getCount = getRawSessionMessageOrdinalCount;
1629
+ function primeTailRawMessageCache(args) {
1630
+ const { sessionId, lastCompartmentEnd, anchorMessageId } = args;
1631
+ if (!activeRawMessageCache)
1632
+ return false;
1633
+ if (activeRawMessageCache.has(sessionId))
1634
+ return false;
1635
+ if (sessionProviders.has(sessionId))
1636
+ return false;
1637
+ if (!openCodeDbExists())
1638
+ return false;
1639
+ if (lastCompartmentEnd < 1 || !anchorMessageId)
1640
+ return false;
1641
+ const result = withReadOnlySessionDb((db) => readRawSessionTailFromDb(db, sessionId, lastCompartmentEnd, anchorMessageId));
1642
+ if (!result)
1643
+ return false;
1644
+ activeRawMessageCache.set(sessionId, result.messages);
1645
+ activeAbsoluteCountCache?.set(sessionId, result.absoluteMessageCount);
1646
+ return true;
1647
+ }
1648
+ function getCachedAbsoluteMessageCount(sessionId) {
1649
+ return activeAbsoluteCountCache?.get(sessionId) ?? null;
1650
+ }
1651
+ function primeInMemoryTailRawMessageCache(args) {
1652
+ const { sessionId, messages, absoluteMessageCount } = args;
1653
+ if (!activeRawMessageCache)
1654
+ return false;
1655
+ if (activeRawMessageCache.has(sessionId))
1656
+ return false;
1657
+ if (sessionProviders.has(sessionId))
1658
+ return false;
1659
+ activeRawMessageCache.set(sessionId, messages);
1660
+ activeAbsoluteCountCache?.set(sessionId, absoluteMessageCount);
1661
+ return true;
1662
+ }
1663
+ function readRawSessionMessageOrdinalPage(sessionId, after, limit) {
1664
+ const provider = sessionProviders.get(sessionId);
1665
+ if (provider?.readMessageOrdinalPage)
1666
+ return provider.readMessageOrdinalPage(after, limit);
1667
+ if (provider) {
1668
+ const rows = provider.readMessages().map((message) => ({
1669
+ id: message.id,
1670
+ timeCreated: message.createdAt ?? message.ordinal,
1671
+ contributesOrdinal: true,
1672
+ hasValidInfo: true
1673
+ })).filter((row) => !after || row.timeCreated > after.timeCreated || row.timeCreated === after.timeCreated && row.id > after.id).sort((left, right) => left.timeCreated - right.timeCreated || left.id.localeCompare(right.id));
1674
+ return rows.slice(0, Math.max(1, Math.floor(limit)));
1675
+ }
1676
+ if (!openCodeDbExists())
1677
+ return [];
1678
+ return withReadOnlySessionDb((db) => readRawSessionMessageOrdinalPageFromDb(db, sessionId, after, limit));
1679
+ }
1680
+ function getRawSessionStoredMessageCount(sessionId) {
1681
+ const provider = sessionProviders.get(sessionId);
1682
+ if (provider?.getStoredMessageCount)
1683
+ return provider.getStoredMessageCount();
1684
+ if (provider)
1685
+ return provider.readMessages().length;
1686
+ if (!openCodeDbExists())
1687
+ return 0;
1688
+ return withReadOnlySessionDb((db) => countStoredRawSessionMessagesFromDb(db, sessionId));
1689
+ }
1690
+ function readRawSessionMessagePartsById(sessionId, messageId) {
1691
+ const provider = sessionProviders.get(sessionId);
1692
+ if (provider?.readMessagePartsById)
1693
+ return provider.readMessagePartsById(messageId);
1694
+ if (provider?.readMessageById)
1695
+ return provider.readMessageById(messageId);
1696
+ if (provider) {
1697
+ return provider.readMessages().find((message) => message.id === messageId) ?? null;
1698
+ }
1699
+ if (!openCodeDbExists())
1700
+ return null;
1701
+ return withReadOnlySessionDb((db) => readRawSessionMessagePartsByIdFromDb(db, sessionId, messageId));
1702
+ }
1703
+ function readRawSessionMessageOrdinalById(sessionId, messageId) {
1704
+ const provider = sessionProviders.get(sessionId);
1705
+ if (provider?.readMessageOrdinalById) {
1706
+ return provider.readMessageOrdinalById(messageId);
1707
+ }
1708
+ if (provider?.readMessageIdOrdinals) {
1709
+ return provider.readMessageIdOrdinals().get(messageId) ?? null;
1710
+ }
1711
+ if (provider?.readMessageOrdinalPage) {
1712
+ let after = null;
1713
+ let ordinal = 0;
1714
+ while (true) {
1715
+ const page = provider.readMessageOrdinalPage(after, 500);
1716
+ if (page.length === 0)
1717
+ return null;
1718
+ for (const entry of page) {
1719
+ if (entry.contributesOrdinal)
1720
+ ordinal += 1;
1721
+ if (entry.id === messageId)
1722
+ return entry.contributesOrdinal ? ordinal : null;
1723
+ }
1724
+ const last = page.at(-1);
1725
+ if (!last || page.length < 500)
1726
+ return null;
1727
+ after = { timeCreated: last.timeCreated, id: last.id };
1728
+ }
1729
+ }
1730
+ if (provider?.readMessageById) {
1731
+ return provider.readMessageById(messageId)?.ordinal ?? null;
1732
+ }
1733
+ if (provider) {
1734
+ return provider.readMessages().find((message) => message.id === messageId)?.ordinal ?? null;
1735
+ }
1736
+ if (!openCodeDbExists())
1737
+ return null;
1738
+ return withReadOnlySessionDb((db) => readRawSessionMessageOrdinalByIdFromDb(db, sessionId, messageId));
1739
+ }
1740
+ function readRawSessionMessageById(sessionId, messageId) {
1741
+ const provider = sessionProviders.get(sessionId);
1742
+ if (provider?.readMessageById) {
1743
+ return provider.readMessageById(messageId);
1744
+ }
1745
+ if (provider) {
1746
+ return provider.readMessages().find((message) => message.id === messageId) ?? null;
1747
+ }
1748
+ if (!openCodeDbExists())
1749
+ return null;
1750
+ return withReadOnlySessionDb((db) => readRawSessionMessageByIdFromDb(db, sessionId, messageId));
1751
+ }
1752
+ function readRawSessionMessagesFromSource(sessionId) {
1753
+ const provider = sessionProviders.get(sessionId);
1754
+ if (provider)
1755
+ return provider.readMessages();
1756
+ if (!openCodeDbExists())
1757
+ return [];
1758
+ return withReadOnlySessionDb((db) => readRawSessionMessagesFromDb(db, sessionId));
1759
+ }
1760
+ function getRawSessionMessageCount(sessionId) {
1761
+ const provider = sessionProviders.get(sessionId);
1762
+ if (provider) {
1763
+ if (provider.getMessageCount)
1764
+ return provider.getMessageCount();
1765
+ return provider.readMessages().length;
1766
+ }
1767
+ if (!openCodeDbExists())
1768
+ return 0;
1769
+ return withReadOnlySessionDb((db) => getRawSessionMessageCountFromDb(db, sessionId));
1770
+ }
1771
+ function getRawSessionTagKeysThrough(sessionId, upToMessageIndex) {
1772
+ const messages = readRawSessionMessages(sessionId);
1773
+ const messageFileKeys = new Set;
1774
+ const toolObservations = new Map;
1775
+ const unpairedInvocations = new Map;
1776
+ for (const message of messages) {
1777
+ if (message.ordinal > upToMessageIndex)
1778
+ break;
1779
+ for (const [partIndex, part] of message.parts.entries()) {
1780
+ if (isTextPart(part)) {
1781
+ messageFileKeys.add(`${message.id}:p${partIndex}`);
1782
+ continue;
1783
+ }
1784
+ if (isFilePart(part)) {
1785
+ messageFileKeys.add(`${message.id}:file${partIndex}`);
1786
+ continue;
1787
+ }
1788
+ const obs = extractToolCallObservation(part);
1789
+ if (!obs)
1790
+ continue;
1791
+ let ownerMsgId;
1792
+ if (obs.kind === "invocation") {
1793
+ ownerMsgId = message.id;
1794
+ const queue = unpairedInvocations.get(obs.callId) ?? [];
1795
+ queue.push(message.id);
1796
+ unpairedInvocations.set(obs.callId, queue);
1797
+ } else {
1798
+ const queue = unpairedInvocations.get(obs.callId);
1799
+ if (queue && queue.length > 0) {
1800
+ const popped = queue.shift();
1801
+ if (queue.length === 0)
1802
+ unpairedInvocations.delete(obs.callId);
1803
+ ownerMsgId = popped ?? message.id;
1804
+ } else {
1805
+ ownerMsgId = message.id;
1806
+ }
1807
+ }
1808
+ const owners = toolObservations.get(obs.callId) ?? new Set;
1809
+ owners.add(ownerMsgId);
1810
+ toolObservations.set(obs.callId, owners);
1811
+ }
1812
+ }
1813
+ return { messageFileKeys, toolObservations };
1814
+ }
1815
+ var PROTECTED_TAIL_USER_TURNS = 5;
1816
+ function getLegacyProtectedTailStartOrdinal(sessionId) {
1817
+ const messages = readRawSessionMessages(sessionId);
1818
+ const userOrdinals = messages.filter((m) => m.role === "user" && hasMeaningfulUserText(m.parts)).map((m) => m.ordinal);
1819
+ if (userOrdinals.length < PROTECTED_TAIL_USER_TURNS) {
1820
+ return 1;
1821
+ }
1822
+ return userOrdinals[userOrdinals.length - PROTECTED_TAIL_USER_TURNS];
1823
+ }
1824
+ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal) {
1825
+ const messages = readRawSessionMessages(sessionId);
1826
+ const totalMessageCount = getCachedAbsoluteMessageCount(sessionId) ?? messages.length;
1827
+ const startOrdinal = Math.max(1, offset);
1828
+ const lines = [];
1829
+ const lineMeta = [];
1830
+ const flushedToolOnlyBlocks = [];
1831
+ let totalTokens = 0;
1832
+ let messagesProcessed = 0;
1833
+ let lastOrdinal = startOrdinal - 1;
1834
+ let highestScannedOrdinal = startOrdinal - 1;
1835
+ let lastMessageId = "";
1836
+ let firstMessageId = "";
1837
+ let currentBlock = null;
1838
+ let pendingNoiseMeta = [];
1839
+ let commitClusters = 0;
1840
+ let lastFlushedRole = "";
1841
+ function recordFilteredNoise(meta) {
1842
+ pendingNoiseMeta.push(meta);
1843
+ if (!currentBlock) {
1844
+ highestScannedOrdinal = Math.max(highestScannedOrdinal, meta.ordinal);
1845
+ }
1846
+ }
1847
+ function flushCurrentBlock() {
1848
+ if (!currentBlock)
1849
+ return true;
1850
+ const blockText = formatBlock(currentBlock);
1851
+ const blockTokens = estimateBlockTokens(blockText);
1852
+ if (totalTokens + blockTokens > tokenBudget && totalTokens > 0) {
1853
+ return false;
1854
+ }
1855
+ if (currentBlock.role === "A" && currentBlock.commitHashes.length > 0 && lastFlushedRole !== "A") {
1856
+ commitClusters++;
1857
+ }
1858
+ lastFlushedRole = currentBlock.role;
1859
+ if (!firstMessageId)
1860
+ firstMessageId = currentBlock.meta[0]?.messageId ?? "";
1861
+ lastOrdinal = currentBlock.meta[currentBlock.meta.length - 1]?.ordinal ?? currentBlock.endOrdinal;
1862
+ highestScannedOrdinal = Math.max(highestScannedOrdinal, lastOrdinal);
1863
+ lastMessageId = currentBlock.meta[currentBlock.meta.length - 1]?.messageId ?? "";
1864
+ messagesProcessed += currentBlock.meta.length;
1865
+ lines.push(blockText);
1866
+ lineMeta.push(...currentBlock.meta);
1867
+ totalTokens += blockTokens;
1868
+ if (currentBlock.isToolOnly) {
1869
+ flushedToolOnlyBlocks.push({
1870
+ start: currentBlock.startOrdinal,
1871
+ end: currentBlock.endOrdinal
1872
+ });
1873
+ }
1874
+ currentBlock = null;
1875
+ return true;
1876
+ }
1877
+ for (const msg of messages) {
1878
+ if (eligibleEndOrdinal !== undefined && msg.ordinal >= eligibleEndOrdinal)
1879
+ break;
1880
+ if (msg.ordinal < startOrdinal)
1881
+ continue;
1882
+ const meta = { ordinal: msg.ordinal, messageId: msg.id };
1883
+ if (msg.role === "user" && !hasMeaningfulUserText(msg.parts)) {
1884
+ const tcSummaries = extractToolCallSummaries(msg.parts);
1885
+ if (tcSummaries.length === 0) {
1886
+ recordFilteredNoise(meta);
1887
+ continue;
1888
+ }
1889
+ const tcText = tcSummaries.join(" / ");
1890
+ if (currentBlock && currentBlock.role === "A") {
1891
+ currentBlock.endOrdinal = msg.ordinal;
1892
+ currentBlock.parts.push(tcText);
1893
+ currentBlock.meta.push(...pendingNoiseMeta, meta);
1894
+ pendingNoiseMeta = [];
1895
+ } else {
1896
+ if (!flushCurrentBlock())
1897
+ break;
1898
+ currentBlock = {
1899
+ role: "A",
1900
+ startOrdinal: pendingNoiseMeta[0]?.ordinal ?? msg.ordinal,
1901
+ endOrdinal: msg.ordinal,
1902
+ parts: [tcText],
1903
+ meta: [...pendingNoiseMeta, meta],
1904
+ commitHashes: [],
1905
+ isToolOnly: true
1906
+ };
1907
+ pendingNoiseMeta = [];
1908
+ }
1909
+ continue;
1910
+ }
1911
+ const role = compactRole(msg.role);
1912
+ const textParts = extractTexts(msg.parts).map((t) => msg.role === "user" ? cleanUserText(t) : t).map(normalizeText).filter((value) => value.length > 0);
1913
+ const toolSummaries = textParts.length === 0 ? extractToolCallSummaries(msg.parts) : [];
1914
+ const allParts = [...textParts, ...toolSummaries];
1915
+ const compacted = compactTextForSummary(allParts.join(" / "), msg.role);
1916
+ const text = compacted.text;
1917
+ if (!text) {
1918
+ recordFilteredNoise(meta);
1919
+ continue;
1920
+ }
1921
+ const msgHasNarrative = textParts.length > 0;
1922
+ if (currentBlock && currentBlock.role === role) {
1923
+ currentBlock.endOrdinal = msg.ordinal;
1924
+ currentBlock.parts.push(text);
1925
+ currentBlock.meta.push(...pendingNoiseMeta, meta);
1926
+ currentBlock.commitHashes = mergeCommitHashes(currentBlock.commitHashes, compacted.commitHashes);
1927
+ if (msgHasNarrative)
1928
+ currentBlock.isToolOnly = false;
1929
+ pendingNoiseMeta = [];
1930
+ continue;
1931
+ }
1932
+ if (!flushCurrentBlock())
1933
+ break;
1934
+ currentBlock = {
1935
+ role,
1936
+ startOrdinal: pendingNoiseMeta[0]?.ordinal ?? msg.ordinal,
1937
+ endOrdinal: msg.ordinal,
1938
+ parts: [text],
1939
+ meta: [...pendingNoiseMeta, meta],
1940
+ commitHashes: [...compacted.commitHashes],
1941
+ isToolOnly: !msgHasNarrative
1942
+ };
1943
+ pendingNoiseMeta = [];
1944
+ }
1945
+ if (flushCurrentBlock() && pendingNoiseMeta.length > 0) {
1946
+ highestScannedOrdinal = Math.max(highestScannedOrdinal, pendingNoiseMeta[pendingNoiseMeta.length - 1]?.ordinal ?? highestScannedOrdinal);
1947
+ }
1948
+ const toolOnlyRanges = [];
1949
+ for (const range of flushedToolOnlyBlocks) {
1950
+ const last = toolOnlyRanges[toolOnlyRanges.length - 1];
1951
+ if (last && range.start === last.end + 1) {
1952
+ last.end = range.end;
1953
+ } else {
1954
+ toolOnlyRanges.push({ start: range.start, end: range.end });
1955
+ }
1956
+ }
1957
+ const completedToolArcs = buildToolArcs(messages).flatMap((arc) => arc.resOrdinal === null ? [] : [{ start: arc.invOrdinal, end: arc.resOrdinal }]);
1958
+ return {
1959
+ startIndex: startOrdinal,
1960
+ endIndex: lastOrdinal,
1961
+ startMessageId: firstMessageId,
1962
+ endMessageId: lastMessageId,
1963
+ messageCount: messagesProcessed,
1964
+ tokenEstimate: totalTokens,
1965
+ hasMore: Math.max(lastOrdinal, highestScannedOrdinal) < (eligibleEndOrdinal !== undefined ? Math.min(eligibleEndOrdinal - 1, totalMessageCount) : totalMessageCount),
1966
+ text: lines.join(`
1967
+ `),
1968
+ lines: lineMeta,
1969
+ commitClusterCount: commitClusters,
1970
+ toolOnlyRanges,
1971
+ completedToolArcs
1972
+ };
1973
+ }
1974
+
1975
+ // src/features/magic-context/message-index.ts
1976
+ var MESSAGE_HISTORY_ORPHAN_SWEEP_BATCH_SIZE = 200;
1977
+ var MESSAGE_HISTORY_ORPHAN_SAFETY_AGE_MS = 24 * 60 * 60 * 1000;
1978
+ var MESSAGE_HISTORY_ORPHAN_SWEEP_COOLDOWN_MS = 10 * 60 * 1000;
1979
+ var MESSAGE_HISTORY_ORPHAN_UNAVAILABLE_REPROBE_MS = 24 * 60 * 60 * 1000;
1980
+ var lastIndexedStatements = new WeakMap;
1981
+ var insertMessageStatements = new WeakMap;
1982
+ var upsertProgressStatements = new WeakMap;
1983
+ var upsertDirtyFloorStatements = new WeakMap;
1984
+ var deleteFtsStatements = new WeakMap;
1985
+ var deleteFtsRangeStatements = new WeakMap;
1986
+ var deleteIndexStatements = new WeakMap;
1987
+ var countIndexedMessageStatements = new WeakMap;
1988
+ var getMessageSourceStatements = new WeakMap;
1989
+ var upsertMessageSourceStatements = new WeakMap;
1990
+ var deleteMessageSourceStatements = new WeakMap;
1991
+ var deleteMessageSourceRangeStatements = new WeakMap;
1992
+ var deleteMessageFtsStatements = new WeakMap;
1993
+ function normalizeIndexText(text) {
1994
+ return text.replace(/\s+/g, " ").trim();
1995
+ }
1996
+ function getLastIndexedStatement(db) {
1997
+ let stmt = lastIndexedStatements.get(db);
1998
+ if (!stmt) {
1999
+ stmt = db.prepare("SELECT last_indexed_ordinal, dirty_floor_ordinal FROM message_history_index WHERE session_id = ?");
2000
+ lastIndexedStatements.set(db, stmt);
2001
+ }
2002
+ return stmt;
2003
+ }
2004
+ function getInsertMessageStatement(db) {
2005
+ let stmt = insertMessageStatements.get(db);
2006
+ if (!stmt) {
2007
+ stmt = db.prepare("INSERT INTO message_history_fts (session_id, message_ordinal, message_id, role, content) VALUES (?, ?, ?, ?, ?)");
2008
+ insertMessageStatements.set(db, stmt);
2009
+ }
2010
+ return stmt;
2011
+ }
2012
+ function getUpsertProgressStatement(db) {
2013
+ let stmt = upsertProgressStatements.get(db);
2014
+ if (!stmt) {
2015
+ stmt = db.prepare("INSERT INTO message_history_index (session_id, last_indexed_ordinal, dirty_floor_ordinal, updated_at, harness) VALUES (?, ?, ?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET last_indexed_ordinal = excluded.last_indexed_ordinal, dirty_floor_ordinal = excluded.dirty_floor_ordinal, updated_at = excluded.updated_at");
2016
+ upsertProgressStatements.set(db, stmt);
2017
+ }
2018
+ return stmt;
2019
+ }
2020
+ function getUpsertDirtyFloorStatement(db) {
2021
+ let stmt = upsertDirtyFloorStatements.get(db);
2022
+ if (!stmt) {
2023
+ stmt = db.prepare("INSERT INTO message_history_index (session_id, last_indexed_ordinal, dirty_floor_ordinal, updated_at, harness) VALUES (?, ?, ?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET last_indexed_ordinal = MAX(message_history_index.last_indexed_ordinal, excluded.last_indexed_ordinal), dirty_floor_ordinal = CASE WHEN message_history_index.dirty_floor_ordinal <= 0 THEN excluded.dirty_floor_ordinal WHEN excluded.dirty_floor_ordinal <= 0 THEN message_history_index.dirty_floor_ordinal ELSE MIN(message_history_index.dirty_floor_ordinal, excluded.dirty_floor_ordinal) END, updated_at = excluded.updated_at");
2024
+ upsertDirtyFloorStatements.set(db, stmt);
2025
+ }
2026
+ return stmt;
2027
+ }
2028
+ function getDeleteFtsStatement(db) {
2029
+ let stmt = deleteFtsStatements.get(db);
2030
+ if (!stmt) {
2031
+ stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ?");
2032
+ deleteFtsStatements.set(db, stmt);
2033
+ }
2034
+ return stmt;
2035
+ }
2036
+ function getDeleteFtsRangeStatement(db) {
2037
+ let stmt = deleteFtsRangeStatements.get(db);
2038
+ if (!stmt) {
2039
+ stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ? AND CAST(message_ordinal AS INTEGER) BETWEEN ? AND ?");
2040
+ deleteFtsRangeStatements.set(db, stmt);
2041
+ }
2042
+ return stmt;
2043
+ }
2044
+ function getDeleteIndexStatement(db) {
2045
+ let stmt = deleteIndexStatements.get(db);
2046
+ if (!stmt) {
2047
+ stmt = db.prepare("DELETE FROM message_history_index WHERE session_id = ?");
2048
+ deleteIndexStatements.set(db, stmt);
2049
+ }
2050
+ return stmt;
2051
+ }
2052
+ function getCountIndexedMessageStatement(db) {
2053
+ let stmt = countIndexedMessageStatements.get(db);
2054
+ if (!stmt) {
2055
+ stmt = db.prepare("SELECT COUNT(*) AS count FROM message_history_fts WHERE session_id = ? AND message_id = ?");
2056
+ countIndexedMessageStatements.set(db, stmt);
2057
+ }
2058
+ return stmt;
2059
+ }
2060
+ function getMessageSourceStatement(db) {
2061
+ let stmt = getMessageSourceStatements.get(db);
2062
+ if (!stmt) {
2063
+ stmt = db.prepare("SELECT message_ordinal, source_version, normalized_content_hash, role FROM message_history_source WHERE session_id = ? AND message_id = ?");
2064
+ getMessageSourceStatements.set(db, stmt);
2065
+ }
2066
+ return stmt;
2067
+ }
2068
+ function getUpsertMessageSourceStatement(db) {
2069
+ let stmt = upsertMessageSourceStatements.get(db);
2070
+ if (!stmt) {
2071
+ stmt = db.prepare(`INSERT INTO message_history_source (
2072
+ session_id, message_id, message_ordinal, source_version,
2073
+ normalized_content_hash, role, harness, updated_at
2074
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
2075
+ ON CONFLICT(session_id, message_id) DO UPDATE SET
2076
+ message_ordinal = excluded.message_ordinal,
2077
+ source_version = excluded.source_version,
2078
+ normalized_content_hash = excluded.normalized_content_hash,
2079
+ role = excluded.role,
2080
+ harness = excluded.harness,
2081
+ updated_at = excluded.updated_at`);
2082
+ upsertMessageSourceStatements.set(db, stmt);
2083
+ }
2084
+ return stmt;
2085
+ }
2086
+ function getDeleteMessageSourceStatement(db) {
2087
+ let stmt = deleteMessageSourceStatements.get(db);
2088
+ if (!stmt) {
2089
+ stmt = db.prepare("DELETE FROM message_history_source WHERE session_id = ?");
2090
+ deleteMessageSourceStatements.set(db, stmt);
2091
+ }
2092
+ return stmt;
2093
+ }
2094
+ function getDeleteMessageSourceRangeStatement(db) {
2095
+ let stmt = deleteMessageSourceRangeStatements.get(db);
2096
+ if (!stmt) {
2097
+ stmt = db.prepare("DELETE FROM message_history_source WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?");
2098
+ deleteMessageSourceRangeStatements.set(db, stmt);
2099
+ }
2100
+ return stmt;
2101
+ }
2102
+ function getDeleteMessageFtsStatement(db) {
2103
+ let stmt = deleteMessageFtsStatements.get(db);
2104
+ if (!stmt) {
2105
+ stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ? AND message_id = ?");
2106
+ deleteMessageFtsStatements.set(db, stmt);
2107
+ }
2108
+ return stmt;
2109
+ }
2110
+ function normalizeSourceVersion(version) {
2111
+ if (typeof version === "number")
2112
+ return `number:${version}`;
2113
+ if (typeof version === "string")
2114
+ return `string:${version}`;
2115
+ return "null";
2116
+ }
2117
+ function getMessageSourceSnapshot(message) {
2118
+ const content = getIndexableContent(message.role, message.parts);
2119
+ return {
2120
+ ordinal: message.ordinal,
2121
+ sourceVersion: normalizeSourceVersion(message.version),
2122
+ contentHash: createHash("sha256").update(content).digest("hex"),
2123
+ role: message.role,
2124
+ content
2125
+ };
2126
+ }
2127
+ function getMessageIndexSourceIdentity(message) {
2128
+ const source = getMessageSourceSnapshot(message);
2129
+ return JSON.stringify([source.ordinal, source.sourceVersion, source.contentHash, source.role]);
2130
+ }
2131
+ function isMessageIndexSourceCurrent(db, sessionId, message) {
2132
+ const source = getMessageSourceSnapshot(message);
2133
+ const row = getMessageSourceStatement(db).get(sessionId, message.id);
2134
+ return row?.message_ordinal === source.ordinal && row.source_version === source.sourceVersion && row.normalized_content_hash === source.contentHash && row.role === source.role;
2135
+ }
2136
+ function setMessageSource(db, sessionId, message, now) {
2137
+ const source = getMessageSourceSnapshot(message);
2138
+ getUpsertMessageSourceStatement(db).run(sessionId, message.id, source.ordinal, source.sourceVersion, source.contentHash, source.role, getHarness(), now);
2139
+ return source.content;
2140
+ }
2141
+ function getLastIndexedOrdinal(db, sessionId) {
2142
+ const row = getLastIndexedStatement(db).get(sessionId);
2143
+ return typeof row?.last_indexed_ordinal === "number" ? row.last_indexed_ordinal : 0;
2144
+ }
2145
+ function getIndexedMessageCorpusSize(db, sessionId, maxOrdinal) {
2146
+ const watermark = getLastIndexedOrdinal(db, sessionId);
2147
+ return maxOrdinal === null ? watermark : Math.min(watermark, Math.max(0, maxOrdinal));
2148
+ }
2149
+ function getDirtyIndexFloor(db, sessionId) {
2150
+ const row = getLastIndexedStatement(db).get(sessionId);
2151
+ return typeof row?.dirty_floor_ordinal === "number" && row.dirty_floor_ordinal > 0 ? row.dirty_floor_ordinal : null;
2152
+ }
2153
+ function markMessageIndexDirty(db, sessionId, floorOrdinal) {
2154
+ const dirtyFloor = Math.max(1, Math.floor(floorOrdinal));
2155
+ getUpsertDirtyFloorStatement(db).run(sessionId, getLastIndexedOrdinal(db, sessionId), dirtyFloor, Date.now(), getHarness());
2156
+ }
2157
+ function isMessageAlreadyIndexed(db, sessionId, messageId) {
2158
+ const row = getCountIndexedMessageStatement(db).get(sessionId, messageId);
2159
+ return (typeof row?.count === "number" ? row.count : 0) > 0;
2160
+ }
2161
+ function setIndexProgress(db, sessionId, watermark, dirtyFloor, now) {
2162
+ getUpsertProgressStatement(db).run(sessionId, Math.max(0, Math.floor(watermark)), dirtyFloor ?? 0, now, getHarness());
2163
+ }
2164
+ function getMessageIndexReconciliationStartOrdinal(db, sessionId) {
2165
+ const watermark = getLastIndexedOrdinal(db, sessionId);
2166
+ const dirtyFloor = getDirtyIndexFloor(db, sessionId);
2167
+ return dirtyFloor === null ? watermark : Math.min(watermark, dirtyFloor - 1);
2168
+ }
2169
+ function isMessageIndexReconciledThrough(db, sessionId, finalWatermark) {
2170
+ const dirtyFloor = getDirtyIndexFloor(db, sessionId);
2171
+ return getLastIndexedOrdinal(db, sessionId) >= finalWatermark && dirtyFloor === null;
2172
+ }
2173
+ function deleteIndexedMessage(db, sessionId, messageId) {
2174
+ const row = getCountIndexedMessageStatement(db).get(sessionId, messageId);
2175
+ const count = typeof row?.count === "number" ? row.count : 0;
2176
+ clearIndexedMessages(db, sessionId);
2177
+ return count;
2178
+ }
2179
+ function clearIndexedMessages(db, sessionId) {
2180
+ db.transaction(() => {
2181
+ getDeleteFtsStatement(db).run(sessionId);
2182
+ getDeleteMessageSourceStatement(db).run(sessionId);
2183
+ getDeleteIndexStatement(db).run(sessionId);
2184
+ clearCompressionDepth(db, sessionId);
2185
+ })();
2186
+ }
2187
+ function getIndexableContent(role, parts) {
2188
+ if (role === "user") {
2189
+ if (!hasMeaningfulUserText(parts)) {
2190
+ return "";
2191
+ }
2192
+ return extractTexts(parts).map(cleanUserText).map(normalizeIndexText).filter((text) => text.length > 0).join(" / ");
2193
+ }
2194
+ if (role === "assistant") {
2195
+ return extractTexts(parts).map(removeSystemReminders).map(normalizeIndexText).filter((text) => text.length > 0).join(" / ");
2196
+ }
2197
+ return "";
2198
+ }
2199
+ function indexSingleMessageInTransaction(db, sessionId, message, now, dirtyFloorBeforeAttempt) {
2200
+ const currentWatermark = getLastIndexedOrdinal(db, sessionId);
2201
+ const dirtyFloor = getDirtyIndexFloor(db, sessionId);
2202
+ if (message.ordinal <= currentWatermark) {
2203
+ if (isMessageIndexSourceCurrent(db, sessionId, message)) {
2204
+ return false;
2205
+ }
2206
+ getDeleteMessageFtsStatement(db).run(sessionId, message.id);
2207
+ const content2 = setMessageSource(db, sessionId, message, now);
2208
+ if (content2.length > 0 && (message.role === "user" || message.role === "assistant")) {
2209
+ getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content2);
2210
+ }
2211
+ setIndexProgress(db, sessionId, currentWatermark, dirtyFloorBeforeAttempt === message.ordinal ? null : dirtyFloorBeforeAttempt, now);
2212
+ return true;
2213
+ }
2214
+ if (message.ordinal !== currentWatermark + 1 || dirtyFloor !== null && dirtyFloor !== message.ordinal) {
2215
+ return false;
2216
+ }
2217
+ const content = setMessageSource(db, sessionId, message, now);
2218
+ let inserted = false;
2219
+ if (content.length > 0 && (message.role === "user" || message.role === "assistant") && !isMessageAlreadyIndexed(db, sessionId, message.id)) {
2220
+ getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
2221
+ inserted = true;
2222
+ }
2223
+ setIndexProgress(db, sessionId, message.ordinal, dirtyFloorBeforeAttempt === message.ordinal ? null : dirtyFloorBeforeAttempt, now);
2224
+ return inserted;
2225
+ }
2226
+ function indexSingleMessage(db, sessionId, message) {
2227
+ const currentWatermark = getLastIndexedOrdinal(db, sessionId);
2228
+ if (message.ordinal <= currentWatermark && isMessageIndexSourceCurrent(db, sessionId, message)) {
2229
+ return false;
2230
+ }
2231
+ const dirtyFloorBeforeAttempt = getDirtyIndexFloor(db, sessionId);
2232
+ markMessageIndexDirty(db, sessionId, Math.min(message.ordinal, currentWatermark + 1));
2233
+ db.exec("BEGIN IMMEDIATE");
2234
+ let committed = false;
2235
+ try {
2236
+ const result = indexSingleMessageInTransaction(db, sessionId, message, Date.now(), dirtyFloorBeforeAttempt);
2237
+ db.exec("COMMIT");
2238
+ committed = true;
2239
+ return result;
2240
+ } finally {
2241
+ if (!committed) {
2242
+ try {
2243
+ db.exec("ROLLBACK");
2244
+ } catch {}
2245
+ }
2246
+ }
2247
+ }
2248
+ function indexMessagesAfterOrdinal(db, sessionId, messages, _lastIndexedOrdinal, finalWatermark = messages.length) {
2249
+ const now = Date.now();
2250
+ let inserted = 0;
2251
+ db.exec("BEGIN IMMEDIATE");
2252
+ let committed = false;
2253
+ try {
2254
+ const currentWatermark = getLastIndexedOrdinal(db, sessionId);
2255
+ const dirtyFloor = getDirtyIndexFloor(db, sessionId);
2256
+ const effectiveWatermark = dirtyFloor === null ? currentWatermark : Math.min(currentWatermark, Math.max(0, dirtyFloor - 1));
2257
+ if (dirtyFloor !== null && dirtyFloor <= finalWatermark) {
2258
+ getDeleteFtsRangeStatement(db).run(sessionId, dirtyFloor, finalWatermark);
2259
+ getDeleteMessageSourceRangeStatement(db).run(sessionId, dirtyFloor, finalWatermark);
2260
+ }
2261
+ const messagesByOrdinal = new Map;
2262
+ for (const message of messages) {
2263
+ if (message.ordinal > effectiveWatermark && message.ordinal <= finalWatermark) {
2264
+ messagesByOrdinal.set(message.ordinal, message);
2265
+ }
2266
+ }
2267
+ let coveredWatermark = effectiveWatermark;
2268
+ while (coveredWatermark < finalWatermark && messagesByOrdinal.has(coveredWatermark + 1)) {
2269
+ coveredWatermark += 1;
2270
+ }
2271
+ for (let ordinal = effectiveWatermark + 1;ordinal <= coveredWatermark; ordinal++) {
2272
+ const message = messagesByOrdinal.get(ordinal);
2273
+ if (!message)
2274
+ continue;
2275
+ const content = setMessageSource(db, sessionId, message, now);
2276
+ if (content.length === 0 || message.role !== "user" && message.role !== "assistant" || isMessageAlreadyIndexed(db, sessionId, message.id)) {
2277
+ continue;
2278
+ }
2279
+ getInsertMessageStatement(db).run(sessionId, message.ordinal, message.id, message.role, content);
2280
+ inserted += 1;
2281
+ }
2282
+ const missingFloor = coveredWatermark < finalWatermark ? coveredWatermark + 1 : null;
2283
+ const preservedFloor = dirtyFloor !== null && dirtyFloor > finalWatermark ? dirtyFloor : null;
2284
+ const nextDirtyFloor = missingFloor === null ? preservedFloor : preservedFloor === null ? missingFloor : Math.min(missingFloor, preservedFloor);
2285
+ setIndexProgress(db, sessionId, coveredWatermark, nextDirtyFloor, now);
2286
+ db.exec("COMMIT");
2287
+ committed = true;
2288
+ } finally {
2289
+ if (!committed) {
2290
+ try {
2291
+ db.exec("ROLLBACK");
2292
+ } catch {}
2293
+ }
2294
+ }
2295
+ return inserted;
2296
+ }
2297
+ function getMessageHistoryOrphanSweepState(db) {
2298
+ return db.prepare("SELECT cursor_session_id, last_swept_at FROM message_history_orphan_sweep WHERE harness = 'opencode'").get() ?? {};
2299
+ }
2300
+ function persistMessageHistoryOrphanSweepState(db, cursor, lastSweptAt) {
2301
+ db.prepare(`INSERT INTO message_history_orphan_sweep (harness, cursor_session_id, last_swept_at)
2302
+ VALUES ('opencode', ?, ?)
2303
+ ON CONFLICT(harness) DO UPDATE SET
2304
+ cursor_session_id = excluded.cursor_session_id,
2305
+ last_swept_at = excluded.last_swept_at`).run(cursor, lastSweptAt);
2306
+ }
2307
+ function sweepOrphanedOpenCodeMessageIndexes(db, openReadableOpenCodeDb, options = {}) {
2308
+ const now = options.now ?? Date.now();
2309
+ const batchSize = Math.max(1, Math.floor(options.batchSize ?? MESSAGE_HISTORY_ORPHAN_SWEEP_BATCH_SIZE));
2310
+ const safetyAgeMs = Math.max(0, options.safetyAgeMs ?? MESSAGE_HISTORY_ORPHAN_SAFETY_AGE_MS);
2311
+ const cooldownMs = Math.max(0, options.cooldownMs ?? MESSAGE_HISTORY_ORPHAN_SWEEP_COOLDOWN_MS);
2312
+ const unavailableReprobeMs = Math.max(cooldownMs, options.unavailableReprobeMs ?? MESSAGE_HISTORY_ORPHAN_UNAVAILABLE_REPROBE_MS);
2313
+ const state = getMessageHistoryOrphanSweepState(db);
2314
+ const cursor = typeof state.cursor_session_id === "string" ? state.cursor_session_id : "";
2315
+ if (typeof state.last_swept_at === "number" && state.last_swept_at + cooldownMs > now) {
2316
+ return { status: "cooldown", scanned: 0, deleted: 0, cursor };
2317
+ }
2318
+ let openCodeDb = null;
2319
+ try {
2320
+ openCodeDb = openReadableOpenCodeDb();
2321
+ } catch {
2322
+ openCodeDb = null;
2323
+ }
2324
+ if (!openCodeDb) {
2325
+ persistMessageHistoryOrphanSweepState(db, cursor, now + unavailableReprobeMs - cooldownMs);
2326
+ return { status: "source_unavailable", scanned: 0, deleted: 0, cursor };
2327
+ }
2328
+ try {
2329
+ const cutoff = now - safetyAgeMs;
2330
+ const candidates = db.prepare(`SELECT session_id
2331
+ FROM message_history_index
2332
+ WHERE harness = 'opencode'
2333
+ AND updated_at <= ?
2334
+ AND session_id > ?
2335
+ ORDER BY session_id ASC
2336
+ LIMIT ?`).all(cutoff, cursor, batchSize);
2337
+ const sessionExists = openCodeDb.prepare("SELECT 1 FROM session WHERE id = ? LIMIT 1");
2338
+ const missingSessionIds = candidates.filter((candidate) => !sessionExists.get(candidate.session_id)).map((candidate) => candidate.session_id);
2339
+ const nextCursor = candidates.length < batchSize ? "" : candidates[candidates.length - 1]?.session_id ?? cursor;
2340
+ const completedAt = candidates.length < batchSize ? now : null;
2341
+ db.exec("BEGIN IMMEDIATE");
2342
+ let committed = false;
2343
+ let deleted = 0;
2344
+ try {
2345
+ const stillEligible = db.prepare("SELECT 1 FROM message_history_index WHERE session_id = ? AND harness = 'opencode' AND updated_at <= ?");
2346
+ for (const sessionId of missingSessionIds) {
2347
+ if (!stillEligible.get(sessionId, cutoff))
2348
+ continue;
2349
+ getDeleteFtsStatement(db).run(sessionId);
2350
+ getDeleteMessageSourceStatement(db).run(sessionId);
2351
+ const result = db.prepare("DELETE FROM message_history_index WHERE session_id = ? AND harness = 'opencode' AND updated_at <= ?").run(sessionId, cutoff);
2352
+ if (result.changes === 1)
2353
+ deleted += 1;
2354
+ }
2355
+ persistMessageHistoryOrphanSweepState(db, nextCursor, completedAt);
2356
+ db.exec("COMMIT");
2357
+ committed = true;
2358
+ } finally {
2359
+ if (!committed) {
2360
+ try {
2361
+ db.exec("ROLLBACK");
2362
+ } catch {}
2363
+ }
2364
+ }
2365
+ return {
2366
+ status: "swept",
2367
+ scanned: candidates.length,
2368
+ deleted,
2369
+ cursor: nextCursor
2370
+ };
2371
+ } finally {
2372
+ closeQuietly(openCodeDb);
2373
+ }
2374
+ }
2375
+
2376
+ // src/features/magic-context/resolve-subagent-fallback.ts
2377
+ function resolveIsSubagentFromOpenCodeDb(sessionId) {
2378
+ try {
2379
+ return withReadOnlySessionDb((openCodeDb) => {
2380
+ const row = openCodeDb.prepare("SELECT parent_id FROM session WHERE id = ?").get(sessionId);
2381
+ if (!row)
2382
+ return null;
2383
+ return typeof row.parent_id === "string" && row.parent_id.length > 0;
2384
+ });
2385
+ } catch (error) {
2386
+ log(`[magic-context] resolveIsSubagentFromOpenCodeDb failed for ${sessionId}:`, error);
2387
+ return null;
2388
+ }
2389
+ }
2390
+
2391
+ // src/features/magic-context/storage-meta-shared.ts
2392
+ import { Buffer } from "node:buffer";
2393
+ var SESSION_META_SELECT_COLUMNS = [
2394
+ "session_id",
2395
+ "last_response_time",
2396
+ "cache_ttl",
2397
+ "counter",
2398
+ "last_nudge_tokens",
2399
+ "last_nudge_band",
2400
+ "last_transform_error",
2401
+ "is_subagent",
2402
+ "last_context_percentage",
2403
+ "last_input_tokens",
2404
+ "observed_safe_input_tokens",
2405
+ "cache_alert_sent",
2406
+ "times_execute_threshold_reached",
2407
+ "compartment_in_progress",
2408
+ "system_prompt_hash",
2409
+ "system_prompt_tokens",
2410
+ "conversation_tokens",
2411
+ "tool_call_tokens",
2412
+ "cleared_reasoning_through_tag",
2413
+ "tool_reclaim_watermark",
2414
+ "last_todo_state",
2415
+ "cached_m0_bytes",
2416
+ "cached_m0_mural_data_url",
2417
+ "cached_m0_mural_hash",
2418
+ "cached_m1_bytes",
2419
+ "cached_m0_project_memory_epoch",
2420
+ "cached_m0_workspace_fingerprint",
2421
+ "cached_m0_project_user_profile_version",
2422
+ "cached_m0_max_compartment_seq",
2423
+ "cached_m0_max_memory_id",
2424
+ "cached_m0_max_mutation_id",
2425
+ "cached_m0_max_memory_mutation_id",
2426
+ "cached_m0_project_docs_hash",
2427
+ "cached_m0_materialized_at",
2428
+ "cached_m0_session_facts_version",
2429
+ "cached_m0_upgrade_state",
2430
+ "cached_m0_system_hash",
2431
+ "cached_m0_tool_set_hash",
2432
+ "cached_m0_model_key",
2433
+ "cached_m0_project_identity",
2434
+ "last_observed_model_key",
2435
+ "last_usage_context_limit",
2436
+ "prior_boundary_ordinal",
2437
+ "protected_tail_policy_version",
2438
+ "protected_tail_drain_window_started_at",
2439
+ "protected_tail_drain_tokens",
2440
+ "recovery_no_eligible_head_count",
2441
+ "force_emergency_bypass_window_start",
2442
+ "force_emergency_bypass_used",
2443
+ "emergency_drain_active",
2444
+ "historian_drain_failure_at",
2445
+ "upgrade_reminded_at",
2446
+ "upgrade_reminder_last_sent_at",
2447
+ "upgrade_reminder_count",
2448
+ "pi_stable_id_scheme"
2449
+ ];
2450
+ var META_COLUMNS = {
2451
+ lastResponseTime: "last_response_time",
2452
+ cacheTtl: "cache_ttl",
2453
+ counter: "counter",
2454
+ lastNudgeTokens: "last_nudge_tokens",
2455
+ lastNudgeBand: "last_nudge_band",
2456
+ lastTransformError: "last_transform_error",
2457
+ isSubagent: "is_subagent",
2458
+ lastContextPercentage: "last_context_percentage",
2459
+ lastInputTokens: "last_input_tokens",
2460
+ observedSafeInputTokens: "observed_safe_input_tokens",
2461
+ cacheAlertSent: "cache_alert_sent",
2462
+ timesExecuteThresholdReached: "times_execute_threshold_reached",
2463
+ compartmentInProgress: "compartment_in_progress",
2464
+ systemPromptHash: "system_prompt_hash",
2465
+ systemPromptTokens: "system_prompt_tokens",
2466
+ conversationTokens: "conversation_tokens",
2467
+ toolCallTokens: "tool_call_tokens",
2468
+ clearedReasoningThroughTag: "cleared_reasoning_through_tag",
2469
+ toolReclaimWatermark: "tool_reclaim_watermark",
2470
+ lastTodoState: "last_todo_state",
2471
+ cachedM0Bytes: "cached_m0_bytes",
2472
+ cachedM0MuralDataUrl: "cached_m0_mural_data_url",
2473
+ cachedM0MuralHash: "cached_m0_mural_hash",
2474
+ cachedM1Bytes: "cached_m1_bytes",
2475
+ cachedM0ProjectMemoryEpoch: "cached_m0_project_memory_epoch",
2476
+ cachedM0WorkspaceFingerprint: "cached_m0_workspace_fingerprint",
2477
+ cachedM0ProjectUserProfileVersion: "cached_m0_project_user_profile_version",
2478
+ cachedM0MaxCompartmentSeq: "cached_m0_max_compartment_seq",
2479
+ cachedM0MaxMemoryId: "cached_m0_max_memory_id",
2480
+ cachedM0MaxMutationId: "cached_m0_max_mutation_id",
2481
+ cachedM0MaxMemoryMutationId: "cached_m0_max_memory_mutation_id",
2482
+ cachedM0ProjectDocsHash: "cached_m0_project_docs_hash",
2483
+ cachedM0MaterializedAt: "cached_m0_materialized_at",
2484
+ cachedM0SessionFactsVersion: "cached_m0_session_facts_version",
2485
+ cachedM0UpgradeState: "cached_m0_upgrade_state",
2486
+ cachedM0SystemHash: "cached_m0_system_hash",
2487
+ cachedM0ToolSetHash: "cached_m0_tool_set_hash",
2488
+ cachedM0ModelKey: "cached_m0_model_key",
2489
+ cachedM0ProjectIdentity: "cached_m0_project_identity",
2490
+ lastObservedModelKey: "last_observed_model_key",
2491
+ lastUsageContextLimit: "last_usage_context_limit",
2492
+ priorBoundaryOrdinal: "prior_boundary_ordinal",
2493
+ protectedTailPolicyVersion: "protected_tail_policy_version",
2494
+ protectedTailDrainWindowStartedAt: "protected_tail_drain_window_started_at",
2495
+ protectedTailDrainTokens: "protected_tail_drain_tokens",
2496
+ recoveryNoEligibleHeadCount: "recovery_no_eligible_head_count",
2497
+ forceEmergencyBypassWindowStart: "force_emergency_bypass_window_start",
2498
+ forceEmergencyBypassUsed: "force_emergency_bypass_used",
2499
+ emergencyDrainActive: "emergency_drain_active",
2500
+ historianDrainFailureAt: "historian_drain_failure_at",
2501
+ upgradeRemindedAt: "upgrade_reminded_at",
2502
+ upgradeReminderLastSentAt: "upgrade_reminder_last_sent_at",
2503
+ upgradeReminderCount: "upgrade_reminder_count",
2504
+ piStableIdScheme: "pi_stable_id_scheme"
2505
+ };
2506
+ var BOOLEAN_META_KEYS = new Set(["isSubagent", "compartmentInProgress", "cacheAlertSent"]);
2507
+ var NULL_BIND_META_KEYS = new Set([
2508
+ "cachedM0Bytes",
2509
+ "cachedM0MuralDataUrl",
2510
+ "cachedM0MuralHash",
2511
+ "cachedM1Bytes",
2512
+ "cachedM0ProjectMemoryEpoch",
2513
+ "cachedM0WorkspaceFingerprint",
2514
+ "cachedM0ProjectUserProfileVersion",
2515
+ "cachedM0MaxCompartmentSeq",
2516
+ "cachedM0MaxMemoryId",
2517
+ "cachedM0MaxMutationId",
2518
+ "cachedM0MaxMemoryMutationId",
2519
+ "cachedM0ProjectDocsHash",
2520
+ "cachedM0MaterializedAt",
2521
+ "cachedM0SessionFactsVersion",
2522
+ "cachedM0UpgradeState",
2523
+ "cachedM0ProjectIdentity",
2524
+ "lastObservedModelKey",
2525
+ "upgradeRemindedAt",
2526
+ "upgradeReminderLastSentAt",
2527
+ "piStableIdScheme"
2528
+ ]);
2529
+ function isStringOrNull(value) {
2530
+ return value === null || typeof value === "string";
2531
+ }
2532
+ function isNumberOrNull(value) {
2533
+ return value === null || typeof value === "number";
2534
+ }
2535
+ function isBlobOrNull(value) {
2536
+ return value === null || Buffer.isBuffer(value) || value instanceof Uint8Array;
2537
+ }
2538
+ function toBufferOrNull(value) {
2539
+ if (value === null)
2540
+ return null;
2541
+ if (Buffer.isBuffer(value))
2542
+ return value;
2543
+ return Buffer.from(value.buffer, value.byteOffset, value.byteLength);
2544
+ }
2545
+ function isSessionMetaRow(row) {
2546
+ if (row === null || typeof row !== "object")
2547
+ return false;
2548
+ const r = row;
2549
+ return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isStringOrNull(r.cached_m0_mural_data_url) && isStringOrNull(r.cached_m0_mural_hash) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isStringOrNull(r.cached_m0_workspace_fingerprint) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.cached_m0_project_identity) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.last_usage_context_limit) && isNumberOrNull(r.prior_boundary_ordinal) && isNumberOrNull(r.protected_tail_policy_version) && isNumberOrNull(r.protected_tail_drain_window_started_at) && isNumberOrNull(r.protected_tail_drain_tokens) && isNumberOrNull(r.recovery_no_eligible_head_count) && isNumberOrNull(r.force_emergency_bypass_window_start) && isNumberOrNull(r.force_emergency_bypass_used) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.upgrade_reminder_last_sent_at) && isNumberOrNull(r.upgrade_reminder_count) && isNumberOrNull(r.pi_stable_id_scheme) && isNumberOrNull(r.tool_reclaim_watermark);
2550
+ }
2551
+ function getDefaultSessionMeta(sessionId) {
2552
+ return {
2553
+ sessionId,
2554
+ lastResponseTime: 0,
2555
+ cacheTtl: "5m",
2556
+ counter: 0,
2557
+ lastNudgeTokens: 0,
2558
+ lastNudgeBand: null,
2559
+ lastTransformError: null,
2560
+ isSubagent: false,
2561
+ lastContextPercentage: 0,
2562
+ lastInputTokens: 0,
2563
+ observedSafeInputTokens: 0,
2564
+ cacheAlertSent: false,
2565
+ timesExecuteThresholdReached: 0,
2566
+ compartmentInProgress: false,
2567
+ systemPromptHash: "",
2568
+ systemPromptTokens: 0,
2569
+ conversationTokens: 0,
2570
+ toolCallTokens: 0,
2571
+ clearedReasoningThroughTag: 0,
2572
+ toolReclaimWatermark: 0,
2573
+ lastTodoState: "",
2574
+ cachedM0Bytes: null,
2575
+ cachedM0MuralDataUrl: null,
2576
+ cachedM0MuralHash: null,
2577
+ cachedM1Bytes: null,
2578
+ cachedM0ProjectMemoryEpoch: null,
2579
+ cachedM0WorkspaceFingerprint: null,
2580
+ cachedM0ProjectUserProfileVersion: null,
2581
+ cachedM0MaxCompartmentSeq: null,
2582
+ cachedM0MaxMemoryId: null,
2583
+ cachedM0MaxMutationId: null,
2584
+ cachedM0MaxMemoryMutationId: null,
2585
+ cachedM0ProjectDocsHash: null,
2586
+ cachedM0MaterializedAt: null,
2587
+ cachedM0SessionFactsVersion: null,
2588
+ cachedM0UpgradeState: null,
2589
+ cachedM0SystemHash: null,
2590
+ cachedM0ToolSetHash: null,
2591
+ cachedM0ModelKey: null,
2592
+ cachedM0ProjectIdentity: null,
2593
+ lastObservedModelKey: null,
2594
+ lastUsageContextLimit: 0,
2595
+ priorBoundaryOrdinal: 1,
2596
+ protectedTailPolicyVersion: 0,
2597
+ protectedTailDrainWindowStartedAt: 0,
2598
+ protectedTailDrainTokens: 0,
2599
+ recoveryNoEligibleHeadCount: 0,
2600
+ forceEmergencyBypassWindowStart: 0,
2601
+ forceEmergencyBypassUsed: 0,
2602
+ upgradeRemindedAt: null,
2603
+ upgradeReminderLastSentAt: null,
2604
+ upgradeReminderCount: 0,
2605
+ piStableIdScheme: null
2606
+ };
2607
+ }
2608
+ function ensureSessionMetaRow(db, sessionId) {
2609
+ const defaults = getDefaultSessionMeta(sessionId);
2610
+ db.prepare("INSERT OR IGNORE INTO session_meta (session_id, harness, last_response_time, cache_ttl, counter, last_nudge_tokens, last_nudge_band, last_transform_error, is_subagent, last_context_percentage, last_input_tokens, observed_safe_input_tokens, cache_alert_sent, times_execute_threshold_reached, compartment_in_progress, system_prompt_hash, cleared_reasoning_through_tag) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)").run(sessionId, getHarness(), defaults.lastResponseTime, defaults.cacheTtl, defaults.counter, defaults.lastNudgeTokens, defaults.lastNudgeBand ?? "", defaults.lastTransformError ?? "", defaults.isSubagent ? 1 : 0, defaults.lastContextPercentage, defaults.lastInputTokens, defaults.observedSafeInputTokens, defaults.cacheAlertSent ? 1 : 0, defaults.timesExecuteThresholdReached, defaults.compartmentInProgress ? 1 : 0, defaults.systemPromptHash ?? "", defaults.clearedReasoningThroughTag);
2611
+ }
2612
+ function toSessionMeta(row) {
2613
+ const nudgeBandRaw = typeof row.last_nudge_band === "string" ? row.last_nudge_band : "";
2614
+ const transformErrorRaw = typeof row.last_transform_error === "string" ? row.last_transform_error : "";
2615
+ const cacheTtlRaw = typeof row.cache_ttl === "string" && row.cache_ttl.length > 0 ? row.cache_ttl : "5m";
2616
+ const systemPromptHashRaw = row.system_prompt_hash == null ? "" : row.system_prompt_hash;
2617
+ const lastTodoStateRaw = typeof row.last_todo_state === "string" ? row.last_todo_state : "";
2618
+ const numOrZero = (value) => typeof value === "number" ? value : 0;
2619
+ const numOrNull = (value) => typeof value === "number" ? value : null;
2620
+ const stringOrNull = (value) => typeof value === "string" ? value : null;
2621
+ return {
2622
+ sessionId: row.session_id,
2623
+ lastResponseTime: row.last_response_time,
2624
+ cacheTtl: cacheTtlRaw,
2625
+ counter: row.counter,
2626
+ lastNudgeTokens: row.last_nudge_tokens,
2627
+ lastNudgeBand: nudgeBandRaw.length > 0 ? nudgeBandRaw : null,
2628
+ lastTransformError: transformErrorRaw.length > 0 ? transformErrorRaw : null,
2629
+ isSubagent: row.is_subagent === 1,
2630
+ lastContextPercentage: row.last_context_percentage,
2631
+ lastInputTokens: row.last_input_tokens,
2632
+ observedSafeInputTokens: numOrZero(row.observed_safe_input_tokens),
2633
+ cacheAlertSent: numOrZero(row.cache_alert_sent) === 1,
2634
+ timesExecuteThresholdReached: numOrZero(row.times_execute_threshold_reached),
2635
+ compartmentInProgress: row.compartment_in_progress === 1,
2636
+ systemPromptHash: String(systemPromptHashRaw),
2637
+ systemPromptTokens: numOrZero(row.system_prompt_tokens),
2638
+ conversationTokens: numOrZero(row.conversation_tokens),
2639
+ toolCallTokens: numOrZero(row.tool_call_tokens),
2640
+ clearedReasoningThroughTag: numOrZero(row.cleared_reasoning_through_tag),
2641
+ toolReclaimWatermark: numOrZero(row.tool_reclaim_watermark),
2642
+ lastTodoState: lastTodoStateRaw,
2643
+ cachedM0Bytes: toBufferOrNull(row.cached_m0_bytes),
2644
+ cachedM0MuralDataUrl: stringOrNull(row.cached_m0_mural_data_url),
2645
+ cachedM0MuralHash: stringOrNull(row.cached_m0_mural_hash),
2646
+ cachedM1Bytes: toBufferOrNull(row.cached_m1_bytes),
2647
+ cachedM0ProjectMemoryEpoch: numOrNull(row.cached_m0_project_memory_epoch),
2648
+ cachedM0WorkspaceFingerprint: stringOrNull(row.cached_m0_workspace_fingerprint),
2649
+ cachedM0ProjectUserProfileVersion: numOrNull(row.cached_m0_project_user_profile_version),
2650
+ cachedM0MaxCompartmentSeq: numOrNull(row.cached_m0_max_compartment_seq),
2651
+ cachedM0MaxMemoryId: numOrNull(row.cached_m0_max_memory_id),
2652
+ cachedM0MaxMutationId: numOrNull(row.cached_m0_max_mutation_id),
2653
+ cachedM0MaxMemoryMutationId: numOrNull(row.cached_m0_max_memory_mutation_id),
2654
+ cachedM0ProjectDocsHash: stringOrNull(row.cached_m0_project_docs_hash),
2655
+ cachedM0MaterializedAt: numOrNull(row.cached_m0_materialized_at),
2656
+ cachedM0SessionFactsVersion: numOrNull(row.cached_m0_session_facts_version),
2657
+ cachedM0UpgradeState: stringOrNull(row.cached_m0_upgrade_state),
2658
+ cachedM0SystemHash: stringOrNull(row.cached_m0_system_hash),
2659
+ cachedM0ToolSetHash: stringOrNull(row.cached_m0_tool_set_hash),
2660
+ cachedM0ModelKey: stringOrNull(row.cached_m0_model_key),
2661
+ cachedM0ProjectIdentity: stringOrNull(row.cached_m0_project_identity),
2662
+ lastObservedModelKey: stringOrNull(row.last_observed_model_key),
2663
+ lastUsageContextLimit: numOrZero(row.last_usage_context_limit),
2664
+ priorBoundaryOrdinal: Math.max(1, numOrZero(row.prior_boundary_ordinal) || 1),
2665
+ protectedTailPolicyVersion: numOrZero(row.protected_tail_policy_version),
2666
+ protectedTailDrainWindowStartedAt: numOrZero(row.protected_tail_drain_window_started_at),
2667
+ protectedTailDrainTokens: numOrZero(row.protected_tail_drain_tokens),
2668
+ recoveryNoEligibleHeadCount: numOrZero(row.recovery_no_eligible_head_count),
2669
+ forceEmergencyBypassWindowStart: numOrZero(row.force_emergency_bypass_window_start),
2670
+ forceEmergencyBypassUsed: numOrZero(row.force_emergency_bypass_used),
2671
+ upgradeRemindedAt: numOrNull(row.upgrade_reminded_at),
2672
+ upgradeReminderLastSentAt: numOrNull(row.upgrade_reminder_last_sent_at),
2673
+ upgradeReminderCount: numOrZero(row.upgrade_reminder_count),
2674
+ piStableIdScheme: numOrNull(row.pi_stable_id_scheme)
2675
+ };
2676
+ }
2677
+ function persistCachedM0(db, sessionId, payload) {
2678
+ ensureSessionMetaRow(db, sessionId);
2679
+ db.prepare(`UPDATE session_meta SET
2680
+ cached_m0_bytes = ?,
2681
+ cached_m0_mural_data_url = ?,
2682
+ cached_m0_mural_hash = ?,
2683
+ cached_m0_project_memory_epoch = ?,
2684
+ cached_m0_workspace_fingerprint = ?,
2685
+ cached_m0_project_user_profile_version = ?,
2686
+ cached_m0_max_compartment_seq = ?,
2687
+ cached_m0_max_memory_id = ?,
2688
+ cached_m0_max_mutation_id = ?,
2689
+ cached_m0_max_memory_mutation_id = ?,
2690
+ cached_m1_bytes = ?,
2691
+ cached_m0_project_docs_hash = ?,
2692
+ cached_m0_materialized_at = ?,
2693
+ cached_m0_session_facts_version = ?,
2694
+ cached_m0_upgrade_state = ?,
2695
+ cached_m0_system_hash = ?,
2696
+ cached_m0_model_key = ?,
2697
+ cached_m0_project_identity = ?
2698
+ WHERE session_id = ?`).run(Buffer.from(payload.m0Bytes), payload.muralDataUrl ?? null, payload.muralHash ?? null, payload.projectMemoryEpoch, payload.workspaceFingerprint ?? null, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, payload.systemHash ?? "", payload.modelKey ?? "", payload.projectIdentity ?? null, sessionId);
2699
+ }
2700
+ function clearCachedM0M1(db, sessionId) {
2701
+ ensureSessionMetaRow(db, sessionId);
2702
+ const existingColumns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
2703
+ const clears = [
2704
+ ["cached_m0_bytes", null],
2705
+ ["cached_m0_mural_data_url", null],
2706
+ ["cached_m0_mural_hash", null],
2707
+ ["cached_m1_bytes", null],
2708
+ ["cached_m0_project_memory_epoch", null],
2709
+ ["cached_m0_workspace_fingerprint", null],
2710
+ ["cached_m0_project_user_profile_version", null],
2711
+ ["cached_m0_max_compartment_seq", null],
2712
+ ["cached_m0_max_memory_id", null],
2713
+ ["cached_m0_max_mutation_id", null],
2714
+ ["cached_m0_max_memory_mutation_id", null],
2715
+ ["cached_m0_project_docs_hash", null],
2716
+ ["cached_m0_materialized_at", null],
2717
+ ["cached_m0_session_facts_version", null],
2718
+ ["cached_m0_upgrade_state", null],
2719
+ ["cached_m0_system_hash", null],
2720
+ ["cached_m0_tool_set_hash", null],
2721
+ ["cached_m0_model_key", null],
2722
+ ["cached_m0_project_identity", null],
2723
+ ["cached_m0_last_baseline_end_message_id", null],
2724
+ ["memory_block_cache", ""],
2725
+ ["memory_block_count", 0],
2726
+ ["memory_block_ids", ""]
2727
+ ];
2728
+ const setClauses = [];
2729
+ const values = [];
2730
+ for (const [column, value] of clears) {
2731
+ if (!existingColumns.has(column))
2732
+ continue;
2733
+ setClauses.push(`${column} = ?`);
2734
+ values.push(value);
2735
+ }
2736
+ if (setClauses.length === 0)
2737
+ return;
2738
+ db.prepare(`UPDATE session_meta SET ${setClauses.join(", ")} WHERE session_id = ?`).run(...values, sessionId);
2739
+ }
2740
+
2741
+ // src/features/magic-context/storage-meta-session.ts
2742
+ var SESSION_META_FALLBACK_SELECTS = {
2743
+ cache_ttl: "'5m' AS cache_ttl",
2744
+ last_nudge_band: "'' AS last_nudge_band",
2745
+ last_transform_error: "'' AS last_transform_error",
2746
+ system_prompt_hash: "'' AS system_prompt_hash",
2747
+ last_todo_state: "'' AS last_todo_state",
2748
+ tool_reclaim_watermark: "0 AS tool_reclaim_watermark",
2749
+ cached_m0_bytes: "NULL AS cached_m0_bytes",
2750
+ cached_m0_mural_data_url: "NULL AS cached_m0_mural_data_url",
2751
+ cached_m0_mural_hash: "NULL AS cached_m0_mural_hash",
2752
+ cached_m1_bytes: "NULL AS cached_m1_bytes",
2753
+ cached_m0_project_memory_epoch: "NULL AS cached_m0_project_memory_epoch",
2754
+ cached_m0_project_user_profile_version: "NULL AS cached_m0_project_user_profile_version",
2755
+ cached_m0_max_compartment_seq: "NULL AS cached_m0_max_compartment_seq",
2756
+ cached_m0_max_memory_id: "NULL AS cached_m0_max_memory_id",
2757
+ cached_m0_max_mutation_id: "NULL AS cached_m0_max_mutation_id",
2758
+ cached_m0_max_memory_mutation_id: "NULL AS cached_m0_max_memory_mutation_id",
2759
+ cached_m0_project_docs_hash: "NULL AS cached_m0_project_docs_hash",
2760
+ cached_m0_materialized_at: "NULL AS cached_m0_materialized_at",
2761
+ cached_m0_session_facts_version: "NULL AS cached_m0_session_facts_version",
2762
+ cached_m0_upgrade_state: "NULL AS cached_m0_upgrade_state",
2763
+ cached_m0_system_hash: "NULL AS cached_m0_system_hash",
2764
+ cached_m0_tool_set_hash: "NULL AS cached_m0_tool_set_hash",
2765
+ cached_m0_model_key: "NULL AS cached_m0_model_key",
2766
+ cached_m0_project_identity: "NULL AS cached_m0_project_identity",
2767
+ last_observed_model_key: "NULL AS last_observed_model_key",
2768
+ upgrade_reminded_at: "NULL AS upgrade_reminded_at",
2769
+ upgrade_reminder_last_sent_at: "NULL AS upgrade_reminder_last_sent_at",
2770
+ upgrade_reminder_count: "0 AS upgrade_reminder_count"
2771
+ };
2772
+ var sessionMetaSelectColumnsCache = new WeakMap;
2773
+ function getSessionMetaSelectColumns(db) {
2774
+ const cached = sessionMetaSelectColumnsCache.get(db);
2775
+ if (cached !== undefined)
2776
+ return cached;
2777
+ const existingColumns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
2778
+ const projection = SESSION_META_SELECT_COLUMNS.map((column) => {
2779
+ if (existingColumns.has(column))
2780
+ return column;
2781
+ return SESSION_META_FALLBACK_SELECTS[column] ?? `0 AS ${column}`;
2782
+ }).join(", ");
2783
+ sessionMetaSelectColumnsCache.set(db, projection);
2784
+ return projection;
2785
+ }
2786
+ function getOrCreateSessionMeta(db, sessionId) {
2787
+ const result = db.prepare(`SELECT ${getSessionMetaSelectColumns(db)} FROM session_meta WHERE session_id = ?`).get(sessionId);
2788
+ if (isSessionMetaRow(result)) {
2789
+ return toSessionMeta(result);
2790
+ }
2791
+ const defaults = getDefaultSessionMeta(sessionId);
2792
+ const fallbackSubagent = getHarness() === "opencode" ? resolveIsSubagentFromOpenCodeDb(sessionId) : null;
2793
+ if (fallbackSubagent === true) {
2794
+ defaults.isSubagent = true;
2795
+ }
2796
+ ensureSessionMetaRow(db, sessionId);
2797
+ if (fallbackSubagent === true) {
2798
+ db.prepare("UPDATE session_meta SET is_subagent = 1 WHERE session_id = ?").run(sessionId);
2799
+ }
2800
+ return defaults;
2801
+ }
2802
+ function updateSessionMeta(db, sessionId, updates) {
2803
+ const setClauses = [];
2804
+ const values = [];
2805
+ for (const [key, column] of Object.entries(META_COLUMNS)) {
2806
+ const value = updates[key];
2807
+ if (value === undefined)
2808
+ continue;
2809
+ if (value === null) {
2810
+ setClauses.push(`${column} = ?`);
2811
+ values.push(NULL_BIND_META_KEYS.has(key) ? null : "");
2812
+ } else if ((key === "cachedM0Bytes" || key === "cachedM1Bytes") && value instanceof Uint8Array) {
2813
+ setClauses.push(`${column} = ?`);
2814
+ values.push(Buffer2.from(value.buffer, value.byteOffset, value.byteLength));
2815
+ } else if (BOOLEAN_META_KEYS.has(key)) {
2816
+ setClauses.push(`${column} = ?`);
2817
+ values.push(value ? 1 : 0);
2818
+ } else if (typeof value === "string" || typeof value === "number") {
2819
+ setClauses.push(`${column} = ?`);
2820
+ values.push(value);
2821
+ }
2822
+ }
2823
+ if (setClauses.length === 0) {
2824
+ return;
2825
+ }
2826
+ db.transaction(() => {
2827
+ ensureSessionMetaRow(db, sessionId);
2828
+ db.prepare(`UPDATE session_meta SET ${setClauses.join(", ")} WHERE session_id = ?`).run(...values, sessionId);
2829
+ })();
2830
+ }
2831
+ function advanceToolReclaimWatermark(db, sessionId, maxTagNumber) {
2832
+ if (maxTagNumber <= 0)
2833
+ return;
2834
+ db.transaction(() => {
2835
+ ensureSessionMetaRow(db, sessionId);
2836
+ db.prepare("UPDATE session_meta SET tool_reclaim_watermark = MAX(COALESCE(tool_reclaim_watermark, 0), ?) WHERE session_id = ?").run(maxTagNumber, sessionId);
2837
+ })();
2838
+ }
2839
+ function markSessionCleanupPending(db, sessionId) {
2840
+ db.prepare(`INSERT INTO pending_session_cleanup (session_id, harness, requested_at, last_attempt_at)
2841
+ VALUES (?, ?, ?, NULL)
2842
+ ON CONFLICT(session_id) DO UPDATE SET
2843
+ harness = excluded.harness,
2844
+ requested_at = MIN(pending_session_cleanup.requested_at, excluded.requested_at)`).run(sessionId, getHarness(), Date.now());
2845
+ }
2846
+ function retryPendingSessionCleanups(db, limit = 200) {
2847
+ const rows = db.prepare("SELECT session_id FROM pending_session_cleanup ORDER BY requested_at ASC, session_id ASC LIMIT ?").all(Math.max(1, Math.floor(limit)));
2848
+ const failedSessionIds = [];
2849
+ let cleared = 0;
2850
+ for (const row of rows) {
2851
+ try {
2852
+ db.prepare("UPDATE pending_session_cleanup SET last_attempt_at = ? WHERE session_id = ?").run(Date.now(), row.session_id);
2853
+ clearSession(db, row.session_id);
2854
+ cleared += 1;
2855
+ } catch {
2856
+ failedSessionIds.push(row.session_id);
2857
+ }
2858
+ }
2859
+ return { attempted: rows.length, cleared, failedSessionIds };
2860
+ }
2861
+ function clearSession(db, sessionId) {
2862
+ db.transaction(() => {
2863
+ db.prepare("DELETE FROM pending_ops WHERE session_id = ?").run(sessionId);
2864
+ db.prepare("DELETE FROM source_contents WHERE session_id = ?").run(sessionId);
2865
+ db.prepare("DELETE FROM tool_owner_backfill_state WHERE session_id = ?").run(sessionId);
2866
+ db.prepare("DELETE FROM tags WHERE session_id = ?").run(sessionId);
2867
+ db.prepare("DELETE FROM session_meta WHERE session_id = ?").run(sessionId);
2868
+ db.prepare("DELETE FROM session_projects WHERE session_id = ?").run(sessionId);
2869
+ db.prepare("DELETE FROM compartment_chunk_embeddings WHERE session_id = ?").run(sessionId);
2870
+ db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
2871
+ clearCompressionDepth(db, sessionId);
2872
+ db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
2873
+ db.prepare("DELETE FROM compartment_state_lease WHERE session_id = ?").run(sessionId);
2874
+ db.prepare("DELETE FROM notes WHERE session_id = ? AND type = 'session'").run(sessionId);
2875
+ db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
2876
+ db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
2877
+ db.prepare("DELETE FROM user_memory_candidates WHERE session_id = ?").run(sessionId);
2878
+ db.prepare("DELETE FROM primer_candidates WHERE session_id = ?").run(sessionId);
2879
+ db.prepare("DELETE FROM m0_mutation_log WHERE session_id = ?").run(sessionId);
2880
+ db.prepare("DELETE FROM compartment_events WHERE session_id = ?").run(sessionId);
2881
+ db.prepare("DELETE FROM subagent_invocations WHERE session_id = ?").run(sessionId);
2882
+ db.prepare("DELETE FROM historian_runs WHERE session_id = ?").run(sessionId);
2883
+ db.prepare("DELETE FROM plugin_messages WHERE session_id = ?").run(sessionId);
2884
+ db.prepare("DELETE FROM transform_decisions WHERE session_id = ?").run(sessionId);
2885
+ db.prepare("DELETE FROM synapse_batch_ledger WHERE session_id = ?").run(sessionId);
2886
+ db.prepare("DELETE FROM embedding_measurement_corpus WHERE session_id = ?").run(sessionId);
2887
+ db.prepare("DELETE FROM pending_session_cleanup WHERE session_id = ?").run(sessionId);
2888
+ clearIndexedMessages(db, sessionId);
2889
+ })();
2890
+ }
2891
+
2892
+ export { textMentionsRecentCommit, hasMeaningfulUserText, extractTexts, extractToolCallSummaries, estimateTokens, normalizeText, stableStringify, clearCompressionDepth, clearCompressionDepthRange, ensureSessionMetaRow, persistCachedM0, clearCachedM0M1, isRawCompactionSummaryInfo, extractInMemoryMessageViews, buildInMemoryTailRawMessages, isRecord, completedToolArcCrossesBoundary, estimateTrueRawMessageTokens, buildToolArcs, fenceBoundaryForToolArcs, buildTrueRawTokenIndex, computeRawRangeFingerprint, invalidateTrueRawTokenCache, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isThinkingPart, isTextPart, isToolPartWithOutput, isFilePart, buildFileSourceContent, isEditTool, partHasCompletedResult, extractToolCallObservation, ToolMutationBatch, createToolDropTarget, setRawMessageProvider, cleanUserText, withRawSessionMessageCache, readRawSessionMessages, primeTailRawMessageCache, getCachedAbsoluteMessageCount, primeInMemoryTailRawMessageCache, readRawSessionMessageOrdinalPage, getRawSessionStoredMessageCount, readRawSessionMessagePartsById, readRawSessionMessageOrdinalById, readRawSessionMessageById, getRawSessionMessageCount, getRawSessionTagKeysThrough, getLegacyProtectedTailStartOrdinal, readSessionChunk, getMessageIndexSourceIdentity, isMessageIndexSourceCurrent, getLastIndexedOrdinal, getIndexedMessageCorpusSize, getMessageIndexReconciliationStartOrdinal, isMessageIndexReconciledThrough, deleteIndexedMessage, clearIndexedMessages, indexSingleMessage, indexMessagesAfterOrdinal, sweepOrphanedOpenCodeMessageIndexes, getOrCreateSessionMeta, updateSessionMeta, advanceToolReclaimWatermark, markSessionCleanupPending, retryPendingSessionCleanups, clearSession };