@cortexkit/opencode-magic-context 0.33.1 → 0.34.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 (205) hide show
  1. package/dist/config/agent-disable.d.ts +22 -0
  2. package/dist/config/agent-disable.d.ts.map +1 -1
  3. package/dist/config/index.d.ts.map +1 -1
  4. package/dist/config/project-security.d.ts +7 -0
  5. package/dist/config/project-security.d.ts.map +1 -1
  6. package/dist/config/schema/magic-context.d.ts +82 -2
  7. package/dist/config/schema/magic-context.d.ts.map +1 -1
  8. package/dist/config/transform-mode.d.ts +2 -0
  9. package/dist/config/transform-mode.d.ts.map +1 -1
  10. package/dist/{conflict-warning-hook-n48c783v.js → conflict-warning-hook-fvpfvt0w.js} +1 -1
  11. package/dist/{derive-budgets-e9j09sjr.js → derive-budgets-9crp0cvd.js} +1 -1
  12. package/dist/features/builtin-commands/commands.d.ts +1 -1
  13. package/dist/features/builtin-commands/commands.d.ts.map +1 -1
  14. package/dist/features/magic-context/compaction-marker.d.ts +57 -0
  15. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  16. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  17. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  18. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  19. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  21. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  23. package/dist/features/magic-context/fail-closed-block.d.ts +10 -0
  24. package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
  25. package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -1
  26. package/dist/features/magic-context/git-commits/storage-git-commits.d.ts.map +1 -1
  27. package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -1
  28. package/dist/features/magic-context/memory/embedding-local.d.ts +7 -1
  29. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  30. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
  31. package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
  32. package/dist/features/magic-context/memory/project-identity.d.ts +2 -6
  33. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  34. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
  35. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  36. package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
  37. package/dist/features/magic-context/mural/render-mural.d.ts.map +1 -1
  38. package/dist/features/magic-context/overflow-detection.d.ts +8 -1
  39. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  40. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  41. package/dist/features/magic-context/scheduler.d.ts.map +1 -1
  42. package/dist/features/magic-context/schema-fence-probe.d.ts +28 -0
  43. package/dist/features/magic-context/schema-fence-probe.d.ts.map +1 -0
  44. package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
  45. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
  46. package/dist/features/magic-context/storage-db.d.ts +35 -1
  47. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  48. package/dist/features/magic-context/storage-meta-persisted.d.ts +38 -4
  49. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  50. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  51. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  52. package/dist/features/magic-context/storage.d.ts +1 -1
  53. package/dist/features/magic-context/storage.d.ts.map +1 -1
  54. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
  55. package/dist/hooks/magic-context/boundary-execution.d.ts +1 -1
  56. package/dist/hooks/magic-context/boundary-execution.d.ts.map +1 -1
  57. package/dist/hooks/magic-context/cache-busting-signals.d.ts +1 -0
  58. package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
  59. package/dist/hooks/magic-context/child-session-spawn.d.ts +26 -0
  60. package/dist/hooks/magic-context/child-session-spawn.d.ts.map +1 -0
  61. package/dist/hooks/magic-context/command-handler.d.ts +2 -0
  62. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  63. package/dist/hooks/magic-context/compaction-off-transition.d.ts +96 -0
  64. package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -0
  65. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +2 -0
  66. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  67. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  68. package/dist/hooks/magic-context/compartment-runner-mapping.d.ts.map +1 -1
  69. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  70. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  71. package/dist/hooks/magic-context/compartment-trigger.d.ts +12 -5
  72. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  73. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +47 -1
  74. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
  75. package/dist/hooks/magic-context/emergency-drop.d.ts +2 -2
  76. package/dist/hooks/magic-context/event-handler.d.ts +7 -0
  77. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  78. package/dist/hooks/magic-context/event-resolvers.d.ts +13 -21
  79. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  80. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
  81. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  82. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +1 -1
  83. package/dist/hooks/magic-context/hook-handlers.d.ts +1 -0
  84. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  85. package/dist/hooks/magic-context/hook.d.ts +11 -1
  86. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  87. package/dist/hooks/magic-context/inject-compartments.d.ts +9 -0
  88. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  89. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  90. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  91. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  92. package/dist/hooks/magic-context/rust-mode-transform.d.ts +3 -0
  93. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  94. package/dist/hooks/magic-context/send-session-notification.d.ts +20 -1
  95. package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
  96. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +3 -0
  97. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  98. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +30 -0
  99. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  100. package/dist/hooks/magic-context/transform.d.ts +27 -0
  101. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  102. package/dist/{index-ey1bc14z.js → index-b563sga5.js} +7 -264
  103. package/dist/{index-y1c9tcm3.js → index-cn960ffd.js} +101 -20
  104. package/dist/{index-xyaekybw.js → index-dtas91s5.js} +6 -4
  105. package/dist/index-fcyvznch.js +279 -0
  106. package/dist/{index-63dq2g4d.js → index-ry8rh8cv.js} +138 -24
  107. package/dist/{index-c2gahrks.js → index-s0mdn690.js} +1599 -892
  108. package/dist/index.d.ts.map +1 -1
  109. package/dist/index.js +1292 -623
  110. package/dist/plugin/embedding-bootstrap.d.ts.map +1 -1
  111. package/dist/plugin/hooks/create-session-hooks.d.ts +11 -0
  112. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  113. package/dist/plugin/messages-transform.d.ts +10 -0
  114. package/dist/plugin/messages-transform.d.ts.map +1 -1
  115. package/dist/plugin/rpc-handlers.d.ts +3 -7
  116. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  117. package/dist/plugin/tool-registry.d.ts +8 -0
  118. package/dist/plugin/tool-registry.d.ts.map +1 -1
  119. package/dist/{recomp-orchestrator-2yb2hfh2.js → recomp-orchestrator-8e82vmvb.js} +6 -4
  120. package/dist/send-session-notification-6njqewzk.js +20 -0
  121. package/dist/shared/conflict-detector.d.ts +38 -1
  122. package/dist/shared/conflict-detector.d.ts.map +1 -1
  123. package/dist/shared/conflict-fixer.d.ts +18 -1
  124. package/dist/shared/conflict-fixer.d.ts.map +1 -1
  125. package/dist/shared/context-limit-provenance.d.ts +3 -0
  126. package/dist/shared/context-limit-provenance.d.ts.map +1 -0
  127. package/dist/shared/escalation-bands.d.ts +9 -0
  128. package/dist/shared/escalation-bands.d.ts.map +1 -0
  129. package/dist/shared/format-threshold.d.ts +1 -1
  130. package/dist/shared/models-dev-cache.d.ts +29 -3
  131. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  132. package/dist/shared/rpc-server.d.ts.map +1 -1
  133. package/dist/shared/rpc-types.d.ts +46 -1
  134. package/dist/shared/rpc-types.d.ts.map +1 -1
  135. package/dist/shared/storage-permissions.d.ts +5 -0
  136. package/dist/shared/storage-permissions.d.ts.map +1 -0
  137. package/dist/{storage-meta-session-td6bwtky.js → storage-meta-session-xt41zbw4.js} +2 -1
  138. package/dist/tui/compaction-off.d.ts +13 -0
  139. package/dist/tui/compaction-off.d.ts.map +1 -0
  140. package/dist/tui/data/context-db.d.ts.map +1 -1
  141. package/dist/tui-compiled/compaction-off.d.ts +13 -0
  142. package/dist/tui-compiled/compaction-off.d.ts.map +1 -0
  143. package/dist/tui-compiled/data/context-db.d.ts.map +1 -1
  144. package/package.json +7 -2
  145. package/src/agents/dreamer.ts +68 -0
  146. package/src/agents/hidden-agent-registrations.ts +331 -0
  147. package/src/agents/historian.ts +3 -0
  148. package/src/agents/language-directive.test.ts +138 -0
  149. package/src/agents/language-directive.ts +121 -0
  150. package/src/agents/magic-context-prompt.language.test.ts +35 -0
  151. package/src/agents/magic-context-prompt.test.ts +292 -0
  152. package/src/agents/magic-context-prompt.ts +182 -0
  153. package/src/agents/permissions.test.ts +252 -0
  154. package/src/agents/permissions.ts +186 -0
  155. package/src/agents/sidekick.ts +1 -0
  156. package/src/agents/smart-note-compiler.ts +1 -0
  157. package/src/config/agent-disable.ts +106 -0
  158. package/src/config/compaction-accessor-guard.test.ts +82 -0
  159. package/src/config/compaction-backcompat.test.ts +52 -0
  160. package/src/config/index.test.ts +904 -0
  161. package/src/config/index.ts +601 -0
  162. package/src/config/migrate-config-location.test.ts +332 -0
  163. package/src/config/migrate-config-location.ts +635 -0
  164. package/src/config/migrate-dreamer-v2.test.ts +287 -0
  165. package/src/config/migrate-dreamer-v2.ts +336 -0
  166. package/src/config/migrate-experimental.ts +159 -0
  167. package/src/config/project-security.test.ts +366 -0
  168. package/src/config/project-security.ts +588 -0
  169. package/src/config/prune-config-leaf.test.ts +78 -0
  170. package/src/config/prune-config-leaf.ts +68 -0
  171. package/src/config/removed-config-keys.test.ts +116 -0
  172. package/src/config/schema/agent-overrides.ts +45 -0
  173. package/src/config/schema/magic-context.test.ts +358 -0
  174. package/src/config/schema/magic-context.ts +1002 -0
  175. package/src/config/transform-mode.test.ts +62 -0
  176. package/src/config/transform-mode.ts +34 -0
  177. package/src/config/variable.test.ts +323 -0
  178. package/src/config/variable.ts +192 -0
  179. package/src/features/magic-context/defaults.ts +1 -0
  180. package/src/features/magic-context/dreamer/cron.ts +243 -0
  181. package/src/features/magic-context/dreamer/task-registry.ts +104 -0
  182. package/src/shared/conflict-detector.test.ts +121 -0
  183. package/src/shared/conflict-detector.ts +50 -3
  184. package/src/shared/conflict-fixer.test.ts +309 -0
  185. package/src/shared/conflict-fixer.ts +82 -5
  186. package/src/shared/context-limit-provenance.ts +6 -0
  187. package/src/shared/escalation-bands.test.ts +23 -0
  188. package/src/shared/escalation-bands.ts +18 -0
  189. package/src/shared/format-threshold.ts +1 -1
  190. package/src/shared/models-dev-cache.test.ts +171 -0
  191. package/src/shared/models-dev-cache.ts +195 -38
  192. package/src/shared/rpc-server.ts +27 -18
  193. package/src/shared/rpc-types.ts +46 -1
  194. package/src/shared/storage-permissions.ts +20 -0
  195. package/src/tui/compaction-off.test.ts +56 -0
  196. package/src/tui/compaction-off.ts +29 -0
  197. package/src/tui/data/context-db.ts +6 -0
  198. package/src/tui/index.tsx +113 -65
  199. package/src/tui/slots/sidebar-content.tsx +139 -83
  200. package/src/tui-compiled/compaction-off.ts +29 -0
  201. package/src/tui-compiled/data/context-db.ts +6 -0
  202. package/src/tui-compiled/index.tsx +558 -455
  203. package/src/tui-compiled/slots/sidebar-content.tsx +237 -161
  204. package/dist/send-session-notification-tghq9gnh.js +0 -11
  205. /package/dist/{index-v7fmc1s2.js → index-ygcng9t8.js} +0 -0
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  deriveTriggerBudget,
3
- modelSupportsVision
4
- } from "./index-63dq2g4d.js";
3
+ modelSupportsVision,
4
+ piModelRefToCanonical,
5
+ shouldEnforcePrivateStoragePermissions
6
+ } from "./index-ry8rh8cv.js";
5
7
  import {
6
8
  parseProviderModel
7
9
  } from "./index-td9depx5.js";
@@ -9,18 +11,15 @@ import {
9
11
  describeError,
10
12
  getErrorMessage,
11
13
  sendIgnoredMessage
12
- } from "./index-y1c9tcm3.js";
14
+ } from "./index-cn960ffd.js";
13
15
  import {
14
- Database,
15
16
  clearCachedM0M1,
16
17
  clearCompressionDepth,
17
18
  clearCompressionDepthRange,
18
- closeQuietly,
19
19
  ensureSessionMetaRow,
20
20
  estimateTokens,
21
21
  getCachedAbsoluteMessageCount,
22
22
  getLegacyProtectedTailStartOrdinal,
23
- getMessageTimesFromOpenCodeDb,
24
23
  getRawSessionMessageCount,
25
24
  getRawSessionTagKeysThrough,
26
25
  hasMeaningfulUserText,
@@ -29,9 +28,17 @@ import {
29
28
  persistCachedM0,
30
29
  readRawSessionMessages,
31
30
  readSessionChunk,
32
- updateSessionMeta,
31
+ updateSessionMeta
32
+ } from "./index-b563sga5.js";
33
+ import {
34
+ Database,
35
+ closeQuietly,
36
+ getMessageTimesFromOpenCodeDb,
33
37
  withPrivilegedWriter
34
- } from "./index-ey1bc14z.js";
38
+ } from "./index-fcyvznch.js";
39
+ import {
40
+ pushNotification
41
+ } from "./index-d62ypazr.js";
35
42
  import {
36
43
  log,
37
44
  sessionLog
@@ -372,462 +379,95 @@ function buildPrimaryLanguageDirective(language) {
372
379
  return "";
373
380
  return `Use ${target} for your natural-language replies to the user unless the user explicitly asks for another language. Keep code, identifiers, file paths, commands, logs, and quoted text verbatim.`;
374
381
  }
375
- // src/features/magic-context/overflow-detection.ts
376
- var OVERFLOW_PATTERNS = [
377
- /prompt is too long/i,
378
- /input is too long for requested model/i,
379
- /exceeds the context window/i,
380
- /input token count.*exceeds the maximum/i,
381
- /maximum prompt length is \d+/i,
382
- /reduce the length of the messages/i,
383
- /maximum context length is \d+ tokens/i,
384
- /exceeds the limit of \d+/i,
385
- /exceeds the available context size/i,
386
- /greater than the context length/i,
387
- /context window exceeds limit/i,
388
- /exceeded model token limit/i,
389
- /context[_ ]length[_ ]exceeded/i,
390
- /request entity too large/i,
391
- /context length is only \d+ tokens/i,
392
- /input length.*exceeds.*context length/i,
393
- /prompt too long; exceeded (?:max )?context length/i,
394
- /too large for model with \d+ maximum context length/i,
395
- /model_context_window_exceeded/i,
396
- /context size has been exceeded/i
397
- ];
398
- var LIMIT_EXTRACTION_PATTERNS = [
399
- /maximum prompt length is (\d+)/i,
400
- /maximum context length is (\d+) tokens?/i,
401
- /context length is only (\d+) tokens?/i,
402
- /exceeds the limit of (\d+)/i,
403
- /too large for model with (\d+) maximum context length/i,
404
- /context size.*(\d+) tokens?/i,
405
- /exceeds? the context length of (\d+)/i,
406
- />\s*(\d+)\s*(?:tokens?\s*)?(?:maximum|max|limit)\b/i,
407
- /max(?:imum)?.*context.*?(\d+)/i
408
- ];
409
- var MIN_PLAUSIBLE_LIMIT = 1024;
410
- var MAX_PLAUSIBLE_LIMIT = 1e7;
411
- function extractErrorMessage(error) {
412
- if (!error)
413
- return "";
414
- if (typeof error === "string")
415
- return error;
416
- if (typeof error === "object") {
417
- const obj = error;
418
- const nested = obj.error;
419
- if (nested && typeof nested.message === "string" && nested.message.length > 0) {
420
- return nested.message;
421
- }
422
- }
423
- if (error instanceof Error)
424
- return error.message;
425
- if (typeof error === "object") {
426
- const obj = error;
427
- if (typeof obj.message === "string")
428
- return obj.message;
429
- if (typeof obj.responseBody === "string")
430
- return obj.responseBody;
431
- try {
432
- return JSON.stringify(error);
433
- } catch {
434
- return String(error);
435
- }
436
- }
437
- return String(error);
382
+
383
+ // src/features/magic-context/storage-db.ts
384
+ import {
385
+ chmodSync,
386
+ copyFileSync,
387
+ cpSync,
388
+ existsSync as existsSync3,
389
+ mkdirSync,
390
+ mkdtempSync,
391
+ readdirSync,
392
+ readFileSync,
393
+ unlinkSync
394
+ } from "node:fs";
395
+ import { basename, dirname, join as join3 } from "node:path";
396
+
397
+ // src/plugin/boot-quiet.ts
398
+ var BOOT_QUIET_MS = 120000;
399
+ var bootQuietUntilMs = 0;
400
+ function beginBootQuietPeriod(now = Date.now()) {
401
+ if (bootQuietUntilMs === 0)
402
+ bootQuietUntilMs = now + BOOT_QUIET_MS;
438
403
  }
439
- function detectOverflow(error) {
440
- const message = extractErrorMessage(error);
441
- if (!message) {
442
- return { isOverflow: false };
443
- }
444
- const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
445
- let matched;
446
- for (const pattern of OVERFLOW_PATTERNS) {
447
- if (pattern.test(message)) {
448
- matched = pattern;
449
- break;
450
- }
451
- }
452
- if (!matched && !hasStatus413) {
453
- return { isOverflow: false };
454
- }
455
- const reportedLimit = parseReportedLimit(message);
456
- return {
457
- isOverflow: true,
458
- reportedLimit,
459
- matchedPattern: matched?.source
460
- };
404
+ function bootQuietRemainingMs(now = Date.now()) {
405
+ return Math.max(0, bootQuietUntilMs - now);
461
406
  }
462
- function parseReportedLimit(message) {
463
- if (!message)
464
- return;
465
- for (const pattern of LIMIT_EXTRACTION_PATTERNS) {
466
- const match = message.match(pattern);
467
- if (!match)
468
- continue;
469
- const raw = match[1];
470
- if (!raw)
471
- continue;
472
- const value = Number.parseInt(raw, 10);
473
- if (!Number.isFinite(value))
474
- continue;
475
- if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
476
- continue;
477
- return value;
478
- }
479
- return;
407
+ function scheduleAfterBootQuiet(task, additionalDelayMs = 0) {
408
+ const timer = setTimeout(task, bootQuietRemainingMs() + Math.max(0, additionalDelayMs));
409
+ timer.unref?.();
410
+ return timer;
480
411
  }
481
412
 
482
- // src/shared/model-suggestion-retry.ts
483
- var ABORT_CALL_TIMEOUT_MS = 3000;
484
- function copyPromptArgs(args, body) {
485
- return { ...args, body: { ...body } };
413
+ // src/shared/rpc-utils.ts
414
+ import { createHash } from "node:crypto";
415
+ import { join } from "node:path";
416
+ function projectHash(directory) {
417
+ const normalized = directory.replace(/\/+$/, "");
418
+ return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
486
419
  }
487
- function extractMessage(error) {
488
- if (typeof error === "string")
489
- return error;
490
- if (error instanceof Error)
491
- return error.message;
492
- if (typeof error === "object" && error !== null) {
493
- const obj = error;
494
- if (typeof obj.message === "string")
495
- return obj.message;
496
- }
497
- try {
498
- return JSON.stringify(error);
499
- } catch (_error) {
500
- return String(error);
501
- }
420
+ function rpcPortDir(storageDir, directory) {
421
+ return join(storageDir, "rpc", projectHash(directory));
502
422
  }
503
- function parseModelSuggestion(error) {
504
- if (!error)
505
- return null;
506
- if (typeof error === "object" && error !== null) {
507
- const errObj = error;
508
- if (errObj.name === "ProviderModelNotFoundError" && typeof errObj.data === "object" && errObj.data !== null) {
509
- const data = errObj.data;
510
- const suggestions = data.suggestions;
511
- if (Array.isArray(suggestions) && typeof suggestions[0] === "string") {
512
- return {
513
- providerID: String(data.providerID ?? ""),
514
- modelID: String(data.modelID ?? ""),
515
- suggestion: suggestions[0]
516
- };
517
- }
518
- }
519
- for (const key of ["data", "error", "cause"]) {
520
- const nested = errObj[key];
521
- if (nested && typeof nested === "object") {
522
- const result = parseModelSuggestion(nested);
523
- if (result)
524
- return result;
525
- }
526
- }
527
- }
528
- const message = extractMessage(error);
529
- const modelMatch = message.match(/model not found:\s*([^/\s]+)\s*\/\s*([^.,\s]+)/i);
530
- const suggestionMatch = message.match(/did you mean:\s*([^,?]+)/i);
531
- if (!modelMatch || !suggestionMatch) {
532
- return null;
533
- }
534
- return {
535
- providerID: modelMatch[1].trim(),
536
- modelID: modelMatch[2].trim(),
537
- suggestion: suggestionMatch[1].trim()
538
- };
423
+ function rpcPortFilePath(storageDir, directory, pid = process.pid, instanceId) {
424
+ const suffix = instanceId ? `-${instanceId}` : "";
425
+ return join(rpcPortDir(storageDir, directory), `port-${pid}${suffix}.json`);
539
426
  }
540
- async function promptWithTimeout(client, args, timeoutMs, signal) {
541
- if (signal?.aborted) {
542
- throw new Error("prompt aborted by external signal");
543
- }
544
- const controller = new AbortController;
545
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
546
- const onExternalAbort = () => controller.abort();
547
- signal?.addEventListener("abort", onExternalAbort);
548
- try {
549
- await client.session.prompt({
550
- ...args,
551
- signal: controller.signal
552
- });
553
- } catch (error) {
554
- if (signal?.aborted) {
555
- await abortChildRun(client, args.path.id);
556
- throw new Error("prompt aborted by external signal");
557
- }
558
- if (controller.signal.aborted) {
559
- await abortChildRun(client, args.path.id);
560
- throw new Error(`prompt timed out after ${timeoutMs}ms`);
561
- }
562
- throw error;
563
- } finally {
564
- clearTimeout(timeout);
565
- signal?.removeEventListener("abort", onExternalAbort);
566
- }
567
- }
568
- async function abortChildRun(client, sessionId) {
427
+ function isPidAlive(pid) {
428
+ if (!Number.isInteger(pid) || pid <= 0)
429
+ return false;
569
430
  try {
570
- await Promise.race([
571
- client.session.abort({ path: { id: sessionId } }),
572
- new Promise((resolve) => setTimeout(resolve, ABORT_CALL_TIMEOUT_MS))
573
- ]);
574
- } catch (error) {
575
- log(`[model-retry] child session abort failed for ${sessionId}: ${String(error)}`);
576
- }
577
- }
578
- function isNonRetryable(error, externalSignal) {
579
- if (externalSignal?.aborted)
580
- return true;
581
- if (error instanceof Error) {
582
- if (error.name === "AbortError")
583
- return true;
584
- if (error.message === "prompt aborted by external signal")
585
- return true;
586
- if (/^prompt timed out after \d+ms$/.test(error.message))
587
- return true;
588
- }
589
- if (detectOverflow(error).isOverflow)
431
+ process.kill(pid, 0);
590
432
  return true;
591
- return false;
592
- }
593
- function shortErr(error) {
594
- if (error instanceof Error) {
595
- return error.name && error.name !== "Error" ? `${error.name}: ${error.message}` : error.message;
596
- }
597
- return extractMessage(error);
598
- }
599
- async function attemptOnce(client, args, timeoutMs, signal, callContext, label) {
600
- const originalBody = { ...args.body };
601
- const attemptArgs = copyPromptArgs(args, originalBody);
602
- try {
603
- await promptWithTimeout(client, attemptArgs, timeoutMs, signal);
604
- return;
605
- } catch (error) {
606
- if (isNonRetryable(error, signal))
607
- throw error;
608
- const suggestion = parseModelSuggestion(error);
609
- if (!suggestion || !originalBody.model) {
610
- throw error;
611
- }
612
- log(`[${callContext}] ${label}: model not found, retrying with suggestion`, {
613
- original: `${suggestion.providerID}/${suggestion.modelID}`,
614
- suggested: suggestion.suggestion
615
- });
616
- await promptWithTimeout(client, copyPromptArgs(args, {
617
- ...originalBody,
618
- model: {
619
- providerID: suggestion.providerID,
620
- modelID: suggestion.suggestion
621
- }
622
- }), timeoutMs, signal);
623
- }
624
- }
625
- async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
626
- const timeoutMs = options.timeoutMs ?? 300000;
627
- const callContext = options.callContext ?? "subagent";
628
- const fallbacks = options.fallbackModels ?? [];
629
- const baseBody = { ...args.body };
630
- const baseArgs = copyPromptArgs(args, baseBody);
631
- const explicitPrimaryLabel = baseBody.model?.providerID && baseBody.model.modelID ? `${baseBody.model.providerID}/${baseBody.model.modelID}` : "primary";
632
- let lastError = null;
633
- try {
634
- await attemptOnce(client, baseArgs, timeoutMs, options.signal, callContext, explicitPrimaryLabel);
635
- return;
636
- } catch (error) {
637
- lastError = error;
638
- if (isNonRetryable(error, options.signal))
639
- throw error;
640
- if (fallbacks.length === 0) {
641
- throw error;
642
- }
643
- log(`[${callContext}] primary (${explicitPrimaryLabel}) failed: ${shortErr(error)}; trying ${fallbacks.length} fallback(s)`);
644
- }
645
- for (let i = 0;i < fallbacks.length; i += 1) {
646
- const parsed = parseProviderModel(fallbacks[i]);
647
- if (!parsed) {
648
- log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
649
- continue;
650
- }
651
- const label = `${parsed.providerID}/${parsed.modelID}`;
652
- const attemptArgs = copyPromptArgs(baseArgs, {
653
- ...baseBody,
654
- model: parsed
655
- });
656
- try {
657
- await attemptOnce(client, attemptArgs, timeoutMs, options.signal, callContext, label);
658
- log(`[${callContext}] fallback succeeded with ${label} (attempt ${i + 2}/${fallbacks.length + 1})`);
659
- return;
660
- } catch (error) {
661
- lastError = error;
662
- if (isNonRetryable(error, options.signal))
663
- throw error;
664
- const remaining = fallbacks.length - i - 1;
665
- if (remaining > 0) {
666
- log(`[${callContext}] ${label} failed: ${shortErr(error)}; ${remaining} fallback(s) left`);
667
- }
668
- }
433
+ } catch (err) {
434
+ return err.code === "EPERM";
669
435
  }
670
- log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; last error: ${shortErr(lastError)}`);
671
- throw lastError ?? new Error("All fallback models failed");
672
436
  }
673
- async function attemptAndValidate(client, args, timeoutMs, signal, callContext, attempt, options) {
674
- await attemptOnce(client, args, timeoutMs, signal, callContext, attempt.label);
675
- const output = await options.fetchOutput(args, attempt);
676
- const validated = await options.validateOutput(output, attempt);
677
- return { output, validated, attempt };
678
- }
679
- async function promptSyncWithValidatedOutputRetry(client, args, options) {
680
- const timeoutMs = options.timeoutMs ?? 300000;
681
- const callContext = options.callContext ?? "subagent";
682
- const fallbacks = options.fallbackModels ?? [];
683
- const baseBody = { ...args.body };
684
- const baseArgs = copyPromptArgs(args, baseBody);
685
- const explicitPrimaryLabel = baseBody.model?.providerID && baseBody.model.modelID ? `${baseBody.model.providerID}/${baseBody.model.modelID}` : "primary";
686
- const totalAttempts = fallbacks.length + 1;
687
- let firstError = null;
688
- let lastError = null;
689
- try {
690
- return await attemptAndValidate(client, baseArgs, timeoutMs, options.signal, callContext, {
691
- label: explicitPrimaryLabel,
692
- attemptIndex: 0,
693
- isFallback: false,
694
- totalAttempts,
695
- model: baseBody.model
696
- }, options);
697
- } catch (error) {
698
- firstError = error;
699
- lastError = error;
700
- if (isNonRetryable(error, options.signal))
701
- throw error;
702
- if (fallbacks.length === 0) {
703
- throw error;
704
- }
705
- log(`[${callContext}] primary (${explicitPrimaryLabel}) failed validation/prompt: ${shortErr(error)}; trying ${fallbacks.length} fallback(s)`);
706
- }
707
- for (let i = 0;i < fallbacks.length; i += 1) {
708
- const parsed = parseProviderModel(fallbacks[i]);
709
- if (!parsed) {
710
- log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
711
- continue;
712
- }
713
- const label = `${parsed.providerID}/${parsed.modelID}`;
714
- const attemptArgs = copyPromptArgs(baseArgs, {
715
- ...baseBody,
716
- model: parsed
717
- });
718
- const attempt = {
719
- label,
720
- attemptIndex: i + 1,
721
- isFallback: true,
722
- totalAttempts,
723
- model: parsed
724
- };
437
+ function parseRpcPortFile(content, fallbackPid = 0) {
438
+ const trimmed = content.trim();
439
+ if (!trimmed)
440
+ return null;
441
+ if (trimmed.startsWith("{")) {
725
442
  try {
726
- const result = await attemptAndValidate(client, attemptArgs, timeoutMs, options.signal, callContext, attempt, options);
727
- log(`[${callContext}] fallback succeeded with ${label} (attempt ${i + 2}/${fallbacks.length + 1})`);
728
- return result;
729
- } catch (error) {
730
- if (firstError === null)
731
- firstError = error;
732
- lastError = error;
733
- if (isNonRetryable(error, options.signal))
734
- throw error;
735
- const remaining = fallbacks.length - i - 1;
736
- if (remaining > 0) {
737
- log(`[${callContext}] ${label} failed validation/prompt: ${shortErr(error)}; ${remaining} fallback(s) left`);
738
- }
739
- }
740
- }
741
- log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; original error: ${shortErr(firstError)}; last error: ${shortErr(lastError)}`);
742
- throw firstError ?? lastError ?? new Error("All fallback models failed validation");
743
- }
744
- // src/shared/normalize-sdk-response.ts
745
- function normalizeSDKResponse(response, fallback, options) {
746
- if (response === null || response === undefined) {
747
- return fallback;
748
- }
749
- if (Array.isArray(response)) {
750
- return response;
751
- }
752
- if (typeof response === "object" && "data" in response) {
753
- const data = response.data;
754
- if (data !== null && data !== undefined) {
755
- return data;
756
- }
757
- if (options?.preferResponseOnMissingData === true) {
758
- return response;
443
+ const parsed = JSON.parse(trimmed);
444
+ const port2 = Number(parsed.port);
445
+ const pid = Number(parsed.pid);
446
+ const startedAt = Number(parsed.started_at);
447
+ if (!isValidPort(port2) || !Number.isInteger(pid) || pid <= 0)
448
+ return null;
449
+ return {
450
+ port: port2,
451
+ pid,
452
+ started_at: Number.isFinite(startedAt) ? startedAt : 0,
453
+ token: typeof parsed.token === "string" ? parsed.token : undefined,
454
+ instance_id: typeof parsed.instance_id === "string" ? parsed.instance_id : undefined
455
+ };
456
+ } catch {
457
+ return null;
759
458
  }
760
- return fallback;
761
- }
762
- if (options?.preferResponseOnMissingData === true) {
763
- return response;
764
459
  }
765
- return fallback;
766
- }
767
- // src/shared/assistant-message-extractor.ts
768
- function asSessionMessage(value) {
769
- if (!isRecord(value))
460
+ const port = Number.parseInt(trimmed, 10);
461
+ if (!isValidPort(port))
770
462
  return null;
771
- const info = value.info;
772
- const parts = value.parts;
773
- return {
774
- info: isRecord(info) ? {
775
- role: typeof info.role === "string" ? info.role : undefined,
776
- time: isRecord(info.time) ? {
777
- created: typeof info.time.created === "number" ? info.time.created : undefined
778
- } : undefined
779
- } : undefined,
780
- parts
781
- };
463
+ return { port, pid: fallbackPid, started_at: 0 };
782
464
  }
783
- function getCreatedTime(message) {
784
- return message.info?.time?.created ?? 0;
785
- }
786
- function getTextParts(message) {
787
- if (!Array.isArray(message.parts))
788
- return [];
789
- return message.parts.filter((part) => isRecord(part)).map((part) => ({
790
- type: typeof part.type === "string" ? part.type : undefined,
791
- text: typeof part.text === "string" ? part.text : undefined
792
- })).filter((part) => part.type === "text" && Boolean(part.text));
793
- }
794
- function extractLatestAssistantText(messages) {
795
- if (!Array.isArray(messages) || messages.length === 0)
796
- return null;
797
- const assistantMessages = messages.map(asSessionMessage).filter((message) => message !== null).filter((message) => message.info?.role === "assistant").sort((a, b) => getCreatedTime(b) - getCreatedTime(a));
798
- const latest = assistantMessages[0];
799
- if (!latest)
800
- return null;
801
- return getTextParts(latest).map((part) => part.text).join(`
802
- `) || null;
803
- }
804
- function hasLengthCappedOutput(value) {
805
- if (Array.isArray(value))
806
- return value.some((item) => hasLengthCappedOutput(item));
807
- if (!isRecord(value))
808
- return false;
809
- if (value.length_capped === true || value.lengthCapped === true)
810
- return true;
811
- const finishReason = value.finish_reason ?? value.finishReason;
812
- if (typeof finishReason === "string") {
813
- const normalized = finishReason.toLowerCase();
814
- if (normalized === "length" || normalized === "max_tokens" || normalized === "max_output_tokens") {
815
- return true;
816
- }
817
- }
818
- return Object.values(value).some((item) => hasLengthCappedOutput(item));
465
+ function isValidPort(port) {
466
+ return Number.isInteger(port) && port > 0 && port <= 65535;
819
467
  }
820
468
 
821
- // src/shared/keep-subagents.ts
822
- var keepSubagents = false;
823
- function setKeepSubagents(value) {
824
- keepSubagents = value === true;
825
- }
826
- function shouldKeepSubagents() {
827
- return keepSubagents;
828
- }
829
469
  // src/features/magic-context/context-authority.ts
830
- import { createHash, randomUUID } from "node:crypto";
470
+ import { createHash as createHash2, randomUUID } from "node:crypto";
831
471
  var AUTHORITY_DOMAINS = ["memories", "notes"];
832
472
  var moduleNoteEvaluationBridges = new Map;
833
473
  function registerModuleNoteEvaluationBridge(projectPath, bridge) {
@@ -959,7 +599,7 @@ function checksumAuthoritySeedRows(rows) {
959
599
  const rightId = seedSourceRowId(right) ?? Number.MAX_SAFE_INTEGER;
960
600
  return leftId - rightId;
961
601
  });
962
- return createHash("sha256").update(JSON.stringify(ordered.map(canonicalizeSeedValue))).digest("hex");
602
+ return createHash2("sha256").update(JSON.stringify(ordered.map(canonicalizeSeedValue))).digest("hex");
963
603
  }
964
604
  function maxDomainRowId(db, domain, projectPath) {
965
605
  const row = domain === "memories" ? db.prepare("SELECT COALESCE(MAX(rowid), 0) AS max_rowid FROM memories WHERE project_path = ?").get(projectPath) : db.prepare(`SELECT COALESCE(MAX(n.rowid), 0) AS max_rowid
@@ -1047,10 +687,14 @@ async function prepareAuthority(args) {
1047
687
  domain,
1048
688
  rows: page
1049
689
  });
1050
- const identities = (seedResponse.module_row_ids ?? []).map((moduleRowId, index) => ({
1051
- moduleRowId,
1052
- sourceRowId: seedSourceRowId(page[index])
1053
- })).filter((identity) => identity.sourceRowId !== null);
690
+ const identityByModuleRowId = new Map;
691
+ for (const [index, moduleRowId] of (seedResponse.module_row_ids ?? []).entries()) {
692
+ const sourceRowId = seedSourceRowId(page[index]);
693
+ if (sourceRowId === null)
694
+ continue;
695
+ identityByModuleRowId.set(moduleRowId, { moduleRowId, sourceRowId });
696
+ }
697
+ const identities = [...identityByModuleRowId.values()];
1054
698
  if (identities.length > 0) {
1055
699
  args.db.transaction(() => {
1056
700
  for (const identity of identities) {
@@ -1951,6 +1595,7 @@ function pullMemoryMirrorOnce(args) {
1951
1595
  mirrorFlights.set(args.module, flight);
1952
1596
  return flight;
1953
1597
  }
1598
+
1954
1599
  // src/hooks/magic-context/compartment-parser.ts
1955
1600
  var COMPARTMENT_REGEX = /<compartment\s+([^>]*?)\s*>(.*?)<\/compartment>/gs;
1956
1601
  var ATTR_START_REGEX = /\bstart="(\d+)"/;
@@ -2221,7 +1866,7 @@ function healMissingMemoryBlockIds(db, columns) {
2221
1866
  }
2222
1867
 
2223
1868
  // src/features/magic-context/workspaces.ts
2224
- import { createHash as createHash3 } from "node:crypto";
1869
+ import { createHash as createHash4 } from "node:crypto";
2225
1870
 
2226
1871
  // src/features/magic-context/memory/constants.ts
2227
1872
  var V2_MEMORY_CATEGORIES = [
@@ -2275,7 +1920,7 @@ var CATEGORY_DEFAULT_TTL = {
2275
1920
 
2276
1921
  // src/features/magic-context/memory/project-identity.ts
2277
1922
  import { execFileSync } from "node:child_process";
2278
- import { createHash as createHash2 } from "node:crypto";
1923
+ import { createHash as createHash3 } from "node:crypto";
2279
1924
  import { existsSync, realpathSync, statSync } from "node:fs";
2280
1925
  import { homedir } from "node:os";
2281
1926
  import path from "node:path";
@@ -2290,6 +1935,7 @@ var dubiousOwnershipLoggedDirectories = new Set;
2290
1935
  var dubiousOwnershipWarnedDirectories = new Set;
2291
1936
  var transientGitIdentityReuseLoggedDirectories = new Set;
2292
1937
  var execFileSyncForIdentity = execFileSync;
1938
+ var userHomeDirectoryForIdentity = () => homedir();
2293
1939
  var nowMs = () => Date.now();
2294
1940
 
2295
1941
  class ProjectIdentityError extends Error {
@@ -2343,7 +1989,7 @@ function getErrorStderr(error) {
2343
1989
  }
2344
1990
  function directoryFallback(directory) {
2345
1991
  const canonical = path.resolve(directory);
2346
- const hash = createHash2("md5").update(canonical, "utf8").digest("hex").slice(0, 12);
1992
+ const hash = createHash3("md5").update(canonical, "utf8").digest("hex").slice(0, 12);
2347
1993
  return `dir:${hash}`;
2348
1994
  }
2349
1995
  function assertDirectoryUsable(canonicalDirectory, rawDirectory) {
@@ -2494,9 +2140,12 @@ function takeDubiousOwnershipProjectIdentityWarning(directory) {
2494
2140
  dubiousOwnershipWarnedDirectories.add(canonical);
2495
2141
  return formatDubiousOwnershipWarning(canonical);
2496
2142
  }
2143
+ function canonicalUserHomeDirectory() {
2144
+ return realpathSync.native(userHomeDirectoryForIdentity());
2145
+ }
2497
2146
  function isUserHomeDirectory(directory) {
2498
2147
  try {
2499
- return realpathSync.native(path.resolve(directory)) === realpathSync.native(homedir());
2148
+ return realpathSync.native(path.resolve(directory)) === canonicalUserHomeDirectory();
2500
2149
  } catch {
2501
2150
  return false;
2502
2151
  }
@@ -2565,22 +2214,52 @@ function hasGitDir(canonical) {
2565
2214
  return false;
2566
2215
  }
2567
2216
  }
2568
- function hasGitDirInAncestorChain(startDirectory) {
2217
+ function gitRootInAncestorChain(startDirectory) {
2569
2218
  let current = startDirectory;
2570
2219
  while (true) {
2571
2220
  if (existsSync(path.join(current, ".git"))) {
2572
- return true;
2221
+ try {
2222
+ return realpathSync.native(current);
2223
+ } catch {
2224
+ return path.resolve(current);
2225
+ }
2573
2226
  }
2574
2227
  const parent = path.dirname(current);
2575
2228
  if (parent === current) {
2576
- return false;
2229
+ return null;
2577
2230
  }
2578
2231
  current = parent;
2579
2232
  }
2580
2233
  }
2581
- function resolveProjectIdentityForSession(directory) {
2582
- if (isUserHomeDirectory(directory))
2583
- return;
2234
+ function hasGitDirInAncestorChain(startDirectory) {
2235
+ return gitRootInAncestorChain(startDirectory) !== null;
2236
+ }
2237
+ function gitRootDirectory(canonical) {
2238
+ const direct = gitRootInAncestorChain(canonical);
2239
+ if (direct)
2240
+ return direct;
2241
+ try {
2242
+ const realCanonical = realpathSync.native(canonical);
2243
+ return realCanonical === canonical ? null : gitRootInAncestorChain(realCanonical);
2244
+ } catch {
2245
+ return null;
2246
+ }
2247
+ }
2248
+ function resolveProjectIdentityForSession(directory, allowHomeProject = false) {
2249
+ const canonicalHome = canonicalUserHomeDirectory();
2250
+ const canonicalDirectory = (() => {
2251
+ try {
2252
+ return realpathSync.native(path.resolve(directory));
2253
+ } catch {
2254
+ return path.resolve(directory);
2255
+ }
2256
+ })();
2257
+ const inheritsHomeRepository = gitRootDirectory(canonicalDirectory) === canonicalHome;
2258
+ if (canonicalDirectory === canonicalHome || inheritsHomeRepository) {
2259
+ if (!allowHomeProject)
2260
+ return;
2261
+ return directoryFallback(canonicalHome);
2262
+ }
2584
2263
  return resolveProjectIdentityOrFallback(directory);
2585
2264
  }
2586
2265
  function normalizeStoredProjectPath(rawOrStored) {
@@ -2782,7 +2461,7 @@ function computeWorkspaceEpochFingerprint(db, identities) {
2782
2461
  const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
2783
2462
  const epochs = getEpochMap(db, canonical);
2784
2463
  const shareCategories = selectWorkspaceShareCategories(db, canonical);
2785
- const hash = createHash3("sha256");
2464
+ const hash = createHash4("sha256");
2786
2465
  hash.update("share_categories", "utf8");
2787
2466
  hash.update("\x00");
2788
2467
  hash.update(shareCategories === null ? "NO_WORKSPACE" : JSON.stringify(shareCategories), "utf8");
@@ -4869,6 +4548,33 @@ var MIGRATIONS = [
4869
4548
  up(db) {
4870
4549
  installLatestAuthorityTriggers(db);
4871
4550
  }
4551
+ },
4552
+ {
4553
+ version: 72,
4554
+ description: "add per-session compaction mode record column (issue #266)",
4555
+ up(db) {
4556
+ if (tableExists2(db, "session_meta")) {
4557
+ ensureColumn(db, "session_meta", "compaction_mode_record", "TEXT");
4558
+ }
4559
+ }
4560
+ },
4561
+ {
4562
+ version: 73,
4563
+ description: "persist the last successful todowrite permission verdict",
4564
+ up(db) {
4565
+ if (tableExists2(db, "session_meta")) {
4566
+ ensureColumn(db, "session_meta", "todo_permission_denied", "INTEGER NOT NULL DEFAULT 2");
4567
+ }
4568
+ }
4569
+ },
4570
+ {
4571
+ version: 74,
4572
+ description: "persist detected context-limit provenance",
4573
+ up(db) {
4574
+ if (tableExists2(db, "session_meta")) {
4575
+ ensureColumn(db, "session_meta", "detected_context_limit_provenance", "TEXT NOT NULL DEFAULT 'unknown'");
4576
+ }
4577
+ }
4872
4578
  }
4873
4579
  ];
4874
4580
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -4978,151 +4684,6 @@ async function runMigrationsWithRetry(db, options = {}) {
4978
4684
  }
4979
4685
  }
4980
4686
  }
4981
- // src/features/magic-context/project-docs-hash.ts
4982
- import { createHash as createHash4 } from "node:crypto";
4983
- import { lstatSync, readFileSync, statSync as statSync2 } from "node:fs";
4984
- import path2 from "node:path";
4985
- var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
4986
- var PROJECT_DOCS_DELIMITER = `
4987
-
4988
- ---
4989
-
4990
- `;
4991
- var MAX_PROJECT_DOC_BYTES = 256 * 1024;
4992
- var docsCache = new Map;
4993
- function canonicalizeDocContent(raw) {
4994
- return raw.replace(/^\uFEFF/, "").replace(/\r\n/g, `
4995
- `).split(`
4996
- `).map((line) => line.replace(/[ \t]+$/, "")).join(`
4997
- `).replace(/\n+$/, "");
4998
- }
4999
- function fingerprintFile(filePath) {
5000
- try {
5001
- const stat = lstatSync(filePath);
5002
- const isReadableDoc = stat.isFile() && stat.size <= MAX_PROJECT_DOC_BYTES;
5003
- return {
5004
- exists: isReadableDoc,
5005
- mtimeMs: stat.mtimeMs,
5006
- size: stat.size
5007
- };
5008
- } catch {
5009
- return { exists: false, mtimeMs: 0, size: 0 };
5010
- }
5011
- }
5012
- function readDirectoryMtimeMs(projectDirectory) {
5013
- try {
5014
- return statSync2(projectDirectory).mtimeMs;
5015
- } catch {
5016
- return 0;
5017
- }
5018
- }
5019
- function fingerprintsEqual(a, b) {
5020
- return a?.exists === b.exists && a.mtimeMs === b.mtimeMs && a.size === b.size;
5021
- }
5022
- function cacheFilesEqual(cachedFiles, currentFiles) {
5023
- for (const [filePath, current] of currentFiles) {
5024
- if (!fingerprintsEqual(cachedFiles.get(filePath), current)) {
5025
- return false;
5026
- }
5027
- }
5028
- return true;
5029
- }
5030
- function readCurrentFingerprints(projectDirectory) {
5031
- const files = new Map;
5032
- for (const filename of PROJECT_DOC_FILES) {
5033
- const filePath = path2.join(projectDirectory, filename);
5034
- files.set(filePath, fingerprintFile(filePath));
5035
- }
5036
- return { directoryMtimeMs: readDirectoryMtimeMs(projectDirectory), files };
5037
- }
5038
- function readCanonicalPieces(projectDirectory, files) {
5039
- const hashPieces = [];
5040
- const renderedSections = [];
5041
- for (const filename of PROJECT_DOC_FILES) {
5042
- const filePath = path2.join(projectDirectory, filename);
5043
- const fingerprint = files.get(filePath);
5044
- if (!fingerprint?.exists) {
5045
- continue;
5046
- }
5047
- let safeToRead = false;
5048
- try {
5049
- const st = lstatSync(filePath);
5050
- safeToRead = st.isFile() && st.size <= MAX_PROJECT_DOC_BYTES;
5051
- } catch {
5052
- safeToRead = false;
5053
- }
5054
- if (!safeToRead) {
5055
- continue;
5056
- }
5057
- const canonicalContent = canonicalizeDocContent(readFileSync(filePath, "utf8"));
5058
- hashPieces.push(`file:${filename}
5059
- ${canonicalContent}`);
5060
- renderedSections.push(`<file name="${escapeXmlAttr(filename)}">
5061
- ${escapeXmlContent(canonicalContent)}
5062
- </file>`);
5063
- }
5064
- return { hashPieces, renderedSections };
5065
- }
5066
- function buildRenderedBlock(renderedSections) {
5067
- if (renderedSections.length === 0) {
5068
- return "";
5069
- }
5070
- return `<project-docs>
5071
- ${renderedSections.join(`
5072
-
5073
- `)}
5074
- </project-docs>`;
5075
- }
5076
- function hashCanonicalPieces(hashPieces) {
5077
- if (hashPieces.length === 0) {
5078
- return "";
5079
- }
5080
- return createHash4("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
5081
- }
5082
- function readProjectDocsCanonical(projectDirectory) {
5083
- const canonicalDirectory = path2.resolve(projectDirectory);
5084
- const current = readCurrentFingerprints(canonicalDirectory);
5085
- const cached = docsCache.get(canonicalDirectory);
5086
- if (cached && cacheFilesEqual(cached.files, current.files)) {
5087
- cached.directoryMtimeMs = current.directoryMtimeMs;
5088
- return {
5089
- renderedBlock: cached.cachedRendered,
5090
- canonicalHash: cached.cachedHash
5091
- };
5092
- }
5093
- const { hashPieces, renderedSections } = readCanonicalPieces(canonicalDirectory, current.files);
5094
- const canonicalHash = hashCanonicalPieces(hashPieces);
5095
- const renderedBlock = buildRenderedBlock(renderedSections);
5096
- docsCache.set(canonicalDirectory, {
5097
- directoryMtimeMs: current.directoryMtimeMs,
5098
- files: current.files,
5099
- cachedHash: canonicalHash,
5100
- cachedRendered: renderedBlock
5101
- });
5102
- return { renderedBlock, canonicalHash };
5103
- }
5104
- function computeProjectDocsHash(projectDirectory) {
5105
- return readProjectDocsCanonical(projectDirectory).canonicalHash;
5106
- }
5107
- // src/features/magic-context/storage-db.ts
5108
- import { chmodSync, copyFileSync, cpSync, existsSync as existsSync3, mkdirSync, mkdtempSync } from "node:fs";
5109
- import { dirname, join as join2 } from "node:path";
5110
-
5111
- // src/plugin/boot-quiet.ts
5112
- var BOOT_QUIET_MS = 120000;
5113
- var bootQuietUntilMs = 0;
5114
- function beginBootQuietPeriod(now = Date.now()) {
5115
- if (bootQuietUntilMs === 0)
5116
- bootQuietUntilMs = now + BOOT_QUIET_MS;
5117
- }
5118
- function bootQuietRemainingMs(now = Date.now()) {
5119
- return Math.max(0, bootQuietUntilMs - now);
5120
- }
5121
- function scheduleAfterBootQuiet(task, additionalDelayMs = 0) {
5122
- const timer = setTimeout(task, bootQuietRemainingMs() + Math.max(0, additionalDelayMs));
5123
- timer.unref?.();
5124
- return timer;
5125
- }
5126
4687
 
5127
4688
  // src/features/magic-context/tool-definition-tokens.ts
5128
4689
  import { createHash as createHash5 } from "node:crypto";
@@ -5236,11 +4797,11 @@ function getMeasuredToolDefinitionTokens(providerID, modelID, agentName) {
5236
4797
 
5237
4798
  // src/features/magic-context/tool-owner-backfill.ts
5238
4799
  import { existsSync as existsSync2 } from "node:fs";
5239
- import { join } from "node:path";
4800
+ import { join as join2 } from "node:path";
5240
4801
  var LEASE_DURATION_MS = 5 * 60 * 1000;
5241
4802
  var LEASE_RENEWAL_MS = 60 * 1000;
5242
4803
  function resolveOpencodeDbPath() {
5243
- return join(getDataDir(), "opencode", "opencode.db");
4804
+ return join2(getDataDir(), "opencode", "opencode.db");
5244
4805
  }
5245
4806
  function ensureBackfillStateTable(db) {
5246
4807
  db.exec(`
@@ -5495,30 +5056,40 @@ var persistenceByDatabase = new WeakMap;
5495
5056
  var persistenceErrorByDatabase = new WeakMap;
5496
5057
  var pathByDatabase = new WeakMap;
5497
5058
  var lastSchemaFenceRejection = null;
5059
+ var lastMigrationOnOpenRefusal = null;
5498
5060
  function getSchemaFenceRejection() {
5499
5061
  return lastSchemaFenceRejection;
5500
5062
  }
5501
- var LATEST_SUPPORTED_VERSION = 71;
5063
+ function getMigrationOnOpenRefusal() {
5064
+ return lastMigrationOnOpenRefusal;
5065
+ }
5066
+ var LATEST_SUPPORTED_VERSION = 74;
5502
5067
  var PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
5068
+ var defaultStoragePermissionFs = { chmodSync, mkdirSync };
5069
+ var storagePermissionFs = defaultStoragePermissionFs;
5503
5070
  function ensureSecureStorageDir(dir) {
5504
- mkdirSync(dir, { recursive: true, mode: 448 });
5071
+ if (!shouldEnforcePrivateStoragePermissions()) {
5072
+ storagePermissionFs.mkdirSync(dir, { recursive: true });
5073
+ return;
5074
+ }
5075
+ storagePermissionFs.mkdirSync(dir, { recursive: true, mode: 448 });
5505
5076
  if (!PERMISSIONS_ENFORCEABLE)
5506
5077
  return;
5507
5078
  try {
5508
- chmodSync(dir, 448);
5079
+ storagePermissionFs.chmodSync(dir, 448);
5509
5080
  } catch (error) {
5510
5081
  log(`[magic-context] could not restrict storage dir permissions on ${dir}: ${getErrorMessage(error)}`);
5511
5082
  }
5512
5083
  }
5513
5084
  function restrictDatabaseFilePermissions(dbPath) {
5514
- if (!PERMISSIONS_ENFORCEABLE)
5085
+ if (!PERMISSIONS_ENFORCEABLE || !shouldEnforcePrivateStoragePermissions())
5515
5086
  return;
5516
5087
  for (const suffix of ["", "-wal", "-shm"]) {
5517
5088
  const file = `${dbPath}${suffix}`;
5518
5089
  if (!existsSync3(file))
5519
5090
  continue;
5520
5091
  try {
5521
- chmodSync(file, 384);
5092
+ storagePermissionFs.chmodSync(file, 384);
5522
5093
  } catch (error) {
5523
5094
  log(`[magic-context] could not restrict DB file permissions on ${file}: ${getErrorMessage(error)}`);
5524
5095
  }
@@ -5530,12 +5101,12 @@ function resolveDatabasePath(dbPathOverride) {
5530
5101
  }
5531
5102
  const testDataDir = process.env.MAGIC_CONTEXT_TEST_DATA_DIR;
5532
5103
  if (testDataDir && !process.env.XDG_DATA_HOME) {
5533
- const dbDir2 = join2(testDataDir, "cortexkit", "magic-context");
5534
- return { dbDir: dbDir2, dbPath: join2(dbDir2, "context.db") };
5104
+ const dbDir2 = join3(testDataDir, "cortexkit", "magic-context");
5105
+ return { dbDir: dbDir2, dbPath: join3(dbDir2, "context.db") };
5535
5106
  }
5536
5107
  if (false) {}
5537
5108
  const dbDir = getMagicContextStorageDir();
5538
- return { dbDir, dbPath: join2(dbDir, "context.db") };
5109
+ return { dbDir, dbPath: join3(dbDir, "context.db") };
5539
5110
  }
5540
5111
  function getDatabasePath(db) {
5541
5112
  return pathByDatabase.get(db) ?? null;
@@ -5544,7 +5115,7 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
5544
5115
  if (existsSync3(targetDbPath))
5545
5116
  return;
5546
5117
  const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
5547
- const legacyDbPath = join2(legacyDir, "context.db");
5118
+ const legacyDbPath = join3(legacyDir, "context.db");
5548
5119
  if (!existsSync3(legacyDbPath))
5549
5120
  return;
5550
5121
  log(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
@@ -5561,7 +5132,7 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
5561
5132
  }
5562
5133
  for (const suffix of ["", "-wal", "-shm"]) {
5563
5134
  const src = `${legacyDbPath}${suffix}`;
5564
- const dst = join2(targetDbDir, `context.db${suffix}`);
5135
+ const dst = join3(targetDbDir, `context.db${suffix}`);
5565
5136
  if (existsSync3(src)) {
5566
5137
  try {
5567
5138
  copyFileSync(src, dst);
@@ -5570,8 +5141,8 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
5570
5141
  }
5571
5142
  }
5572
5143
  }
5573
- const legacyModelsDir = join2(legacyDir, "models");
5574
- const targetModelsDir = join2(targetDbDir, "models");
5144
+ const legacyModelsDir = join3(legacyDir, "models");
5145
+ const targetModelsDir = join3(targetDbDir, "models");
5575
5146
  if (existsSync3(legacyModelsDir) && !existsSync3(targetModelsDir)) {
5576
5147
  try {
5577
5148
  cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
@@ -5588,6 +5159,9 @@ function getPersistedSchemaVersion(db) {
5588
5159
  const row = db.prepare("SELECT MAX(version) AS version FROM schema_migrations").get();
5589
5160
  return row?.version ?? 0;
5590
5161
  }
5162
+ function formatSchemaFenceBootLog(persistedVersion, supportedVersion) {
5163
+ return `[magic-context] storage schema at boot: database=v${persistedVersion}, supported_fence=v${supportedVersion}`;
5164
+ }
5591
5165
  function getRuntimeLatestSupportedVersion(options) {
5592
5166
  if (options?.latestSupportedVersion !== undefined) {
5593
5167
  return options.latestSupportedVersion;
@@ -5604,12 +5178,109 @@ function getRuntimeLatestSupportedVersion(options) {
5604
5178
  function enforceSchemaFence(db, dbPath, latestSupportedVersion) {
5605
5179
  const persistedVersion = getPersistedSchemaVersion(db);
5606
5180
  if (persistedVersion <= latestSupportedVersion) {
5181
+ lastSchemaFenceRejection = null;
5607
5182
  return true;
5608
5183
  }
5609
5184
  lastSchemaFenceRejection = { persistedVersion, supportedVersion: latestSupportedVersion };
5610
5185
  log(`[magic-context] storage fatal: refusing to open ${dbPath}; database schema v${persistedVersion} is newer than this binary supports (max v${latestSupportedVersion}). A pinned or stale plugin is likely sharing this database with a newer instance; update or unpin Magic Context with 'npx @cortexkit/magic-context@latest doctor --force', then restart.`);
5611
5186
  return false;
5612
5187
  }
5188
+ function unreadableDiscovery(path2) {
5189
+ return {
5190
+ state: "unreadable",
5191
+ serverPids: [],
5192
+ staleFiles: [],
5193
+ unreadableFile: path2
5194
+ };
5195
+ }
5196
+ function inspectRpcServerDiscovery(storageDir) {
5197
+ const rpcRoot = join3(storageDir, "rpc");
5198
+ let projectEntries;
5199
+ try {
5200
+ projectEntries = readdirSync(rpcRoot, { withFileTypes: true });
5201
+ } catch (error) {
5202
+ if (error.code === "ENOENT") {
5203
+ return { state: "absent", serverPids: [], staleFiles: [] };
5204
+ }
5205
+ return unreadableDiscovery(rpcRoot);
5206
+ }
5207
+ const portFiles = [];
5208
+ for (const projectEntry of projectEntries) {
5209
+ if (!projectEntry.isDirectory())
5210
+ continue;
5211
+ const projectDir = join3(rpcRoot, projectEntry.name);
5212
+ let entries;
5213
+ try {
5214
+ entries = readdirSync(projectDir);
5215
+ } catch {
5216
+ return unreadableDiscovery(projectDir);
5217
+ }
5218
+ for (const entry of entries) {
5219
+ if (entry === "port" || entry.startsWith("port-") && entry.endsWith(".json")) {
5220
+ portFiles.push(join3(projectDir, entry));
5221
+ }
5222
+ }
5223
+ }
5224
+ if (portFiles.length === 0) {
5225
+ return { state: "absent", serverPids: [], staleFiles: [] };
5226
+ }
5227
+ const pids = new Set;
5228
+ const staleFiles = [];
5229
+ for (const portFile of portFiles) {
5230
+ let raw;
5231
+ try {
5232
+ raw = readFileSync(portFile, "utf8");
5233
+ } catch {
5234
+ return unreadableDiscovery(portFile);
5235
+ }
5236
+ const filename = basename(portFile);
5237
+ const pidFromName = /^port-(\d+)/.exec(filename)?.[1];
5238
+ const record = parseRpcPortFile(raw, pidFromName ? Number(pidFromName) : 0);
5239
+ if (!record || !Number.isInteger(record.pid) || record.pid <= 0) {
5240
+ return unreadableDiscovery(portFile);
5241
+ }
5242
+ if (isPidAlive(record.pid))
5243
+ pids.add(record.pid);
5244
+ else
5245
+ staleFiles.push(portFile);
5246
+ }
5247
+ const serverPids = [...pids].sort((a, b) => a - b);
5248
+ if (serverPids.length > 0) {
5249
+ return { state: "live", serverPids, staleFiles };
5250
+ }
5251
+ for (const staleFile of staleFiles) {
5252
+ try {
5253
+ unlinkSync(staleFile);
5254
+ } catch {
5255
+ return unreadableDiscovery(staleFile);
5256
+ }
5257
+ }
5258
+ return { state: "stale", serverPids: [], staleFiles };
5259
+ }
5260
+ function enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion) {
5261
+ const persistedVersion = getPersistedSchemaVersion(db);
5262
+ if (persistedVersion >= latestSupportedVersion) {
5263
+ lastMigrationOnOpenRefusal = null;
5264
+ return true;
5265
+ }
5266
+ const discovery = inspectRpcServerDiscovery(dbDir);
5267
+ if (discovery.state === "absent" || discovery.state === "stale") {
5268
+ lastMigrationOnOpenRefusal = null;
5269
+ return true;
5270
+ }
5271
+ lastMigrationOnOpenRefusal = {
5272
+ persistedVersion,
5273
+ supportedVersion: latestSupportedVersion,
5274
+ serverPids: discovery.serverPids,
5275
+ ...discovery.unreadableFile ? { unreadableFile: discovery.unreadableFile } : {}
5276
+ };
5277
+ if (discovery.state === "unreadable") {
5278
+ log(`[magic-context] storage fatal: refusing to migrate ${dbPath} from schema v${persistedVersion} to v${latestSupportedVersion} because RPC discovery file ${discovery.unreadableFile ?? "<unknown>"} is unreadable or invalid, so the absence of a live OpenCode server cannot be proven. Restart OpenCode, remove or repair the named discovery file, then retry this process.`);
5279
+ } else {
5280
+ log(`[magic-context] storage fatal: refusing to migrate ${dbPath} from schema v${persistedVersion} to v${latestSupportedVersion} while live OpenCode server PID(s) ${discovery.serverPids.join(", ")} may still use the old plugin build. Restart OpenCode, then retry this process.`);
5281
+ }
5282
+ return false;
5283
+ }
5613
5284
  var sqlitePragmaConfig = {
5614
5285
  cacheSizeMb: 64,
5615
5286
  mmapSizeMb: 0
@@ -5654,6 +5325,9 @@ function finishDatabaseOpen(db, dbPath, explicitDbPath, latestSupportedVersion)
5654
5325
  pathByDatabase.set(db, dbPath);
5655
5326
  persistenceByDatabase.set(db, true);
5656
5327
  persistenceErrorByDatabase.delete(db);
5328
+ if (!explicitDbPath) {
5329
+ log(formatSchemaFenceBootLog(getPersistedSchemaVersion(db), latestSupportedVersion));
5330
+ }
5657
5331
  return db;
5658
5332
  }
5659
5333
  function initializeDatabase(db) {
@@ -6254,12 +5928,14 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6254
5928
  note_nudge_anchors TEXT NOT NULL DEFAULT '[]',
6255
5929
  auto_search_hint_decisions TEXT NOT NULL DEFAULT '[]',
6256
5930
  last_todo_state TEXT DEFAULT '',
5931
+ todo_permission_denied INTEGER NOT NULL DEFAULT 2,
6257
5932
  todo_synthetic_call_id TEXT DEFAULT '',
6258
5933
  todo_synthetic_anchor_message_id TEXT DEFAULT '',
6259
5934
  todo_synthetic_state_json TEXT DEFAULT '',
6260
5935
  is_subagent INTEGER DEFAULT 0,
6261
5936
  last_context_percentage REAL DEFAULT 0,
6262
5937
  last_input_tokens INTEGER DEFAULT 0,
5938
+ detected_context_limit_provenance TEXT NOT NULL DEFAULT 'unknown',
6263
5939
  observed_safe_input_tokens INTEGER NOT NULL DEFAULT 0,
6264
5940
  cache_alert_sent INTEGER NOT NULL DEFAULT 0,
6265
5941
  times_execute_threshold_reached INTEGER DEFAULT 0,
@@ -6314,6 +5990,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6314
5990
  emergency_drain_active INTEGER NOT NULL DEFAULT 0,
6315
5991
  historian_drain_failure_at INTEGER NOT NULL DEFAULT 0,
6316
5992
  wrapup_in_progress_state TEXT,
5993
+ compaction_mode_record TEXT,
6317
5994
  cached_m0_materialized_at INTEGER,
6318
5995
  cached_m0_session_facts_version INTEGER,
6319
5996
  cached_m0_upgrade_state TEXT,
@@ -6513,6 +6190,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6513
6190
  ensureColumn(db, "session_meta", "note_nudge_anchors", "TEXT NOT NULL DEFAULT '[]'");
6514
6191
  ensureColumn(db, "session_meta", "auto_search_hint_decisions", "TEXT NOT NULL DEFAULT '[]'");
6515
6192
  ensureColumn(db, "session_meta", "last_todo_state", "TEXT DEFAULT ''");
6193
+ ensureColumn(db, "session_meta", "todo_permission_denied", "INTEGER NOT NULL DEFAULT 2");
6516
6194
  ensureColumn(db, "session_meta", "todo_synthetic_call_id", "TEXT DEFAULT ''");
6517
6195
  ensureColumn(db, "session_meta", "todo_synthetic_anchor_message_id", "TEXT DEFAULT ''");
6518
6196
  ensureColumn(db, "session_meta", "todo_synthetic_state_json", "TEXT DEFAULT ''");
@@ -6569,6 +6247,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6569
6247
  ensureColumn(db, "session_meta", "recomp_partial_range_end", "INTEGER DEFAULT 0");
6570
6248
  ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
6571
6249
  ensureColumn(db, "session_meta", "detected_context_limit_model_key", "TEXT");
6250
+ ensureColumn(db, "session_meta", "detected_context_limit_provenance", "TEXT NOT NULL DEFAULT 'unknown'");
6572
6251
  ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
6573
6252
  ensureColumn(db, "session_meta", "emergency_recovery_origin", "TEXT DEFAULT ''");
6574
6253
  ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
@@ -6619,6 +6298,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6619
6298
  ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
6620
6299
  ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
6621
6300
  ensureColumn(db, "session_meta", "wrapup_in_progress_state", "TEXT");
6301
+ ensureColumn(db, "session_meta", "compaction_mode_record", "TEXT");
6622
6302
  ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
6623
6303
  ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
6624
6304
  ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
@@ -6758,6 +6438,8 @@ function openDatabase(dbPathOrOptions) {
6758
6438
  const explicitDbPath = options?.dbPath !== undefined;
6759
6439
  const { dbDir, dbPath } = resolveDatabasePath(options?.dbPath);
6760
6440
  const latestSupportedVersion = getRuntimeLatestSupportedVersion(options);
6441
+ lastSchemaFenceRejection = null;
6442
+ lastMigrationOnOpenRefusal = null;
6761
6443
  const existing = databases.get(dbPath);
6762
6444
  if (existing) {
6763
6445
  if (!enforceSchemaFence(existing, dbPath, latestSupportedVersion)) {
@@ -6779,6 +6461,10 @@ function openDatabase(dbPathOrOptions) {
6779
6461
  closeQuietly(db);
6780
6462
  return null;
6781
6463
  }
6464
+ if (!enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)) {
6465
+ closeQuietly(db);
6466
+ return null;
6467
+ }
6782
6468
  initializeDatabase(db);
6783
6469
  runMigrations(db);
6784
6470
  ensureContextStoreUuid(db);
@@ -6794,6 +6480,8 @@ async function openDatabaseAsync(dbPathOrOptions) {
6794
6480
  const explicitDbPath = options?.dbPath !== undefined;
6795
6481
  const { dbDir, dbPath } = resolveDatabasePath(options?.dbPath);
6796
6482
  const latestSupportedVersion = getRuntimeLatestSupportedVersion(options);
6483
+ lastSchemaFenceRejection = null;
6484
+ lastMigrationOnOpenRefusal = null;
6797
6485
  const existing = databases.get(dbPath);
6798
6486
  if (existing) {
6799
6487
  if (!enforceSchemaFence(existing, dbPath, latestSupportedVersion))
@@ -6817,6 +6505,10 @@ async function openDatabaseAsync(dbPathOrOptions) {
6817
6505
  closeQuietly(db);
6818
6506
  return null;
6819
6507
  }
6508
+ if (!enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)) {
6509
+ closeQuietly(db);
6510
+ return null;
6511
+ }
6820
6512
  initializeDatabase(db);
6821
6513
  await runMigrationsWithRetry(db);
6822
6514
  ensureContextStoreUuid(db);
@@ -6847,11 +6539,188 @@ function getDatabasePersistenceError(db) {
6847
6539
  return null;
6848
6540
  return persistenceErrorByDatabase.get(db) ?? null;
6849
6541
  }
6850
- // src/features/magic-context/storage-embedding-measurements.ts
6542
+
6543
+ // src/features/magic-context/schema-fence-probe.ts
6544
+ var STALE_CHILD_SPAWN_FAILURE = "stale_schema_fence";
6545
+ var STALE_CHILD_SPAWN_LATCH_THRESHOLD = 2;
6546
+ var state = {
6547
+ consecutiveFailures: 0,
6548
+ totalFailures: 0,
6549
+ latched: false,
6550
+ noticeEmitted: false,
6551
+ failure: null
6552
+ };
6553
+ function recordStaleFence(persistedVersion, supportedVersion) {
6554
+ state.consecutiveFailures += 1;
6555
+ state.totalFailures += 1;
6556
+ const latched = state.consecutiveFailures >= STALE_CHILD_SPAWN_LATCH_THRESHOLD;
6557
+ state.latched ||= latched;
6558
+ const failure = {
6559
+ failureClass: STALE_CHILD_SPAWN_FAILURE,
6560
+ persistedVersion,
6561
+ supportedVersion,
6562
+ consecutiveFailures: state.consecutiveFailures,
6563
+ totalFailures: state.totalFailures,
6564
+ latched: state.latched
6565
+ };
6566
+ state.failure = failure;
6567
+ const shouldSurface = state.latched && !state.noticeEmitted;
6568
+ if (shouldSurface)
6569
+ state.noticeEmitted = true;
6570
+ return { allowSpawn: false, failure, shouldSurface };
6571
+ }
6572
+ function probeChildSpawnFence(db) {
6573
+ if (!db) {
6574
+ const knownRejection = getSchemaFenceRejection();
6575
+ if (knownRejection) {
6576
+ return recordStaleFence(knownRejection.persistedVersion, knownRejection.supportedVersion);
6577
+ }
6578
+ return { allowSpawn: true };
6579
+ }
6580
+ try {
6581
+ const persistedVersion = getPersistedSchemaVersion(db);
6582
+ if (persistedVersion > LATEST_SUPPORTED_VERSION) {
6583
+ return recordStaleFence(persistedVersion, LATEST_SUPPORTED_VERSION);
6584
+ }
6585
+ } catch {
6586
+ return { allowSpawn: true };
6587
+ }
6588
+ state.consecutiveFailures = 0;
6589
+ state.latched = false;
6590
+ state.noticeEmitted = false;
6591
+ return { allowSpawn: true };
6592
+ }
6593
+ // src/features/magic-context/project-docs-hash.ts
6851
6594
  import { createHash as createHash6 } from "node:crypto";
6595
+ import { lstatSync, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
6596
+ import path2 from "node:path";
6597
+ var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
6598
+ var PROJECT_DOCS_DELIMITER = `
6599
+
6600
+ ---
6601
+
6602
+ `;
6603
+ var MAX_PROJECT_DOC_BYTES = 256 * 1024;
6604
+ var docsCache = new Map;
6605
+ function canonicalizeDocContent(raw) {
6606
+ return raw.replace(/^\uFEFF/, "").replace(/\r\n/g, `
6607
+ `).split(`
6608
+ `).map((line) => line.replace(/[ \t]+$/, "")).join(`
6609
+ `).replace(/\n+$/, "");
6610
+ }
6611
+ function fingerprintFile(filePath) {
6612
+ try {
6613
+ const stat = lstatSync(filePath);
6614
+ const isReadableDoc = stat.isFile() && stat.size <= MAX_PROJECT_DOC_BYTES;
6615
+ return {
6616
+ exists: isReadableDoc,
6617
+ mtimeMs: stat.mtimeMs,
6618
+ size: stat.size
6619
+ };
6620
+ } catch {
6621
+ return { exists: false, mtimeMs: 0, size: 0 };
6622
+ }
6623
+ }
6624
+ function readDirectoryMtimeMs(projectDirectory) {
6625
+ try {
6626
+ return statSync2(projectDirectory).mtimeMs;
6627
+ } catch {
6628
+ return 0;
6629
+ }
6630
+ }
6631
+ function fingerprintsEqual(a, b) {
6632
+ return a?.exists === b.exists && a.mtimeMs === b.mtimeMs && a.size === b.size;
6633
+ }
6634
+ function cacheFilesEqual(cachedFiles, currentFiles) {
6635
+ for (const [filePath, current] of currentFiles) {
6636
+ if (!fingerprintsEqual(cachedFiles.get(filePath), current)) {
6637
+ return false;
6638
+ }
6639
+ }
6640
+ return true;
6641
+ }
6642
+ function readCurrentFingerprints(projectDirectory) {
6643
+ const files = new Map;
6644
+ for (const filename of PROJECT_DOC_FILES) {
6645
+ const filePath = path2.join(projectDirectory, filename);
6646
+ files.set(filePath, fingerprintFile(filePath));
6647
+ }
6648
+ return { directoryMtimeMs: readDirectoryMtimeMs(projectDirectory), files };
6649
+ }
6650
+ function readCanonicalPieces(projectDirectory, files) {
6651
+ const hashPieces = [];
6652
+ const renderedSections = [];
6653
+ for (const filename of PROJECT_DOC_FILES) {
6654
+ const filePath = path2.join(projectDirectory, filename);
6655
+ const fingerprint = files.get(filePath);
6656
+ if (!fingerprint?.exists) {
6657
+ continue;
6658
+ }
6659
+ let safeToRead = false;
6660
+ try {
6661
+ const st = lstatSync(filePath);
6662
+ safeToRead = st.isFile() && st.size <= MAX_PROJECT_DOC_BYTES;
6663
+ } catch {
6664
+ safeToRead = false;
6665
+ }
6666
+ if (!safeToRead) {
6667
+ continue;
6668
+ }
6669
+ const canonicalContent = canonicalizeDocContent(readFileSync2(filePath, "utf8"));
6670
+ hashPieces.push(`file:${filename}
6671
+ ${canonicalContent}`);
6672
+ renderedSections.push(`<file name="${escapeXmlAttr(filename)}">
6673
+ ${escapeXmlContent(canonicalContent)}
6674
+ </file>`);
6675
+ }
6676
+ return { hashPieces, renderedSections };
6677
+ }
6678
+ function buildRenderedBlock(renderedSections) {
6679
+ if (renderedSections.length === 0) {
6680
+ return "";
6681
+ }
6682
+ return `<project-docs>
6683
+ ${renderedSections.join(`
6684
+
6685
+ `)}
6686
+ </project-docs>`;
6687
+ }
6688
+ function hashCanonicalPieces(hashPieces) {
6689
+ if (hashPieces.length === 0) {
6690
+ return "";
6691
+ }
6692
+ return createHash6("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
6693
+ }
6694
+ function readProjectDocsCanonical(projectDirectory) {
6695
+ const canonicalDirectory = path2.resolve(projectDirectory);
6696
+ const current = readCurrentFingerprints(canonicalDirectory);
6697
+ const cached = docsCache.get(canonicalDirectory);
6698
+ if (cached && cacheFilesEqual(cached.files, current.files)) {
6699
+ cached.directoryMtimeMs = current.directoryMtimeMs;
6700
+ return {
6701
+ renderedBlock: cached.cachedRendered,
6702
+ canonicalHash: cached.cachedHash
6703
+ };
6704
+ }
6705
+ const { hashPieces, renderedSections } = readCanonicalPieces(canonicalDirectory, current.files);
6706
+ const canonicalHash = hashCanonicalPieces(hashPieces);
6707
+ const renderedBlock = buildRenderedBlock(renderedSections);
6708
+ docsCache.set(canonicalDirectory, {
6709
+ directoryMtimeMs: current.directoryMtimeMs,
6710
+ files: current.files,
6711
+ cachedHash: canonicalHash,
6712
+ cachedRendered: renderedBlock
6713
+ });
6714
+ return { renderedBlock, canonicalHash };
6715
+ }
6716
+ function computeProjectDocsHash(projectDirectory) {
6717
+ return readProjectDocsCanonical(projectDirectory).canonicalHash;
6718
+ }
6719
+ // src/features/magic-context/storage-embedding-measurements.ts
6720
+ import { createHash as createHash7 } from "node:crypto";
6852
6721
  function normalizedQueryHash(query) {
6853
6722
  const normalized = query.trim().replace(/\s+/g, " ").toLowerCase();
6854
- return createHash6("sha256").update(normalized).digest("hex");
6723
+ return createHash7("sha256").update(normalized).digest("hex");
6855
6724
  }
6856
6725
  var MEASUREMENT_CORPUS_SESSION_ROW_CAP = 2000;
6857
6726
  function recordEmbeddingMeasurement(db, input) {
@@ -7067,7 +6936,7 @@ function getMemoryMutationsForRenderByIdentitySet(db, projectPaths, afterId, ren
7067
6936
  }
7068
6937
  visited.add(terminal);
7069
6938
  const next = byTarget.get(terminal);
7070
- if (!next || next.mutationType !== "superseded")
6939
+ if (next?.mutationType !== "superseded")
7071
6940
  break;
7072
6941
  if (depth >= MAX_MEMORY_REPLACEMENT_DEPTH - 1) {
7073
6942
  terminal = null;
@@ -7101,6 +6970,24 @@ function getMaxMemoryMutationIdForProjects(db, projectPaths) {
7101
6970
  WHERE project_path IN (${placeholders2(identities)})`).get(...identities);
7102
6971
  return row?.max_id ?? null;
7103
6972
  }
6973
+ // src/shared/context-limit-provenance.ts
6974
+ function normalizeContextLimitProvenance(value) {
6975
+ if (value === "prompt_only" || value === "combined")
6976
+ return value;
6977
+ return "unknown";
6978
+ }
6979
+
6980
+ // src/shared/escalation-bands.ts
6981
+ var MAX_EXECUTE_THRESHOLD = 90;
6982
+ var ABSOLUTE_EMERGENCY_PERCENTAGE = 95;
6983
+ function escalationBands(effectiveThresholdPercentage) {
6984
+ const threshold = Number.isFinite(effectiveThresholdPercentage) ? Math.min(effectiveThresholdPercentage, MAX_EXECUTE_THRESHOLD) : 65;
6985
+ return {
6986
+ forceMaterializationPercentage: Math.max(85, threshold + 2),
6987
+ emergencyPercentage: ABSOLUTE_EMERGENCY_PERCENTAGE
6988
+ };
6989
+ }
6990
+
7104
6991
  // src/features/magic-context/storage-meta-persisted.ts
7105
6992
  var emergencyRecoveryArmedSessions = new Set;
7106
6993
  var providerOverflowReconfirmedSessions = new Set;
@@ -7322,11 +7209,11 @@ function readRawWrapupState(db, sessionId) {
7322
7209
  return parseWrapupState(row?.wrapup_in_progress_state);
7323
7210
  }
7324
7211
  function getWrapupInProgressState(db, sessionId, now = Date.now()) {
7325
- const state = readRawWrapupState(db, sessionId);
7326
- if (!state)
7212
+ const state2 = readRawWrapupState(db, sessionId);
7213
+ if (!state2)
7327
7214
  return null;
7328
- if (state.expiresAt > now)
7329
- return state;
7215
+ if (state2.expiresAt > now)
7216
+ return state2;
7330
7217
  try {
7331
7218
  db.exec("BEGIN IMMEDIATE");
7332
7219
  } catch {
@@ -7352,10 +7239,10 @@ function getWrapupInProgressState(db, sessionId, now = Date.now()) {
7352
7239
  function isWrapupInProgress(db, sessionId, now = Date.now()) {
7353
7240
  return getWrapupInProgressState(db, sessionId, now) !== null;
7354
7241
  }
7355
- function acquireWrapupInProgress(db, sessionId, state, now = Date.now()) {
7242
+ function acquireWrapupInProgress(db, sessionId, state2, now = Date.now()) {
7356
7243
  const acquiredAt = now;
7357
7244
  const next = {
7358
- ...state,
7245
+ ...state2,
7359
7246
  acquiredAt,
7360
7247
  expiresAt: acquiredAt + WRAPUP_IN_PROGRESS_TTL_MS,
7361
7248
  updatedAt: acquiredAt
@@ -7365,7 +7252,7 @@ function acquireWrapupInProgress(db, sessionId, state, now = Date.now()) {
7365
7252
  try {
7366
7253
  ensureSessionMetaRow(db, sessionId);
7367
7254
  const current = readRawWrapupState(db, sessionId);
7368
- if (current && current.expiresAt > now && current.holderId !== state.holderId) {
7255
+ if (current && current.expiresAt > now && current.holderId !== state2.holderId) {
7369
7256
  db.exec("COMMIT");
7370
7257
  finished = true;
7371
7258
  return { ok: false, state: current };
@@ -7429,6 +7316,45 @@ function releaseWrapupInProgress(db, sessionId, holderId) {
7429
7316
  }
7430
7317
  }
7431
7318
  }
7319
+ var COMPACTION_MODE_RECORD_VALUES = new Set([
7320
+ "on",
7321
+ "off",
7322
+ "on_notice_pending",
7323
+ "off_notice_pending",
7324
+ "off_cleanup_pending"
7325
+ ]);
7326
+ function normalizeCompactionModeRecord(value) {
7327
+ if (value === null || value === undefined)
7328
+ return null;
7329
+ if (typeof value === "string" && COMPACTION_MODE_RECORD_VALUES.has(value)) {
7330
+ return value;
7331
+ }
7332
+ return null;
7333
+ }
7334
+ function resolveCompactionModeRecord(record) {
7335
+ switch (record) {
7336
+ case "on":
7337
+ case "on_notice_pending":
7338
+ return "on";
7339
+ case "off":
7340
+ case "off_notice_pending":
7341
+ case "off_cleanup_pending":
7342
+ return "off";
7343
+ default:
7344
+ return null;
7345
+ }
7346
+ }
7347
+ function getCompactionModeRecord(db, sessionId) {
7348
+ const row = db.prepare("SELECT compaction_mode_record FROM session_meta WHERE session_id = ?").get(sessionId);
7349
+ return normalizeCompactionModeRecord(row?.compaction_mode_record);
7350
+ }
7351
+ function setCompactionModeRecord(db, sessionId, value) {
7352
+ if (value !== null && !COMPACTION_MODE_RECORD_VALUES.has(value)) {
7353
+ throw new Error(`Invalid compaction_mode_record value: ${String(value)} (expected a supported compaction mode record or null)`);
7354
+ }
7355
+ ensureSessionMetaRow(db, sessionId);
7356
+ db.prepare("UPDATE session_meta SET compaction_mode_record = ? WHERE session_id = ?").run(value, sessionId);
7357
+ }
7432
7358
  function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
7433
7359
  if (usagePercentage >= 95)
7434
7360
  return Math.min(1e6, Math.max(4 * perRunCap, Math.round(0.5 * usable)));
@@ -7436,7 +7362,6 @@ function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
7436
7362
  return Math.min(750000, Math.max(3 * perRunCap, Math.round(0.35 * usable)));
7437
7363
  return Math.min(500000, Math.max(perRunCap, Math.round(0.2 * usable)));
7438
7364
  }
7439
- var EMERGENCY_DRAIN_ENTER_PERCENTAGE = 95;
7440
7365
  var EMERGENCY_DRAIN_EXIT_MARGIN = 10;
7441
7366
  var EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE = 55;
7442
7367
  var EMERGENCY_DRAIN_FAILURE_BACKOFF_MS = 60000;
@@ -7471,7 +7396,8 @@ function reserveProtectedTailDrainTokens(args) {
7471
7396
  }
7472
7397
  const exitThreshold = emergencyDrainExitThreshold(args.executeThresholdPercentage);
7473
7398
  let latchActiveSince = meta.emergencyDrainActive;
7474
- if (args.usagePercentage >= EMERGENCY_DRAIN_ENTER_PERCENTAGE) {
7399
+ const { forceMaterializationPercentage } = escalationBands(args.executeThresholdPercentage);
7400
+ if (args.usagePercentage >= forceMaterializationPercentage) {
7475
7401
  if (latchActiveSince <= 0)
7476
7402
  latchActiveSince = now;
7477
7403
  } else if (latchActiveSince > 0) {
@@ -7623,13 +7549,20 @@ function getChannel2NudgeState(db, sessionId) {
7623
7549
  function getChannel2NudgeClaim(db, sessionId) {
7624
7550
  const result = db.prepare("SELECT channel2_nudge_state, channel2_nudge_claimed_at, channel2_nudge_claim_token FROM session_meta WHERE session_id = ?").get(sessionId);
7625
7551
  const rawState = typeof result?.channel2_nudge_state === "string" ? result.channel2_nudge_state : "";
7626
- const state = rawState === "pending" || rawState === "claimed" || rawState === "delivered" ? rawState : "";
7552
+ const state2 = rawState === "pending" || rawState === "claimed" || rawState === "delivered" ? rawState : "";
7627
7553
  return {
7628
- state,
7554
+ state: state2,
7629
7555
  claimedAt: typeof result?.channel2_nudge_claimed_at === "number" ? result.channel2_nudge_claimed_at : 0,
7630
7556
  claimToken: typeof result?.channel2_nudge_claim_token === "string" ? result.channel2_nudge_claim_token : ""
7631
7557
  };
7632
7558
  }
7559
+ function setChannel2NudgeState(db, sessionId, state2) {
7560
+ db.transaction(() => {
7561
+ ensureSessionMetaRow(db, sessionId);
7562
+ const claimedAt = state2 === "claimed" ? Date.now() : 0;
7563
+ db.prepare("UPDATE session_meta SET channel2_nudge_state = ?, channel2_nudge_claimed_at = ?, channel2_nudge_claim_token = '' WHERE session_id = ?").run(state2, claimedAt, sessionId);
7564
+ })();
7565
+ }
7633
7566
  function casChannel2NudgeState(db, sessionId, from, to) {
7634
7567
  let changed = false;
7635
7568
  db.transaction(() => {
@@ -7809,6 +7742,18 @@ function removeAutoSearchHintDecisionByMessageId(db, sessionId, messageId) {
7809
7742
  }, { ensureRow: false });
7810
7743
  return ok && removed;
7811
7744
  }
7745
+ function getPersistedTodoPermissionDenied(db, sessionId) {
7746
+ const row = db.prepare("SELECT todo_permission_denied FROM session_meta WHERE session_id = ?").get(sessionId);
7747
+ if (row?.todo_permission_denied === 1)
7748
+ return true;
7749
+ if (row?.todo_permission_denied === 0)
7750
+ return false;
7751
+ return null;
7752
+ }
7753
+ function setPersistedTodoPermissionDenied(db, sessionId, denied) {
7754
+ ensureSessionMetaRow(db, sessionId);
7755
+ db.prepare("UPDATE session_meta SET todo_permission_denied = ? WHERE session_id = ?").run(denied ? 1 : 0, sessionId);
7756
+ }
7812
7757
  function getPersistedTodoSyntheticAnchor(db, sessionId) {
7813
7758
  const result = db.prepare("SELECT todo_synthetic_call_id, todo_synthetic_anchor_message_id, todo_synthetic_state_json FROM session_meta WHERE session_id = ?").get(sessionId);
7814
7759
  if (!isPersistedTodoSyntheticAnchorRow(result)) {
@@ -7885,17 +7830,19 @@ function normalizeEmergencyRecoveryOrigin(value) {
7885
7830
  return value === "provider_overflow" || value === "proactive_model_shrink" ? value : null;
7886
7831
  }
7887
7832
  function getOverflowState(db, sessionId, modelKey) {
7888
- const result = db.prepare("SELECT detected_context_limit, detected_context_limit_model_key, needs_emergency_recovery, emergency_recovery_origin FROM session_meta WHERE session_id = ?").get(sessionId);
7833
+ const result = db.prepare("SELECT detected_context_limit, detected_context_limit_model_key, detected_context_limit_provenance, needs_emergency_recovery, emergency_recovery_origin FROM session_meta WHERE session_id = ?").get(sessionId);
7889
7834
  if (!result) {
7890
7835
  return {
7891
7836
  detectedContextLimit: 0,
7892
7837
  detectedContextLimitModelKey: null,
7838
+ detectedContextLimitProvenance: "unknown",
7893
7839
  needsEmergencyRecovery: false,
7894
7840
  emergencyRecoveryOrigin: null
7895
7841
  };
7896
7842
  }
7897
7843
  const storedModelKey = normalizeDetectedLimitModelKey(result.detected_context_limit_model_key);
7898
7844
  const requestedModelKey = normalizeDetectedLimitModelKey(modelKey);
7845
+ const provenance = normalizeContextLimitProvenance(result.detected_context_limit_provenance);
7899
7846
  const limit = typeof result.detected_context_limit === "number" && result.detected_context_limit > 0 ? result.detected_context_limit : 0;
7900
7847
  const modelMatches = limit > 0 && requestedModelKey && storedModelKey ? requestedModelKey === storedModelKey : true;
7901
7848
  const needs = typeof result.needs_emergency_recovery === "number" && result.needs_emergency_recovery > 0;
@@ -7904,11 +7851,12 @@ function getOverflowState(db, sessionId, modelKey) {
7904
7851
  return {
7905
7852
  detectedContextLimit: modelMatches ? limit : 0,
7906
7853
  detectedContextLimitModelKey: storedModelKey,
7854
+ detectedContextLimitProvenance: provenance,
7907
7855
  needsEmergencyRecovery: needs,
7908
7856
  emergencyRecoveryOrigin: recoveryOrigin
7909
7857
  };
7910
7858
  }
7911
- function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin = "provider_overflow") {
7859
+ function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin = "provider_overflow", provenance = "unknown") {
7912
7860
  emergencyRecoveryArmedSessions.add(sessionId);
7913
7861
  db.transaction(() => {
7914
7862
  ensureSessionMetaRow(db, sessionId);
@@ -7917,18 +7865,18 @@ function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin =
7917
7865
  providerOverflowReconfirmedSessions.add(sessionId);
7918
7866
  }
7919
7867
  if (typeof reportedLimit === "number" && reportedLimit > 0) {
7920
- db.prepare("UPDATE session_meta SET detected_context_limit = ?, detected_context_limit_model_key = ?, needs_emergency_recovery = 1, emergency_recovery_origin = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, normalizeDetectedLimitModelKey(modelKey), origin, sessionId);
7868
+ db.prepare("UPDATE session_meta SET detected_context_limit = ?, detected_context_limit_model_key = ?, detected_context_limit_provenance = ?, needs_emergency_recovery = 1, emergency_recovery_origin = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, normalizeDetectedLimitModelKey(modelKey), normalizeContextLimitProvenance(provenance), origin, sessionId);
7921
7869
  } else {
7922
7870
  db.prepare("UPDATE session_meta SET needs_emergency_recovery = 1, emergency_recovery_origin = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(origin, sessionId);
7923
7871
  }
7924
7872
  })();
7925
7873
  }
7926
- function recordDetectedContextLimit(db, sessionId, reportedLimit, modelKey) {
7874
+ function recordDetectedContextLimit(db, sessionId, reportedLimit, modelKey, provenance = "unknown") {
7927
7875
  if (!(reportedLimit > 0))
7928
7876
  return;
7929
7877
  db.transaction(() => {
7930
7878
  ensureSessionMetaRow(db, sessionId);
7931
- db.prepare("UPDATE session_meta SET detected_context_limit = ?, detected_context_limit_model_key = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, normalizeDetectedLimitModelKey(modelKey), sessionId);
7879
+ db.prepare("UPDATE session_meta SET detected_context_limit = ?, detected_context_limit_model_key = ?, detected_context_limit_provenance = ?, observed_safe_input_tokens = 0, cache_alert_sent = 0 WHERE session_id = ?").run(reportedLimit, normalizeDetectedLimitModelKey(modelKey), normalizeContextLimitProvenance(provenance), sessionId);
7932
7880
  })();
7933
7881
  }
7934
7882
  function clearEmergencyRecovery(db, sessionId) {
@@ -7946,7 +7894,7 @@ function clearEmergencyRecovery(db, sessionId) {
7946
7894
  function clearDetectedContextLimit(db, sessionId) {
7947
7895
  db.transaction(() => {
7948
7896
  ensureSessionMetaRow(db, sessionId);
7949
- db.prepare("UPDATE session_meta SET detected_context_limit = 0, detected_context_limit_model_key = NULL WHERE session_id = ?").run(sessionId);
7897
+ db.prepare("UPDATE session_meta SET detected_context_limit = 0, detected_context_limit_model_key = NULL, detected_context_limit_provenance = 'unknown' WHERE session_id = ?").run(sessionId);
7950
7898
  })();
7951
7899
  }
7952
7900
  function getPersistedCompactionMarkerState(db, sessionId) {
@@ -7966,10 +7914,10 @@ function getPersistedCompactionMarkerState(db, sessionId) {
7966
7914
  } catch {}
7967
7915
  return null;
7968
7916
  }
7969
- function setPersistedCompactionMarkerState(db, sessionId, state) {
7917
+ function setPersistedCompactionMarkerState(db, sessionId, state2) {
7970
7918
  ensureSessionMetaRow(db, sessionId);
7971
- const json = state ? JSON.stringify(state) : "";
7972
- db.prepare("UPDATE session_meta SET compaction_marker_state = ?, compaction_marker_target_end_message_id = ? WHERE session_id = ?").run(json, state?.targetEndMessageId ?? null, sessionId);
7919
+ const json = state2 ? JSON.stringify(state2) : "";
7920
+ db.prepare("UPDATE session_meta SET compaction_marker_state = ?, compaction_marker_target_end_message_id = ? WHERE session_id = ?").run(json, state2?.targetEndMessageId ?? null, sessionId);
7973
7921
  }
7974
7922
  function getStrippedPlaceholderIds(db, sessionId) {
7975
7923
  const row = db.prepare("SELECT stripped_placeholder_ids FROM session_meta WHERE session_id = ?").get(sessionId);
@@ -8101,9 +8049,9 @@ function getPendingCompactionMarkerState(db, sessionId) {
8101
8049
  } catch {}
8102
8050
  return null;
8103
8051
  }
8104
- function setPendingCompactionMarkerState(db, sessionId, state) {
8052
+ function setPendingCompactionMarkerState(db, sessionId, state2) {
8105
8053
  ensureSessionMetaRow(db, sessionId);
8106
- const blob = state ? stableStringify(state) : null;
8054
+ const blob = state2 ? stableStringify(state2) : null;
8107
8055
  db.prepare("UPDATE session_meta SET pending_compaction_marker_state = ? WHERE session_id = ?").run(blob, sessionId);
8108
8056
  }
8109
8057
  function clearPendingCompactionMarkerStateIf(db, sessionId, expected) {
@@ -8374,6 +8322,14 @@ function getPendingOpsStatement(db) {
8374
8322
  }
8375
8323
  return stmt;
8376
8324
  }
8325
+ function getClearPendingOpsStatement(db) {
8326
+ let stmt = clearPendingOpsStatements.get(db);
8327
+ if (!stmt) {
8328
+ stmt = db.prepare("DELETE FROM pending_ops WHERE session_id = ?");
8329
+ clearPendingOpsStatements.set(db, stmt);
8330
+ }
8331
+ return stmt;
8332
+ }
8377
8333
  function getRemovePendingOpStatement(db) {
8378
8334
  let stmt = removePendingOpStatements.get(db);
8379
8335
  if (!stmt) {
@@ -8408,6 +8364,9 @@ function getPendingOps(db, sessionId) {
8408
8364
  const rows = getPendingOpsStatement(db).all(sessionId).filter(isPendingOpRow);
8409
8365
  return rows.map(toPendingOp).filter((op) => op !== null);
8410
8366
  }
8367
+ function clearPendingOps(db, sessionId) {
8368
+ getClearPendingOpsStatement(db).run(sessionId);
8369
+ }
8411
8370
  function removePendingOp(db, sessionId, tagId) {
8412
8371
  getRemovePendingOpStatement(db).run(sessionId, tagId);
8413
8372
  }
@@ -8603,11 +8562,11 @@ function bumpProjectMemoryEpoch(db, projectPath, now = Date.now()) {
8603
8562
  ON CONFLICT(project_path) DO UPDATE SET
8604
8563
  project_memory_epoch = project_memory_epoch + 1,
8605
8564
  updated_at = excluded.updated_at`).run(projectPath, now);
8606
- const state = getProjectState(db, projectPath);
8607
- if (!state) {
8565
+ const state2 = getProjectState(db, projectPath);
8566
+ if (!state2) {
8608
8567
  throw new Error(`Failed to bump project memory epoch for ${projectPath}`);
8609
8568
  }
8610
- return state;
8569
+ return state2;
8611
8570
  }
8612
8571
  function bumpProjectUserProfileVersion(db, projectPath = GLOBAL_USER_PROFILE_PROJECT_PATH, now = Date.now()) {
8613
8572
  db.prepare(`INSERT INTO project_state
@@ -8616,11 +8575,11 @@ function bumpProjectUserProfileVersion(db, projectPath = GLOBAL_USER_PROFILE_PRO
8616
8575
  ON CONFLICT(project_path) DO UPDATE SET
8617
8576
  project_user_profile_version = project_user_profile_version + 1,
8618
8577
  updated_at = excluded.updated_at`).run(projectPath, now);
8619
- const state = getProjectState(db, projectPath);
8620
- if (!state) {
8578
+ const state2 = getProjectState(db, projectPath);
8579
+ if (!state2) {
8621
8580
  throw new Error(`Failed to bump project user profile version for ${projectPath}`);
8622
8581
  }
8623
- return state;
8582
+ return state2;
8624
8583
  }
8625
8584
  // src/features/magic-context/storage-source.ts
8626
8585
  function isSourceContentRow(row) {
@@ -9210,6 +9169,518 @@ var ERROR_CLASSES = new Set([
9210
9169
  "permission_denied",
9211
9170
  "unknown"
9212
9171
  ]);
9172
+ // src/hooks/magic-context/child-session-spawn.ts
9173
+ var STALE_PLUGIN_RESTART_NOTICE = "Magic Context: plugin build is older than its database — restart OpenCode";
9174
+ async function surfaceStalePluginBuild(args) {
9175
+ if (!args.parentSessionId)
9176
+ return;
9177
+ try {
9178
+ if (args.db) {
9179
+ updateSessionMeta(args.db, args.parentSessionId, {
9180
+ lastTransformError: STALE_PLUGIN_RESTART_NOTICE
9181
+ });
9182
+ }
9183
+ pushNotification("toast", {
9184
+ title: "Magic Context",
9185
+ message: STALE_PLUGIN_RESTART_NOTICE,
9186
+ variant: "error",
9187
+ duration: 1e4
9188
+ }, args.parentSessionId);
9189
+ pushNotification("action", { action: "refresh-sidebar" }, args.parentSessionId);
9190
+ await sendIgnoredMessage(args.client, args.parentSessionId, STALE_PLUGIN_RESTART_NOTICE, args.notificationParams ?? {}, true);
9191
+ } catch (error) {
9192
+ sessionLog(args.parentSessionId, `stale plugin-build warning delivery failed: ${error instanceof Error ? error.message : String(error)}`);
9193
+ }
9194
+ }
9195
+ async function createChildSessionWithFence(args) {
9196
+ const verdict = probeChildSpawnFence(args.db);
9197
+ if (!verdict.allowSpawn) {
9198
+ if (args.parentSessionId) {
9199
+ sessionLog(args.parentSessionId, `child session skipped (${verdict.failure.failureClass}): database=v${verdict.failure.persistedVersion}, supported_fence=v${verdict.failure.supportedVersion}, consecutive=${verdict.failure.consecutiveFailures}, total=${verdict.failure.totalFailures}`);
9200
+ }
9201
+ if (verdict.shouldSurface) {
9202
+ if (args.onFenceLatched)
9203
+ await args.onFenceLatched(verdict.failure);
9204
+ else
9205
+ await surfaceStalePluginBuild(args);
9206
+ }
9207
+ return null;
9208
+ }
9209
+ return args.client.session.create({
9210
+ body: {
9211
+ ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
9212
+ title: args.title
9213
+ },
9214
+ query: { directory: args.directory }
9215
+ });
9216
+ }
9217
+ // src/features/magic-context/overflow-detection.ts
9218
+ var OVERFLOW_PATTERNS = [
9219
+ /prompt is too long/i,
9220
+ /input is too long for requested model/i,
9221
+ /exceeds the context window/i,
9222
+ /input token count.*exceeds the maximum/i,
9223
+ /maximum prompt length is \d+/i,
9224
+ /reduce the length of the messages/i,
9225
+ /maximum context length is \d+ tokens/i,
9226
+ /maximum model length is \d+/i,
9227
+ /exceeds the limit of \d+/i,
9228
+ /exceeds the available context size/i,
9229
+ /greater than the context length/i,
9230
+ /context window exceeds limit/i,
9231
+ /exceeded model token limit/i,
9232
+ /context[_ ]length[_ ]exceeded/i,
9233
+ /request entity too large/i,
9234
+ /context length is only \d+ tokens/i,
9235
+ /input length.*exceeds.*context length/i,
9236
+ /prompt too long; exceeded (?:max )?context length/i,
9237
+ /too large for model with \d+ maximum context length/i,
9238
+ /model_context_window_exceeded/i,
9239
+ /context size has been exceeded/i
9240
+ ];
9241
+ var LIMIT_EXTRACTION_PATTERNS = [
9242
+ { pattern: /maximum prompt length is (\d+)/i, provenance: "prompt_only" },
9243
+ {
9244
+ pattern: /maximum context length is (\d+) tokens?/i,
9245
+ provenance: "combined"
9246
+ },
9247
+ { pattern: /maximum model length is (\d+)/i, provenance: "combined" },
9248
+ { pattern: /context length is only (\d+) tokens?/i, provenance: "combined" },
9249
+ { pattern: /exceeds the limit of (\d+)/i, provenance: "unknown" },
9250
+ {
9251
+ pattern: /too large for model with (\d+) maximum context length/i,
9252
+ provenance: "combined"
9253
+ },
9254
+ { pattern: /context size.*(\d+) tokens?/i, provenance: "combined" },
9255
+ { pattern: /exceeds? the context length of (\d+)/i, provenance: "combined" },
9256
+ {
9257
+ pattern: />\s*(\d+)\s*(?:tokens?\s*)?(?:maximum|max|limit)\b/i,
9258
+ provenance: "prompt_only"
9259
+ },
9260
+ { pattern: /max(?:imum)?.*context.*?(\d+)/i, provenance: "unknown" }
9261
+ ];
9262
+ var MIN_PLAUSIBLE_LIMIT = 1024;
9263
+ var MAX_PLAUSIBLE_LIMIT = 1e7;
9264
+ function extractErrorMessage(error) {
9265
+ if (!error)
9266
+ return "";
9267
+ if (typeof error === "string")
9268
+ return error;
9269
+ if (typeof error === "object") {
9270
+ const obj = error;
9271
+ const nested = obj.error;
9272
+ if (nested && typeof nested.message === "string" && nested.message.length > 0) {
9273
+ return nested.message;
9274
+ }
9275
+ }
9276
+ if (error instanceof Error)
9277
+ return error.message;
9278
+ if (typeof error === "object") {
9279
+ const obj = error;
9280
+ if (typeof obj.message === "string")
9281
+ return obj.message;
9282
+ if (typeof obj.responseBody === "string")
9283
+ return obj.responseBody;
9284
+ try {
9285
+ return JSON.stringify(error);
9286
+ } catch {
9287
+ return String(error);
9288
+ }
9289
+ }
9290
+ return String(error);
9291
+ }
9292
+ function detectOverflow(error) {
9293
+ const message = extractErrorMessage(error);
9294
+ if (!message) {
9295
+ return { isOverflow: false };
9296
+ }
9297
+ const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
9298
+ let matched;
9299
+ for (const pattern of OVERFLOW_PATTERNS) {
9300
+ if (pattern.test(message)) {
9301
+ matched = pattern;
9302
+ break;
9303
+ }
9304
+ }
9305
+ if (!matched && !hasStatus413) {
9306
+ return { isOverflow: false };
9307
+ }
9308
+ const reportedLimit = parseReportedLimit(message);
9309
+ return {
9310
+ isOverflow: true,
9311
+ reportedLimit: reportedLimit?.value,
9312
+ reportedLimitProvenance: reportedLimit?.provenance,
9313
+ matchedPattern: matched?.source
9314
+ };
9315
+ }
9316
+ function parseReportedLimit(message) {
9317
+ if (!message)
9318
+ return;
9319
+ for (const { pattern, provenance } of LIMIT_EXTRACTION_PATTERNS) {
9320
+ const match = message.match(pattern);
9321
+ if (!match)
9322
+ continue;
9323
+ const raw = match[1];
9324
+ if (!raw)
9325
+ continue;
9326
+ const value = Number.parseInt(raw, 10);
9327
+ if (!Number.isFinite(value))
9328
+ continue;
9329
+ if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
9330
+ continue;
9331
+ return { value, provenance };
9332
+ }
9333
+ return;
9334
+ }
9335
+
9336
+ // src/shared/model-suggestion-retry.ts
9337
+ var ABORT_CALL_TIMEOUT_MS = 3000;
9338
+ function copyPromptArgs(args, body) {
9339
+ return { ...args, body: { ...body } };
9340
+ }
9341
+ function extractMessage(error) {
9342
+ if (typeof error === "string")
9343
+ return error;
9344
+ if (error instanceof Error)
9345
+ return error.message;
9346
+ if (typeof error === "object" && error !== null) {
9347
+ const obj = error;
9348
+ if (typeof obj.message === "string")
9349
+ return obj.message;
9350
+ }
9351
+ try {
9352
+ return JSON.stringify(error);
9353
+ } catch (_error) {
9354
+ return String(error);
9355
+ }
9356
+ }
9357
+ function parseModelSuggestion(error) {
9358
+ if (!error)
9359
+ return null;
9360
+ if (typeof error === "object" && error !== null) {
9361
+ const errObj = error;
9362
+ if (errObj.name === "ProviderModelNotFoundError" && typeof errObj.data === "object" && errObj.data !== null) {
9363
+ const data = errObj.data;
9364
+ const suggestions = data.suggestions;
9365
+ if (Array.isArray(suggestions) && typeof suggestions[0] === "string") {
9366
+ return {
9367
+ providerID: String(data.providerID ?? ""),
9368
+ modelID: String(data.modelID ?? ""),
9369
+ suggestion: suggestions[0]
9370
+ };
9371
+ }
9372
+ }
9373
+ for (const key of ["data", "error", "cause"]) {
9374
+ const nested = errObj[key];
9375
+ if (nested && typeof nested === "object") {
9376
+ const result = parseModelSuggestion(nested);
9377
+ if (result)
9378
+ return result;
9379
+ }
9380
+ }
9381
+ }
9382
+ const message = extractMessage(error);
9383
+ const modelMatch = message.match(/model not found:\s*([^/\s]+)\s*\/\s*([^.,\s]+)/i);
9384
+ const suggestionMatch = message.match(/did you mean:\s*([^,?]+)/i);
9385
+ if (!modelMatch || !suggestionMatch) {
9386
+ return null;
9387
+ }
9388
+ return {
9389
+ providerID: modelMatch[1].trim(),
9390
+ modelID: modelMatch[2].trim(),
9391
+ suggestion: suggestionMatch[1].trim()
9392
+ };
9393
+ }
9394
+ async function promptWithTimeout(client, args, timeoutMs, signal) {
9395
+ if (signal?.aborted) {
9396
+ throw new Error("prompt aborted by external signal");
9397
+ }
9398
+ const controller = new AbortController;
9399
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
9400
+ const onExternalAbort = () => controller.abort();
9401
+ signal?.addEventListener("abort", onExternalAbort);
9402
+ try {
9403
+ await client.session.prompt({
9404
+ ...args,
9405
+ signal: controller.signal
9406
+ });
9407
+ } catch (error) {
9408
+ if (signal?.aborted) {
9409
+ await abortChildRun(client, args.path.id);
9410
+ throw new Error("prompt aborted by external signal");
9411
+ }
9412
+ if (controller.signal.aborted) {
9413
+ await abortChildRun(client, args.path.id);
9414
+ throw new Error(`prompt timed out after ${timeoutMs}ms`);
9415
+ }
9416
+ throw error;
9417
+ } finally {
9418
+ clearTimeout(timeout);
9419
+ signal?.removeEventListener("abort", onExternalAbort);
9420
+ }
9421
+ }
9422
+ async function abortChildRun(client, sessionId) {
9423
+ try {
9424
+ await Promise.race([
9425
+ client.session.abort({ path: { id: sessionId } }),
9426
+ new Promise((resolve) => setTimeout(resolve, ABORT_CALL_TIMEOUT_MS))
9427
+ ]);
9428
+ } catch (error) {
9429
+ log(`[model-retry] child session abort failed for ${sessionId}: ${String(error)}`);
9430
+ }
9431
+ }
9432
+ function isNonRetryable(error, externalSignal) {
9433
+ if (externalSignal?.aborted)
9434
+ return true;
9435
+ if (error instanceof Error) {
9436
+ if (error.name === "AbortError")
9437
+ return true;
9438
+ if (error.message === "prompt aborted by external signal")
9439
+ return true;
9440
+ if (/^prompt timed out after \d+ms$/.test(error.message))
9441
+ return true;
9442
+ }
9443
+ if (detectOverflow(error).isOverflow)
9444
+ return true;
9445
+ return false;
9446
+ }
9447
+ function shortErr(error) {
9448
+ if (error instanceof Error) {
9449
+ return error.name && error.name !== "Error" ? `${error.name}: ${error.message}` : error.message;
9450
+ }
9451
+ return extractMessage(error);
9452
+ }
9453
+ async function attemptOnce(client, args, timeoutMs, signal, callContext, label) {
9454
+ const originalBody = { ...args.body };
9455
+ const attemptArgs = copyPromptArgs(args, originalBody);
9456
+ try {
9457
+ await promptWithTimeout(client, attemptArgs, timeoutMs, signal);
9458
+ return;
9459
+ } catch (error) {
9460
+ if (isNonRetryable(error, signal))
9461
+ throw error;
9462
+ const suggestion = parseModelSuggestion(error);
9463
+ if (!suggestion || !originalBody.model) {
9464
+ throw error;
9465
+ }
9466
+ log(`[${callContext}] ${label}: model not found, retrying with suggestion`, {
9467
+ original: `${suggestion.providerID}/${suggestion.modelID}`,
9468
+ suggested: suggestion.suggestion
9469
+ });
9470
+ await promptWithTimeout(client, copyPromptArgs(args, {
9471
+ ...originalBody,
9472
+ model: {
9473
+ providerID: suggestion.providerID,
9474
+ modelID: suggestion.suggestion
9475
+ }
9476
+ }), timeoutMs, signal);
9477
+ }
9478
+ }
9479
+ async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
9480
+ const timeoutMs = options.timeoutMs ?? 300000;
9481
+ const callContext = options.callContext ?? "subagent";
9482
+ const fallbacks = options.fallbackModels ?? [];
9483
+ const baseBody = { ...args.body };
9484
+ const baseArgs = copyPromptArgs(args, baseBody);
9485
+ const explicitPrimaryLabel = baseBody.model?.providerID && baseBody.model.modelID ? `${baseBody.model.providerID}/${baseBody.model.modelID}` : "primary";
9486
+ let lastError = null;
9487
+ try {
9488
+ await attemptOnce(client, baseArgs, timeoutMs, options.signal, callContext, explicitPrimaryLabel);
9489
+ return;
9490
+ } catch (error) {
9491
+ lastError = error;
9492
+ if (isNonRetryable(error, options.signal))
9493
+ throw error;
9494
+ if (fallbacks.length === 0) {
9495
+ throw error;
9496
+ }
9497
+ log(`[${callContext}] primary (${explicitPrimaryLabel}) failed: ${shortErr(error)}; trying ${fallbacks.length} fallback(s)`);
9498
+ }
9499
+ for (let i = 0;i < fallbacks.length; i += 1) {
9500
+ const parsed = parseProviderModel(fallbacks[i]);
9501
+ if (!parsed) {
9502
+ log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
9503
+ continue;
9504
+ }
9505
+ const label = `${parsed.providerID}/${parsed.modelID}`;
9506
+ const attemptArgs = copyPromptArgs(baseArgs, {
9507
+ ...baseBody,
9508
+ model: parsed
9509
+ });
9510
+ try {
9511
+ await attemptOnce(client, attemptArgs, timeoutMs, options.signal, callContext, label);
9512
+ log(`[${callContext}] fallback succeeded with ${label} (attempt ${i + 2}/${fallbacks.length + 1})`);
9513
+ return;
9514
+ } catch (error) {
9515
+ lastError = error;
9516
+ if (isNonRetryable(error, options.signal))
9517
+ throw error;
9518
+ const remaining = fallbacks.length - i - 1;
9519
+ if (remaining > 0) {
9520
+ log(`[${callContext}] ${label} failed: ${shortErr(error)}; ${remaining} fallback(s) left`);
9521
+ }
9522
+ }
9523
+ }
9524
+ log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; last error: ${shortErr(lastError)}`);
9525
+ throw lastError ?? new Error("All fallback models failed");
9526
+ }
9527
+ async function attemptAndValidate(client, args, timeoutMs, signal, callContext, attempt, options) {
9528
+ await attemptOnce(client, args, timeoutMs, signal, callContext, attempt.label);
9529
+ const output = await options.fetchOutput(args, attempt);
9530
+ const validated = await options.validateOutput(output, attempt);
9531
+ return { output, validated, attempt };
9532
+ }
9533
+ async function promptSyncWithValidatedOutputRetry(client, args, options) {
9534
+ const timeoutMs = options.timeoutMs ?? 300000;
9535
+ const callContext = options.callContext ?? "subagent";
9536
+ const fallbacks = options.fallbackModels ?? [];
9537
+ const baseBody = { ...args.body };
9538
+ const baseArgs = copyPromptArgs(args, baseBody);
9539
+ const explicitPrimaryLabel = baseBody.model?.providerID && baseBody.model.modelID ? `${baseBody.model.providerID}/${baseBody.model.modelID}` : "primary";
9540
+ const totalAttempts = fallbacks.length + 1;
9541
+ let firstError = null;
9542
+ let lastError = null;
9543
+ try {
9544
+ return await attemptAndValidate(client, baseArgs, timeoutMs, options.signal, callContext, {
9545
+ label: explicitPrimaryLabel,
9546
+ attemptIndex: 0,
9547
+ isFallback: false,
9548
+ totalAttempts,
9549
+ model: baseBody.model
9550
+ }, options);
9551
+ } catch (error) {
9552
+ firstError = error;
9553
+ lastError = error;
9554
+ if (isNonRetryable(error, options.signal))
9555
+ throw error;
9556
+ if (fallbacks.length === 0) {
9557
+ throw error;
9558
+ }
9559
+ log(`[${callContext}] primary (${explicitPrimaryLabel}) failed validation/prompt: ${shortErr(error)}; trying ${fallbacks.length} fallback(s)`);
9560
+ }
9561
+ for (let i = 0;i < fallbacks.length; i += 1) {
9562
+ const parsed = parseProviderModel(fallbacks[i]);
9563
+ if (!parsed) {
9564
+ log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
9565
+ continue;
9566
+ }
9567
+ const label = `${parsed.providerID}/${parsed.modelID}`;
9568
+ const attemptArgs = copyPromptArgs(baseArgs, {
9569
+ ...baseBody,
9570
+ model: parsed
9571
+ });
9572
+ const attempt = {
9573
+ label,
9574
+ attemptIndex: i + 1,
9575
+ isFallback: true,
9576
+ totalAttempts,
9577
+ model: parsed
9578
+ };
9579
+ try {
9580
+ const result = await attemptAndValidate(client, attemptArgs, timeoutMs, options.signal, callContext, attempt, options);
9581
+ log(`[${callContext}] fallback succeeded with ${label} (attempt ${i + 2}/${fallbacks.length + 1})`);
9582
+ return result;
9583
+ } catch (error) {
9584
+ if (firstError === null)
9585
+ firstError = error;
9586
+ lastError = error;
9587
+ if (isNonRetryable(error, options.signal))
9588
+ throw error;
9589
+ const remaining = fallbacks.length - i - 1;
9590
+ if (remaining > 0) {
9591
+ log(`[${callContext}] ${label} failed validation/prompt: ${shortErr(error)}; ${remaining} fallback(s) left`);
9592
+ }
9593
+ }
9594
+ }
9595
+ log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; original error: ${shortErr(firstError)}; last error: ${shortErr(lastError)}`);
9596
+ throw firstError ?? lastError ?? new Error("All fallback models failed validation");
9597
+ }
9598
+ // src/shared/normalize-sdk-response.ts
9599
+ function normalizeSDKResponse(response, fallback, options) {
9600
+ if (response === null || response === undefined) {
9601
+ return fallback;
9602
+ }
9603
+ if (Array.isArray(response)) {
9604
+ return response;
9605
+ }
9606
+ if (typeof response === "object" && "data" in response) {
9607
+ const data = response.data;
9608
+ if (data !== null && data !== undefined) {
9609
+ return data;
9610
+ }
9611
+ if (options?.preferResponseOnMissingData === true) {
9612
+ return response;
9613
+ }
9614
+ return fallback;
9615
+ }
9616
+ if (options?.preferResponseOnMissingData === true) {
9617
+ return response;
9618
+ }
9619
+ return fallback;
9620
+ }
9621
+ // src/shared/assistant-message-extractor.ts
9622
+ function asSessionMessage(value) {
9623
+ if (!isRecord(value))
9624
+ return null;
9625
+ const info = value.info;
9626
+ const parts = value.parts;
9627
+ return {
9628
+ info: isRecord(info) ? {
9629
+ role: typeof info.role === "string" ? info.role : undefined,
9630
+ time: isRecord(info.time) ? {
9631
+ created: typeof info.time.created === "number" ? info.time.created : undefined
9632
+ } : undefined
9633
+ } : undefined,
9634
+ parts
9635
+ };
9636
+ }
9637
+ function getCreatedTime(message) {
9638
+ return message.info?.time?.created ?? 0;
9639
+ }
9640
+ function getTextParts(message) {
9641
+ if (!Array.isArray(message.parts))
9642
+ return [];
9643
+ return message.parts.filter((part) => isRecord(part)).map((part) => ({
9644
+ type: typeof part.type === "string" ? part.type : undefined,
9645
+ text: typeof part.text === "string" ? part.text : undefined
9646
+ })).filter((part) => part.type === "text" && Boolean(part.text));
9647
+ }
9648
+ function extractLatestAssistantText(messages) {
9649
+ if (!Array.isArray(messages) || messages.length === 0)
9650
+ return null;
9651
+ const assistantMessages = messages.map(asSessionMessage).filter((message) => message !== null).filter((message) => message.info?.role === "assistant").sort((a, b) => getCreatedTime(b) - getCreatedTime(a));
9652
+ const latest = assistantMessages[0];
9653
+ if (!latest)
9654
+ return null;
9655
+ return getTextParts(latest).map((part) => part.text).join(`
9656
+ `) || null;
9657
+ }
9658
+ function hasLengthCappedOutput(value) {
9659
+ if (Array.isArray(value))
9660
+ return value.some((item) => hasLengthCappedOutput(item));
9661
+ if (!isRecord(value))
9662
+ return false;
9663
+ if (value.length_capped === true || value.lengthCapped === true)
9664
+ return true;
9665
+ const finishReason = value.finish_reason ?? value.finishReason;
9666
+ if (typeof finishReason === "string") {
9667
+ const normalized = finishReason.toLowerCase();
9668
+ if (normalized === "length" || normalized === "max_tokens" || normalized === "max_output_tokens") {
9669
+ return true;
9670
+ }
9671
+ }
9672
+ return Object.values(value).some((item) => hasLengthCappedOutput(item));
9673
+ }
9674
+
9675
+ // src/shared/keep-subagents.ts
9676
+ var keepSubagents = false;
9677
+ function setKeepSubagents(value) {
9678
+ keepSubagents = value === true;
9679
+ }
9680
+ function shouldKeepSubagents() {
9681
+ return keepSubagents;
9682
+ }
9683
+
9213
9684
  // src/features/magic-context/user-memory/storage-user-memory.ts
9214
9685
  var USER_MEMORY_CANDIDATE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
9215
9686
  function insertUserMemoryCandidates(db, candidates) {
@@ -9277,9 +9748,9 @@ function parseUserMemoryRow(row) {
9277
9748
  }
9278
9749
 
9279
9750
  // src/features/magic-context/mural/storage-mural-cues.ts
9280
- import { createHash as createHash7 } from "node:crypto";
9751
+ import { createHash as createHash8 } from "node:crypto";
9281
9752
  function computeCueContentHash(content) {
9282
- return createHash7("sha256").update(content).digest("hex");
9753
+ return createHash8("sha256").update(content).digest("hex");
9283
9754
  }
9284
9755
  var muralCueColumnCache = new WeakMap;
9285
9756
  function hasMuralCueColumns(db) {
@@ -9305,10 +9776,10 @@ function getMuralCueState(db, memoryIds) {
9305
9776
  }
9306
9777
  return out;
9307
9778
  }
9308
- function memoryNeedsCue(state, currentContent) {
9309
- if (!state || state.cue === null || state.hash === null)
9779
+ function memoryNeedsCue(state2, currentContent) {
9780
+ if (!state2 || state2.cue === null || state2.hash === null)
9310
9781
  return true;
9311
- return state.hash !== computeCueContentHash(currentContent);
9782
+ return state2.hash !== computeCueContentHash(currentContent);
9312
9783
  }
9313
9784
  function setMuralCue(db, projectPath, id, cue, contentHash) {
9314
9785
  if (!hasMuralCueColumns(db))
@@ -9330,7 +9801,6 @@ var deleteEmbeddingStatements = new WeakMap;
9330
9801
  var getStoredModelIdStatements = new WeakMap;
9331
9802
  var clearAllEmbeddingsStatements = new WeakMap;
9332
9803
  var clearModelEmbeddingsStatements = new WeakMap;
9333
- var getDistinctStoredModelIdsStatements = new WeakMap;
9334
9804
  function isEmbeddingBlob(value) {
9335
9805
  return value instanceof Uint8Array || value instanceof ArrayBuffer;
9336
9806
  }
@@ -9447,13 +9917,13 @@ function invalidateMemory(projectPath, memoryId) {
9447
9917
  }
9448
9918
 
9449
9919
  // src/features/magic-context/memory/normalize-hash.ts
9450
- import { createHash as createHash8 } from "node:crypto";
9920
+ import { createHash as createHash9 } from "node:crypto";
9451
9921
  function normalizeMemoryContent(content) {
9452
9922
  return content.toLowerCase().replace(/\s+/g, " ").trim();
9453
9923
  }
9454
9924
  function computeNormalizedHash(content) {
9455
9925
  const normalized = normalizeMemoryContent(content);
9456
- return createHash8("md5").update(normalized).digest("hex");
9926
+ return createHash9("md5").update(normalized).digest("hex");
9457
9927
  }
9458
9928
 
9459
9929
  // src/features/magic-context/memory/visibility.ts
@@ -10317,9 +10787,12 @@ async function runMemoryMigration(deps) {
10317
10787
  const modelOverride = modelId ? parseProviderModel(modelId) : null;
10318
10788
  await cleanupChildSession(agentSessionId);
10319
10789
  agentSessionId = null;
10320
- const createResponse = await client.session.create({
10321
- body: { parentID: parentSessionId, title: "magic-context-memory-migration" },
10322
- query: { directory }
10790
+ const createResponse = await createChildSessionWithFence({
10791
+ client,
10792
+ db,
10793
+ parentSessionId,
10794
+ title: "magic-context-memory-migration",
10795
+ directory
10323
10796
  });
10324
10797
  const created = normalizeSDKResponse(createResponse, null, {
10325
10798
  preferResponseOnMissingData: true
@@ -10419,7 +10892,7 @@ async function runMemoryMigration(deps) {
10419
10892
  }
10420
10893
 
10421
10894
  // src/features/magic-context/compartment-chunk-embedding.ts
10422
- import { createHash as createHash9 } from "node:crypto";
10895
+ import { createHash as createHash10 } from "node:crypto";
10423
10896
 
10424
10897
  // src/features/magic-context/recursive-text-splitter.ts
10425
10898
  var DEFAULT_SEPARATORS = [`
@@ -10514,9 +10987,6 @@ var existingHashStatements = new WeakMap;
10514
10987
  var existingHashByProjectStatements = new WeakMap;
10515
10988
  var deleteByCompartmentStatements = new WeakMap;
10516
10989
  var insertEmbeddingStatements = new WeakMap;
10517
- var distinctModelStatements = new WeakMap;
10518
- var clearProjectStatements = new WeakMap;
10519
- var clearProjectModelStatements = new WeakMap;
10520
10990
  var searchRowsStatements = new WeakMap;
10521
10991
  var searchRowsByModelStatements = new WeakMap;
10522
10992
  var searchPoolProbeStatements = new WeakMap;
@@ -10707,7 +11177,7 @@ function parseCanonicalLineRange(line) {
10707
11177
  return { start, end };
10708
11178
  }
10709
11179
  function hashChunkText(text) {
10710
- return createHash9("sha256").update(text).digest("hex");
11180
+ return createHash10("sha256").update(text).digest("hex");
10711
11181
  }
10712
11182
  function vectorBlob2(vector) {
10713
11183
  return new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength);
@@ -11098,7 +11568,7 @@ function countSessionCompartmentEmbedCoverage(db, projectPath, sessionId, modelI
11098
11568
  }
11099
11569
 
11100
11570
  // src/features/magic-context/project-embedding-registry.ts
11101
- import { createHash as createHash11, randomUUID as randomUUID2 } from "node:crypto";
11571
+ import { createHash as createHash12, randomUUID as randomUUID2 } from "node:crypto";
11102
11572
 
11103
11573
  // src/config/schema/magic-context.ts
11104
11574
  import { homedir as homedir2 } from "node:os";
@@ -25550,7 +26020,7 @@ var AgentOverrideConfigSchema = exports_external.object({
25550
26020
 
25551
26021
  // src/config/schema/magic-context.ts
25552
26022
  var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65;
25553
- var EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 80% for cache safety: a single large agent step can overflow the context window before Magic Context can compact between turns, forcing OpenCode's native compaction (hard to recover from). 80% also leaves headroom below the 85%/95% emergency bands. Use a value between 20 and 80.";
26023
+ var EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 90% for cache safety: output capacity is reserved from the usable context window, and the remaining 10% absorbs mid-turn growth before the absolute 95% emergency wall. Use a value between 20 and 90.";
25554
26024
  var DEFAULT_HISTORIAN_TIMEOUT_MS = 300000;
25555
26025
  var DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15;
25556
26026
  var DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";
@@ -25648,7 +26118,22 @@ var BaseEmbeddingConfigSchema = exports_external.object({
25648
26118
  input_type: exports_external.string().optional().describe("Default input_type for stored/indexed (passage) embeddings in the request body. Required by some openai-compatible providers (e.g. NVIDIA NIM). Omitted from the request when unset."),
25649
26119
  query_input_type: exports_external.string().optional().describe("Optional input_type for query (search) embeddings on asymmetric models (e.g. NVIDIA NIM 'query'). When unset, query embeddings use embedding.input_type. Passage/stored content always uses embedding.input_type."),
25650
26120
  truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset."),
25651
- max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted.")
26121
+ max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted."),
26122
+ local_dtype: exports_external.enum([
26123
+ "auto",
26124
+ "fp32",
26125
+ "fp16",
26126
+ "q8",
26127
+ "int8",
26128
+ "uint8",
26129
+ "q4",
26130
+ "bnb4",
26131
+ "q4f16",
26132
+ "q2",
26133
+ "q2f16",
26134
+ "q1",
26135
+ "q1f16"
26136
+ ]).optional().describe("Local provider only: ONNX model dtype passed to the transformers.js feature-extraction pipeline. Accepts the @huggingface/transformers DataType strings (auto, fp32, fp16, q8, int8, uint8, q4, bnb4, q4f16, q2, q2f16, q1, q1f16). Omitted keeps today's behavior (fp32). A non-default value changes the produced vectors and folds into the embedding model identity, so switching dtype re-embeds rather than mixing vector spaces. Useful for selecting a quantized variant (e.g. q8) of a larger multilingual model to cut memory and CPU cost; see issue #259.")
25652
26137
  }).superRefine((data, ctx) => {
25653
26138
  const validationProvider = data.provider === "synapse" ? data.fallback_provider : data.provider;
25654
26139
  if (validationProvider === "openai-compatible" && !data.endpoint?.trim()) {
@@ -25690,7 +26175,8 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
25690
26175
  return {
25691
26176
  provider: "local",
25692
26177
  model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
25693
- ...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
26178
+ ...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {},
26179
+ ...data.local_dtype ? { local_dtype: data.local_dtype } : {}
25694
26180
  };
25695
26181
  }
25696
26182
  if (data.provider === "openai-compatible") {
@@ -25713,6 +26199,7 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
25713
26199
  });
25714
26200
  var MagicContextConfigSchema = exports_external.object({
25715
26201
  enabled: exports_external.boolean().default(true).describe("Enable magic context (default: true)"),
26202
+ allow_home_project: exports_external.boolean().default(false).describe("Allow Magic Context sessions launched from the exact canonical home directory. The home session uses its deterministic dir: identity so pre-gate memories reconnect. USER-LEVEL ONLY: project config is ignored. The home identity is excluded from registry seed exports, never resolves descendants by containment, and cannot join a workspace."),
25716
26203
  experimental: exports_external.object({
25717
26204
  mural: exports_external.object({
25718
26205
  enabled: exports_external.boolean().default(false),
@@ -25724,15 +26211,19 @@ var MagicContextConfigSchema = exports_external.object({
25724
26211
  language: exports_external.string().trim().toLowerCase().refine((s) => isValidLanguageCode(s), 'language must be a 2-letter ISO 639-1 code (e.g. "tr", "es", "de")').optional().describe("Output language for Magic Context's generated content and guidance, as a " + '2-letter ISO 639-1 code (e.g. "tr", "es", "de", "ja", "pt"). When set, the ' + "historian, dreamer, sidekick, and the agent-guidance block instruct the model to " + "write its PROSE in this language while keeping all structural tokens (XML tags, " + "the five memory category names, code identifiers, file paths) in English. " + "USER-LEVEL ONLY (ignored in project config for security). Unset = today's " + "behavior (model mirrors the conversation; English scaffolding). Changing it " + "triggers one cache re-materialization; existing compartments/memories keep their " + "original language until naturally rewritten."),
25725
26212
  historian: HistorianConfigSchema.describe("Historian agent configuration (model, fallback_models, variant, temperature, maxTokens, permission, two_pass, etc.)"),
25726
26213
  dreamer: DreamerConfigSchema.optional().describe("Dreamer agent + scheduling configuration (model, fallback_models, disable, schedule, tasks, etc.)"),
25727
- cache_ttl: exports_external.union([exports_external.string(), exports_external.object({ default: exports_external.string() }).catchall(exports_external.string())]).default("5m").describe('Cache TTL: string (e.g. "5m") or per-model object ({ default: "5m", "model-id": "10m" })'),
26214
+ cache_ttl: exports_external.union([exports_external.string(), exports_external.object({ default: exports_external.string() }).catchall(exports_external.string())]).default("5m").describe('Cache TTL: string (e.g. "5m", "1h", "30s") or per-model object ({ default: "5m", "model-id": "10m" }). Set to "never" for lanes kept warm by an external keepwarm proxy — disables the idle-TTL heuristic so MC never initiates a rebuild based on elapsed time.'),
26215
+ output_reserve: exports_external.union([
26216
+ exports_external.number().min(0),
26217
+ exports_external.object({ default: exports_external.number().min(0) }).catchall(exports_external.number().min(0))
26218
+ ]).optional().describe('User-only output-token reservation override. Number or per-model object ({ default: 16384, "provider/model": 8192 }); 0 disables reservation. When unset, Magic Context reserves the catalog output limit (capped at 25% of context) for shared-window providers and keeps proven separate-quota Google/Gemini windows unchanged.'),
25728
26219
  toast_duration_ms: exports_external.number().min(0).max(60000).default(5000).describe("TUI toast lifetime in milliseconds for Magic Context notifications. Set to 0 to disable Magic Context toasts entirely (min: 0, max: 60000, default: 5000)"),
25729
26220
  execute_threshold_percentage: exports_external.union([
25730
- exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE),
25731
- exports_external.object({ default: exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE) }).catchall(exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE))
25732
- ]).default(DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE).describe('Context percentage that forces queued operations to execute. Number or per-model object ({ default: 65, "provider/model": 45 }). Values above 80 are rejected because the runtime caps at 80% for cache safety (MAX_EXECUTE_THRESHOLD). Default: DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE'),
26221
+ exports_external.number().min(20).max(90, EXECUTE_THRESHOLD_CAP_MESSAGE),
26222
+ exports_external.object({ default: exports_external.number().min(20).max(90, EXECUTE_THRESHOLD_CAP_MESSAGE) }).catchall(exports_external.number().min(20).max(90, EXECUTE_THRESHOLD_CAP_MESSAGE))
26223
+ ]).default(DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE).describe('Context percentage that forces queued operations to execute. Number or per-model object ({ default: 65, "provider/model": 45 }). Values above 90 are rejected because the runtime caps at 90% of the output-reserved safe window (MAX_EXECUTE_THRESHOLD). Default: DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE'),
25733
26224
  execute_threshold_tokens: exports_external.object({
25734
26225
  default: exports_external.number().min(5000).max(2000000).optional()
25735
- }).catchall(exports_external.number().min(5000).max(2000000)).optional().describe("Absolute token thresholds per model. When matched, overrides execute_threshold_percentage for that model. Accepts `default` for all models or per-model keys. Values above 80% × context_limit are clamped with a warning log. Min 5_000, max 2_000_000."),
26226
+ }).catchall(exports_external.number().min(5000).max(2000000)).optional().describe("Absolute token thresholds per model. When matched, overrides execute_threshold_percentage for that model. Accepts `default` for all models or per-model keys. Values above 90% × context_limit are clamped with a warning log. Min 5_000, max 2_000_000."),
25736
26227
  protected_tags: exports_external.number().min(1).max(100).optional().describe("Number of recent tags to protect from dropping (min: 1, max: 100, default: 20)"),
25737
26228
  clear_reasoning_age: exports_external.number().min(10).default(50).describe("Clear reasoning/thinking blocks older than N tags (default: 50)"),
25738
26229
  history_budget_percentage: exports_external.number().min(0.05).max(0.5).default(DEFAULT_HISTORY_BUDGET_PERCENTAGE).describe("Fraction of usable context (context_limit × execute_threshold) reserved for the session history block (default: 0.15)"),
@@ -25752,6 +26243,9 @@ var MagicContextConfigSchema = exports_external.object({
25752
26243
  cache_size_mb: exports_external.number().min(2).max(2048).default(64).describe("Page-cache size in MiB per connection (PRAGMA cache_size). Larger keeps more hot pages resident, cutting re-reads on repeated full-table scans. (min 2, max 2048, default 64)"),
25753
26244
  mmap_size_mb: exports_external.number().min(0).max(8192).default(0).describe("Memory-mapped I/O size in MiB (PRAGMA mmap_size). 0 disables mmap (SQLite default). Raising it can cut read overhead on large DBs at the cost of address space. (min 0, max 8192, default 0)")
25754
26245
  }).default({ cache_size_mb: 64, mmap_size_mb: 0 }).describe("SQLite connection tuning for Magic Context's own context.db. These are per-connection PRAGMAs applied at open; they do not change the schema or what is stored."),
26246
+ storage: exports_external.object({
26247
+ enforce_private_permissions: exports_external.boolean().default(true).describe("When true (default), Magic Context creates and re-tightens its storage directories to owner-only 0700 and storage files to owner-only 0600. Set false only for a deliberate trusted-group deployment whose operator manages directory, database, WAL/SHM, cache, and RPC file permissions externally; Magic Context then never chmods or supplies restrictive creation modes. USER-LEVEL ONLY — ignored in project config for security. On Windows, POSIX chmod modes are already meaningless, so this setting is a no-op.")
26248
+ }).default({ enforce_private_permissions: true }).describe("Storage permission policy. The default keeps session content and memories owner-private. Disabling enforcement is for trusted shared-group storage managed externally; every group member able to read the storage can read all stored session content and memories."),
25755
26249
  embedding: EmbeddingConfigSchema.default({
25756
26250
  provider: "local",
25757
26251
  model: DEFAULT_LOCAL_EMBEDDING_MODEL
@@ -25765,6 +26259,9 @@ var MagicContextConfigSchema = exports_external.object({
25765
26259
  temporal_awareness: exports_external.boolean().default(true).describe('Inject wall-clock gap markers (<!-- +Xm -->) between user messages where > 5 min elapsed since the previous message, and add compact date ranges to compartment headings. Gives the agent a sense of session pacing and "how long ago" across multi-day sessions. Graduated from experimental.temporal_awareness; default: true (set false to opt out).'),
25766
26260
  keep_subagents: exports_external.boolean().default(false).describe("Debug: keep the child sessions Magic Context spawns for its own subagents (historian, dreamer, sidekick, memory-migration) instead of deleting them on success. Useful for short-term inspection/data collection — their full transcript (prompt, tool calls, token usage, output) stays in the host session store. Kept sessions accumulate until manually cleared; leave false for normal use. Requires a restart to take effect."),
25767
26261
  fail_closed_blocking: exports_external.boolean().default(true).describe("When Magic Context cannot operate (schema fence mismatch, storage open/migration failure), block the primary-session prompt with a loud recovery error instead of silently degrading to native compaction. Default true. Set false only to restore the old degrade-silently behavior (not recommended). USER-LEVEL ONLY — ignored in project config for security. Requires a restart."),
26262
+ compaction: exports_external.object({
26263
+ enabled: exports_external.boolean().default(true).describe("When false, Magic Context stops managing the context window and keeps its knowledge layer: memory and docs/user-profile/key-files injection through additive m[0]/m[1], raw-message FTS indexing, dreamer, notes, ctx_search, ctx_expand, ctx_memory, and /ctx-embed remain available. MC's historian/compartment preparation, tagging, markers, pruning, folding, drops, strips, splicing, synthetic context-management todos, temporal markers, nudges, and fail-closed blocking stop; ctx_expand remains a knowledge-surface tool. fail_closed_blocking is inert: a transform failure passes the input messages through without blocking or cancelling. This setting does not enable native compaction: OpenCode's compaction.auto / compaction.prune or Pi's equivalent owns the window, or nothing does. MC's compaction.enabled in magic-context.jsonc is distinct from OpenCode's compaction.auto / compaction.prune in opencode.jsonc; they are different files and different owners. On the first turn after disabling, a long session may trigger one native compaction cycle; MC removes only its own marker boundary, leaves native boundaries and stored compartments intact, and does no pre-trimming mitigation. Marker cleanup is lazy per session, so an unresumed session is cleaned when it is next resumed. If compaction is enabled again, run /ctx-wrapup when the historian is runnable to catch up. OpenCode peer verification against v1.18.4 confirms native compaction covers child sessions: subagents receive additive memory/docs injection and no MC reclaim in this mode, so keep subagent tasks small or leave compaction.enabled on for long subagent runs. If transform_mode is rust, compaction-off resolves to the TypeScript transform and emits one frozen boot warning because there is no Rust reduced-mode contract. This is boot-resolved and requires a process restart; project-tier compaction.enabled is stripped so a cloned repository cannot disable the user's setting. The sidebar reports raw usage as Context: <pct>% · native compaction or Context: <pct>% · no active compaction and does not show an MC execute-threshold fill. /ctx-wrapup, /ctx-recomp, /ctx-flush, and /ctx-session-upgrade refuse without context-management side effects; /ctx-embed remains functional. Raw content hidden by a native boundary before Magic Context's first pass is not retroactively indexed.")
26264
+ }).default({ enabled: true }).describe("Compaction-off mode gate. Default true (MC manages the context window as today). Set compaction.enabled=false to keep the knowledge layer while letting native compaction (or nothing) own the window. Boot-resolved; requires a restart to change."),
25768
26265
  todowrite: exports_external.object({
25769
26266
  enabled: exports_external.boolean().default(true).describe("Pi only: register Magic Context's todowrite task-list tool. Disable if you use your own todo extension. OpenCode ships its own built-in todowrite; this setting has no effect there."),
25770
26267
  overlay: exports_external.boolean().default(true).describe("Pi only: show the persistent todo overlay above the editor while tasks are active.")
@@ -25811,9 +26308,6 @@ var saveStatements = new WeakMap;
25811
26308
  var loadProjectStatements = new WeakMap;
25812
26309
  var loadUnembeddedStatements = new WeakMap;
25813
26310
  var countEmbeddedStatements = new WeakMap;
25814
- var clearProjectStatements2 = new WeakMap;
25815
- var clearProjectModelStatements2 = new WeakMap;
25816
- var distinctModelIdStatements = new WeakMap;
25817
26311
  function getSaveStatement(db) {
25818
26312
  let stmt = saveStatements.get(db);
25819
26313
  if (!stmt) {
@@ -25884,7 +26378,6 @@ function countEmbeddedCommits(db, projectPath, modelId) {
25884
26378
  var insertStatements = new WeakMap;
25885
26379
  var existingShasStatements = new WeakMap;
25886
26380
  var projectCountStatements = new WeakMap;
25887
- var evictStatements = new WeakMap;
25888
26381
  var evictOverflowStatements = new WeakMap;
25889
26382
  var latestCommitTimeStatements = new WeakMap;
25890
26383
  function getInsertStatement(db) {
@@ -26126,7 +26619,7 @@ function releaseGitSweepLease(db, projectPath, holderId) {
26126
26619
  }
26127
26620
 
26128
26621
  // src/features/magic-context/memory/embedding-synapse.ts
26129
- import { createHash as createHash10 } from "node:crypto";
26622
+ import { createHash as createHash11 } from "node:crypto";
26130
26623
 
26131
26624
  // ../../node_modules/.bun/@cortexkit+subc-client@0.4.1/node_modules/@cortexkit/subc-client/dist/client.js
26132
26625
  import { promises as fs2 } from "node:fs";
@@ -28339,7 +28832,7 @@ function wait(ms) {
28339
28832
  return new Promise((resolve) => setTimeout(resolve, ms));
28340
28833
  }
28341
28834
  function sha256(value) {
28342
- return createHash10("sha256").update(value).digest("hex");
28835
+ return createHash11("sha256").update(value).digest("hex");
28343
28836
  }
28344
28837
  function stableJson(value) {
28345
28838
  if (Array.isArray(value))
@@ -28387,7 +28880,7 @@ function extractCatalogEntries(value) {
28387
28880
  const batchRecord = asRecord(rawBatch);
28388
28881
  const recommendedBatch = typeof rawBatch === "number" ? rawBatch : batchRecord ? batchRecord.rows : undefined;
28389
28882
  const recommendedTokenBudget = batchRecord ? batchRecord.token_budget : undefined;
28390
- const state = typeof record2.state === "string" ? record2.state : undefined;
28883
+ const state2 = typeof record2.state === "string" ? record2.state : undefined;
28391
28884
  return [
28392
28885
  {
28393
28886
  model,
@@ -28398,7 +28891,7 @@ function extractCatalogEntries(value) {
28398
28891
  ...typeof recommendedTokenBudget === "number" && recommendedTokenBudget > 0 ? { recommended_token_budget: Math.floor(recommendedTokenBudget) } : {},
28399
28892
  ...record2.provenance !== undefined ? { provenance: record2.provenance } : {},
28400
28893
  ...typeof record2.certified === "boolean" ? { certified: record2.certified } : {},
28401
- ...typeof record2.status === "string" ? { status: record2.status } : state ? { status: state } : {}
28894
+ ...typeof record2.status === "string" ? { status: record2.status } : state2 ? { status: state2 } : {}
28402
28895
  }
28403
28896
  ];
28404
28897
  });
@@ -28784,6 +29277,7 @@ function getEmbeddingProviderIdentity(config2) {
28784
29277
  throw new Error("Unknown embedding provider");
28785
29278
  }
28786
29279
  const truncate = config2.provider === "openai-compatible" ? config2.truncate?.trim() : undefined;
29280
+ const localDtype = config2.provider === "local" && config2.local_dtype && config2.local_dtype !== "fp32" ? config2.local_dtype : undefined;
28787
29281
  const identityInput = config2.provider === "openai-compatible" ? {
28788
29282
  provider: "openai-compatible",
28789
29283
  model: config2.model.trim(),
@@ -28795,7 +29289,8 @@ function getEmbeddingProviderIdentity(config2) {
28795
29289
  provider: "local",
28796
29290
  model: config2.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
28797
29291
  endpoint: "",
28798
- apiKeyPresent: false
29292
+ apiKeyPresent: false,
29293
+ ...localDtype ? { localDtype } : {}
28799
29294
  };
28800
29295
  return `embedding-provider:${computeNormalizedHash(JSON.stringify(identityInput))}`;
28801
29296
  }
@@ -28803,7 +29298,7 @@ function getEmbeddingProviderIdentity(config2) {
28803
29298
  // src/features/magic-context/memory/embedding-local.ts
28804
29299
  import { chmodSync as chmodSync2, mkdirSync as mkdirSync2 } from "node:fs";
28805
29300
  import { open, stat, unlink, writeFile } from "node:fs/promises";
28806
- import { dirname as dirname2, join as join3 } from "node:path";
29301
+ import { dirname as dirname2, join as join4 } from "node:path";
28807
29302
  import { pathToFileURL } from "node:url";
28808
29303
  var LOCK_POLL_MS = 150;
28809
29304
  var STALE_LOCK_MS = 3 * 60000;
@@ -28883,6 +29378,7 @@ async function injectWasmOrtForElectron() {
28883
29378
  return false;
28884
29379
  }
28885
29380
  }
29381
+ var DEFAULT_LOCAL_DTYPE = "fp32";
28886
29382
  async function withQuietConsole(fn) {
28887
29383
  const origWarn = console.warn;
28888
29384
  const origError = console.error;
@@ -28959,16 +29455,22 @@ class LocalEmbeddingProvider {
28959
29455
  modelId;
28960
29456
  maxInputTokens;
28961
29457
  model;
29458
+ dtype;
28962
29459
  pipeline = null;
28963
29460
  initPromise = null;
28964
29461
  inFlight = 0;
28965
29462
  disposing = false;
28966
29463
  disposePromise = null;
28967
29464
  inFlightWaiters = [];
28968
- constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
29465
+ constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512, dtype = DEFAULT_LOCAL_DTYPE) {
28969
29466
  this.model = model;
28970
29467
  this.maxInputTokens = maxInputTokens;
28971
- this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
29468
+ this.dtype = dtype || DEFAULT_LOCAL_DTYPE;
29469
+ this.modelId = getEmbeddingProviderIdentity({
29470
+ provider: "local",
29471
+ model,
29472
+ ...dtype && dtype !== DEFAULT_LOCAL_DTYPE ? { local_dtype: dtype } : {}
29473
+ });
28972
29474
  }
28973
29475
  async initialize() {
28974
29476
  if (this.disposing) {
@@ -28997,20 +29499,24 @@ class LocalEmbeddingProvider {
28997
29499
  if (LogLevel && "ERROR" in LogLevel) {
28998
29500
  env.logLevel = LogLevel.ERROR;
28999
29501
  }
29000
- const modelCacheDir = join3(getMagicContextStorageDir(), "models");
29502
+ const modelCacheDir = join4(getMagicContextStorageDir(), "models");
29001
29503
  try {
29002
- mkdirSync2(modelCacheDir, { recursive: true, mode: 448 });
29003
- if (process.platform !== "win32") {
29004
- try {
29005
- chmodSync2(modelCacheDir, 448);
29006
- } catch {}
29504
+ if (shouldEnforcePrivateStoragePermissions()) {
29505
+ mkdirSync2(modelCacheDir, { recursive: true, mode: 448 });
29506
+ if (process.platform !== "win32") {
29507
+ try {
29508
+ chmodSync2(modelCacheDir, 448);
29509
+ } catch {}
29510
+ }
29511
+ } else {
29512
+ mkdirSync2(modelCacheDir, { recursive: true });
29007
29513
  }
29008
29514
  env.cacheDir = modelCacheDir;
29009
29515
  } catch {
29010
29516
  log("[magic-context] could not create model cache dir, using library default");
29011
29517
  }
29012
29518
  const createPipeline = transformersModule.pipeline;
29013
- const lockPath = join3(modelCacheDir, ".load.lock");
29519
+ const lockPath = join4(modelCacheDir, ".load.lock");
29014
29520
  const releaseLock = await acquireModelLoadLock(lockPath);
29015
29521
  const stopHeartbeat = startLockHeartbeat(lockPath);
29016
29522
  try {
@@ -29019,7 +29525,7 @@ class LocalEmbeddingProvider {
29019
29525
  for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
29020
29526
  try {
29021
29527
  const pipeline = await withQuietConsole(() => createPipeline("feature-extraction", this.model, {
29022
- dtype: "fp32",
29528
+ dtype: this.dtype,
29023
29529
  ...injectedWasmOrt ? { device: "auto" } : {}
29024
29530
  }));
29025
29531
  if (this.disposing) {
@@ -29670,7 +30176,8 @@ function resolveEmbeddingConfig(config2) {
29670
30176
  model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
29671
30177
  ...config2?.max_input_tokens ? {
29672
30178
  max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
29673
- } : {}
30179
+ } : {},
30180
+ ...config2?.local_dtype ? { local_dtype: config2.local_dtype } : {}
29674
30181
  };
29675
30182
  }
29676
30183
  if (config2.provider === "openai-compatible") {
@@ -29729,7 +30236,7 @@ function createProvider(config2, context) {
29729
30236
  });
29730
30237
  }
29731
30238
  if (config2.provider === "local") {
29732
- return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
30239
+ return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens, config2.local_dtype);
29733
30240
  }
29734
30241
  if (config2.provider === "synapse") {
29735
30242
  const synapse = config2;
@@ -29758,10 +30265,10 @@ function stableStringify2(value) {
29758
30265
  return JSON.stringify(value);
29759
30266
  }
29760
30267
  function sha256Prefix(value, length = 16) {
29761
- return createHash11("sha256").update(value).digest("hex").slice(0, length);
30268
+ return createHash12("sha256").update(value).digest("hex").slice(0, length);
29762
30269
  }
29763
30270
  function contentSha256(value) {
29764
- return createHash11("sha256").update(value).digest("hex");
30271
+ return createHash12("sha256").update(value).digest("hex");
29765
30272
  }
29766
30273
  function getRuntimeFingerprint(config2) {
29767
30274
  if (config2.provider === "off") {
@@ -31036,12 +31543,12 @@ function parseFields(json2) {
31036
31543
  }
31037
31544
 
31038
31545
  // src/hooks/magic-context/historian-state-file.ts
31039
- import { mkdirSync as mkdirSync3, unlinkSync, writeFileSync } from "node:fs";
31546
+ import { mkdirSync as mkdirSync3, unlinkSync as unlinkSync2, writeFileSync } from "node:fs";
31040
31547
  function cleanupHistorianStateFile(path3) {
31041
31548
  if (!path3)
31042
31549
  return;
31043
31550
  try {
31044
- unlinkSync(path3);
31551
+ unlinkSync2(path3);
31045
31552
  } catch {}
31046
31553
  }
31047
31554
  // src/features/magic-context/memory/cosine-similarity.ts
@@ -31084,7 +31591,7 @@ function createProvider2(config2) {
31084
31591
  });
31085
31592
  }
31086
31593
  if (config2.provider === "local") {
31087
- return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
31594
+ return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens, config2.local_dtype);
31088
31595
  }
31089
31596
  if (config2.provider === "synapse") {
31090
31597
  const synapse = config2;
@@ -31356,8 +31863,8 @@ function getMemoryVerifications(db, memoryIds) {
31356
31863
  existing.mappedAt = Math.max(existing.mappedAt, row.mapped_at ?? 0);
31357
31864
  result.set(row.memory_id, existing);
31358
31865
  }
31359
- for (const state of result.values()) {
31360
- state.files.sort();
31866
+ for (const state2 of result.values()) {
31867
+ state2.files.sort();
31361
31868
  }
31362
31869
  return result;
31363
31870
  }
@@ -31594,18 +32101,18 @@ function tallyFactsByCategory(facts) {
31594
32101
  }
31595
32102
 
31596
32103
  // src/hooks/magic-context/compaction-marker-manager.ts
31597
- import { join as join5 } from "node:path";
32104
+ import { join as join6 } from "node:path";
31598
32105
 
31599
32106
  // src/features/magic-context/compaction-marker.ts
31600
- import { createHash as createHash12 } from "node:crypto";
32107
+ import { createHash as createHash13 } from "node:crypto";
31601
32108
  import { existsSync as existsSync5 } from "node:fs";
31602
- import { join as join4 } from "node:path";
32109
+ import { join as join5 } from "node:path";
31603
32110
  var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
31604
32111
  var ID_PREFIX_HEX_LENGTH = 12;
31605
32112
  var ID_SUFFIX_LENGTH = 14;
31606
32113
  var ID_PREFIX_MASK = (1n << BigInt(ID_PREFIX_HEX_LENGTH * 4)) - 1n;
31607
32114
  function deterministicBase62(seed, length) {
31608
- let value = BigInt(`0x${createHash12("sha256").update(seed).digest("hex")}`);
32115
+ let value = BigInt(`0x${createHash13("sha256").update(seed).digest("hex")}`);
31609
32116
  const chars = Array(length);
31610
32117
  for (let index = length - 1;index >= 0; index -= 1) {
31611
32118
  chars[index] = BASE62_CHARS[Number(value % 62n)];
@@ -31625,7 +32132,7 @@ function generatePartId(timestampMs, counter = 0n, identity = "") {
31625
32132
  return generateId("prt", timestampMs, counter, identity);
31626
32133
  }
31627
32134
  function getOpenCodeDbPath() {
31628
- return join4(getDataDir(), "opencode", "opencode.db");
32135
+ return join5(getDataDir(), "opencode", "opencode.db");
31629
32136
  }
31630
32137
  var cachedWriteDb = null;
31631
32138
  var REQUIRED_MESSAGE_COLUMNS = ["id", "session_id", "time_created", "time_updated", "data"];
@@ -31885,13 +32392,176 @@ function removeForeignCompactionMarker(sessionId, marker, protectedSummaryMessag
31885
32392
  return false;
31886
32393
  }
31887
32394
  }
31888
- function removeCompactionMarker(state) {
32395
+ function dataReferencesTailStart(data) {
32396
+ if (typeof data !== "object" || data === null)
32397
+ return null;
32398
+ const record2 = data;
32399
+ if (typeof record2.tail_start_id === "string" && record2.tail_start_id.length > 0) {
32400
+ return record2.tail_start_id;
32401
+ }
32402
+ const nested = record2.compaction;
32403
+ if (typeof nested === "object" && nested !== null) {
32404
+ const nestedTail = nested.tail_start_id;
32405
+ if (typeof nestedTail === "string" && nestedTail.length > 0)
32406
+ return nestedTail;
32407
+ }
32408
+ return null;
32409
+ }
32410
+ function isMcCanonicalCompactionPartData(data) {
32411
+ if (typeof data !== "object" || data === null || Array.isArray(data))
32412
+ return false;
32413
+ const record2 = data;
32414
+ const keys = Object.keys(record2).sort();
32415
+ return keys.length === 2 && keys[0] === "auto" && keys[1] === "type" && record2.type === "compaction" && record2.auto === true;
32416
+ }
32417
+ function removeMcOwnedCompactionMarkers(sessionId, summaryText) {
32418
+ const db = getWritableOpenCodeDb();
32419
+ if (!isOpenCodeSchemaCompatible(db, getOpenCodeDbPath())) {
32420
+ return {
32421
+ verified: false,
32422
+ removedLineages: 0,
32423
+ removedRows: 0,
32424
+ retainedLineages: 0
32425
+ };
32426
+ }
32427
+ const canonicalSummaries = db.prepare(`SELECT id, COALESCE(json_extract(data, '$.parentID'), '') AS parent_id
32428
+ FROM message
32429
+ WHERE session_id = ?
32430
+ AND COALESCE(json_extract(data, '$.summary'), 0) = 1
32431
+ AND COALESCE(json_extract(data, '$.finish'), '') = 'stop'
32432
+ AND COALESCE(json_extract(data, '$.providerID'), '') = 'magic-context'`).all(sessionId);
32433
+ const legacySummaries = db.prepare(`SELECT m.id, COALESCE(json_extract(m.data, '$.parentID'), '') AS parent_id
32434
+ FROM message m
32435
+ WHERE m.session_id = ?
32436
+ AND COALESCE(json_extract(m.data, '$.summary'), 0) = 1
32437
+ AND COALESCE(json_extract(m.data, '$.finish'), '') = 'stop'
32438
+ AND COALESCE(json_extract(m.data, '$.providerID'), '') <> 'magic-context'
32439
+ AND EXISTS (
32440
+ SELECT 1
32441
+ FROM part p
32442
+ WHERE p.session_id = m.session_id
32443
+ AND p.message_id = m.id
32444
+ AND COALESCE(json_extract(p.data, '$.type'), '') = 'text'
32445
+ AND COALESCE(json_extract(p.data, '$.text'), '') = ?
32446
+ )`).all(sessionId, summaryText);
32447
+ const summariesByBoundary = new Map;
32448
+ const orphanSummaryIds = new Set;
32449
+ for (const row of [...canonicalSummaries, ...legacySummaries]) {
32450
+ if (typeof row.id !== "string")
32451
+ continue;
32452
+ if (typeof row.parent_id === "string" && row.parent_id.length > 0) {
32453
+ const set2 = summariesByBoundary.get(row.parent_id) ?? new Set;
32454
+ set2.add(row.id);
32455
+ summariesByBoundary.set(row.parent_id, set2);
32456
+ } else {
32457
+ orphanSummaryIds.add(row.id);
32458
+ }
32459
+ }
32460
+ const compactionParts = db.prepare(`SELECT id, message_id, data
32461
+ FROM part
32462
+ WHERE session_id = ?
32463
+ AND COALESCE(json_extract(data, '$.type'), '') = 'compaction'`).all(sessionId);
32464
+ const parsedParts = [];
32465
+ for (const part of compactionParts) {
32466
+ if (typeof part.id !== "string" || typeof part.message_id !== "string")
32467
+ continue;
32468
+ let data;
32469
+ try {
32470
+ data = typeof part.data === "string" ? JSON.parse(part.data) : part.data;
32471
+ } catch {
32472
+ data = null;
32473
+ }
32474
+ parsedParts.push({
32475
+ id: part.id,
32476
+ messageId: part.message_id,
32477
+ data,
32478
+ tailStartId: dataReferencesTailStart(data)
32479
+ });
32480
+ }
32481
+ const messageTailRefs = db.prepare(`SELECT id, data
32482
+ FROM message
32483
+ WHERE session_id = ?
32484
+ AND json_extract(data, '$.compaction.tail_start_id') IS NOT NULL`).all(sessionId);
32485
+ const messageTailStartIds = new Set;
32486
+ for (const row of messageTailRefs) {
32487
+ if (typeof row.id !== "string")
32488
+ continue;
32489
+ let data;
32490
+ try {
32491
+ data = typeof row.data === "string" ? JSON.parse(row.data) : row.data;
32492
+ } catch {
32493
+ data = null;
32494
+ }
32495
+ const ref = dataReferencesTailStart(data);
32496
+ if (ref)
32497
+ messageTailStartIds.add(ref);
32498
+ }
32499
+ let removedLineages = 0;
32500
+ let removedRows = 0;
32501
+ let retainedLineages = 0;
32502
+ const deletePartsOfMessage = db.prepare("DELETE FROM part WHERE session_id = ? AND message_id = ?");
32503
+ const deleteMessage = db.prepare("DELETE FROM message WHERE session_id = ? AND id = ?");
32504
+ const deletePart = db.prepare("DELETE FROM part WHERE session_id = ? AND id = ?");
32505
+ const deleteSummaries = (summaryIds) => {
32506
+ let rows = 0;
32507
+ for (const summaryId of summaryIds) {
32508
+ rows += deletePartsOfMessage.run(sessionId, summaryId).changes;
32509
+ rows += deleteMessage.run(sessionId, summaryId).changes;
32510
+ }
32511
+ return rows;
32512
+ };
32513
+ for (const [boundaryMessageId, summaryIds] of summariesByBoundary) {
32514
+ const boundaryParts = parsedParts.filter((part) => part.messageId === boundaryMessageId);
32515
+ const mcPartIds = boundaryParts.filter((part) => isMcCanonicalCompactionPartData(part.data)).map((part) => part.id);
32516
+ const rowsToDelete = new Set([...summaryIds, ...mcPartIds]);
32517
+ const survivingPartsReferenceDeletion = parsedParts.some((part) => !mcPartIds.includes(part.id) && part.tailStartId !== null && rowsToDelete.has(part.tailStartId));
32518
+ const messageFieldReferencesDeletion = [...rowsToDelete].some((id) => messageTailStartIds.has(id));
32519
+ if (survivingPartsReferenceDeletion || messageFieldReferencesDeletion) {
32520
+ retainedLineages += 1;
32521
+ log(`[magic-context] compaction-marker: flip-off cleanup RETAINED lineage at boundary ${boundaryMessageId} — a surviving tail_start_id references a row the deletion would remove`);
32522
+ continue;
32523
+ }
32524
+ const rows = db.transaction(() => {
32525
+ let changed = deleteSummaries(summaryIds);
32526
+ for (const partId of mcPartIds) {
32527
+ changed += deletePart.run(sessionId, partId).changes;
32528
+ }
32529
+ return changed;
32530
+ })();
32531
+ if (rows > 0 || summaryIds.size > 0 || mcPartIds.length > 0) {
32532
+ removedLineages += 1;
32533
+ removedRows += rows;
32534
+ }
32535
+ }
32536
+ if (orphanSummaryIds.size > 0) {
32537
+ const rowsToDelete = new Set(orphanSummaryIds);
32538
+ const survivingPartsReferenceDeletion = parsedParts.some((part) => part.tailStartId !== null && rowsToDelete.has(part.tailStartId));
32539
+ const messageFieldReferencesDeletion = [...rowsToDelete].some((id) => messageTailStartIds.has(id));
32540
+ if (survivingPartsReferenceDeletion || messageFieldReferencesDeletion) {
32541
+ retainedLineages += 1;
32542
+ } else {
32543
+ const rows = db.transaction(() => deleteSummaries(orphanSummaryIds))();
32544
+ removedLineages += 1;
32545
+ removedRows += rows;
32546
+ }
32547
+ }
32548
+ if (removedLineages > 0 || retainedLineages > 0) {
32549
+ log(`[magic-context] compaction-marker: flip-off cleanup for ${sessionId} removed ${removedLineages} lineage(s) (${removedRows} rows), retained ${retainedLineages}`);
32550
+ }
32551
+ return {
32552
+ verified: retainedLineages === 0,
32553
+ removedLineages,
32554
+ removedRows,
32555
+ retainedLineages
32556
+ };
32557
+ }
32558
+ function removeCompactionMarker(state2) {
31889
32559
  try {
31890
32560
  const db = getWritableOpenCodeDb();
31891
32561
  db.transaction(() => {
31892
- db.prepare("DELETE FROM part WHERE id = ?").run(state.summaryPartId);
31893
- db.prepare("DELETE FROM message WHERE id = ?").run(state.summaryMessageId);
31894
- db.prepare("DELETE FROM part WHERE id = ?").run(state.compactionPartId);
32562
+ db.prepare("DELETE FROM part WHERE id = ?").run(state2.summaryPartId);
32563
+ db.prepare("DELETE FROM message WHERE id = ?").run(state2.summaryMessageId);
32564
+ db.prepare("DELETE FROM part WHERE id = ?").run(state2.compactionPartId);
31895
32565
  })();
31896
32566
  return true;
31897
32567
  } catch (error51) {
@@ -31907,9 +32577,9 @@ function dropMarkerSummaryTag(db, sessionId, summaryMessageId) {
31907
32577
  if (tagNumber !== null)
31908
32578
  updateTagStatus(db, sessionId, tagNumber, "dropped");
31909
32579
  }
31910
- function persistMarkerStateAndDropReplacedTag(db, sessionId, state, replacedSummaryMessageId) {
32580
+ function persistMarkerStateAndDropReplacedTag(db, sessionId, state2, replacedSummaryMessageId) {
31911
32581
  db.transaction(() => {
31912
- setPersistedCompactionMarkerState(db, sessionId, state);
32582
+ setPersistedCompactionMarkerState(db, sessionId, state2);
31913
32583
  if (replacedSummaryMessageId !== null) {
31914
32584
  dropMarkerSummaryTag(db, sessionId, replacedSummaryMessageId);
31915
32585
  }
@@ -32130,7 +32800,7 @@ function reconcileForkOrphanedCompactionMarkers(db, sessionId) {
32130
32800
  }
32131
32801
  }
32132
32802
  function checkCompactionMarkerConsistency(db) {
32133
- const opencodeDbPath = join5(getDataDir(), "opencode", "opencode.db");
32803
+ const opencodeDbPath = join6(getDataDir(), "opencode", "opencode.db");
32134
32804
  let opencodeDb;
32135
32805
  try {
32136
32806
  opencodeDb = new Database(opencodeDbPath, { readonly: true });
@@ -32146,19 +32816,19 @@ function checkCompactionMarkerConsistency(db) {
32146
32816
  const checkPart = opencodeDb.prepare("SELECT 1 FROM part WHERE id = ? LIMIT 1");
32147
32817
  let reconciledCount = 0;
32148
32818
  for (const row of persistedRows) {
32149
- const state = getPersistedCompactionMarkerState(db, row.session_id);
32150
- if (!state)
32819
+ const state2 = getPersistedCompactionMarkerState(db, row.session_id);
32820
+ if (!state2)
32151
32821
  continue;
32152
- const boundaryExists = checkMessage.get(state.boundaryMessageId) != null;
32153
- const summaryMessageExists = checkMessage.get(state.summaryMessageId) != null;
32154
- const compactionPartExists = checkPart.get(state.compactionPartId) != null;
32155
- const summaryPartExists = checkPart.get(state.summaryPartId) != null;
32822
+ const boundaryExists = checkMessage.get(state2.boundaryMessageId) != null;
32823
+ const summaryMessageExists = checkMessage.get(state2.summaryMessageId) != null;
32824
+ const compactionPartExists = checkPart.get(state2.compactionPartId) != null;
32825
+ const summaryPartExists = checkPart.get(state2.summaryPartId) != null;
32156
32826
  const allPresent = boundaryExists && summaryMessageExists && compactionPartExists && summaryPartExists;
32157
32827
  if (allPresent)
32158
32828
  continue;
32159
32829
  let removedOk = false;
32160
32830
  try {
32161
- removedOk = removeCompactionMarker(state);
32831
+ removedOk = removeCompactionMarker(state2);
32162
32832
  } catch (error51) {
32163
32833
  sessionLog(row.session_id, "compaction-marker consistency: partial cleanup of half-written marker failed:", error51);
32164
32834
  }
@@ -33108,8 +33778,8 @@ function queueDropsForCompartmentalizedMessages(db, sessionId, upToMessageIndex)
33108
33778
  }
33109
33779
 
33110
33780
  // src/hooks/magic-context/compartment-runner-historian.ts
33111
- import { mkdirSync as mkdirSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
33112
- import { join as join6 } from "node:path";
33781
+ import { mkdirSync as mkdirSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "node:fs";
33782
+ import { join as join7 } from "node:path";
33113
33783
 
33114
33784
  // src/features/magic-context/subagent-token-capture.ts
33115
33785
  function asNumber(value) {
@@ -33405,6 +34075,24 @@ function historianResponseDumpDir(directory) {
33405
34075
  return getProjectMagicContextHistorianDir(directory);
33406
34076
  }
33407
34077
  var MAX_HISTORIAN_RETRIES = 2;
34078
+ var HISTORIAN_REASONING_PART_TYPES = new Set(["reasoning", "thinking", "redacted_thinking"]);
34079
+ function extractLatestHistorianReasoning(messages) {
34080
+ if (!Array.isArray(messages))
34081
+ return null;
34082
+ const latest = messages.filter((message) => isRecord(message) && isRecord(message.info) && message.info.role === "assistant").sort((left, right) => historianMessageCreatedAt(right) - historianMessageCreatedAt(left))[0];
34083
+ if (!latest || !Array.isArray(latest.parts))
34084
+ return null;
34085
+ return latest.parts.filter(isHistorianReasoningPart).map((part) => part.text).join(`
34086
+ `) || null;
34087
+ }
34088
+ function isHistorianReasoningPart(part) {
34089
+ return isRecord(part) && typeof part.type === "string" && HISTORIAN_REASONING_PART_TYPES.has(part.type) && typeof part.text === "string" && part.text.length > 0;
34090
+ }
34091
+ function historianMessageCreatedAt(message) {
34092
+ if (!isRecord(message.info) || !isRecord(message.info.time))
34093
+ return 0;
34094
+ return typeof message.info.time.created === "number" ? message.info.time.created : 0;
34095
+ }
33408
34096
  async function runValidatedHistorianPass(args) {
33409
34097
  const firstRun = await runHistorianPrompt({
33410
34098
  ...args,
@@ -33470,6 +34158,7 @@ async function runEditorPassOrFallback(args) {
33470
34158
  sessionLog(args.parentSessionId, "historian two-pass: running editor on draft");
33471
34159
  const editorRun = await runHistorianPrompt({
33472
34160
  client: args.client,
34161
+ db: args.db,
33473
34162
  parentSessionId: args.parentSessionId,
33474
34163
  sessionDirectory: args.sessionDirectory,
33475
34164
  prompt: buildHistorianEditorPrompt(args.draftXml),
@@ -33496,6 +34185,7 @@ async function runEditorPassOrFallback(args) {
33496
34185
  async function runHistorianPrompt(args) {
33497
34186
  const {
33498
34187
  client,
34188
+ db,
33499
34189
  parentSessionId,
33500
34190
  sessionDirectory,
33501
34191
  prompt,
@@ -33529,12 +34219,12 @@ async function runHistorianPrompt(args) {
33529
34219
  };
33530
34220
  try {
33531
34221
  sessionLog(parentSessionId, `historian: creating child session (agent=${agentId}, model=${modelOverride ? `${modelOverride.providerID}/${modelOverride.modelID}` : `agent:${agentId}`})`);
33532
- const createResponse = await client.session.create({
33533
- body: {
33534
- parentID: parentSessionId,
33535
- title: "magic-context-compartment"
33536
- },
33537
- query: { directory: sessionDirectory }
34222
+ const createResponse = await createChildSessionWithFence({
34223
+ client,
34224
+ db,
34225
+ parentSessionId,
34226
+ title: "magic-context-compartment",
34227
+ directory: sessionDirectory
33538
34228
  });
33539
34229
  const createdSession = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
33540
34230
  agentSessionId = typeof createdSession?.id === "string" ? createdSession.id : null;
@@ -33582,7 +34272,18 @@ async function runHistorianPrompt(args) {
33582
34272
  preferResponseOnMissingData: true
33583
34273
  });
33584
34274
  const invocationId = recordInvocation({ status: "completed", messages });
33585
- const result = extractLatestAssistantText(messages);
34275
+ const lengthCapped = hasLengthCappedOutput(messages);
34276
+ const textResult = extractLatestAssistantText(messages);
34277
+ const reasoningResult = textResult ? null : extractLatestHistorianReasoning(messages);
34278
+ if (!textResult && reasoningResult && lengthCapped) {
34279
+ const outputTokens = sumTokensFromChildMessages(messages).output;
34280
+ return {
34281
+ ok: false,
34282
+ error: `historian output length-capped at ${outputTokens} tokens (all reasoning, no text) — set historian.maxTokens or route historian.model to a low-reasoning lane/variant`,
34283
+ invocationId: invocationId ?? undefined
34284
+ };
34285
+ }
34286
+ const result = textResult ?? reasoningResult;
33586
34287
  if (!result) {
33587
34288
  return {
33588
34289
  ok: false,
@@ -33634,6 +34335,7 @@ async function runFallbackHistorianPass(args) {
33634
34335
  args.callbacks?.onModelFallback?.(modelId, i + 1, chain.length);
33635
34336
  const fallbackRun = await runHistorianPrompt({
33636
34337
  client: args.client,
34338
+ db: args.db,
33637
34339
  parentSessionId: args.parentSessionId,
33638
34340
  sessionDirectory: args.sessionDirectory,
33639
34341
  prompt: args.prompt,
@@ -33695,7 +34397,7 @@ function cleanupHistorianDump(sessionId, dumpPath) {
33695
34397
  if (!dumpPath)
33696
34398
  return;
33697
34399
  try {
33698
- unlinkSync2(dumpPath);
34400
+ unlinkSync3(dumpPath);
33699
34401
  } catch (error51) {
33700
34402
  sessionLog(sessionId, "compartment agent: failed to remove historian response dump", {
33701
34403
  dumpPath,
@@ -33710,7 +34412,7 @@ function dumpHistorianResponse(sessionId, directory, label, text) {
33710
34412
  ensureCortexKitArtifactGitignore(directory);
33711
34413
  const safeSessionId = sanitizeDumpName(sessionId);
33712
34414
  const safeLabel = sanitizeDumpName(label);
33713
- const dumpPath = join6(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
34415
+ const dumpPath = join7(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
33714
34416
  writeFileSync2(dumpPath, text, "utf8");
33715
34417
  sessionLog(sessionId, "compartment agent: historian response dumped", {
33716
34418
  label,
@@ -33733,26 +34435,7 @@ function sanitizeDumpName(value) {
33733
34435
  import { Buffer as Buffer3 } from "node:buffer";
33734
34436
 
33735
34437
  // src/features/magic-context/mural/render-trigger.ts
33736
- import { createHash as createHash13 } from "node:crypto";
33737
-
33738
- // src/shared/harness-provider-map.ts
33739
- var PI_TO_CANONICAL_PROVIDER = {
33740
- "openai-codex": "openai",
33741
- "google-antigravity": "google"
33742
- };
33743
- function remapProviderPrefix(ref, map2) {
33744
- if (typeof ref !== "string")
33745
- return ref;
33746
- const slash = ref.indexOf("/");
33747
- if (slash <= 0)
33748
- return ref;
33749
- const provider2 = ref.slice(0, slash);
33750
- const mapped = map2[provider2];
33751
- return mapped ? `${mapped}${ref.slice(slash)}` : ref;
33752
- }
33753
- function piModelRefToCanonical(ref) {
33754
- return remapProviderPrefix(ref, PI_TO_CANONICAL_PROVIDER);
33755
- }
34438
+ import { createHash as createHash14 } from "node:crypto";
33756
34439
 
33757
34440
  // src/features/magic-context/mural/mural-selection.ts
33758
34441
  var DEFAULT_MURAL_MEMORY_BUDGET = 8000;
@@ -33955,6 +34638,8 @@ function naturalLineLengths(entries, roomWidth) {
33955
34638
  let currentCategory = null;
33956
34639
  for (let index = 0;index < entries.length; index++) {
33957
34640
  const entry = entries[index];
34641
+ if (!entry)
34642
+ continue;
33958
34643
  if (entry.category !== currentCategory) {
33959
34644
  currentCategory = entry.category;
33960
34645
  lengths.push(codepoints(` <${entry.category}> `));
@@ -33987,6 +34672,8 @@ function planLines(entries, roomWidth) {
33987
34672
  let currentCategory = null;
33988
34673
  for (let index = 0;index < entries.length; index++) {
33989
34674
  const entry = entries[index];
34675
+ if (!entry)
34676
+ continue;
33990
34677
  if (entry.category !== currentCategory) {
33991
34678
  currentCategory = entry.category;
33992
34679
  lines.push({
@@ -34050,8 +34737,11 @@ function renderLayout(entries, plan, roomWidth, columnCount) {
34050
34737
  const usage = {};
34051
34738
  let filledLineCount = 0;
34052
34739
  for (const [column, columnPlan] of splitPlan(plan, columnCount).entries()) {
34740
+ const columnGrid = grid[column];
34741
+ if (!columnGrid)
34742
+ continue;
34053
34743
  for (const [row, line] of columnPlan.entries()) {
34054
- grid[column][row] = line.text;
34744
+ columnGrid[row] = line.text;
34055
34745
  filledLineCount += 1;
34056
34746
  usage[line.category] = (usage[line.category] ?? 0) + 1;
34057
34747
  const placementLine = row + 1;
@@ -34162,6 +34852,7 @@ function glyph(character) {
34162
34852
  }
34163
34853
  function drawGlyph(pixels, width, height, x, y, character, color) {
34164
34854
  const glyphData = glyph(character);
34855
+ const [red, green, blue] = color;
34165
34856
  for (let row = 0;row < MURAL_CELL_HEIGHT; row++) {
34166
34857
  const pattern = glyphData.rows[row] ?? 0;
34167
34858
  for (let column = 0;column < glyphData.width; column++) {
@@ -34172,9 +34863,9 @@ function drawGlyph(pixels, width, height, x, y, character, color) {
34172
34863
  if (px < 0 || py < 0 || px >= width || py >= height)
34173
34864
  continue;
34174
34865
  const offset = (py * width + px) * 3;
34175
- pixels[offset] = color[0];
34176
- pixels[offset + 1] = color[1];
34177
- pixels[offset + 2] = color[2];
34866
+ pixels[offset] = red;
34867
+ pixels[offset + 1] = green;
34868
+ pixels[offset + 2] = blue;
34178
34869
  }
34179
34870
  }
34180
34871
  }
@@ -34186,6 +34877,7 @@ function drawText(pixels, width, height, x, y, text, color) {
34186
34877
  }
34187
34878
  }
34188
34879
  function fillRect(pixels, canvasWidth, canvasHeight, x, y, width, height, color) {
34880
+ const [red, green, blue] = color;
34189
34881
  const left = Math.max(0, x);
34190
34882
  const top = Math.max(0, y);
34191
34883
  const right = Math.min(canvasWidth, x + width);
@@ -34193,9 +34885,9 @@ function fillRect(pixels, canvasWidth, canvasHeight, x, y, width, height, color)
34193
34885
  for (let py = top;py < bottom; py++) {
34194
34886
  for (let px = left;px < right; px++) {
34195
34887
  const offset = (py * canvasWidth + px) * 3;
34196
- pixels[offset] = color[0];
34197
- pixels[offset + 1] = color[1];
34198
- pixels[offset + 2] = color[2];
34888
+ pixels[offset] = red;
34889
+ pixels[offset + 1] = green;
34890
+ pixels[offset + 2] = blue;
34199
34891
  }
34200
34892
  }
34201
34893
  }
@@ -34222,6 +34914,9 @@ function renderMural(entries) {
34222
34914
  });
34223
34915
  const fittingCandidates = candidates.filter((candidate) => candidate.layout.droppedIds.length === 0);
34224
34916
  const candidatesToCompare = fittingCandidates.length > 0 ? fittingCandidates : candidates;
34917
+ const firstCandidate = candidatesToCompare[0];
34918
+ if (!firstCandidate)
34919
+ throw new Error("mural layout candidate list is empty");
34225
34920
  const selected = candidatesToCompare.reduce((best, candidate) => {
34226
34921
  if (!best)
34227
34922
  return candidate;
@@ -34232,7 +34927,7 @@ function renderMural(entries) {
34232
34927
  return candidate.tileArea < best.tileArea ? candidate : best;
34233
34928
  }
34234
34929
  return candidate.requestedColumnCount < best.requestedColumnCount ? candidate : best;
34235
- }, candidatesToCompare[0]);
34930
+ }, firstCandidate);
34236
34931
  const { layout, width, height } = selected;
34237
34932
  const pixels = new Uint8Array(width * height * 3).fill(255);
34238
34933
  const contentWidth = layout.columnCount === 0 ? 0 : layout.columnCount * roomWidth * MURAL_CELL_WIDTH + MURAL_COLUMN_GAP * (layout.columnCount - 1) * MURAL_CELL_WIDTH;
@@ -34276,8 +34971,8 @@ function getMuralCoverage(db, projectIdentity) {
34276
34971
  const cueState = getMuralCueState(db, memories.map((memory) => memory.id));
34277
34972
  let cuedMemoryCount = 0;
34278
34973
  for (const memory of memories) {
34279
- const state = cueState.get(memory.id);
34280
- if (state && typeof state.cue === "string" && state.cue.trim() !== "" && state.hash !== null && state.hash === computeCueContentHash(memory.content)) {
34974
+ const state2 = cueState.get(memory.id);
34975
+ if (state2 && typeof state2.cue === "string" && state2.cue.trim() !== "" && state2.hash !== null && state2.hash === computeCueContentHash(memory.content)) {
34281
34976
  cuedMemoryCount += 1;
34282
34977
  }
34283
34978
  }
@@ -34291,16 +34986,16 @@ function resolveMural(db, projectIdentity, budgetTokens = DEFAULT_MURAL_MEMORY_B
34291
34986
  const cueState = getMuralCueState(db, overflow.map((memory) => memory.id));
34292
34987
  const entries = [];
34293
34988
  for (const memory of overflow) {
34294
- const state = cueState.get(memory.id);
34295
- if (!state || state.cue === null || state.hash === null)
34989
+ const state2 = cueState.get(memory.id);
34990
+ if (!state2 || state2.cue === null || state2.hash === null)
34296
34991
  continue;
34297
- if (state.hash !== computeCueContentHash(memory.content))
34992
+ if (state2.hash !== computeCueContentHash(memory.content))
34298
34993
  continue;
34299
34994
  entries.push({
34300
34995
  id: memory.id,
34301
34996
  category: memory.category,
34302
34997
  importance: memory.importance ?? 50,
34303
- cue: state.cue
34998
+ cue: state2.cue
34304
34999
  });
34305
35000
  }
34306
35001
  entries.sort(compareMuralEntries);
@@ -34366,7 +35061,7 @@ function ensureMuralRendered(db, projectIdentity, budgetTokens = DEFAULT_MURAL_M
34366
35061
  return { hasMural: false, rerendered: false };
34367
35062
  }
34368
35063
  const rendered = renderMural(entries);
34369
- const textHash = createHash13("sha256").update(rendered.sha256Input).digest("hex");
35064
+ const textHash = createHash14("sha256").update(rendered.sha256Input).digest("hex");
34370
35065
  const existing = getMural(db, projectIdentity);
34371
35066
  if (existing && existing.contentHash === textHash && existing.width === rendered.width && existing.height === rendered.height) {
34372
35067
  return {
@@ -35491,41 +36186,41 @@ function readCurrentM0SnapshotMarkers(args) {
35491
36186
  });
35492
36187
  return fresh.markers;
35493
36188
  }
35494
- function snapshotMarkersFromCachedM0(state) {
35495
- if (!state.cachedM0Bytes)
36189
+ function snapshotMarkersFromCachedM0(state2) {
36190
+ if (!state2.cachedM0Bytes)
35496
36191
  return null;
35497
- const cachedUpgradeIdentity = decodeCachedM0UpgradeIdentity(state.cachedM0UpgradeState);
35498
- if (state.cachedM0ProjectMemoryEpoch === null)
36192
+ const cachedUpgradeIdentity = decodeCachedM0UpgradeIdentity(state2.cachedM0UpgradeState);
36193
+ if (state2.cachedM0ProjectMemoryEpoch === null)
35499
36194
  return null;
35500
- if (state.cachedM0ProjectUserProfileVersion === null)
36195
+ if (state2.cachedM0ProjectUserProfileVersion === null)
35501
36196
  return null;
35502
- if (state.cachedM0MaxCompartmentSeq === null)
36197
+ if (state2.cachedM0MaxCompartmentSeq === null)
35503
36198
  return null;
35504
- if (state.cachedM0MaxMemoryId === null)
36199
+ if (state2.cachedM0MaxMemoryId === null)
35505
36200
  return null;
35506
- if (state.cachedM0MaxMutationId === null)
36201
+ if (state2.cachedM0MaxMutationId === null)
35507
36202
  return null;
35508
- if (state.cachedM0MaxMemoryMutationId === null)
36203
+ if (state2.cachedM0MaxMemoryMutationId === null)
35509
36204
  return null;
35510
- if (state.cachedM0SessionFactsVersion === null)
36205
+ if (state2.cachedM0SessionFactsVersion === null)
35511
36206
  return null;
35512
36207
  return {
35513
- projectMemoryEpoch: state.cachedM0ProjectMemoryEpoch,
35514
- workspaceFingerprint: state.cachedM0WorkspaceFingerprint,
35515
- projectUserProfileVersion: state.cachedM0ProjectUserProfileVersion,
35516
- maxCompartmentSeq: state.cachedM0MaxCompartmentSeq,
35517
- maxMemoryId: state.cachedM0MaxMemoryId,
35518
- maxMutationId: state.cachedM0MaxMutationId,
35519
- maxMemoryMutationId: state.cachedM0MaxMemoryMutationId,
35520
- projectDocsHash: state.cachedM0ProjectDocsHash ?? "",
35521
- materializedAt: state.cachedM0MaterializedAt ?? 0,
35522
- sessionFactsVersion: state.cachedM0SessionFactsVersion,
36208
+ projectMemoryEpoch: state2.cachedM0ProjectMemoryEpoch,
36209
+ workspaceFingerprint: state2.cachedM0WorkspaceFingerprint,
36210
+ projectUserProfileVersion: state2.cachedM0ProjectUserProfileVersion,
36211
+ maxCompartmentSeq: state2.cachedM0MaxCompartmentSeq,
36212
+ maxMemoryId: state2.cachedM0MaxMemoryId,
36213
+ maxMutationId: state2.cachedM0MaxMutationId,
36214
+ maxMemoryMutationId: state2.cachedM0MaxMemoryMutationId,
36215
+ projectDocsHash: state2.cachedM0ProjectDocsHash ?? "",
36216
+ materializedAt: state2.cachedM0MaterializedAt ?? 0,
36217
+ sessionFactsVersion: state2.cachedM0SessionFactsVersion,
35523
36218
  upgradeState: cachedUpgradeIdentity.upgradeState,
35524
36219
  compartmentRenderEpoch: cachedUpgradeIdentity.compartmentRenderEpoch,
35525
- systemHash: state.cachedM0SystemHash ?? "",
35526
- modelKey: state.cachedM0ModelKey ?? "",
35527
- projectIdentity: state.cachedM0ProjectIdentity ?? null,
35528
- muralHash: state.cachedM0MuralHash ?? null
36220
+ systemHash: state2.cachedM0SystemHash ?? "",
36221
+ modelKey: state2.cachedM0ModelKey ?? "",
36222
+ projectIdentity: state2.cachedM0ProjectIdentity ?? null,
36223
+ muralHash: state2.cachedM0MuralHash ?? null
35529
36224
  };
35530
36225
  }
35531
36226
  function mustMaterialize(args) {
@@ -35841,26 +36536,26 @@ ${sessionHistory}
35841
36536
 
35842
36537
  `).trim();
35843
36538
  }
35844
- function applyMarkersToState(state, m0Bytes, markers, m1Bytes) {
35845
- state.cachedM0Bytes = m0Bytes;
36539
+ function applyMarkersToState(state2, m0Bytes, markers, m1Bytes) {
36540
+ state2.cachedM0Bytes = m0Bytes;
35846
36541
  if (m1Bytes)
35847
- state.cachedM1Bytes = m1Bytes;
35848
- state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
35849
- state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
35850
- state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
35851
- state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
35852
- state.cachedM0MaxMemoryId = markers.maxMemoryId;
35853
- state.cachedM0MaxMutationId = markers.maxMutationId;
35854
- state.cachedM0MaxMemoryMutationId = markers.maxMemoryMutationId;
35855
- state.cachedM0ProjectDocsHash = markers.projectDocsHash;
35856
- state.cachedM0MaterializedAt = markers.materializedAt;
35857
- state.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
35858
- state.cachedM0UpgradeState = encodeCachedM0UpgradeIdentity(markers.upgradeState, markers.compartmentRenderEpoch);
35859
- state.cachedM0SystemHash = markers.systemHash;
35860
- state.cachedM0ModelKey = markers.modelKey;
35861
- state.cachedM0ProjectIdentity = markers.projectIdentity;
35862
- state.cachedM0MuralHash = markers.muralHash ?? null;
35863
- state.snapshotMarkers = markers;
36542
+ state2.cachedM1Bytes = m1Bytes;
36543
+ state2.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
36544
+ state2.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
36545
+ state2.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
36546
+ state2.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
36547
+ state2.cachedM0MaxMemoryId = markers.maxMemoryId;
36548
+ state2.cachedM0MaxMutationId = markers.maxMutationId;
36549
+ state2.cachedM0MaxMemoryMutationId = markers.maxMemoryMutationId;
36550
+ state2.cachedM0ProjectDocsHash = markers.projectDocsHash;
36551
+ state2.cachedM0MaterializedAt = markers.materializedAt;
36552
+ state2.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
36553
+ state2.cachedM0UpgradeState = encodeCachedM0UpgradeIdentity(markers.upgradeState, markers.compartmentRenderEpoch);
36554
+ state2.cachedM0SystemHash = markers.systemHash;
36555
+ state2.cachedM0ModelKey = markers.modelKey;
36556
+ state2.cachedM0ProjectIdentity = markers.projectIdentity;
36557
+ state2.cachedM0MuralHash = markers.muralHash ?? null;
36558
+ state2.snapshotMarkers = markers;
35864
36559
  }
35865
36560
  function historySliceTokens(m0Text) {
35866
36561
  const slice = extractM0Block(m0Text, "session-history");
@@ -35910,7 +36605,7 @@ function materializeM0(options) {
35910
36605
  });
35911
36606
  docs = readProjectDocsForM0(projectDirectory, options.injectDocs);
35912
36607
  snapshotMarkers.projectDocsHash = docs.canonicalHash;
35913
- compartments = readM0Compartments(options.db, options.sessionId);
36608
+ compartments = options.compactionOff ? [] : readM0Compartments(options.db, options.sessionId);
35914
36609
  facts = [];
35915
36610
  memories = projectPath ? workspace.isWorkspaced ? getMemoriesByProjects(options.db, workspace.expandedIdentities, ["active", "permanent"], foldMaterializedAt, workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(options.db, projectPath, ["active", "permanent"], foldMaterializedAt) : [];
35916
36611
  userMemories = safeGetActiveUserMemories(options.db);
@@ -36275,39 +36970,39 @@ function markersFromCachedRow(row) {
36275
36970
  muralHash: row.cached_m0_mural_hash ?? null
36276
36971
  };
36277
36972
  }
36278
- function cachedRowMatchesState(row, state) {
36279
- return bufferEqualsNullable(row.cached_m0_bytes, state.cachedM0Bytes) && (row.cached_m0_mural_data_url ?? null) === (state.cachedM0MuralDataUrl ?? null) && (row.cached_m0_mural_hash ?? null) === (state.cachedM0MuralHash ?? null) && row.cached_m0_project_memory_epoch === state.cachedM0ProjectMemoryEpoch && (row.cached_m0_workspace_fingerprint ?? null) === (state.cachedM0WorkspaceFingerprint ?? null) && row.cached_m0_project_user_profile_version === state.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state.cachedM0MaxMemoryMutationId && row.cached_m0_materialized_at === state.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state.cachedM0SystemHash ?? "") && (row.cached_m0_model_key ?? "") === (state.cachedM0ModelKey ?? "") && (row.cached_m0_project_identity ?? null) === (state.cachedM0ProjectIdentity ?? null);
36973
+ function cachedRowMatchesState(row, state2) {
36974
+ return bufferEqualsNullable(row.cached_m0_bytes, state2.cachedM0Bytes) && (row.cached_m0_mural_data_url ?? null) === (state2.cachedM0MuralDataUrl ?? null) && (row.cached_m0_mural_hash ?? null) === (state2.cachedM0MuralHash ?? null) && row.cached_m0_project_memory_epoch === state2.cachedM0ProjectMemoryEpoch && (row.cached_m0_workspace_fingerprint ?? null) === (state2.cachedM0WorkspaceFingerprint ?? null) && row.cached_m0_project_user_profile_version === state2.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state2.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state2.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state2.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state2.cachedM0MaxMemoryMutationId && row.cached_m0_materialized_at === state2.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state2.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state2.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state2.cachedM0SystemHash ?? "") && (row.cached_m0_model_key ?? "") === (state2.cachedM0ModelKey ?? "") && (row.cached_m0_project_identity ?? null) === (state2.cachedM0ProjectIdentity ?? null);
36280
36975
  }
36281
- function applyCachedRowToState(state, row) {
36976
+ function applyCachedRowToState(state2, row) {
36282
36977
  const markers = markersFromCachedRow(row);
36283
36978
  if (!row.cached_m0_bytes || !row.cached_m1_bytes || !markers) {
36284
- throw new RenderM1InvalidMarkersError(state.sessionId);
36285
- }
36286
- state.cachedM0Bytes = toBuffer(row.cached_m0_bytes);
36287
- state.cachedM0MuralDataUrl = row.cached_m0_mural_data_url ?? null;
36288
- state.cachedM0MuralHash = row.cached_m0_mural_hash ?? null;
36289
- state.cachedM1Bytes = toBuffer(row.cached_m1_bytes);
36290
- state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
36291
- state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
36292
- state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
36293
- state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
36294
- state.cachedM0MaxMemoryId = markers.maxMemoryId;
36295
- state.cachedM0MaxMutationId = markers.maxMutationId;
36296
- state.cachedM0MaxMemoryMutationId = markers.maxMemoryMutationId;
36297
- state.cachedM0ProjectDocsHash = markers.projectDocsHash;
36298
- state.cachedM0MaterializedAt = markers.materializedAt;
36299
- state.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
36300
- state.cachedM0UpgradeState = encodeCachedM0UpgradeIdentity(markers.upgradeState, markers.compartmentRenderEpoch);
36301
- state.cachedM0SystemHash = markers.systemHash;
36302
- state.cachedM0ModelKey = markers.modelKey;
36303
- state.cachedM0ProjectIdentity = markers.projectIdentity;
36304
- state.snapshotMarkers = markers;
36305
- }
36306
- function replayCachedM1(state) {
36307
- if (!state.cachedM1Bytes) {
36308
- throw new RenderM1InvalidMarkersError(state.sessionId);
36309
- }
36310
- return decodeM0Bytes(state.cachedM1Bytes) ?? M1_EMPTY_PLACEHOLDER;
36979
+ throw new RenderM1InvalidMarkersError(state2.sessionId);
36980
+ }
36981
+ state2.cachedM0Bytes = toBuffer(row.cached_m0_bytes);
36982
+ state2.cachedM0MuralDataUrl = row.cached_m0_mural_data_url ?? null;
36983
+ state2.cachedM0MuralHash = row.cached_m0_mural_hash ?? null;
36984
+ state2.cachedM1Bytes = toBuffer(row.cached_m1_bytes);
36985
+ state2.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
36986
+ state2.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
36987
+ state2.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
36988
+ state2.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
36989
+ state2.cachedM0MaxMemoryId = markers.maxMemoryId;
36990
+ state2.cachedM0MaxMutationId = markers.maxMutationId;
36991
+ state2.cachedM0MaxMemoryMutationId = markers.maxMemoryMutationId;
36992
+ state2.cachedM0ProjectDocsHash = markers.projectDocsHash;
36993
+ state2.cachedM0MaterializedAt = markers.materializedAt;
36994
+ state2.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
36995
+ state2.cachedM0UpgradeState = encodeCachedM0UpgradeIdentity(markers.upgradeState, markers.compartmentRenderEpoch);
36996
+ state2.cachedM0SystemHash = markers.systemHash;
36997
+ state2.cachedM0ModelKey = markers.modelKey;
36998
+ state2.cachedM0ProjectIdentity = markers.projectIdentity;
36999
+ state2.snapshotMarkers = markers;
37000
+ }
37001
+ function replayCachedM1(state2) {
37002
+ if (!state2.cachedM1Bytes) {
37003
+ throw new RenderM1InvalidMarkersError(state2.sessionId);
37004
+ }
37005
+ return decodeM0Bytes(state2.cachedM1Bytes) ?? M1_EMPTY_PLACEHOLDER;
36311
37006
  }
36312
37007
  function softRefreshCachedM1(options) {
36313
37008
  options.db.exec("BEGIN IMMEDIATE");
@@ -36391,7 +37086,7 @@ function renderFreshM0NonPersisted(options) {
36391
37086
  const docs = readProjectDocsForM0(projectDirectory ?? "", options.injectDocs);
36392
37087
  snapshotMarkers.projectDocsHash = docs.canonicalHash;
36393
37088
  snapshotMarkers.materializedAt = options.state.cachedM0MaterializedAt ?? 0;
36394
- const compartments = withCompartmentDates(options.sessionId, readM0Compartments(options.db, options.sessionId), options.temporalAwareness);
37089
+ const compartments = options.compactionOff ? [] : withCompartmentDates(options.sessionId, readM0Compartments(options.db, options.sessionId), options.temporalAwareness);
36395
37090
  const memories = projectPath ? workspace.isWorkspaced ? getMemoriesByProjects(options.db, workspace.expandedIdentities, ["active", "permanent"], snapshotMarkers.materializedAt, workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(options.db, projectPath, ["active", "permanent"], snapshotMarkers.materializedAt) : [];
36396
37091
  const userMemories = safeGetActiveUserMemories(options.db);
36397
37092
  const memoryBudget = options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
@@ -36469,7 +37164,7 @@ function injectM0M1(options) {
36469
37164
  m0Bytes: options.state.cachedM0Bytes,
36470
37165
  m1Text: null
36471
37166
  };
36472
- if (options.state.isSubagent)
37167
+ if (options.state.isSubagent && !options.compactionOff)
36473
37168
  return skipped;
36474
37169
  const decision = mustMaterialize({
36475
37170
  db: options.db,
@@ -36598,14 +37293,14 @@ function onNoteTrigger(db, sessionId, trigger) {
36598
37293
  sessionLog(sessionId, `note-nudge: trigger fired (${trigger}), triggerPending=true`);
36599
37294
  }
36600
37295
  function peekNoteNudgeText(db, sessionId, currentUserMessageId, projectIdentity, noteReadStillVisible) {
36601
- const state = getPersistedNoteNudge(db, sessionId);
36602
- if (!state.triggerPending)
37296
+ const state2 = getPersistedNoteNudge(db, sessionId);
37297
+ if (!state2.triggerPending)
36603
37298
  return null;
36604
- if (!state.triggerMessageId && currentUserMessageId) {
37299
+ if (!state2.triggerMessageId && currentUserMessageId) {
36605
37300
  setPersistedNoteNudgeTriggerMessageId(db, sessionId, currentUserMessageId);
36606
- state.triggerMessageId = currentUserMessageId;
37301
+ state2.triggerMessageId = currentUserMessageId;
36607
37302
  }
36608
- if (state.triggerMessageId && currentUserMessageId && state.triggerMessageId === currentUserMessageId) {
37303
+ if (state2.triggerMessageId && currentUserMessageId && state2.triggerMessageId === currentUserMessageId) {
36609
37304
  sessionLog(sessionId, `note-nudge: deferring — current user message ${currentUserMessageId} is same as trigger-time message`);
36610
37305
  return null;
36611
37306
  }
@@ -36807,29 +37502,29 @@ function callIdFromPart(part) {
36807
37502
  const direct = firstStringField(part, ["callID", "callId", "toolCallId", "tool_call_id", "id"]);
36808
37503
  if (direct)
36809
37504
  return direct;
36810
- const state = isRecord(part.state) ? part.state : null;
36811
- return state ? firstStringField(state, ["callID", "callId", "toolCallId", "tool_call_id", "id"]) ?? "" : "";
37505
+ const state2 = isRecord(part.state) ? part.state : null;
37506
+ return state2 ? firstStringField(state2, ["callID", "callId", "toolCallId", "tool_call_id", "id"]) ?? "" : "";
36812
37507
  }
36813
37508
  function toolSignalFromPart(part) {
36814
37509
  if (!isRecord(part))
36815
37510
  return null;
36816
37511
  const type = partType(part);
36817
- const state = isRecord(part.state) ? part.state : null;
37512
+ const state2 = isRecord(part.state) ? part.state : null;
36818
37513
  const callId = callIdFromPart(part);
36819
37514
  if (!callId && type !== "tool")
36820
37515
  return null;
36821
37516
  if (type === "tool") {
36822
- const hasInput = state !== null && hasOwn(state, "input");
36823
- const outputKey = state ? hasOwn(state, "output") ? "output" : hasOwn(state, "error") ? "error" : hasOwn(state, "result") ? "result" : null : null;
37517
+ const hasInput = state2 !== null && hasOwn(state2, "input");
37518
+ const outputKey = state2 ? hasOwn(state2, "output") ? "output" : hasOwn(state2, "error") ? "error" : hasOwn(state2, "result") ? "result" : null : null;
36824
37519
  const hasOutput = outputKey !== null;
36825
- const outputValue = outputKey && state ? state[outputKey] : undefined;
37520
+ const outputValue = outputKey && state2 ? state2[outputKey] : undefined;
36826
37521
  const providerExecuted = part.providerExecuted === true;
36827
37522
  const openInvocation = !providerExecuted && !hasOutput;
36828
37523
  return {
36829
37524
  callId,
36830
37525
  hasInput: hasInput || openInvocation,
36831
37526
  hasOutput,
36832
- inputText: hasInput && state ? stringValue(state.input) : "",
37527
+ inputText: hasInput && state2 ? stringValue(state2.input) : "",
36833
37528
  outputText: hasOutput ? stringValue(outputValue) : ""
36834
37529
  };
36835
37530
  }
@@ -37057,24 +37752,27 @@ function tokenForMessage(message, options) {
37057
37752
  function buildTrueRawTokenIndex(sessionId, messages, options) {
37058
37753
  const ordered = [...messages].sort((a, b) => a.ordinal - b.ordinal);
37059
37754
  const sliceCount = ordered.length;
37060
- const maxOrdinal = ordered.length > 0 ? ordered[ordered.length - 1].ordinal : 0;
37061
- const rawMessageCount = Math.max(sliceCount, maxOrdinal, options.absoluteMessageCount ?? sliceCount);
37755
+ const firstOrdinal = ordered.length > 0 ? ordered[0].ordinal : 1;
37756
+ const terminalOrdinal = ordered.length > 0 ? ordered[ordered.length - 1].ordinal : 0;
37757
+ const rawMessageCount = Math.max(sliceCount, terminalOrdinal, options.absoluteMessageCount ?? sliceCount);
37758
+ const ordinalSpan = terminalOrdinal >= firstOrdinal ? terminalOrdinal - firstOrdinal + 1 : 0;
37062
37759
  const tokensByOrdinal = new Map;
37063
37760
  const idsByOrdinal = new Map;
37064
- const prefix = new Array(rawMessageCount + 1).fill(0);
37761
+ const prefix = new Array(ordinalSpan + 1).fill(0);
37065
37762
  for (const message of ordered) {
37066
37763
  const stored = options.storedTotalForMessage?.(message);
37067
37764
  const total = stored !== undefined && stored !== null ? stored : tokenForMessage(message, options).total;
37068
37765
  tokensByOrdinal.set(message.ordinal, total);
37069
37766
  idsByOrdinal.set(message.ordinal, message.id);
37070
- if (message.ordinal >= 1 && message.ordinal <= rawMessageCount) {
37071
- prefix[message.ordinal] = total;
37767
+ const relative = message.ordinal - firstOrdinal + 1;
37768
+ if (relative >= 1 && relative <= ordinalSpan) {
37769
+ prefix[relative] = total;
37072
37770
  }
37073
37771
  }
37074
- for (let k = 1;k <= rawMessageCount; k += 1) {
37772
+ for (let k = 1;k <= ordinalSpan; k += 1) {
37075
37773
  prefix[k] += prefix[k - 1];
37076
37774
  }
37077
- const ordinalToIndex = (ordinal) => Math.max(0, Math.min(rawMessageCount, ordinal - 1));
37775
+ const ordinalToIndex = (ordinal) => Math.max(0, Math.min(ordinalSpan, ordinal - firstOrdinal));
37078
37776
  return {
37079
37777
  sessionId,
37080
37778
  providerShapeVersion: options.providerShapeVersion,
@@ -37086,27 +37784,27 @@ function buildTrueRawTokenIndex(sessionId, messages, options) {
37086
37784
  return idsByOrdinal.get(ordinal) ?? null;
37087
37785
  },
37088
37786
  suffixTokensFromOrdinal(ordinal) {
37089
- if (ordinal <= 1)
37090
- return prefix[rawMessageCount];
37091
- if (ordinal > rawMessageCount)
37787
+ if (ordinal <= firstOrdinal)
37788
+ return prefix[ordinalSpan];
37789
+ if (ordinal > terminalOrdinal)
37092
37790
  return 0;
37093
- return prefix[rawMessageCount] - prefix[ordinalToIndex(ordinal)];
37791
+ return prefix[ordinalSpan] - prefix[ordinalToIndex(ordinal)];
37094
37792
  },
37095
37793
  rangeTokens(startInclusive, endExclusive) {
37096
- const start = Math.max(1, startInclusive);
37097
- const end = Math.max(start, Math.min(rawMessageCount + 1, endExclusive));
37098
- return prefix[end - 1] - prefix[start - 1];
37794
+ const start = Math.max(firstOrdinal, startInclusive);
37795
+ const end = Math.max(start, Math.min(terminalOrdinal + 1, endExclusive));
37796
+ return prefix[end - firstOrdinal] - prefix[start - firstOrdinal];
37099
37797
  },
37100
37798
  findSuffixStartForTokens(tokens) {
37101
37799
  if (!Number.isFinite(tokens) || tokens <= 0)
37102
- return rawMessageCount + 1;
37800
+ return terminalOrdinal + 1;
37103
37801
  const target = Math.max(0, Math.floor(tokens));
37104
- const total = prefix[rawMessageCount];
37802
+ const total = prefix[ordinalSpan];
37105
37803
  if (total < target)
37106
- return 1;
37804
+ return firstOrdinal;
37107
37805
  const cut = total - target;
37108
37806
  let lo = 0;
37109
- let hi = rawMessageCount;
37807
+ let hi = ordinalSpan;
37110
37808
  let best = 0;
37111
37809
  while (lo <= hi) {
37112
37810
  const mid = lo + hi >> 1;
@@ -37117,29 +37815,31 @@ function buildTrueRawTokenIndex(sessionId, messages, options) {
37117
37815
  hi = mid - 1;
37118
37816
  }
37119
37817
  }
37120
- return best + 1;
37818
+ return firstOrdinal + best;
37121
37819
  },
37122
37820
  findHeadEndForCap(startInclusive, endExclusive, capTokens) {
37123
- const start = Math.max(1, Math.min(rawMessageCount + 1, startInclusive));
37124
- const end = Math.max(start, Math.min(rawMessageCount + 1, endExclusive));
37821
+ const start = Math.max(firstOrdinal, Math.min(terminalOrdinal + 1, startInclusive));
37822
+ const end = Math.max(start, Math.min(terminalOrdinal + 1, endExclusive));
37125
37823
  if (!Number.isFinite(capTokens) || capTokens <= 0)
37126
37824
  return start;
37127
- const startPrefix = prefix[start - 1];
37128
- const cut = startPrefix + Math.floor(capTokens);
37129
- let lo = start;
37130
- let hi = end - 1;
37131
- let bestEnd = start;
37825
+ const startIndex = start - firstOrdinal;
37826
+ const endIndex = end - firstOrdinal;
37827
+ const cut = prefix[startIndex] + Math.floor(capTokens);
37828
+ let lo = startIndex + 1;
37829
+ let hi = endIndex;
37830
+ let bestEndIndex = startIndex;
37132
37831
  while (lo <= hi) {
37133
37832
  const mid = lo + hi >> 1;
37134
37833
  if (prefix[mid] <= cut) {
37135
- bestEnd = mid + 1;
37834
+ bestEndIndex = mid;
37136
37835
  lo = mid + 1;
37137
37836
  } else {
37138
37837
  hi = mid - 1;
37139
37838
  }
37140
37839
  }
37840
+ let bestEnd = firstOrdinal + bestEndIndex;
37141
37841
  if (bestEnd === start && start < end)
37142
- return start + 1;
37842
+ bestEnd = start + 1;
37143
37843
  return Math.min(bestEnd, end);
37144
37844
  }
37145
37845
  };
@@ -37456,7 +38156,8 @@ function resolveProtectedTailBoundary(ctx) {
37456
38156
  if (ctx.migrationFloorActive)
37457
38157
  runtimeFloor = Math.max(runtimeFloor, ctx.priorBoundaryOrdinal);
37458
38158
  let protectedTailStart = Math.max(boundary, runtimeFloor);
37459
- if (!ctx.emergencyTailScale && usagePercentage < 80) {
38159
+ const forceMaterializationPercentage = escalationBands(ctx.executeThresholdPercentage).forceMaterializationPercentage;
38160
+ if (!ctx.emergencyTailScale && usagePercentage < forceMaterializationPercentage) {
37460
38161
  let lastMeaningfulUserOrdinal = 0;
37461
38162
  for (let i = messages.length - 1;i >= 0; i--) {
37462
38163
  const message = messages[i];
@@ -37697,7 +38398,8 @@ function getRawHistoryEligibility(db, sessionId) {
37697
38398
  function hasRunnableCompartmentWindow(snapshot) {
37698
38399
  if (snapshot.offset >= snapshot.protectedTailStart)
37699
38400
  return false;
37700
- if (snapshot.usagePercentage >= 80 || snapshot.emergencyTailScale) {
38401
+ const forceMaterializationPercentage = escalationBands(snapshot.executeThresholdPercentage).forceMaterializationPercentage;
38402
+ if (snapshot.usagePercentage >= forceMaterializationPercentage || snapshot.emergencyTailScale) {
37701
38403
  return snapshot.trueRawEligibleTokens >= deriveMinForceEligibleTokens(snapshot.N) || snapshot.eligibleEndOrdinal > snapshot.offset;
37702
38404
  }
37703
38405
  return snapshot.eligibleEndOrdinal > snapshot.offset;
@@ -37760,8 +38462,10 @@ function validateBoundarySnapshot(args) {
37760
38462
  return { ok: true };
37761
38463
  }
37762
38464
  function recordHighPressureNoEligibleHead(db, snapshot) {
37763
- if (snapshot.usagePercentage < 80 && !snapshot.emergencyTailScale)
38465
+ const forceMaterializationPercentage = escalationBands(snapshot.executeThresholdPercentage).forceMaterializationPercentage;
38466
+ if (snapshot.usagePercentage < forceMaterializationPercentage && !snapshot.emergencyTailScale) {
37764
38467
  return 0;
38468
+ }
37765
38469
  return recordProtectedTailNoEligibleHead(db, snapshot.sessionId);
37766
38470
  }
37767
38471
 
@@ -39792,6 +40496,7 @@ ${chunkText}`,
39792
40496
  retainDrainReservationForRetryThrottle = true;
39793
40497
  const validatedPass = await runValidatedHistorianPass({
39794
40498
  client,
40499
+ db,
39795
40500
  parentSessionId: sessionId,
39796
40501
  sessionDirectory,
39797
40502
  prompt,
@@ -40252,6 +40957,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
40252
40957
  emitProgress(`Running historian (pass ${passCount + 1})…`);
40253
40958
  const validatedPass = await runValidatedHistorianPass({
40254
40959
  client,
40960
+ db,
40255
40961
  parentSessionId: sessionId,
40256
40962
  sessionDirectory,
40257
40963
  prompt,
@@ -40671,6 +41377,7 @@ ${chunk.text}`,
40671
41377
  Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${chunk.startIndex}-${chunk.endIndex}.`, notifParams());
40672
41378
  const validatedPass = await runValidatedHistorianPass({
40673
41379
  client,
41380
+ db,
40674
41381
  parentSessionId: sessionId,
40675
41382
  sessionDirectory,
40676
41383
  prompt,
@@ -40922,7 +41629,7 @@ async function executeContextRecomp(deps, options = {}) {
40922
41629
  }
40923
41630
 
40924
41631
  // src/hooks/magic-context/lkg-slot.ts
40925
- import { createHash as createHash14 } from "node:crypto";
41632
+ import { createHash as createHash15 } from "node:crypto";
40926
41633
  var LKG_TOTAL_BYTES = 64 * 1024 * 1024;
40927
41634
  var LKG_SINGLE_SLOT_BYTES = 24 * 1024 * 1024;
40928
41635
  var LKG_METADATA_BYTES = 256;
@@ -40933,7 +41640,7 @@ function slotBytes(slot) {
40933
41640
  return 2 * slot.jsonPrefix.length + digestBytes + LKG_METADATA_BYTES;
40934
41641
  }
40935
41642
  function lkgContentDigest(message) {
40936
- const hash2 = createHash14("sha256");
41643
+ const hash2 = createHash15("sha256");
40937
41644
  const seen = new WeakSet;
40938
41645
  const visit = (value) => {
40939
41646
  if (value === null) {
@@ -41299,4 +42006,4 @@ async function runUpgradeMemoryMigration(ctx, sessionId, migrationDirectory) {
41299
42006
  }
41300
42007
  }
41301
42008
 
41302
- export { withContentLanguageDirective, buildPrimaryLanguageDirective, exports_external, DEFAULT_PROTECTED_TAGS, parseCron, nextOccurrence, nextDueAtMs, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, DEFAULT_LOCAL_EMBEDDING_MODEL, MagicContextConfigSchema, getOpenCodeDbPath, ProjectIdentityError, resolveProjectIdentityStrict, takeDubiousOwnershipProjectIdentityWarning, resolveProjectIdentity, resolveProjectIdentityForSession, normalizeStoredProjectPath, storedPathBelongsToIdentity, recordSessionProjectIdentity, detectOverflow, promptSyncWithValidatedOutputRetry, normalizeSDKResponse, extractLatestAssistantText, hasLengthCappedOutput, setKeepSubagents, shouldKeepSubagents, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, clearRecompStaging, registerModuleNoteEvaluationBridge, getModuleNoteEvaluationBridge, getContextStoreUuid, ensureContextStoreUuid, getAuthorityManagedMarker, reconcileAuthorityProject, checksumAuthoritySeedRows, prepareAuthority, drainAuthority, getMirrorCursor, applyMirrorPage, pullMemoryMirrorOnce, V2_MEMORY_CATEGORIES, CATEGORY_PRIORITY, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, resolveStoredPathWorkspaceIdentity, storedPathBelongsToWorkspace, sourceNameForMemory, computeWorkspaceEpochFingerprint, beginBootQuietPeriod, bootQuietRemainingMs, scheduleAfterBootQuiet, recordToolDefinition, getMeasuredToolDefinitionTokens, getSchemaFenceRejection, getDatabasePath, setSqlitePragmaConfig, runSqliteOptimize, openDatabase, openDatabaseAsync, isDatabasePersisted, getDatabasePersistenceError, recordEmbeddingMeasurement, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationIdForProjects, isEmergencyRecoveryArmed, isProviderOverflowReconfirmed, loadPersistedUsage, loadProtectedTailMeta, resetProtectedTailNoEligibleHead, getWrapupInProgressState, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, getPersistedReasoningWatermark, setPersistedReasoningWatermark, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getLastNudgeLevel, setLastNudgeLevel, resetLastNudgeCycle, resetLastNudgeCycleIfTailShrank, getChannel2NudgeState, getChannel2NudgeClaim, casChannel2NudgeState, claimChannel2NudgeState, casChannel2NudgeClaim, getPersistedNoteNudge, getNoteNudgeAnchors, getAutoSearchHintDecisions, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, removeNoteNudgeAnchorByMessageId, removeAutoSearchHintDecisionByMessageId, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, setNoteLastReadAt, getHistorianFailureState, clearHistorianFailureState, getOverflowState, recordOverflowDetected, recordDetectedContextLimit, clearEmergencyRecovery, clearDetectedContextLimit, getPersistedCompactionMarkerState, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, removeStrippedPlaceholderId, getStaleReduceStrippedIds, addStaleReduceStrippedIds, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, getSessionsWithPendingMarker, setSessionWorkMetrics, getNotes, addNote, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, updateNote, dismissNote, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectMemoryEpoch, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, getActiveTagTokenAggregate, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, updateTagMessageId, deleteTagsByMessageId, getMaxTagNumberBySession, getTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getDroppedTagsBySession, getTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, recordChildInvocation, COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_EDITOR_SYSTEM_PROMPT, COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, Priority, AdmissionClass, StaleRouteHandleError, SocketClosedError, SocketTimeoutError, SubcClient, isConsumerReconnectTransient, getCompartmentEvents, loadCompartmentChunkEmbeddingsForSearch, cosineSimilarity, SYNAPSE_DEFAULT_MODEL, SynapseEmbeddingProvider, computeNormalizedHash, saveCommitEmbedding, loadProjectCommitEmbeddings, loadUnembeddedCommits, countEmbeddedCommits, upsertCommits, getLatestIndexedCommitTimeMs, enforceProjectCap, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, saveEmbeddingIfHashMatches, getProjectEmbeddings, peekProjectEmbeddings, invalidateProject, invalidateMemory, markProjectLoadUntrusted, contentSha256, sweepStaleEmbeddingIdentitiesForProject, registerProjectEmbedding, registerProjectShadowEmbedding, getShadowEmbeddingMeasurementCohort, getPrimaryEmbeddingMeasurementCohort, embedShadowTextForProject, enqueueShadowEmbeddingItems, registerProjectInObservationMode, getProjectEmbeddingSnapshot, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, isEmbeddingEnabled, embedText, ensureMemoryEmbeddings, computeCueContentHash, getMuralCueState, memoryNeedsCue, setMuralCue, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, ModuleMemoryAuthorityError, insertMemory, insertMemoryIdempotent, getMemoryByHash, getMemoriesByProject, buildWorkspaceMemorySqlFilter, getMemoriesByProjects, getMaxMemoryIdForProjects, readNewMemoriesForM1Union, getMemoryById, getMemoriesByIds, updateMemorySeenCount, updateMemoryRetrievalCount, setMemoryClassification, supersededMemory, mergeMemoryStats, archiveMemory, getMemoryCountsByStatus, sanitizeFtsQuery, searchMemoriesFTS, searchMemoriesFTSUnion, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, MARKER_SUMMARY_TEXT, applyDeferredCompactionMarker, removeCompactionMarkerForSession, checkCompactionMarkerConsistency, getMural, BoundedSessionMap, extractM0Block, formatDate, injectTemporalMarkers, clearInjectionCache, getVisibleMemoryIds, prepareCompartmentInjection, renderCompartmentInjection, mustMaterialize, trimMemoriesToBudgetV2, renderMemoryBlockV2, injectM0M1, onNoteTrigger, peekNoteNudgeText, markNoteNudgeDelivered, clearNoteNudgeTriggerAndCooldown, resetNoteNudgeCooldownOnly, clearNoteNudgeTriggerOnly, estimateTrueRawMessageTokens, invalidateTrueRawTokenCache, RECOVERY_NO_HEAD_LIMIT, resolveOpenCodeProtectedTailBoundary, resolveWrapupProtectedTailBoundary, getRawHistoryEligibility, hasRunnableCompartmentWindow, recordHighPressureNoEligibleHead, runCompartmentAgent, snapRangeToCompartments, lkgContentDigest, captureSlot, getSlot, dropSlot, noteEntry, getActiveCompartmentRun, markActiveCompartmentRunPublished, registerActiveCompartmentRun, startCompartmentAgent, isRecompFailure, isRecompSkip, isRecompComplete, extractRecompReason, contextualizeUpgradeReason, setRecompStarting, setRecompNote, setRecompTerminal, runManagedRecomp, runManagedUpgrade };
42009
+ export { withContentLanguageDirective, buildPrimaryLanguageDirective, exports_external, DEFAULT_PROTECTED_TAGS, parseCron, nextOccurrence, nextDueAtMs, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, DEFAULT_LOCAL_EMBEDDING_MODEL, MagicContextConfigSchema, getOpenCodeDbPath, removeMcOwnedCompactionMarkers, ProjectIdentityError, resolveProjectIdentityStrict, takeDubiousOwnershipProjectIdentityWarning, resolveProjectIdentity, resolveProjectIdentityForSession, normalizeStoredProjectPath, storedPathBelongsToIdentity, recordSessionProjectIdentity, beginBootQuietPeriod, bootQuietRemainingMs, scheduleAfterBootQuiet, rpcPortDir, rpcPortFilePath, isPidAlive, parseRpcPortFile, registerModuleNoteEvaluationBridge, getModuleNoteEvaluationBridge, getContextStoreUuid, ensureContextStoreUuid, getAuthorityManagedMarker, reconcileAuthorityProject, checksumAuthoritySeedRows, prepareAuthority, drainAuthority, getMirrorCursor, applyMirrorPage, pullMemoryMirrorOnce, V2_MEMORY_CATEGORIES, CATEGORY_PRIORITY, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, resolveStoredPathWorkspaceIdentity, storedPathBelongsToWorkspace, sourceNameForMemory, computeWorkspaceEpochFingerprint, recordToolDefinition, getMeasuredToolDefinitionTokens, getSchemaFenceRejection, getMigrationOnOpenRefusal, LATEST_SUPPORTED_VERSION, getDatabasePath, getPersistedSchemaVersion, setSqlitePragmaConfig, runSqliteOptimize, openDatabase, openDatabaseAsync, isDatabasePersisted, getDatabasePersistenceError, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, clearRecompStaging, recordEmbeddingMeasurement, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationIdForProjects, MAX_EXECUTE_THRESHOLD, escalationBands, isEmergencyRecoveryArmed, isProviderOverflowReconfirmed, loadPersistedUsage, loadProtectedTailMeta, resetProtectedTailNoEligibleHead, getWrapupInProgressState, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, resolveCompactionModeRecord, getCompactionModeRecord, setCompactionModeRecord, getPersistedReasoningWatermark, setPersistedReasoningWatermark, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getLastNudgeLevel, setLastNudgeLevel, resetLastNudgeCycle, resetLastNudgeCycleIfTailShrank, getChannel2NudgeState, getChannel2NudgeClaim, setChannel2NudgeState, casChannel2NudgeState, claimChannel2NudgeState, casChannel2NudgeClaim, getPersistedNoteNudge, getNoteNudgeAnchors, getAutoSearchHintDecisions, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, removeNoteNudgeAnchorByMessageId, removeAutoSearchHintDecisionByMessageId, getPersistedTodoPermissionDenied, setPersistedTodoPermissionDenied, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, setNoteLastReadAt, getHistorianFailureState, clearHistorianFailureState, getOverflowState, recordOverflowDetected, recordDetectedContextLimit, clearEmergencyRecovery, clearDetectedContextLimit, getPersistedCompactionMarkerState, setPersistedCompactionMarkerState, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, removeStrippedPlaceholderId, getStaleReduceStrippedIds, addStaleReduceStrippedIds, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, getSessionsWithPendingMarker, setSessionWorkMetrics, getNotes, addNote, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, updateNote, dismissNote, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, clearPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectMemoryEpoch, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, getActiveTagTokenAggregate, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, getActiveTagTokenTotalsByMessage, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, updateTagMessageId, deleteTagsByMessageId, getMaxTagNumberBySession, getTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getDroppedTagsBySession, getTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, getCandidateToolOwners, pickNearestPriorOwner, createChildSessionWithFence, detectOverflow, promptSyncWithValidatedOutputRetry, normalizeSDKResponse, extractLatestAssistantText, hasLengthCappedOutput, setKeepSubagents, shouldKeepSubagents, recordChildInvocation, COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_EDITOR_SYSTEM_PROMPT, COMPARTMENT_STRUCTURAL_SYSTEM_PROMPT, Priority, AdmissionClass, StaleRouteHandleError, SocketClosedError, SocketTimeoutError, SubcClient, isConsumerReconnectTransient, getCompartmentEvents, loadCompartmentChunkEmbeddingsForSearch, cosineSimilarity, SYNAPSE_DEFAULT_MODEL, SynapseEmbeddingProvider, computeNormalizedHash, saveCommitEmbedding, loadProjectCommitEmbeddings, loadUnembeddedCommits, countEmbeddedCommits, upsertCommits, getLatestIndexedCommitTimeMs, enforceProjectCap, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, saveEmbeddingIfHashMatches, getProjectEmbeddings, peekProjectEmbeddings, invalidateProject, invalidateMemory, markProjectLoadUntrusted, contentSha256, sweepStaleEmbeddingIdentitiesForProject, registerProjectEmbedding, registerProjectShadowEmbedding, getShadowEmbeddingMeasurementCohort, getPrimaryEmbeddingMeasurementCohort, embedShadowTextForProject, enqueueShadowEmbeddingItems, registerProjectInObservationMode, getProjectEmbeddingSnapshot, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, isEmbeddingEnabled, embedText, ensureMemoryEmbeddings, computeCueContentHash, getMuralCueState, memoryNeedsCue, setMuralCue, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, ModuleMemoryAuthorityError, insertMemory, insertMemoryIdempotent, getMemoryByHash, getMemoriesByProject, buildWorkspaceMemorySqlFilter, getMemoriesByProjects, getMaxMemoryIdForProjects, readNewMemoriesForM1Union, getMemoryById, getMemoriesByIds, updateMemorySeenCount, updateMemoryRetrievalCount, setMemoryClassification, supersededMemory, mergeMemoryStats, archiveMemory, getMemoryCountsByStatus, sanitizeFtsQuery, searchMemoriesFTS, searchMemoriesFTSUnion, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, MARKER_SUMMARY_TEXT, applyDeferredCompactionMarker, removeCompactionMarkerForSession, checkCompactionMarkerConsistency, getMural, BoundedSessionMap, extractM0Block, formatDate, injectTemporalMarkers, clearInjectionCache, getVisibleMemoryIds, prepareCompartmentInjection, renderCompartmentInjection, mustMaterialize, trimMemoriesToBudgetV2, renderMemoryBlockV2, injectM0M1, onNoteTrigger, peekNoteNudgeText, markNoteNudgeDelivered, clearNoteNudgeTriggerAndCooldown, resetNoteNudgeCooldownOnly, clearNoteNudgeTriggerOnly, estimateTrueRawMessageTokens, invalidateTrueRawTokenCache, RECOVERY_NO_HEAD_LIMIT, resolveOpenCodeProtectedTailBoundary, resolveWrapupProtectedTailBoundary, getRawHistoryEligibility, hasRunnableCompartmentWindow, recordHighPressureNoEligibleHead, runCompartmentAgent, snapRangeToCompartments, lkgContentDigest, captureSlot, getSlot, dropSlot, noteEntry, getActiveCompartmentRun, markActiveCompartmentRunPublished, registerActiveCompartmentRun, startCompartmentAgent, isRecompFailure, isRecompSkip, isRecompComplete, extractRecompReason, contextualizeUpgradeReason, setRecompStarting, setRecompNote, setRecompTerminal, runManagedRecomp, runManagedUpgrade };