@cortexkit/opencode-magic-context 0.33.0 → 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 (265) 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 +144 -24
  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-bwa99a04.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 +106 -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 +0 -2
  17. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  18. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  19. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  21. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  23. package/dist/features/magic-context/dreamer/task-registry.d.ts +0 -1
  24. package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
  25. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  26. package/dist/features/magic-context/fail-closed-block.d.ts +10 -0
  27. package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
  28. package/dist/features/magic-context/git-commits/index.d.ts +2 -2
  29. package/dist/features/magic-context/git-commits/index.d.ts.map +1 -1
  30. package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts +0 -2
  31. package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -1
  32. package/dist/features/magic-context/git-commits/storage-git-commits.d.ts +0 -13
  33. package/dist/features/magic-context/git-commits/storage-git-commits.d.ts.map +1 -1
  34. package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -1
  35. package/dist/features/magic-context/memory/embedding-local.d.ts +7 -1
  36. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  37. package/dist/features/magic-context/memory/embedding.d.ts +1 -2
  38. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
  39. package/dist/features/magic-context/memory/memory-migration.d.ts +0 -6
  40. package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
  41. package/dist/features/magic-context/memory/project-identity.d.ts +2 -6
  42. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  43. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +0 -1
  44. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
  45. package/dist/features/magic-context/memory/storage-memory.d.ts +1 -6
  46. package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
  47. package/dist/features/magic-context/memory/verification-paths.d.ts +0 -1
  48. package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
  49. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  50. package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
  51. package/dist/features/magic-context/mural/render-mural.d.ts.map +1 -1
  52. package/dist/features/magic-context/mural/storage-mural.d.ts +0 -1
  53. package/dist/features/magic-context/mural/storage-mural.d.ts.map +1 -1
  54. package/dist/features/magic-context/overflow-detection.d.ts +8 -1
  55. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  56. package/dist/features/magic-context/project-embedding-registry.d.ts +16 -2
  57. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  58. package/dist/features/magic-context/scheduler.d.ts.map +1 -1
  59. package/dist/features/magic-context/schema-fence-probe.d.ts +28 -0
  60. package/dist/features/magic-context/schema-fence-probe.d.ts.map +1 -0
  61. package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
  62. package/dist/features/magic-context/smart-notes/capabilities.d.ts +0 -2
  63. package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -1
  64. package/dist/features/magic-context/smart-notes/compiler.d.ts +0 -1
  65. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
  66. package/dist/features/magic-context/smart-notes/types.d.ts +0 -16
  67. package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -1
  68. package/dist/features/magic-context/storage-db.d.ts +35 -1
  69. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  70. package/dist/features/magic-context/storage-meta-persisted.d.ts +38 -5
  71. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  72. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  73. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  74. package/dist/features/magic-context/storage.d.ts +1 -1
  75. package/dist/features/magic-context/storage.d.ts.map +1 -1
  76. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
  77. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +0 -2
  78. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
  79. package/dist/hooks/auto-update-checker/types.d.ts +0 -3
  80. package/dist/hooks/auto-update-checker/types.d.ts.map +1 -1
  81. package/dist/hooks/magic-context/boundary-execution.d.ts +1 -1
  82. package/dist/hooks/magic-context/boundary-execution.d.ts.map +1 -1
  83. package/dist/hooks/magic-context/cache-busting-signals.d.ts +1 -1
  84. package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
  85. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  86. package/dist/hooks/magic-context/child-session-spawn.d.ts +26 -0
  87. package/dist/hooks/magic-context/child-session-spawn.d.ts.map +1 -0
  88. package/dist/hooks/magic-context/command-handler.d.ts +2 -0
  89. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  90. package/dist/hooks/magic-context/compaction-marker-manager.d.ts +49 -0
  91. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  92. package/dist/hooks/magic-context/compaction-off-transition.d.ts +96 -0
  93. package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -0
  94. package/dist/hooks/magic-context/compartment-parser.d.ts +12 -0
  95. package/dist/hooks/magic-context/compartment-parser.d.ts.map +1 -1
  96. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +2 -0
  97. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  98. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  99. package/dist/hooks/magic-context/compartment-runner-mapping.d.ts +0 -12
  100. package/dist/hooks/magic-context/compartment-runner-mapping.d.ts.map +1 -1
  101. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  102. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  103. package/dist/hooks/magic-context/compartment-trigger.d.ts +12 -5
  104. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  105. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +47 -1
  106. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
  107. package/dist/hooks/magic-context/emergency-drop.d.ts +2 -2
  108. package/dist/hooks/magic-context/event-handler.d.ts +7 -0
  109. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  110. package/dist/hooks/magic-context/event-resolvers.d.ts +13 -21
  111. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  112. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
  113. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  114. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +1 -1
  115. package/dist/hooks/magic-context/historian-prompt.generated.d.ts +1 -1
  116. package/dist/hooks/magic-context/historian-prompt.generated.d.ts.map +1 -1
  117. package/dist/hooks/magic-context/hook-handlers.d.ts +1 -0
  118. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  119. package/dist/hooks/magic-context/hook.d.ts +11 -1
  120. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  121. package/dist/hooks/magic-context/inject-compartments.d.ts +18 -0
  122. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  123. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  124. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  125. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  126. package/dist/hooks/magic-context/rust-mode-transform.d.ts +3 -0
  127. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  128. package/dist/hooks/magic-context/send-session-notification.d.ts +20 -1
  129. package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
  130. package/dist/hooks/magic-context/sentinel.d.ts +39 -0
  131. package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
  132. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  133. package/dist/hooks/magic-context/tool-drop-target.d.ts +19 -0
  134. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  135. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +3 -0
  136. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  137. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +30 -0
  138. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  139. package/dist/hooks/magic-context/transform.d.ts +27 -0
  140. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  141. package/dist/{index-kxz4tn6m.js → index-56yjaeb2.js} +56 -4
  142. package/dist/{index-bmkea2dq.js → index-b563sga5.js} +40 -287
  143. package/dist/{index-y1c9tcm3.js → index-cn960ffd.js} +101 -20
  144. package/dist/{index-k5y60ymm.js → index-dtas91s5.js} +27 -6
  145. package/dist/index-fcyvznch.js +279 -0
  146. package/dist/{index-63dq2g4d.js → index-ry8rh8cv.js} +138 -24
  147. package/dist/{index-h86twgsp.js → index-s0mdn690.js} +2113 -1067
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +1356 -627
  150. package/dist/plugin/embedding-bootstrap.d.ts.map +1 -1
  151. package/dist/plugin/hooks/create-session-hooks.d.ts +19 -8
  152. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  153. package/dist/plugin/messages-transform.d.ts +10 -0
  154. package/dist/plugin/messages-transform.d.ts.map +1 -1
  155. package/dist/plugin/rpc-handlers.d.ts +3 -7
  156. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  157. package/dist/plugin/tool-registry.d.ts +8 -0
  158. package/dist/plugin/tool-registry.d.ts.map +1 -1
  159. package/dist/{recomp-orchestrator-yh7pepvx.js → recomp-orchestrator-8e82vmvb.js} +6 -5
  160. package/dist/send-session-notification-6njqewzk.js +20 -0
  161. package/dist/shared/conflict-detector.d.ts +38 -1
  162. package/dist/shared/conflict-detector.d.ts.map +1 -1
  163. package/dist/shared/conflict-fixer.d.ts +18 -1
  164. package/dist/shared/conflict-fixer.d.ts.map +1 -1
  165. package/dist/shared/context-limit-provenance.d.ts +3 -0
  166. package/dist/shared/context-limit-provenance.d.ts.map +1 -0
  167. package/dist/shared/escalation-bands.d.ts +9 -0
  168. package/dist/shared/escalation-bands.d.ts.map +1 -0
  169. package/dist/shared/format-threshold.d.ts +1 -1
  170. package/dist/shared/models-dev-cache.d.ts +29 -3
  171. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  172. package/dist/shared/rpc-server.d.ts.map +1 -1
  173. package/dist/shared/rpc-types.d.ts +46 -1
  174. package/dist/shared/rpc-types.d.ts.map +1 -1
  175. package/dist/shared/sqlite.d.ts +9 -4
  176. package/dist/shared/sqlite.d.ts.map +1 -1
  177. package/dist/shared/storage-permissions.d.ts +5 -0
  178. package/dist/shared/storage-permissions.d.ts.map +1 -0
  179. package/dist/{storage-meta-session-1phy0b1z.js → storage-meta-session-xt41zbw4.js} +2 -1
  180. package/dist/{task-config-dn9k9szr.js → task-config-5nx3qfz8.js} +1 -2
  181. package/dist/tui/compaction-off.d.ts +13 -0
  182. package/dist/tui/compaction-off.d.ts.map +1 -0
  183. package/dist/tui/data/context-db.d.ts.map +1 -1
  184. package/dist/tui-compiled/compaction-off.d.ts +13 -0
  185. package/dist/tui-compiled/compaction-off.d.ts.map +1 -0
  186. package/dist/tui-compiled/data/context-db.d.ts.map +1 -1
  187. package/package.json +8 -3
  188. package/src/agents/dreamer.ts +68 -0
  189. package/src/agents/hidden-agent-registrations.ts +331 -0
  190. package/src/agents/historian.ts +3 -0
  191. package/src/agents/language-directive.test.ts +138 -0
  192. package/src/agents/language-directive.ts +121 -0
  193. package/src/agents/magic-context-prompt.language.test.ts +35 -0
  194. package/src/agents/magic-context-prompt.test.ts +292 -0
  195. package/src/agents/magic-context-prompt.ts +182 -0
  196. package/src/agents/permissions.test.ts +252 -0
  197. package/src/agents/permissions.ts +186 -0
  198. package/src/agents/sidekick.ts +1 -0
  199. package/src/agents/smart-note-compiler.ts +1 -0
  200. package/src/config/agent-disable.ts +106 -0
  201. package/src/config/compaction-accessor-guard.test.ts +82 -0
  202. package/src/config/compaction-backcompat.test.ts +52 -0
  203. package/src/config/index.test.ts +904 -0
  204. package/src/config/index.ts +601 -0
  205. package/src/config/migrate-config-location.test.ts +332 -0
  206. package/src/config/migrate-config-location.ts +635 -0
  207. package/src/config/migrate-dreamer-v2.test.ts +287 -0
  208. package/src/config/migrate-dreamer-v2.ts +336 -0
  209. package/src/config/migrate-experimental.ts +159 -0
  210. package/src/config/project-security.test.ts +366 -0
  211. package/src/config/project-security.ts +588 -0
  212. package/src/config/prune-config-leaf.test.ts +78 -0
  213. package/src/config/prune-config-leaf.ts +68 -0
  214. package/src/config/removed-config-keys.test.ts +116 -0
  215. package/src/config/schema/agent-overrides.ts +45 -0
  216. package/src/config/schema/magic-context.test.ts +358 -0
  217. package/src/config/schema/magic-context.ts +1002 -0
  218. package/src/config/transform-mode.test.ts +62 -0
  219. package/src/config/transform-mode.ts +34 -0
  220. package/src/config/variable.test.ts +323 -0
  221. package/src/config/variable.ts +192 -0
  222. package/src/features/magic-context/defaults.ts +1 -0
  223. package/src/features/magic-context/dreamer/cron.ts +243 -0
  224. package/src/features/magic-context/dreamer/task-registry.ts +104 -0
  225. package/src/shared/conflict-detector.test.ts +251 -1
  226. package/src/shared/conflict-detector.ts +84 -5
  227. package/src/shared/conflict-fixer.test.ts +309 -0
  228. package/src/shared/conflict-fixer.ts +82 -5
  229. package/src/shared/context-limit-provenance.ts +6 -0
  230. package/src/shared/escalation-bands.test.ts +23 -0
  231. package/src/shared/escalation-bands.ts +18 -0
  232. package/src/shared/format-threshold.ts +1 -1
  233. package/src/shared/models-dev-cache.test.ts +171 -0
  234. package/src/shared/models-dev-cache.ts +195 -38
  235. package/src/shared/rpc-server.ts +27 -18
  236. package/src/shared/rpc-types.ts +46 -1
  237. package/src/shared/sqlite.ts +13 -33
  238. package/src/shared/storage-permissions.ts +20 -0
  239. package/src/tui/compaction-off.test.ts +56 -0
  240. package/src/tui/compaction-off.ts +29 -0
  241. package/src/tui/data/context-db.ts +6 -0
  242. package/src/tui/index.tsx +113 -65
  243. package/src/tui/slots/sidebar-content.tsx +139 -83
  244. package/src/tui-compiled/compaction-off.ts +29 -0
  245. package/src/tui-compiled/data/context-db.ts +6 -0
  246. package/src/tui-compiled/index.tsx +558 -455
  247. package/src/tui-compiled/slots/sidebar-content.tsx +237 -161
  248. package/dist/config/schema.d.ts +0 -3
  249. package/dist/config/schema.d.ts.map +0 -1
  250. package/dist/features/magic-context/plugin-messages.d.ts +0 -75
  251. package/dist/features/magic-context/plugin-messages.d.ts.map +0 -1
  252. package/dist/hooks/magic-context/compartment-runner-state-xml.d.ts +0 -21
  253. package/dist/hooks/magic-context/compartment-runner-state-xml.d.ts.map +0 -1
  254. package/dist/index-anhrfygk.js +0 -57
  255. package/dist/send-session-notification-tghq9gnh.js +0 -11
  256. package/dist/shared/opencode-compaction-detector.d.ts +0 -2
  257. package/dist/shared/opencode-compaction-detector.d.ts.map +0 -1
  258. package/dist/shared/transcript-opencode.d.ts +0 -71
  259. package/dist/shared/transcript-opencode.d.ts.map +0 -1
  260. package/dist/tools/index.d.ts +0 -6
  261. package/dist/tools/index.d.ts.map +0 -1
  262. package/src/shared/opencode-compaction-detector.test.ts +0 -239
  263. package/src/shared/opencode-compaction-detector.ts +0 -81
  264. package/src/shared/transcript-opencode.ts +0 -302
  265. /package/dist/{index-v7fmc1s2.js → index-ygcng9t8.js} +0 -0
@@ -1,10 +1,9 @@
1
1
  import {
2
2
  deriveTriggerBudget,
3
- modelSupportsVision
4
- } from "./index-63dq2g4d.js";
5
- import {
6
- AGENTIC_DREAM_TASKS
7
- } from "./index-anhrfygk.js";
3
+ modelSupportsVision,
4
+ piModelRefToCanonical,
5
+ shouldEnforcePrivateStoragePermissions
6
+ } from "./index-ry8rh8cv.js";
8
7
  import {
9
8
  parseProviderModel
10
9
  } from "./index-td9depx5.js";
@@ -12,18 +11,15 @@ import {
12
11
  describeError,
13
12
  getErrorMessage,
14
13
  sendIgnoredMessage
15
- } from "./index-y1c9tcm3.js";
14
+ } from "./index-cn960ffd.js";
16
15
  import {
17
- Database,
18
16
  clearCachedM0M1,
19
17
  clearCompressionDepth,
20
18
  clearCompressionDepthRange,
21
- closeQuietly,
22
19
  ensureSessionMetaRow,
23
20
  estimateTokens,
24
21
  getCachedAbsoluteMessageCount,
25
22
  getLegacyProtectedTailStartOrdinal,
26
- getMessageTimesFromOpenCodeDb,
27
23
  getRawSessionMessageCount,
28
24
  getRawSessionTagKeysThrough,
29
25
  hasMeaningfulUserText,
@@ -32,10 +28,17 @@ import {
32
28
  persistCachedM0,
33
29
  readRawSessionMessages,
34
30
  readSessionChunk,
35
- registerPrivilegedWriter,
36
- updateSessionMeta,
31
+ updateSessionMeta
32
+ } from "./index-b563sga5.js";
33
+ import {
34
+ Database,
35
+ closeQuietly,
36
+ getMessageTimesFromOpenCodeDb,
37
37
  withPrivilegedWriter
38
- } from "./index-bmkea2dq.js";
38
+ } from "./index-fcyvznch.js";
39
+ import {
40
+ pushNotification
41
+ } from "./index-d62ypazr.js";
39
42
  import {
40
43
  log,
41
44
  sessionLog
@@ -376,462 +379,95 @@ function buildPrimaryLanguageDirective(language) {
376
379
  return "";
377
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.`;
378
381
  }
379
- // src/features/magic-context/overflow-detection.ts
380
- var OVERFLOW_PATTERNS = [
381
- /prompt is too long/i,
382
- /input is too long for requested model/i,
383
- /exceeds the context window/i,
384
- /input token count.*exceeds the maximum/i,
385
- /maximum prompt length is \d+/i,
386
- /reduce the length of the messages/i,
387
- /maximum context length is \d+ tokens/i,
388
- /exceeds the limit of \d+/i,
389
- /exceeds the available context size/i,
390
- /greater than the context length/i,
391
- /context window exceeds limit/i,
392
- /exceeded model token limit/i,
393
- /context[_ ]length[_ ]exceeded/i,
394
- /request entity too large/i,
395
- /context length is only \d+ tokens/i,
396
- /input length.*exceeds.*context length/i,
397
- /prompt too long; exceeded (?:max )?context length/i,
398
- /too large for model with \d+ maximum context length/i,
399
- /model_context_window_exceeded/i,
400
- /context size has been exceeded/i
401
- ];
402
- var LIMIT_EXTRACTION_PATTERNS = [
403
- /maximum prompt length is (\d+)/i,
404
- /maximum context length is (\d+) tokens?/i,
405
- /context length is only (\d+) tokens?/i,
406
- /exceeds the limit of (\d+)/i,
407
- /too large for model with (\d+) maximum context length/i,
408
- /context size.*(\d+) tokens?/i,
409
- /exceeds? the context length of (\d+)/i,
410
- />\s*(\d+)\s*(?:tokens?\s*)?(?:maximum|max|limit)\b/i,
411
- /max(?:imum)?.*context.*?(\d+)/i
412
- ];
413
- var MIN_PLAUSIBLE_LIMIT = 1024;
414
- var MAX_PLAUSIBLE_LIMIT = 1e7;
415
- function extractErrorMessage(error) {
416
- if (!error)
417
- return "";
418
- if (typeof error === "string")
419
- return error;
420
- if (typeof error === "object") {
421
- const obj = error;
422
- const nested = obj.error;
423
- if (nested && typeof nested.message === "string" && nested.message.length > 0) {
424
- return nested.message;
425
- }
426
- }
427
- if (error instanceof Error)
428
- return error.message;
429
- if (typeof error === "object") {
430
- const obj = error;
431
- if (typeof obj.message === "string")
432
- return obj.message;
433
- if (typeof obj.responseBody === "string")
434
- return obj.responseBody;
435
- try {
436
- return JSON.stringify(error);
437
- } catch {
438
- return String(error);
439
- }
440
- }
441
- 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;
442
403
  }
443
- function detectOverflow(error) {
444
- const message = extractErrorMessage(error);
445
- if (!message) {
446
- return { isOverflow: false };
447
- }
448
- const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
449
- let matched;
450
- for (const pattern of OVERFLOW_PATTERNS) {
451
- if (pattern.test(message)) {
452
- matched = pattern;
453
- break;
454
- }
455
- }
456
- if (!matched && !hasStatus413) {
457
- return { isOverflow: false };
458
- }
459
- const reportedLimit = parseReportedLimit(message);
460
- return {
461
- isOverflow: true,
462
- reportedLimit,
463
- matchedPattern: matched?.source
464
- };
404
+ function bootQuietRemainingMs(now = Date.now()) {
405
+ return Math.max(0, bootQuietUntilMs - now);
465
406
  }
466
- function parseReportedLimit(message) {
467
- if (!message)
468
- return;
469
- for (const pattern of LIMIT_EXTRACTION_PATTERNS) {
470
- const match = message.match(pattern);
471
- if (!match)
472
- continue;
473
- const raw = match[1];
474
- if (!raw)
475
- continue;
476
- const value = Number.parseInt(raw, 10);
477
- if (!Number.isFinite(value))
478
- continue;
479
- if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
480
- continue;
481
- return value;
482
- }
483
- return;
407
+ function scheduleAfterBootQuiet(task, additionalDelayMs = 0) {
408
+ const timer = setTimeout(task, bootQuietRemainingMs() + Math.max(0, additionalDelayMs));
409
+ timer.unref?.();
410
+ return timer;
484
411
  }
485
412
 
486
- // src/shared/model-suggestion-retry.ts
487
- var ABORT_CALL_TIMEOUT_MS = 3000;
488
- function copyPromptArgs(args, body) {
489
- 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);
490
419
  }
491
- function extractMessage(error) {
492
- if (typeof error === "string")
493
- return error;
494
- if (error instanceof Error)
495
- return error.message;
496
- if (typeof error === "object" && error !== null) {
497
- const obj = error;
498
- if (typeof obj.message === "string")
499
- return obj.message;
500
- }
501
- try {
502
- return JSON.stringify(error);
503
- } catch (_error) {
504
- return String(error);
505
- }
420
+ function rpcPortDir(storageDir, directory) {
421
+ return join(storageDir, "rpc", projectHash(directory));
506
422
  }
507
- function parseModelSuggestion(error) {
508
- if (!error)
509
- return null;
510
- if (typeof error === "object" && error !== null) {
511
- const errObj = error;
512
- if (errObj.name === "ProviderModelNotFoundError" && typeof errObj.data === "object" && errObj.data !== null) {
513
- const data = errObj.data;
514
- const suggestions = data.suggestions;
515
- if (Array.isArray(suggestions) && typeof suggestions[0] === "string") {
516
- return {
517
- providerID: String(data.providerID ?? ""),
518
- modelID: String(data.modelID ?? ""),
519
- suggestion: suggestions[0]
520
- };
521
- }
522
- }
523
- for (const key of ["data", "error", "cause"]) {
524
- const nested = errObj[key];
525
- if (nested && typeof nested === "object") {
526
- const result = parseModelSuggestion(nested);
527
- if (result)
528
- return result;
529
- }
530
- }
531
- }
532
- const message = extractMessage(error);
533
- const modelMatch = message.match(/model not found:\s*([^/\s]+)\s*\/\s*([^.,\s]+)/i);
534
- const suggestionMatch = message.match(/did you mean:\s*([^,?]+)/i);
535
- if (!modelMatch || !suggestionMatch) {
536
- return null;
537
- }
538
- return {
539
- providerID: modelMatch[1].trim(),
540
- modelID: modelMatch[2].trim(),
541
- suggestion: suggestionMatch[1].trim()
542
- };
423
+ function rpcPortFilePath(storageDir, directory, pid = process.pid, instanceId) {
424
+ const suffix = instanceId ? `-${instanceId}` : "";
425
+ return join(rpcPortDir(storageDir, directory), `port-${pid}${suffix}.json`);
543
426
  }
544
- async function promptWithTimeout(client, args, timeoutMs, signal) {
545
- if (signal?.aborted) {
546
- throw new Error("prompt aborted by external signal");
547
- }
548
- const controller = new AbortController;
549
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
550
- const onExternalAbort = () => controller.abort();
551
- signal?.addEventListener("abort", onExternalAbort);
552
- try {
553
- await client.session.prompt({
554
- ...args,
555
- signal: controller.signal
556
- });
557
- } catch (error) {
558
- if (signal?.aborted) {
559
- await abortChildRun(client, args.path.id);
560
- throw new Error("prompt aborted by external signal");
561
- }
562
- if (controller.signal.aborted) {
563
- await abortChildRun(client, args.path.id);
564
- throw new Error(`prompt timed out after ${timeoutMs}ms`);
565
- }
566
- throw error;
567
- } finally {
568
- clearTimeout(timeout);
569
- signal?.removeEventListener("abort", onExternalAbort);
570
- }
571
- }
572
- async function abortChildRun(client, sessionId) {
427
+ function isPidAlive(pid) {
428
+ if (!Number.isInteger(pid) || pid <= 0)
429
+ return false;
573
430
  try {
574
- await Promise.race([
575
- client.session.abort({ path: { id: sessionId } }),
576
- new Promise((resolve) => setTimeout(resolve, ABORT_CALL_TIMEOUT_MS))
577
- ]);
578
- } catch (error) {
579
- log(`[model-retry] child session abort failed for ${sessionId}: ${String(error)}`);
580
- }
581
- }
582
- function isNonRetryable(error, externalSignal) {
583
- if (externalSignal?.aborted)
584
- return true;
585
- if (error instanceof Error) {
586
- if (error.name === "AbortError")
587
- return true;
588
- if (error.message === "prompt aborted by external signal")
589
- return true;
590
- if (/^prompt timed out after \d+ms$/.test(error.message))
591
- return true;
592
- }
593
- if (detectOverflow(error).isOverflow)
431
+ process.kill(pid, 0);
594
432
  return true;
595
- return false;
596
- }
597
- function shortErr(error) {
598
- if (error instanceof Error) {
599
- return error.name && error.name !== "Error" ? `${error.name}: ${error.message}` : error.message;
600
- }
601
- return extractMessage(error);
602
- }
603
- async function attemptOnce(client, args, timeoutMs, signal, callContext, label) {
604
- const originalBody = { ...args.body };
605
- const attemptArgs = copyPromptArgs(args, originalBody);
606
- try {
607
- await promptWithTimeout(client, attemptArgs, timeoutMs, signal);
608
- return;
609
- } catch (error) {
610
- if (isNonRetryable(error, signal))
611
- throw error;
612
- const suggestion = parseModelSuggestion(error);
613
- if (!suggestion || !originalBody.model) {
614
- throw error;
615
- }
616
- log(`[${callContext}] ${label}: model not found, retrying with suggestion`, {
617
- original: `${suggestion.providerID}/${suggestion.modelID}`,
618
- suggested: suggestion.suggestion
619
- });
620
- await promptWithTimeout(client, copyPromptArgs(args, {
621
- ...originalBody,
622
- model: {
623
- providerID: suggestion.providerID,
624
- modelID: suggestion.suggestion
625
- }
626
- }), timeoutMs, signal);
627
- }
628
- }
629
- async function promptSyncWithModelSuggestionRetry(client, args, options = {}) {
630
- const timeoutMs = options.timeoutMs ?? 300000;
631
- const callContext = options.callContext ?? "subagent";
632
- const fallbacks = options.fallbackModels ?? [];
633
- const baseBody = { ...args.body };
634
- const baseArgs = copyPromptArgs(args, baseBody);
635
- const explicitPrimaryLabel = baseBody.model?.providerID && baseBody.model.modelID ? `${baseBody.model.providerID}/${baseBody.model.modelID}` : "primary";
636
- let lastError = null;
637
- try {
638
- await attemptOnce(client, baseArgs, timeoutMs, options.signal, callContext, explicitPrimaryLabel);
639
- return;
640
- } catch (error) {
641
- lastError = error;
642
- if (isNonRetryable(error, options.signal))
643
- throw error;
644
- if (fallbacks.length === 0) {
645
- throw error;
646
- }
647
- log(`[${callContext}] primary (${explicitPrimaryLabel}) failed: ${shortErr(error)}; trying ${fallbacks.length} fallback(s)`);
648
- }
649
- for (let i = 0;i < fallbacks.length; i += 1) {
650
- const parsed = parseProviderModel(fallbacks[i]);
651
- if (!parsed) {
652
- log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
653
- continue;
654
- }
655
- const label = `${parsed.providerID}/${parsed.modelID}`;
656
- const attemptArgs = copyPromptArgs(baseArgs, {
657
- ...baseBody,
658
- model: parsed
659
- });
660
- try {
661
- await attemptOnce(client, attemptArgs, timeoutMs, options.signal, callContext, label);
662
- log(`[${callContext}] fallback succeeded with ${label} (attempt ${i + 2}/${fallbacks.length + 1})`);
663
- return;
664
- } catch (error) {
665
- lastError = error;
666
- if (isNonRetryable(error, options.signal))
667
- throw error;
668
- const remaining = fallbacks.length - i - 1;
669
- if (remaining > 0) {
670
- log(`[${callContext}] ${label} failed: ${shortErr(error)}; ${remaining} fallback(s) left`);
671
- }
672
- }
433
+ } catch (err) {
434
+ return err.code === "EPERM";
673
435
  }
674
- log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; last error: ${shortErr(lastError)}`);
675
- throw lastError ?? new Error("All fallback models failed");
676
436
  }
677
- async function attemptAndValidate(client, args, timeoutMs, signal, callContext, attempt, options) {
678
- await attemptOnce(client, args, timeoutMs, signal, callContext, attempt.label);
679
- const output = await options.fetchOutput(args, attempt);
680
- const validated = await options.validateOutput(output, attempt);
681
- return { output, validated, attempt };
682
- }
683
- async function promptSyncWithValidatedOutputRetry(client, args, options) {
684
- const timeoutMs = options.timeoutMs ?? 300000;
685
- const callContext = options.callContext ?? "subagent";
686
- const fallbacks = options.fallbackModels ?? [];
687
- const baseBody = { ...args.body };
688
- const baseArgs = copyPromptArgs(args, baseBody);
689
- const explicitPrimaryLabel = baseBody.model?.providerID && baseBody.model.modelID ? `${baseBody.model.providerID}/${baseBody.model.modelID}` : "primary";
690
- const totalAttempts = fallbacks.length + 1;
691
- let firstError = null;
692
- let lastError = null;
693
- try {
694
- return await attemptAndValidate(client, baseArgs, timeoutMs, options.signal, callContext, {
695
- label: explicitPrimaryLabel,
696
- attemptIndex: 0,
697
- isFallback: false,
698
- totalAttempts,
699
- model: baseBody.model
700
- }, options);
701
- } catch (error) {
702
- firstError = error;
703
- lastError = error;
704
- if (isNonRetryable(error, options.signal))
705
- throw error;
706
- if (fallbacks.length === 0) {
707
- throw error;
708
- }
709
- log(`[${callContext}] primary (${explicitPrimaryLabel}) failed validation/prompt: ${shortErr(error)}; trying ${fallbacks.length} fallback(s)`);
710
- }
711
- for (let i = 0;i < fallbacks.length; i += 1) {
712
- const parsed = parseProviderModel(fallbacks[i]);
713
- if (!parsed) {
714
- log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
715
- continue;
716
- }
717
- const label = `${parsed.providerID}/${parsed.modelID}`;
718
- const attemptArgs = copyPromptArgs(baseArgs, {
719
- ...baseBody,
720
- model: parsed
721
- });
722
- const attempt = {
723
- label,
724
- attemptIndex: i + 1,
725
- isFallback: true,
726
- totalAttempts,
727
- model: parsed
728
- };
437
+ function parseRpcPortFile(content, fallbackPid = 0) {
438
+ const trimmed = content.trim();
439
+ if (!trimmed)
440
+ return null;
441
+ if (trimmed.startsWith("{")) {
729
442
  try {
730
- const result = await attemptAndValidate(client, attemptArgs, timeoutMs, options.signal, callContext, attempt, options);
731
- log(`[${callContext}] fallback succeeded with ${label} (attempt ${i + 2}/${fallbacks.length + 1})`);
732
- return result;
733
- } catch (error) {
734
- if (firstError === null)
735
- firstError = error;
736
- lastError = error;
737
- if (isNonRetryable(error, options.signal))
738
- throw error;
739
- const remaining = fallbacks.length - i - 1;
740
- if (remaining > 0) {
741
- log(`[${callContext}] ${label} failed validation/prompt: ${shortErr(error)}; ${remaining} fallback(s) left`);
742
- }
743
- }
744
- }
745
- log(`[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; original error: ${shortErr(firstError)}; last error: ${shortErr(lastError)}`);
746
- throw firstError ?? lastError ?? new Error("All fallback models failed validation");
747
- }
748
- // src/shared/normalize-sdk-response.ts
749
- function normalizeSDKResponse(response, fallback, options) {
750
- if (response === null || response === undefined) {
751
- return fallback;
752
- }
753
- if (Array.isArray(response)) {
754
- return response;
755
- }
756
- if (typeof response === "object" && "data" in response) {
757
- const data = response.data;
758
- if (data !== null && data !== undefined) {
759
- return data;
760
- }
761
- if (options?.preferResponseOnMissingData === true) {
762
- 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;
763
458
  }
764
- return fallback;
765
- }
766
- if (options?.preferResponseOnMissingData === true) {
767
- return response;
768
459
  }
769
- return fallback;
770
- }
771
- // src/shared/assistant-message-extractor.ts
772
- function asSessionMessage(value) {
773
- if (!isRecord(value))
460
+ const port = Number.parseInt(trimmed, 10);
461
+ if (!isValidPort(port))
774
462
  return null;
775
- const info = value.info;
776
- const parts = value.parts;
777
- return {
778
- info: isRecord(info) ? {
779
- role: typeof info.role === "string" ? info.role : undefined,
780
- time: isRecord(info.time) ? {
781
- created: typeof info.time.created === "number" ? info.time.created : undefined
782
- } : undefined
783
- } : undefined,
784
- parts
785
- };
463
+ return { port, pid: fallbackPid, started_at: 0 };
786
464
  }
787
- function getCreatedTime(message) {
788
- return message.info?.time?.created ?? 0;
789
- }
790
- function getTextParts(message) {
791
- if (!Array.isArray(message.parts))
792
- return [];
793
- return message.parts.filter((part) => isRecord(part)).map((part) => ({
794
- type: typeof part.type === "string" ? part.type : undefined,
795
- text: typeof part.text === "string" ? part.text : undefined
796
- })).filter((part) => part.type === "text" && Boolean(part.text));
797
- }
798
- function extractLatestAssistantText(messages) {
799
- if (!Array.isArray(messages) || messages.length === 0)
800
- return null;
801
- const assistantMessages = messages.map(asSessionMessage).filter((message) => message !== null).filter((message) => message.info?.role === "assistant").sort((a, b) => getCreatedTime(b) - getCreatedTime(a));
802
- const latest = assistantMessages[0];
803
- if (!latest)
804
- return null;
805
- return getTextParts(latest).map((part) => part.text).join(`
806
- `) || null;
807
- }
808
- function hasLengthCappedOutput(value) {
809
- if (Array.isArray(value))
810
- return value.some((item) => hasLengthCappedOutput(item));
811
- if (!isRecord(value))
812
- return false;
813
- if (value.length_capped === true || value.lengthCapped === true)
814
- return true;
815
- const finishReason = value.finish_reason ?? value.finishReason;
816
- if (typeof finishReason === "string") {
817
- const normalized = finishReason.toLowerCase();
818
- if (normalized === "length" || normalized === "max_tokens" || normalized === "max_output_tokens") {
819
- return true;
820
- }
821
- }
822
- return Object.values(value).some((item) => hasLengthCappedOutput(item));
465
+ function isValidPort(port) {
466
+ return Number.isInteger(port) && port > 0 && port <= 65535;
823
467
  }
824
468
 
825
- // src/shared/keep-subagents.ts
826
- var keepSubagents = false;
827
- function setKeepSubagents(value) {
828
- keepSubagents = value === true;
829
- }
830
- function shouldKeepSubagents() {
831
- return keepSubagents;
832
- }
833
469
  // src/features/magic-context/context-authority.ts
834
- import { createHash, randomUUID } from "node:crypto";
470
+ import { createHash as createHash2, randomUUID } from "node:crypto";
835
471
  var AUTHORITY_DOMAINS = ["memories", "notes"];
836
472
  var moduleNoteEvaluationBridges = new Map;
837
473
  function registerModuleNoteEvaluationBridge(projectPath, bridge) {
@@ -963,7 +599,7 @@ function checksumAuthoritySeedRows(rows) {
963
599
  const rightId = seedSourceRowId(right) ?? Number.MAX_SAFE_INTEGER;
964
600
  return leftId - rightId;
965
601
  });
966
- return createHash("sha256").update(JSON.stringify(ordered.map(canonicalizeSeedValue))).digest("hex");
602
+ return createHash2("sha256").update(JSON.stringify(ordered.map(canonicalizeSeedValue))).digest("hex");
967
603
  }
968
604
  function maxDomainRowId(db, domain, projectPath) {
969
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
@@ -1051,10 +687,14 @@ async function prepareAuthority(args) {
1051
687
  domain,
1052
688
  rows: page
1053
689
  });
1054
- const identities = (seedResponse.module_row_ids ?? []).map((moduleRowId, index) => ({
1055
- moduleRowId,
1056
- sourceRowId: seedSourceRowId(page[index])
1057
- })).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()];
1058
698
  if (identities.length > 0) {
1059
699
  args.db.transaction(() => {
1060
700
  for (const identity of identities) {
@@ -1955,6 +1595,185 @@ function pullMemoryMirrorOnce(args) {
1955
1595
  mirrorFlights.set(args.module, flight);
1956
1596
  return flight;
1957
1597
  }
1598
+
1599
+ // src/hooks/magic-context/compartment-parser.ts
1600
+ var COMPARTMENT_REGEX = /<compartment\s+([^>]*?)\s*>(.*?)<\/compartment>/gs;
1601
+ var ATTR_START_REGEX = /\bstart="(\d+)"/;
1602
+ var ATTR_END_REGEX = /\bend="(\d+)"/;
1603
+ var ATTR_TITLE_REGEX = /\btitle="([^"]*)"/;
1604
+ var ATTR_EPISODE_REGEX = /\bepisode_type="([^"]*)"/;
1605
+ var ATTR_IMPORTANCE_REGEX = /\bimportance="(\d+)"/;
1606
+ function makeTierOpenRegex(n) {
1607
+ return new RegExp(`<p${n}\\s*(/?)>`);
1608
+ }
1609
+ var TIER_OPEN_REGEXES = [
1610
+ makeTierOpenRegex(1),
1611
+ makeTierOpenRegex(2),
1612
+ makeTierOpenRegex(3),
1613
+ makeTierOpenRegex(4)
1614
+ ];
1615
+ var TIER_CLOSE_ANY_REGEX = /<\/p\d/;
1616
+ var TIER_OPEN_ANY_REGEX = /<p\d/;
1617
+ var CATEGORY_BLOCK_REGEX = /<(PROJECT_RULES|ARCHITECTURE|CONSTRAINTS|CONFIG_VALUES|NAMING)>(.*?)<\/\1>/gs;
1618
+ var FACT_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
1619
+ var UNPROCESSED_REGEX = /<unprocessed_from>(\d+)<\/unprocessed_from>/;
1620
+ var USER_OBSERVATIONS_REGEX = /<user_observations>(.*?)<\/user_observations>/s;
1621
+ var USER_OBS_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
1622
+ var PRIMER_CANDIDATES_REGEX = /<primer_candidates>(.*?)<\/primer_candidates>/s;
1623
+ var PRIMER_ELEMENT_REGEX = /<primer\s+at_compartment="(\d+)"\s*>(.*?)<\/primer>/gs;
1624
+ var PRIMER_ITEM_REGEX = /^\s*(?:\*|-|\d+\.)\s*(.+)$/gm;
1625
+ var FACTS_BLOCK_REGEX = /<facts>(.*?)<\/facts>/s;
1626
+ var EVENTS_BLOCK_REGEX = /<events>(.*?)<\/events>/s;
1627
+ var EVENT_ELEMENT_REGEX = /<([a-z_]+)\s+at_compartment="(\d+)"\s*>(.*?)<\/\1>/gs;
1628
+ var EVENT_FIELD_REGEX = /<([a-z_]+)\s*>(.*?)<\/\1>/gs;
1629
+ function extractTier(inner, index) {
1630
+ const openMatch = TIER_OPEN_REGEXES[index].exec(inner);
1631
+ if (!openMatch)
1632
+ return;
1633
+ if (openMatch[1] === "/")
1634
+ return "";
1635
+ const rest = inner.slice(openMatch.index + openMatch[0].length);
1636
+ const closeAt = rest.search(TIER_CLOSE_ANY_REGEX);
1637
+ let body = closeAt === -1 ? rest : rest.slice(0, closeAt);
1638
+ const openInside = body.search(TIER_OPEN_ANY_REGEX);
1639
+ if (openInside !== -1)
1640
+ body = body.slice(0, openInside);
1641
+ return unescapeXml(body.trim());
1642
+ }
1643
+ function extractTiersFromInner(inner) {
1644
+ return {
1645
+ p1: extractTier(inner, 0),
1646
+ p2: extractTier(inner, 1),
1647
+ p3: extractTier(inner, 2),
1648
+ p4: extractTier(inner, 3)
1649
+ };
1650
+ }
1651
+ function parseCompartmentOutput(text) {
1652
+ const compartments = [];
1653
+ const facts = [];
1654
+ for (const match of text.matchAll(COMPARTMENT_REGEX)) {
1655
+ const attrs = match[1];
1656
+ const inner = match[2];
1657
+ const startMatch = attrs.match(ATTR_START_REGEX);
1658
+ const endMatch = attrs.match(ATTR_END_REGEX);
1659
+ const titleMatch = attrs.match(ATTR_TITLE_REGEX);
1660
+ if (!startMatch || !endMatch || !titleMatch)
1661
+ continue;
1662
+ const startMessage = parseInt(startMatch[1], 10);
1663
+ const endMessage = parseInt(endMatch[1], 10);
1664
+ const title = unescapeXml(titleMatch[1]);
1665
+ if (Number.isNaN(startMessage) || Number.isNaN(endMessage) || !title)
1666
+ continue;
1667
+ const episodeMatch = attrs.match(ATTR_EPISODE_REGEX);
1668
+ const importanceMatch = attrs.match(ATTR_IMPORTANCE_REGEX);
1669
+ const episodeType = episodeMatch ? unescapeXml(episodeMatch[1]) : undefined;
1670
+ const importance = importanceMatch ? parseInt(importanceMatch[1], 10) : undefined;
1671
+ const p1 = extractTier(inner, 0);
1672
+ if (typeof p1 === "string" && p1.length > 0) {
1673
+ const p2 = extractTier(inner, 1);
1674
+ const p3 = extractTier(inner, 2);
1675
+ const p4 = extractTier(inner, 3);
1676
+ compartments.push({
1677
+ startMessage,
1678
+ endMessage,
1679
+ title,
1680
+ content: p1,
1681
+ p1,
1682
+ p2: typeof p2 === "string" ? p2 : p1,
1683
+ p3: typeof p3 === "string" ? p3 : typeof p2 === "string" ? p2 : p1,
1684
+ p4: typeof p4 === "string" ? p4 : "",
1685
+ importance,
1686
+ episodeType
1687
+ });
1688
+ continue;
1689
+ }
1690
+ const content = unescapeXml(inner.trim());
1691
+ if (content) {
1692
+ compartments.push({
1693
+ startMessage,
1694
+ endMessage,
1695
+ title,
1696
+ content,
1697
+ importance,
1698
+ episodeType
1699
+ });
1700
+ }
1701
+ }
1702
+ const factsBlockMatch = text.match(FACTS_BLOCK_REGEX);
1703
+ const factsScope = factsBlockMatch ? factsBlockMatch[1] : text.replace(EVENTS_BLOCK_REGEX, "").replace(/<compartment\s+[^>]*?\s*>.*?<\/compartment>/gs, "");
1704
+ for (const categoryMatch of factsScope.matchAll(CATEGORY_BLOCK_REGEX)) {
1705
+ const category = categoryMatch[1];
1706
+ const blockContent = categoryMatch[2];
1707
+ for (const itemMatch of blockContent.matchAll(FACT_ITEM_REGEX)) {
1708
+ const content = unescapeXml(itemMatch[1].trim());
1709
+ if (content) {
1710
+ facts.push({ category, content });
1711
+ }
1712
+ }
1713
+ }
1714
+ const unprocessedMatch = text.match(UNPROCESSED_REGEX);
1715
+ const unprocessedFrom = unprocessedMatch ? parseInt(unprocessedMatch[1], 10) : null;
1716
+ const userObservations = [];
1717
+ const userObsMatch = text.match(USER_OBSERVATIONS_REGEX);
1718
+ if (userObsMatch) {
1719
+ for (const itemMatch of userObsMatch[1].matchAll(USER_OBS_ITEM_REGEX)) {
1720
+ const obs = unescapeXml(itemMatch[1].trim());
1721
+ if (obs)
1722
+ userObservations.push(obs);
1723
+ }
1724
+ }
1725
+ const primerCandidates = [];
1726
+ const primerMatch = text.match(PRIMER_CANDIDATES_REGEX);
1727
+ if (primerMatch) {
1728
+ const block = primerMatch[1];
1729
+ let sawElement = false;
1730
+ for (const el of block.matchAll(PRIMER_ELEMENT_REGEX)) {
1731
+ sawElement = true;
1732
+ const question = unescapeXml(el[2].trim());
1733
+ if (question) {
1734
+ primerCandidates.push({
1735
+ question,
1736
+ originCompartmentIndex: Number.parseInt(el[1], 10)
1737
+ });
1738
+ }
1739
+ }
1740
+ if (!sawElement) {
1741
+ for (const itemMatch of block.matchAll(PRIMER_ITEM_REGEX)) {
1742
+ const question = unescapeXml(itemMatch[1].trim());
1743
+ if (question)
1744
+ primerCandidates.push({ question });
1745
+ }
1746
+ }
1747
+ }
1748
+ const events = parseEvents(text);
1749
+ compartments.sort((a, b) => a.startMessage - b.startMessage);
1750
+ return { compartments, facts, events, unprocessedFrom, userObservations, primerCandidates };
1751
+ }
1752
+ function parseEvents(text) {
1753
+ const blockMatch = text.match(EVENTS_BLOCK_REGEX);
1754
+ if (!blockMatch)
1755
+ return [];
1756
+ const block = blockMatch[1];
1757
+ const events = [];
1758
+ for (const elMatch of block.matchAll(EVENT_ELEMENT_REGEX)) {
1759
+ const kind = elMatch[1];
1760
+ const atRaw = parseInt(elMatch[2], 10);
1761
+ const atCompartment = Number.isNaN(atRaw) ? null : atRaw;
1762
+ const fields = {};
1763
+ for (const fieldMatch of elMatch[3].matchAll(EVENT_FIELD_REGEX)) {
1764
+ const name = fieldMatch[1];
1765
+ const value = unescapeXml(fieldMatch[2].trim());
1766
+ if (value)
1767
+ fields[name] = value;
1768
+ }
1769
+ events.push({ kind, atCompartment, fields });
1770
+ }
1771
+ return events;
1772
+ }
1773
+ function unescapeXml(s) {
1774
+ return s.replace(/&amp;/g, "&").replace(/&apos;/g, "'").replace(/&quot;/g, '"').replace(/&lt;/g, "<").replace(/&gt;/g, ">");
1775
+ }
1776
+
1958
1777
  // src/features/magic-context/storage-schema-helpers.ts
1959
1778
  function ensureColumn(db, table, column, definition) {
1960
1779
  if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_"'(),[\]\s]+$/i.test(definition)) {
@@ -2047,7 +1866,7 @@ function healMissingMemoryBlockIds(db, columns) {
2047
1866
  }
2048
1867
 
2049
1868
  // src/features/magic-context/workspaces.ts
2050
- import { createHash as createHash3 } from "node:crypto";
1869
+ import { createHash as createHash4 } from "node:crypto";
2051
1870
 
2052
1871
  // src/features/magic-context/memory/constants.ts
2053
1872
  var V2_MEMORY_CATEGORIES = [
@@ -2101,7 +1920,7 @@ var CATEGORY_DEFAULT_TTL = {
2101
1920
 
2102
1921
  // src/features/magic-context/memory/project-identity.ts
2103
1922
  import { execFileSync } from "node:child_process";
2104
- import { createHash as createHash2 } from "node:crypto";
1923
+ import { createHash as createHash3 } from "node:crypto";
2105
1924
  import { existsSync, realpathSync, statSync } from "node:fs";
2106
1925
  import { homedir } from "node:os";
2107
1926
  import path from "node:path";
@@ -2116,6 +1935,7 @@ var dubiousOwnershipLoggedDirectories = new Set;
2116
1935
  var dubiousOwnershipWarnedDirectories = new Set;
2117
1936
  var transientGitIdentityReuseLoggedDirectories = new Set;
2118
1937
  var execFileSyncForIdentity = execFileSync;
1938
+ var userHomeDirectoryForIdentity = () => homedir();
2119
1939
  var nowMs = () => Date.now();
2120
1940
 
2121
1941
  class ProjectIdentityError extends Error {
@@ -2169,7 +1989,7 @@ function getErrorStderr(error) {
2169
1989
  }
2170
1990
  function directoryFallback(directory) {
2171
1991
  const canonical = path.resolve(directory);
2172
- 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);
2173
1993
  return `dir:${hash}`;
2174
1994
  }
2175
1995
  function assertDirectoryUsable(canonicalDirectory, rawDirectory) {
@@ -2320,9 +2140,12 @@ function takeDubiousOwnershipProjectIdentityWarning(directory) {
2320
2140
  dubiousOwnershipWarnedDirectories.add(canonical);
2321
2141
  return formatDubiousOwnershipWarning(canonical);
2322
2142
  }
2143
+ function canonicalUserHomeDirectory() {
2144
+ return realpathSync.native(userHomeDirectoryForIdentity());
2145
+ }
2323
2146
  function isUserHomeDirectory(directory) {
2324
2147
  try {
2325
- return realpathSync.native(path.resolve(directory)) === realpathSync.native(homedir());
2148
+ return realpathSync.native(path.resolve(directory)) === canonicalUserHomeDirectory();
2326
2149
  } catch {
2327
2150
  return false;
2328
2151
  }
@@ -2391,22 +2214,52 @@ function hasGitDir(canonical) {
2391
2214
  return false;
2392
2215
  }
2393
2216
  }
2394
- function hasGitDirInAncestorChain(startDirectory) {
2217
+ function gitRootInAncestorChain(startDirectory) {
2395
2218
  let current = startDirectory;
2396
2219
  while (true) {
2397
2220
  if (existsSync(path.join(current, ".git"))) {
2398
- return true;
2221
+ try {
2222
+ return realpathSync.native(current);
2223
+ } catch {
2224
+ return path.resolve(current);
2225
+ }
2399
2226
  }
2400
2227
  const parent = path.dirname(current);
2401
2228
  if (parent === current) {
2402
- return false;
2229
+ return null;
2403
2230
  }
2404
2231
  current = parent;
2405
2232
  }
2406
2233
  }
2407
- function resolveProjectIdentityForSession(directory) {
2408
- if (isUserHomeDirectory(directory))
2409
- 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
+ }
2410
2263
  return resolveProjectIdentityOrFallback(directory);
2411
2264
  }
2412
2265
  function normalizeStoredProjectPath(rawOrStored) {
@@ -2608,7 +2461,7 @@ function computeWorkspaceEpochFingerprint(db, identities) {
2608
2461
  const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
2609
2462
  const epochs = getEpochMap(db, canonical);
2610
2463
  const shareCategories = selectWorkspaceShareCategories(db, canonical);
2611
- const hash = createHash3("sha256");
2464
+ const hash = createHash4("sha256");
2612
2465
  hash.update("share_categories", "utf8");
2613
2466
  hash.update("\x00");
2614
2467
  hash.update(shareCategories === null ? "NO_WORKSPACE" : JSON.stringify(shareCategories), "utf8");
@@ -2704,15 +2557,38 @@ function isSqliteLockError(error) {
2704
2557
  function tableExists2(db, name) {
2705
2558
  return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name));
2706
2559
  }
2560
+ function healMismatchedTierClose(db, table, hasLegacy) {
2561
+ if (!tableExists2(db, table))
2562
+ return;
2563
+ const columns = new Set(db.prepare(`PRAGMA table_info(${table})`).all().map((row) => row.name));
2564
+ for (const required of ["content", "p1", "p2", "p3", "p4"]) {
2565
+ if (!columns.has(required))
2566
+ return;
2567
+ }
2568
+ if (hasLegacy && !columns.has("legacy"))
2569
+ return;
2570
+ const predicate = hasLegacy ? "legacy = 1 AND p1 IS NULL AND content LIKE '%<p1%'" : "p1 IS NULL AND content LIKE '%<p1%'";
2571
+ const rows = db.prepare(`SELECT id, content FROM ${table} WHERE ${predicate}`).all();
2572
+ const update = db.prepare(`UPDATE ${table} SET p1 = ?, p2 = ?, p3 = ?, p4 = ?${hasLegacy ? ", legacy = 0" : ""} WHERE id = ?`);
2573
+ for (const row of rows) {
2574
+ const tiers = extractTiersFromInner(row.content);
2575
+ if (typeof tiers.p1 !== "string" || tiers.p1.length === 0)
2576
+ continue;
2577
+ const p1 = tiers.p1;
2578
+ const p2 = typeof tiers.p2 === "string" ? tiers.p2 : p1;
2579
+ const p3 = typeof tiers.p3 === "string" ? tiers.p3 : p2;
2580
+ const p4 = typeof tiers.p4 === "string" ? tiers.p4 : "";
2581
+ update.run(p1, p2, p3, p4, row.id);
2582
+ }
2583
+ }
2707
2584
  function assertForeignKeyIntegrity(db, table) {
2708
2585
  const rows = (table ? db.prepare(`PRAGMA foreign_key_check(${table})`) : db.prepare("PRAGMA foreign_key_check")).all();
2709
2586
  if (rows.length > 0) {
2710
2587
  throw new Error(`foreign_key_check failed after embedding table rebuild${table ? ` (${table})` : ""} (${rows.length} violation(s))`);
2711
2588
  }
2712
2589
  }
2713
- function authorityPrivilegeCheck(db) {
2714
- const native = db;
2715
- return typeof native.function === "function" || typeof native.createFunction === "function" ? "mc_privileged_writer() = 0" : "COALESCE((SELECT enabled FROM context_privilege_state WHERE id = 1), 0) = 0";
2590
+ function authorityPrivilegeCheck() {
2591
+ return "COALESCE((SELECT enabled FROM context_privilege_state WHERE id = 1), 0) = 0";
2716
2592
  }
2717
2593
  function managedAuthorityNoteRow(row) {
2718
2594
  return `(
@@ -2731,7 +2607,7 @@ function managedAuthorityNoteRow(row) {
2731
2607
  )`;
2732
2608
  }
2733
2609
  function installLatestAuthorityTriggers(db) {
2734
- const privilegeCheck = authorityPrivilegeCheck(db);
2610
+ const privilegeCheck = authorityPrivilegeCheck();
2735
2611
  if (tableExists2(db, "memories")) {
2736
2612
  db.exec(`
2737
2613
  DROP TRIGGER IF EXISTS memories_authority_guard_insert;
@@ -4657,6 +4533,48 @@ var MIGRATIONS = [
4657
4533
  ON memory_mutation_log(project_path, target_memory_id, id);
4658
4534
  `);
4659
4535
  }
4536
+ },
4537
+ {
4538
+ version: 70,
4539
+ description: "heal legacy compartments stranded by mismatched tier closing tags (issue #246)",
4540
+ up(db) {
4541
+ healMismatchedTierClose(db, "compartments", true);
4542
+ healMismatchedTierClose(db, "recomp_compartments", false);
4543
+ }
4544
+ },
4545
+ {
4546
+ version: 71,
4547
+ description: "rebuild authority guard triggers to the durable state-table form (issue #253)",
4548
+ up(db) {
4549
+ installLatestAuthorityTriggers(db);
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
+ }
4660
4578
  }
4661
4579
  ];
4662
4580
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -4766,151 +4684,6 @@ async function runMigrationsWithRetry(db, options = {}) {
4766
4684
  }
4767
4685
  }
4768
4686
  }
4769
- // src/features/magic-context/project-docs-hash.ts
4770
- import { createHash as createHash4 } from "node:crypto";
4771
- import { lstatSync, readFileSync, statSync as statSync2 } from "node:fs";
4772
- import path2 from "node:path";
4773
- var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
4774
- var PROJECT_DOCS_DELIMITER = `
4775
-
4776
- ---
4777
-
4778
- `;
4779
- var MAX_PROJECT_DOC_BYTES = 256 * 1024;
4780
- var docsCache = new Map;
4781
- function canonicalizeDocContent(raw) {
4782
- return raw.replace(/^\uFEFF/, "").replace(/\r\n/g, `
4783
- `).split(`
4784
- `).map((line) => line.replace(/[ \t]+$/, "")).join(`
4785
- `).replace(/\n+$/, "");
4786
- }
4787
- function fingerprintFile(filePath) {
4788
- try {
4789
- const stat = lstatSync(filePath);
4790
- const isReadableDoc = stat.isFile() && stat.size <= MAX_PROJECT_DOC_BYTES;
4791
- return {
4792
- exists: isReadableDoc,
4793
- mtimeMs: stat.mtimeMs,
4794
- size: stat.size
4795
- };
4796
- } catch {
4797
- return { exists: false, mtimeMs: 0, size: 0 };
4798
- }
4799
- }
4800
- function readDirectoryMtimeMs(projectDirectory) {
4801
- try {
4802
- return statSync2(projectDirectory).mtimeMs;
4803
- } catch {
4804
- return 0;
4805
- }
4806
- }
4807
- function fingerprintsEqual(a, b) {
4808
- return a?.exists === b.exists && a.mtimeMs === b.mtimeMs && a.size === b.size;
4809
- }
4810
- function cacheFilesEqual(cachedFiles, currentFiles) {
4811
- for (const [filePath, current] of currentFiles) {
4812
- if (!fingerprintsEqual(cachedFiles.get(filePath), current)) {
4813
- return false;
4814
- }
4815
- }
4816
- return true;
4817
- }
4818
- function readCurrentFingerprints(projectDirectory) {
4819
- const files = new Map;
4820
- for (const filename of PROJECT_DOC_FILES) {
4821
- const filePath = path2.join(projectDirectory, filename);
4822
- files.set(filePath, fingerprintFile(filePath));
4823
- }
4824
- return { directoryMtimeMs: readDirectoryMtimeMs(projectDirectory), files };
4825
- }
4826
- function readCanonicalPieces(projectDirectory, files) {
4827
- const hashPieces = [];
4828
- const renderedSections = [];
4829
- for (const filename of PROJECT_DOC_FILES) {
4830
- const filePath = path2.join(projectDirectory, filename);
4831
- const fingerprint = files.get(filePath);
4832
- if (!fingerprint?.exists) {
4833
- continue;
4834
- }
4835
- let safeToRead = false;
4836
- try {
4837
- const st = lstatSync(filePath);
4838
- safeToRead = st.isFile() && st.size <= MAX_PROJECT_DOC_BYTES;
4839
- } catch {
4840
- safeToRead = false;
4841
- }
4842
- if (!safeToRead) {
4843
- continue;
4844
- }
4845
- const canonicalContent = canonicalizeDocContent(readFileSync(filePath, "utf8"));
4846
- hashPieces.push(`file:${filename}
4847
- ${canonicalContent}`);
4848
- renderedSections.push(`<file name="${escapeXmlAttr(filename)}">
4849
- ${escapeXmlContent(canonicalContent)}
4850
- </file>`);
4851
- }
4852
- return { hashPieces, renderedSections };
4853
- }
4854
- function buildRenderedBlock(renderedSections) {
4855
- if (renderedSections.length === 0) {
4856
- return "";
4857
- }
4858
- return `<project-docs>
4859
- ${renderedSections.join(`
4860
-
4861
- `)}
4862
- </project-docs>`;
4863
- }
4864
- function hashCanonicalPieces(hashPieces) {
4865
- if (hashPieces.length === 0) {
4866
- return "";
4867
- }
4868
- return createHash4("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
4869
- }
4870
- function readProjectDocsCanonical(projectDirectory) {
4871
- const canonicalDirectory = path2.resolve(projectDirectory);
4872
- const current = readCurrentFingerprints(canonicalDirectory);
4873
- const cached = docsCache.get(canonicalDirectory);
4874
- if (cached && cacheFilesEqual(cached.files, current.files)) {
4875
- cached.directoryMtimeMs = current.directoryMtimeMs;
4876
- return {
4877
- renderedBlock: cached.cachedRendered,
4878
- canonicalHash: cached.cachedHash
4879
- };
4880
- }
4881
- const { hashPieces, renderedSections } = readCanonicalPieces(canonicalDirectory, current.files);
4882
- const canonicalHash = hashCanonicalPieces(hashPieces);
4883
- const renderedBlock = buildRenderedBlock(renderedSections);
4884
- docsCache.set(canonicalDirectory, {
4885
- directoryMtimeMs: current.directoryMtimeMs,
4886
- files: current.files,
4887
- cachedHash: canonicalHash,
4888
- cachedRendered: renderedBlock
4889
- });
4890
- return { renderedBlock, canonicalHash };
4891
- }
4892
- function computeProjectDocsHash(projectDirectory) {
4893
- return readProjectDocsCanonical(projectDirectory).canonicalHash;
4894
- }
4895
- // src/features/magic-context/storage-db.ts
4896
- import { chmodSync, copyFileSync, cpSync, existsSync as existsSync3, mkdirSync, mkdtempSync } from "node:fs";
4897
- import { dirname, join as join2 } from "node:path";
4898
-
4899
- // src/plugin/boot-quiet.ts
4900
- var BOOT_QUIET_MS = 120000;
4901
- var bootQuietUntilMs = 0;
4902
- function beginBootQuietPeriod(now = Date.now()) {
4903
- if (bootQuietUntilMs === 0)
4904
- bootQuietUntilMs = now + BOOT_QUIET_MS;
4905
- }
4906
- function bootQuietRemainingMs(now = Date.now()) {
4907
- return Math.max(0, bootQuietUntilMs - now);
4908
- }
4909
- function scheduleAfterBootQuiet(task, additionalDelayMs = 0) {
4910
- const timer = setTimeout(task, bootQuietRemainingMs() + Math.max(0, additionalDelayMs));
4911
- timer.unref?.();
4912
- return timer;
4913
- }
4914
4687
 
4915
4688
  // src/features/magic-context/tool-definition-tokens.ts
4916
4689
  import { createHash as createHash5 } from "node:crypto";
@@ -5024,11 +4797,11 @@ function getMeasuredToolDefinitionTokens(providerID, modelID, agentName) {
5024
4797
 
5025
4798
  // src/features/magic-context/tool-owner-backfill.ts
5026
4799
  import { existsSync as existsSync2 } from "node:fs";
5027
- import { join } from "node:path";
4800
+ import { join as join2 } from "node:path";
5028
4801
  var LEASE_DURATION_MS = 5 * 60 * 1000;
5029
4802
  var LEASE_RENEWAL_MS = 60 * 1000;
5030
4803
  function resolveOpencodeDbPath() {
5031
- return join(getDataDir(), "opencode", "opencode.db");
4804
+ return join2(getDataDir(), "opencode", "opencode.db");
5032
4805
  }
5033
4806
  function ensureBackfillStateTable(db) {
5034
4807
  db.exec(`
@@ -5283,30 +5056,40 @@ var persistenceByDatabase = new WeakMap;
5283
5056
  var persistenceErrorByDatabase = new WeakMap;
5284
5057
  var pathByDatabase = new WeakMap;
5285
5058
  var lastSchemaFenceRejection = null;
5059
+ var lastMigrationOnOpenRefusal = null;
5286
5060
  function getSchemaFenceRejection() {
5287
5061
  return lastSchemaFenceRejection;
5288
5062
  }
5289
- var LATEST_SUPPORTED_VERSION = 69;
5063
+ function getMigrationOnOpenRefusal() {
5064
+ return lastMigrationOnOpenRefusal;
5065
+ }
5066
+ var LATEST_SUPPORTED_VERSION = 74;
5290
5067
  var PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
5068
+ var defaultStoragePermissionFs = { chmodSync, mkdirSync };
5069
+ var storagePermissionFs = defaultStoragePermissionFs;
5291
5070
  function ensureSecureStorageDir(dir) {
5292
- 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 });
5293
5076
  if (!PERMISSIONS_ENFORCEABLE)
5294
5077
  return;
5295
5078
  try {
5296
- chmodSync(dir, 448);
5079
+ storagePermissionFs.chmodSync(dir, 448);
5297
5080
  } catch (error) {
5298
5081
  log(`[magic-context] could not restrict storage dir permissions on ${dir}: ${getErrorMessage(error)}`);
5299
5082
  }
5300
5083
  }
5301
5084
  function restrictDatabaseFilePermissions(dbPath) {
5302
- if (!PERMISSIONS_ENFORCEABLE)
5085
+ if (!PERMISSIONS_ENFORCEABLE || !shouldEnforcePrivateStoragePermissions())
5303
5086
  return;
5304
5087
  for (const suffix of ["", "-wal", "-shm"]) {
5305
5088
  const file = `${dbPath}${suffix}`;
5306
5089
  if (!existsSync3(file))
5307
5090
  continue;
5308
5091
  try {
5309
- chmodSync(file, 384);
5092
+ storagePermissionFs.chmodSync(file, 384);
5310
5093
  } catch (error) {
5311
5094
  log(`[magic-context] could not restrict DB file permissions on ${file}: ${getErrorMessage(error)}`);
5312
5095
  }
@@ -5318,12 +5101,12 @@ function resolveDatabasePath(dbPathOverride) {
5318
5101
  }
5319
5102
  const testDataDir = process.env.MAGIC_CONTEXT_TEST_DATA_DIR;
5320
5103
  if (testDataDir && !process.env.XDG_DATA_HOME) {
5321
- const dbDir2 = join2(testDataDir, "cortexkit", "magic-context");
5322
- 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") };
5323
5106
  }
5324
5107
  if (false) {}
5325
5108
  const dbDir = getMagicContextStorageDir();
5326
- return { dbDir, dbPath: join2(dbDir, "context.db") };
5109
+ return { dbDir, dbPath: join3(dbDir, "context.db") };
5327
5110
  }
5328
5111
  function getDatabasePath(db) {
5329
5112
  return pathByDatabase.get(db) ?? null;
@@ -5332,7 +5115,7 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
5332
5115
  if (existsSync3(targetDbPath))
5333
5116
  return;
5334
5117
  const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
5335
- const legacyDbPath = join2(legacyDir, "context.db");
5118
+ const legacyDbPath = join3(legacyDir, "context.db");
5336
5119
  if (!existsSync3(legacyDbPath))
5337
5120
  return;
5338
5121
  log(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
@@ -5349,7 +5132,7 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
5349
5132
  }
5350
5133
  for (const suffix of ["", "-wal", "-shm"]) {
5351
5134
  const src = `${legacyDbPath}${suffix}`;
5352
- const dst = join2(targetDbDir, `context.db${suffix}`);
5135
+ const dst = join3(targetDbDir, `context.db${suffix}`);
5353
5136
  if (existsSync3(src)) {
5354
5137
  try {
5355
5138
  copyFileSync(src, dst);
@@ -5358,8 +5141,8 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
5358
5141
  }
5359
5142
  }
5360
5143
  }
5361
- const legacyModelsDir = join2(legacyDir, "models");
5362
- const targetModelsDir = join2(targetDbDir, "models");
5144
+ const legacyModelsDir = join3(legacyDir, "models");
5145
+ const targetModelsDir = join3(targetDbDir, "models");
5363
5146
  if (existsSync3(legacyModelsDir) && !existsSync3(targetModelsDir)) {
5364
5147
  try {
5365
5148
  cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
@@ -5376,6 +5159,9 @@ function getPersistedSchemaVersion(db) {
5376
5159
  const row = db.prepare("SELECT MAX(version) AS version FROM schema_migrations").get();
5377
5160
  return row?.version ?? 0;
5378
5161
  }
5162
+ function formatSchemaFenceBootLog(persistedVersion, supportedVersion) {
5163
+ return `[magic-context] storage schema at boot: database=v${persistedVersion}, supported_fence=v${supportedVersion}`;
5164
+ }
5379
5165
  function getRuntimeLatestSupportedVersion(options) {
5380
5166
  if (options?.latestSupportedVersion !== undefined) {
5381
5167
  return options.latestSupportedVersion;
@@ -5392,12 +5178,109 @@ function getRuntimeLatestSupportedVersion(options) {
5392
5178
  function enforceSchemaFence(db, dbPath, latestSupportedVersion) {
5393
5179
  const persistedVersion = getPersistedSchemaVersion(db);
5394
5180
  if (persistedVersion <= latestSupportedVersion) {
5181
+ lastSchemaFenceRejection = null;
5395
5182
  return true;
5396
5183
  }
5397
5184
  lastSchemaFenceRejection = { persistedVersion, supportedVersion: latestSupportedVersion };
5398
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.`);
5399
5186
  return false;
5400
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
+ }
5401
5284
  var sqlitePragmaConfig = {
5402
5285
  cacheSizeMb: 64,
5403
5286
  mmapSizeMb: 0
@@ -5442,6 +5325,9 @@ function finishDatabaseOpen(db, dbPath, explicitDbPath, latestSupportedVersion)
5442
5325
  pathByDatabase.set(db, dbPath);
5443
5326
  persistenceByDatabase.set(db, true);
5444
5327
  persistenceErrorByDatabase.delete(db);
5328
+ if (!explicitDbPath) {
5329
+ log(formatSchemaFenceBootLog(getPersistedSchemaVersion(db), latestSupportedVersion));
5330
+ }
5445
5331
  return db;
5446
5332
  }
5447
5333
  function initializeDatabase(db) {
@@ -6042,12 +5928,14 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6042
5928
  note_nudge_anchors TEXT NOT NULL DEFAULT '[]',
6043
5929
  auto_search_hint_decisions TEXT NOT NULL DEFAULT '[]',
6044
5930
  last_todo_state TEXT DEFAULT '',
5931
+ todo_permission_denied INTEGER NOT NULL DEFAULT 2,
6045
5932
  todo_synthetic_call_id TEXT DEFAULT '',
6046
5933
  todo_synthetic_anchor_message_id TEXT DEFAULT '',
6047
5934
  todo_synthetic_state_json TEXT DEFAULT '',
6048
5935
  is_subagent INTEGER DEFAULT 0,
6049
5936
  last_context_percentage REAL DEFAULT 0,
6050
5937
  last_input_tokens INTEGER DEFAULT 0,
5938
+ detected_context_limit_provenance TEXT NOT NULL DEFAULT 'unknown',
6051
5939
  observed_safe_input_tokens INTEGER NOT NULL DEFAULT 0,
6052
5940
  cache_alert_sent INTEGER NOT NULL DEFAULT 0,
6053
5941
  times_execute_threshold_reached INTEGER DEFAULT 0,
@@ -6102,6 +5990,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6102
5990
  emergency_drain_active INTEGER NOT NULL DEFAULT 0,
6103
5991
  historian_drain_failure_at INTEGER NOT NULL DEFAULT 0,
6104
5992
  wrapup_in_progress_state TEXT,
5993
+ compaction_mode_record TEXT,
6105
5994
  cached_m0_materialized_at INTEGER,
6106
5995
  cached_m0_session_facts_version INTEGER,
6107
5996
  cached_m0_upgrade_state TEXT,
@@ -6301,6 +6190,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6301
6190
  ensureColumn(db, "session_meta", "note_nudge_anchors", "TEXT NOT NULL DEFAULT '[]'");
6302
6191
  ensureColumn(db, "session_meta", "auto_search_hint_decisions", "TEXT NOT NULL DEFAULT '[]'");
6303
6192
  ensureColumn(db, "session_meta", "last_todo_state", "TEXT DEFAULT ''");
6193
+ ensureColumn(db, "session_meta", "todo_permission_denied", "INTEGER NOT NULL DEFAULT 2");
6304
6194
  ensureColumn(db, "session_meta", "todo_synthetic_call_id", "TEXT DEFAULT ''");
6305
6195
  ensureColumn(db, "session_meta", "todo_synthetic_anchor_message_id", "TEXT DEFAULT ''");
6306
6196
  ensureColumn(db, "session_meta", "todo_synthetic_state_json", "TEXT DEFAULT ''");
@@ -6357,6 +6247,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6357
6247
  ensureColumn(db, "session_meta", "recomp_partial_range_end", "INTEGER DEFAULT 0");
6358
6248
  ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
6359
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'");
6360
6251
  ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
6361
6252
  ensureColumn(db, "session_meta", "emergency_recovery_origin", "TEXT DEFAULT ''");
6362
6253
  ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
@@ -6407,6 +6298,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
6407
6298
  ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
6408
6299
  ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
6409
6300
  ensureColumn(db, "session_meta", "wrapup_in_progress_state", "TEXT");
6301
+ ensureColumn(db, "session_meta", "compaction_mode_record", "TEXT");
6410
6302
  ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
6411
6303
  ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
6412
6304
  ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
@@ -6546,12 +6438,13 @@ function openDatabase(dbPathOrOptions) {
6546
6438
  const explicitDbPath = options?.dbPath !== undefined;
6547
6439
  const { dbDir, dbPath } = resolveDatabasePath(options?.dbPath);
6548
6440
  const latestSupportedVersion = getRuntimeLatestSupportedVersion(options);
6441
+ lastSchemaFenceRejection = null;
6442
+ lastMigrationOnOpenRefusal = null;
6549
6443
  const existing = databases.get(dbPath);
6550
6444
  if (existing) {
6551
6445
  if (!enforceSchemaFence(existing, dbPath, latestSupportedVersion)) {
6552
6446
  return null;
6553
6447
  }
6554
- registerPrivilegedWriter(existing);
6555
6448
  if (!persistenceByDatabase.has(existing)) {
6556
6449
  persistenceByDatabase.set(existing, true);
6557
6450
  }
@@ -6564,11 +6457,14 @@ function openDatabase(dbPathOrOptions) {
6564
6457
  }
6565
6458
  ensureSecureStorageDir(dbDir);
6566
6459
  const db = new Database(dbPath);
6567
- registerPrivilegedWriter(db);
6568
6460
  if (!enforceSchemaFence(db, dbPath, latestSupportedVersion)) {
6569
6461
  closeQuietly(db);
6570
6462
  return null;
6571
6463
  }
6464
+ if (!enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)) {
6465
+ closeQuietly(db);
6466
+ return null;
6467
+ }
6572
6468
  initializeDatabase(db);
6573
6469
  runMigrations(db);
6574
6470
  ensureContextStoreUuid(db);
@@ -6584,6 +6480,8 @@ async function openDatabaseAsync(dbPathOrOptions) {
6584
6480
  const explicitDbPath = options?.dbPath !== undefined;
6585
6481
  const { dbDir, dbPath } = resolveDatabasePath(options?.dbPath);
6586
6482
  const latestSupportedVersion = getRuntimeLatestSupportedVersion(options);
6483
+ lastSchemaFenceRejection = null;
6484
+ lastMigrationOnOpenRefusal = null;
6587
6485
  const existing = databases.get(dbPath);
6588
6486
  if (existing) {
6589
6487
  if (!enforceSchemaFence(existing, dbPath, latestSupportedVersion))
@@ -6603,11 +6501,14 @@ async function openDatabaseAsync(dbPathOrOptions) {
6603
6501
  migrateLegacyStorageIfNeeded(dbPath, dbDir);
6604
6502
  ensureSecureStorageDir(dbDir);
6605
6503
  db = new Database(dbPath);
6606
- registerPrivilegedWriter(db);
6607
6504
  if (!enforceSchemaFence(db, dbPath, latestSupportedVersion)) {
6608
6505
  closeQuietly(db);
6609
6506
  return null;
6610
6507
  }
6508
+ if (!enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)) {
6509
+ closeQuietly(db);
6510
+ return null;
6511
+ }
6611
6512
  initializeDatabase(db);
6612
6513
  await runMigrationsWithRetry(db);
6613
6514
  ensureContextStoreUuid(db);
@@ -6638,11 +6539,188 @@ function getDatabasePersistenceError(db) {
6638
6539
  return null;
6639
6540
  return persistenceErrorByDatabase.get(db) ?? null;
6640
6541
  }
6641
- // 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
6642
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";
6643
6721
  function normalizedQueryHash(query) {
6644
6722
  const normalized = query.trim().replace(/\s+/g, " ").toLowerCase();
6645
- return createHash6("sha256").update(normalized).digest("hex");
6723
+ return createHash7("sha256").update(normalized).digest("hex");
6646
6724
  }
6647
6725
  var MEASUREMENT_CORPUS_SESSION_ROW_CAP = 2000;
6648
6726
  function recordEmbeddingMeasurement(db, input) {
@@ -6858,7 +6936,7 @@ function getMemoryMutationsForRenderByIdentitySet(db, projectPaths, afterId, ren
6858
6936
  }
6859
6937
  visited.add(terminal);
6860
6938
  const next = byTarget.get(terminal);
6861
- if (!next || next.mutationType !== "superseded")
6939
+ if (next?.mutationType !== "superseded")
6862
6940
  break;
6863
6941
  if (depth >= MAX_MEMORY_REPLACEMENT_DEPTH - 1) {
6864
6942
  terminal = null;
@@ -6892,6 +6970,24 @@ function getMaxMemoryMutationIdForProjects(db, projectPaths) {
6892
6970
  WHERE project_path IN (${placeholders2(identities)})`).get(...identities);
6893
6971
  return row?.max_id ?? null;
6894
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
+
6895
6991
  // src/features/magic-context/storage-meta-persisted.ts
6896
6992
  var emergencyRecoveryArmedSessions = new Set;
6897
6993
  var providerOverflowReconfirmedSessions = new Set;
@@ -7113,11 +7209,11 @@ function readRawWrapupState(db, sessionId) {
7113
7209
  return parseWrapupState(row?.wrapup_in_progress_state);
7114
7210
  }
7115
7211
  function getWrapupInProgressState(db, sessionId, now = Date.now()) {
7116
- const state = readRawWrapupState(db, sessionId);
7117
- if (!state)
7212
+ const state2 = readRawWrapupState(db, sessionId);
7213
+ if (!state2)
7118
7214
  return null;
7119
- if (state.expiresAt > now)
7120
- return state;
7215
+ if (state2.expiresAt > now)
7216
+ return state2;
7121
7217
  try {
7122
7218
  db.exec("BEGIN IMMEDIATE");
7123
7219
  } catch {
@@ -7143,10 +7239,10 @@ function getWrapupInProgressState(db, sessionId, now = Date.now()) {
7143
7239
  function isWrapupInProgress(db, sessionId, now = Date.now()) {
7144
7240
  return getWrapupInProgressState(db, sessionId, now) !== null;
7145
7241
  }
7146
- function acquireWrapupInProgress(db, sessionId, state, now = Date.now()) {
7242
+ function acquireWrapupInProgress(db, sessionId, state2, now = Date.now()) {
7147
7243
  const acquiredAt = now;
7148
7244
  const next = {
7149
- ...state,
7245
+ ...state2,
7150
7246
  acquiredAt,
7151
7247
  expiresAt: acquiredAt + WRAPUP_IN_PROGRESS_TTL_MS,
7152
7248
  updatedAt: acquiredAt
@@ -7156,7 +7252,7 @@ function acquireWrapupInProgress(db, sessionId, state, now = Date.now()) {
7156
7252
  try {
7157
7253
  ensureSessionMetaRow(db, sessionId);
7158
7254
  const current = readRawWrapupState(db, sessionId);
7159
- if (current && current.expiresAt > now && current.holderId !== state.holderId) {
7255
+ if (current && current.expiresAt > now && current.holderId !== state2.holderId) {
7160
7256
  db.exec("COMMIT");
7161
7257
  finished = true;
7162
7258
  return { ok: false, state: current };
@@ -7220,6 +7316,45 @@ function releaseWrapupInProgress(db, sessionId, holderId) {
7220
7316
  }
7221
7317
  }
7222
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
+ }
7223
7358
  function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
7224
7359
  if (usagePercentage >= 95)
7225
7360
  return Math.min(1e6, Math.max(4 * perRunCap, Math.round(0.5 * usable)));
@@ -7227,7 +7362,6 @@ function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
7227
7362
  return Math.min(750000, Math.max(3 * perRunCap, Math.round(0.35 * usable)));
7228
7363
  return Math.min(500000, Math.max(perRunCap, Math.round(0.2 * usable)));
7229
7364
  }
7230
- var EMERGENCY_DRAIN_ENTER_PERCENTAGE = 95;
7231
7365
  var EMERGENCY_DRAIN_EXIT_MARGIN = 10;
7232
7366
  var EMERGENCY_DRAIN_FALLBACK_EXIT_PERCENTAGE = 55;
7233
7367
  var EMERGENCY_DRAIN_FAILURE_BACKOFF_MS = 60000;
@@ -7262,7 +7396,8 @@ function reserveProtectedTailDrainTokens(args) {
7262
7396
  }
7263
7397
  const exitThreshold = emergencyDrainExitThreshold(args.executeThresholdPercentage);
7264
7398
  let latchActiveSince = meta.emergencyDrainActive;
7265
- if (args.usagePercentage >= EMERGENCY_DRAIN_ENTER_PERCENTAGE) {
7399
+ const { forceMaterializationPercentage } = escalationBands(args.executeThresholdPercentage);
7400
+ if (args.usagePercentage >= forceMaterializationPercentage) {
7266
7401
  if (latchActiveSince <= 0)
7267
7402
  latchActiveSince = now;
7268
7403
  } else if (latchActiveSince > 0) {
@@ -7414,13 +7549,20 @@ function getChannel2NudgeState(db, sessionId) {
7414
7549
  function getChannel2NudgeClaim(db, sessionId) {
7415
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);
7416
7551
  const rawState = typeof result?.channel2_nudge_state === "string" ? result.channel2_nudge_state : "";
7417
- const state = rawState === "pending" || rawState === "claimed" || rawState === "delivered" ? rawState : "";
7552
+ const state2 = rawState === "pending" || rawState === "claimed" || rawState === "delivered" ? rawState : "";
7418
7553
  return {
7419
- state,
7554
+ state: state2,
7420
7555
  claimedAt: typeof result?.channel2_nudge_claimed_at === "number" ? result.channel2_nudge_claimed_at : 0,
7421
7556
  claimToken: typeof result?.channel2_nudge_claim_token === "string" ? result.channel2_nudge_claim_token : ""
7422
7557
  };
7423
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
+ }
7424
7566
  function casChannel2NudgeState(db, sessionId, from, to) {
7425
7567
  let changed = false;
7426
7568
  db.transaction(() => {
@@ -7600,6 +7742,18 @@ function removeAutoSearchHintDecisionByMessageId(db, sessionId, messageId) {
7600
7742
  }, { ensureRow: false });
7601
7743
  return ok && removed;
7602
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
+ }
7603
7757
  function getPersistedTodoSyntheticAnchor(db, sessionId) {
7604
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);
7605
7759
  if (!isPersistedTodoSyntheticAnchorRow(result)) {
@@ -7676,17 +7830,19 @@ function normalizeEmergencyRecoveryOrigin(value) {
7676
7830
  return value === "provider_overflow" || value === "proactive_model_shrink" ? value : null;
7677
7831
  }
7678
7832
  function getOverflowState(db, sessionId, modelKey) {
7679
- 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);
7680
7834
  if (!result) {
7681
7835
  return {
7682
7836
  detectedContextLimit: 0,
7683
7837
  detectedContextLimitModelKey: null,
7838
+ detectedContextLimitProvenance: "unknown",
7684
7839
  needsEmergencyRecovery: false,
7685
7840
  emergencyRecoveryOrigin: null
7686
7841
  };
7687
7842
  }
7688
7843
  const storedModelKey = normalizeDetectedLimitModelKey(result.detected_context_limit_model_key);
7689
7844
  const requestedModelKey = normalizeDetectedLimitModelKey(modelKey);
7845
+ const provenance = normalizeContextLimitProvenance(result.detected_context_limit_provenance);
7690
7846
  const limit = typeof result.detected_context_limit === "number" && result.detected_context_limit > 0 ? result.detected_context_limit : 0;
7691
7847
  const modelMatches = limit > 0 && requestedModelKey && storedModelKey ? requestedModelKey === storedModelKey : true;
7692
7848
  const needs = typeof result.needs_emergency_recovery === "number" && result.needs_emergency_recovery > 0;
@@ -7695,11 +7851,12 @@ function getOverflowState(db, sessionId, modelKey) {
7695
7851
  return {
7696
7852
  detectedContextLimit: modelMatches ? limit : 0,
7697
7853
  detectedContextLimitModelKey: storedModelKey,
7854
+ detectedContextLimitProvenance: provenance,
7698
7855
  needsEmergencyRecovery: needs,
7699
7856
  emergencyRecoveryOrigin: recoveryOrigin
7700
7857
  };
7701
7858
  }
7702
- function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin = "provider_overflow") {
7859
+ function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin = "provider_overflow", provenance = "unknown") {
7703
7860
  emergencyRecoveryArmedSessions.add(sessionId);
7704
7861
  db.transaction(() => {
7705
7862
  ensureSessionMetaRow(db, sessionId);
@@ -7708,18 +7865,18 @@ function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin =
7708
7865
  providerOverflowReconfirmedSessions.add(sessionId);
7709
7866
  }
7710
7867
  if (typeof reportedLimit === "number" && reportedLimit > 0) {
7711
- 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);
7712
7869
  } else {
7713
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);
7714
7871
  }
7715
7872
  })();
7716
7873
  }
7717
- function recordDetectedContextLimit(db, sessionId, reportedLimit, modelKey) {
7874
+ function recordDetectedContextLimit(db, sessionId, reportedLimit, modelKey, provenance = "unknown") {
7718
7875
  if (!(reportedLimit > 0))
7719
7876
  return;
7720
7877
  db.transaction(() => {
7721
7878
  ensureSessionMetaRow(db, sessionId);
7722
- 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);
7723
7880
  })();
7724
7881
  }
7725
7882
  function clearEmergencyRecovery(db, sessionId) {
@@ -7737,7 +7894,7 @@ function clearEmergencyRecovery(db, sessionId) {
7737
7894
  function clearDetectedContextLimit(db, sessionId) {
7738
7895
  db.transaction(() => {
7739
7896
  ensureSessionMetaRow(db, sessionId);
7740
- 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);
7741
7898
  })();
7742
7899
  }
7743
7900
  function getPersistedCompactionMarkerState(db, sessionId) {
@@ -7757,10 +7914,10 @@ function getPersistedCompactionMarkerState(db, sessionId) {
7757
7914
  } catch {}
7758
7915
  return null;
7759
7916
  }
7760
- function setPersistedCompactionMarkerState(db, sessionId, state) {
7917
+ function setPersistedCompactionMarkerState(db, sessionId, state2) {
7761
7918
  ensureSessionMetaRow(db, sessionId);
7762
- const json = state ? JSON.stringify(state) : "";
7763
- 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);
7764
7921
  }
7765
7922
  function getStrippedPlaceholderIds(db, sessionId) {
7766
7923
  const row = db.prepare("SELECT stripped_placeholder_ids FROM session_meta WHERE session_id = ?").get(sessionId);
@@ -7892,9 +8049,9 @@ function getPendingCompactionMarkerState(db, sessionId) {
7892
8049
  } catch {}
7893
8050
  return null;
7894
8051
  }
7895
- function setPendingCompactionMarkerState(db, sessionId, state) {
8052
+ function setPendingCompactionMarkerState(db, sessionId, state2) {
7896
8053
  ensureSessionMetaRow(db, sessionId);
7897
- const blob = state ? stableStringify(state) : null;
8054
+ const blob = state2 ? stableStringify(state2) : null;
7898
8055
  db.prepare("UPDATE session_meta SET pending_compaction_marker_state = ? WHERE session_id = ?").run(blob, sessionId);
7899
8056
  }
7900
8057
  function clearPendingCompactionMarkerStateIf(db, sessionId, expected) {
@@ -8165,6 +8322,14 @@ function getPendingOpsStatement(db) {
8165
8322
  }
8166
8323
  return stmt;
8167
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
+ }
8168
8333
  function getRemovePendingOpStatement(db) {
8169
8334
  let stmt = removePendingOpStatements.get(db);
8170
8335
  if (!stmt) {
@@ -8199,6 +8364,9 @@ function getPendingOps(db, sessionId) {
8199
8364
  const rows = getPendingOpsStatement(db).all(sessionId).filter(isPendingOpRow);
8200
8365
  return rows.map(toPendingOp).filter((op) => op !== null);
8201
8366
  }
8367
+ function clearPendingOps(db, sessionId) {
8368
+ getClearPendingOpsStatement(db).run(sessionId);
8369
+ }
8202
8370
  function removePendingOp(db, sessionId, tagId) {
8203
8371
  getRemovePendingOpStatement(db).run(sessionId, tagId);
8204
8372
  }
@@ -8394,11 +8562,11 @@ function bumpProjectMemoryEpoch(db, projectPath, now = Date.now()) {
8394
8562
  ON CONFLICT(project_path) DO UPDATE SET
8395
8563
  project_memory_epoch = project_memory_epoch + 1,
8396
8564
  updated_at = excluded.updated_at`).run(projectPath, now);
8397
- const state = getProjectState(db, projectPath);
8398
- if (!state) {
8565
+ const state2 = getProjectState(db, projectPath);
8566
+ if (!state2) {
8399
8567
  throw new Error(`Failed to bump project memory epoch for ${projectPath}`);
8400
8568
  }
8401
- return state;
8569
+ return state2;
8402
8570
  }
8403
8571
  function bumpProjectUserProfileVersion(db, projectPath = GLOBAL_USER_PROFILE_PROJECT_PATH, now = Date.now()) {
8404
8572
  db.prepare(`INSERT INTO project_state
@@ -8407,11 +8575,11 @@ function bumpProjectUserProfileVersion(db, projectPath = GLOBAL_USER_PROFILE_PRO
8407
8575
  ON CONFLICT(project_path) DO UPDATE SET
8408
8576
  project_user_profile_version = project_user_profile_version + 1,
8409
8577
  updated_at = excluded.updated_at`).run(projectPath, now);
8410
- const state = getProjectState(db, projectPath);
8411
- if (!state) {
8578
+ const state2 = getProjectState(db, projectPath);
8579
+ if (!state2) {
8412
8580
  throw new Error(`Failed to bump project user profile version for ${projectPath}`);
8413
8581
  }
8414
- return state;
8582
+ return state2;
8415
8583
  }
8416
8584
  // src/features/magic-context/storage-source.ts
8417
8585
  function isSourceContentRow(row) {
@@ -9001,6 +9169,518 @@ var ERROR_CLASSES = new Set([
9001
9169
  "permission_denied",
9002
9170
  "unknown"
9003
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
+
9004
9684
  // src/features/magic-context/user-memory/storage-user-memory.ts
9005
9685
  var USER_MEMORY_CANDIDATE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
9006
9686
  function insertUserMemoryCandidates(db, candidates) {
@@ -9068,9 +9748,9 @@ function parseUserMemoryRow(row) {
9068
9748
  }
9069
9749
 
9070
9750
  // src/features/magic-context/mural/storage-mural-cues.ts
9071
- import { createHash as createHash7 } from "node:crypto";
9751
+ import { createHash as createHash8 } from "node:crypto";
9072
9752
  function computeCueContentHash(content) {
9073
- return createHash7("sha256").update(content).digest("hex");
9753
+ return createHash8("sha256").update(content).digest("hex");
9074
9754
  }
9075
9755
  var muralCueColumnCache = new WeakMap;
9076
9756
  function hasMuralCueColumns(db) {
@@ -9096,10 +9776,10 @@ function getMuralCueState(db, memoryIds) {
9096
9776
  }
9097
9777
  return out;
9098
9778
  }
9099
- function memoryNeedsCue(state, currentContent) {
9100
- if (!state || state.cue === null || state.hash === null)
9779
+ function memoryNeedsCue(state2, currentContent) {
9780
+ if (!state2 || state2.cue === null || state2.hash === null)
9101
9781
  return true;
9102
- return state.hash !== computeCueContentHash(currentContent);
9782
+ return state2.hash !== computeCueContentHash(currentContent);
9103
9783
  }
9104
9784
  function setMuralCue(db, projectPath, id, cue, contentHash) {
9105
9785
  if (!hasMuralCueColumns(db))
@@ -9121,7 +9801,6 @@ var deleteEmbeddingStatements = new WeakMap;
9121
9801
  var getStoredModelIdStatements = new WeakMap;
9122
9802
  var clearAllEmbeddingsStatements = new WeakMap;
9123
9803
  var clearModelEmbeddingsStatements = new WeakMap;
9124
- var getDistinctStoredModelIdsStatements = new WeakMap;
9125
9804
  function isEmbeddingBlob(value) {
9126
9805
  return value instanceof Uint8Array || value instanceof ArrayBuffer;
9127
9806
  }
@@ -9238,13 +9917,13 @@ function invalidateMemory(projectPath, memoryId) {
9238
9917
  }
9239
9918
 
9240
9919
  // src/features/magic-context/memory/normalize-hash.ts
9241
- import { createHash as createHash8 } from "node:crypto";
9920
+ import { createHash as createHash9 } from "node:crypto";
9242
9921
  function normalizeMemoryContent(content) {
9243
9922
  return content.toLowerCase().replace(/\s+/g, " ").trim();
9244
9923
  }
9245
9924
  function computeNormalizedHash(content) {
9246
9925
  const normalized = normalizeMemoryContent(content);
9247
- return createHash8("md5").update(normalized).digest("hex");
9926
+ return createHash9("md5").update(normalized).digest("hex");
9248
9927
  }
9249
9928
 
9250
9929
  // src/features/magic-context/memory/visibility.ts
@@ -9636,7 +10315,6 @@ class ModuleMemoryAuthorityError extends Error {
9636
10315
  }
9637
10316
  }
9638
10317
  function assertTsMemoryWriteAllowed(db, projectPath) {
9639
- registerPrivilegedWriter(db);
9640
10318
  try {
9641
10319
  const managed = db.prepare("SELECT 1 FROM authority_managed WHERE project_path = ? UNION SELECT 1 FROM authority_repair_pending WHERE project_path = ? LIMIT 1").get(projectPath, projectPath);
9642
10320
  if (managed)
@@ -10109,9 +10787,12 @@ async function runMemoryMigration(deps) {
10109
10787
  const modelOverride = modelId ? parseProviderModel(modelId) : null;
10110
10788
  await cleanupChildSession(agentSessionId);
10111
10789
  agentSessionId = null;
10112
- const createResponse = await client.session.create({
10113
- body: { parentID: parentSessionId, title: "magic-context-memory-migration" },
10114
- query: { directory }
10790
+ const createResponse = await createChildSessionWithFence({
10791
+ client,
10792
+ db,
10793
+ parentSessionId,
10794
+ title: "magic-context-memory-migration",
10795
+ directory
10115
10796
  });
10116
10797
  const created = normalizeSDKResponse(createResponse, null, {
10117
10798
  preferResponseOnMissingData: true
@@ -10211,7 +10892,7 @@ async function runMemoryMigration(deps) {
10211
10892
  }
10212
10893
 
10213
10894
  // src/features/magic-context/compartment-chunk-embedding.ts
10214
- import { createHash as createHash9 } from "node:crypto";
10895
+ import { createHash as createHash10 } from "node:crypto";
10215
10896
 
10216
10897
  // src/features/magic-context/recursive-text-splitter.ts
10217
10898
  var DEFAULT_SEPARATORS = [`
@@ -10306,9 +10987,6 @@ var existingHashStatements = new WeakMap;
10306
10987
  var existingHashByProjectStatements = new WeakMap;
10307
10988
  var deleteByCompartmentStatements = new WeakMap;
10308
10989
  var insertEmbeddingStatements = new WeakMap;
10309
- var distinctModelStatements = new WeakMap;
10310
- var clearProjectStatements = new WeakMap;
10311
- var clearProjectModelStatements = new WeakMap;
10312
10990
  var searchRowsStatements = new WeakMap;
10313
10991
  var searchRowsByModelStatements = new WeakMap;
10314
10992
  var searchPoolProbeStatements = new WeakMap;
@@ -10499,7 +11177,7 @@ function parseCanonicalLineRange(line) {
10499
11177
  return { start, end };
10500
11178
  }
10501
11179
  function hashChunkText(text) {
10502
- return createHash9("sha256").update(text).digest("hex");
11180
+ return createHash10("sha256").update(text).digest("hex");
10503
11181
  }
10504
11182
  function vectorBlob2(vector) {
10505
11183
  return new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength);
@@ -10890,7 +11568,7 @@ function countSessionCompartmentEmbedCoverage(db, projectPath, sessionId, modelI
10890
11568
  }
10891
11569
 
10892
11570
  // src/features/magic-context/project-embedding-registry.ts
10893
- import { createHash as createHash11, randomUUID as randomUUID2 } from "node:crypto";
11571
+ import { createHash as createHash12, randomUUID as randomUUID2 } from "node:crypto";
10894
11572
 
10895
11573
  // src/config/schema/magic-context.ts
10896
11574
  import { homedir as homedir2 } from "node:os";
@@ -25342,12 +26020,11 @@ var AgentOverrideConfigSchema = exports_external.object({
25342
26020
 
25343
26021
  // src/config/schema/magic-context.ts
25344
26022
  var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65;
25345
- 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.";
25346
26024
  var DEFAULT_HISTORIAN_TIMEOUT_MS = 300000;
25347
26025
  var DEFAULT_HISTORY_BUDGET_PERCENTAGE = 0.15;
25348
26026
  var DEFAULT_LOCAL_EMBEDDING_MODEL = "Xenova/all-MiniLM-L6-v2";
25349
- var DreamingTaskSchema = exports_external.enum(AGENTIC_DREAM_TASKS);
25350
- var PiThinkingLevelSchema = exports_external.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional();
26027
+ var PiThinkingLevelSchema = exports_external.enum(["off", "minimal", "low", "medium", "high", "xhigh", "max"]).optional();
25351
26028
  var PiConfigSchema = exports_external.object({
25352
26029
  subagent_extensions: exports_external.array(exports_external.string().trim().min(1)).optional().describe("User-only allowlist of Pi extensions for Magic Context subagent children. When set, children use --no-extensions and load only these entries (plus Magic Context's scoped child extension where applicable). Relative paths resolve from ~/.pi/agent, matching Pi's settings.json package location. Unset preserves normal Pi extension discovery.")
25353
26030
  }).optional();
@@ -25420,7 +26097,7 @@ var SidekickConfigSchema = AgentOverrideConfigSchema.extend({
25420
26097
  }).optional();
25421
26098
  var HistorianConfigSchema = AgentOverrideConfigSchema.extend({
25422
26099
  two_pass: exports_external.boolean().default(false).describe("Run a second editor pass over historian output to clean low-signal U: lines and cross-compartment duplicates. Adds ~1 extra API call and ~1.3x cost per historian run. Useful for models without extended thinking support. (default: false)"),
25423
- thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh"),
26100
+ thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh | max"),
25424
26101
  disallowed_tools: exports_external.array(exports_external.enum(["*", "read", "aft_outline", "aft_zoom", "aft_search"])).default([]).describe(`OpenCode only. Tools to REMOVE from the historian's default allow-list [read, aft_outline, aft_zoom, aft_search]. Applies to both historian and historian-editor agents. Use ["*"] to strip all tool definitions from the model request — this prevents weak instruction-following models (e.g. mistral-small-latest) from entering tool-calling loops. Individual tool names remove just that tool. Note: a user-supplied historian.permission override can re-allow a tool that disallowed_tools removed — disallowed_tools sets the baseline, permission overrides take precedence. (default: [])`)
25425
26102
  }).optional();
25426
26103
  var EmbeddingFallbackProviderSchema = exports_external.enum(["local", "openai-compatible", "off"]);
@@ -25441,7 +26118,22 @@ var BaseEmbeddingConfigSchema = exports_external.object({
25441
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."),
25442
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."),
25443
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."),
25444
- 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.")
25445
26137
  }).superRefine((data, ctx) => {
25446
26138
  const validationProvider = data.provider === "synapse" ? data.fallback_provider : data.provider;
25447
26139
  if (validationProvider === "openai-compatible" && !data.endpoint?.trim()) {
@@ -25483,7 +26175,8 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
25483
26175
  return {
25484
26176
  provider: "local",
25485
26177
  model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
25486
- ...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 } : {}
25487
26180
  };
25488
26181
  }
25489
26182
  if (data.provider === "openai-compatible") {
@@ -25506,6 +26199,7 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
25506
26199
  });
25507
26200
  var MagicContextConfigSchema = exports_external.object({
25508
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."),
25509
26203
  experimental: exports_external.object({
25510
26204
  mural: exports_external.object({
25511
26205
  enabled: exports_external.boolean().default(false),
@@ -25517,15 +26211,19 @@ var MagicContextConfigSchema = exports_external.object({
25517
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."),
25518
26212
  historian: HistorianConfigSchema.describe("Historian agent configuration (model, fallback_models, variant, temperature, maxTokens, permission, two_pass, etc.)"),
25519
26213
  dreamer: DreamerConfigSchema.optional().describe("Dreamer agent + scheduling configuration (model, fallback_models, disable, schedule, tasks, etc.)"),
25520
- 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.'),
25521
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)"),
25522
26220
  execute_threshold_percentage: exports_external.union([
25523
- exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE),
25524
- 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))
25525
- ]).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'),
25526
26224
  execute_threshold_tokens: exports_external.object({
25527
26225
  default: exports_external.number().min(5000).max(2000000).optional()
25528
- }).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."),
25529
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)"),
25530
26228
  clear_reasoning_age: exports_external.number().min(10).default(50).describe("Clear reasoning/thinking blocks older than N tags (default: 50)"),
25531
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)"),
@@ -25545,6 +26243,9 @@ var MagicContextConfigSchema = exports_external.object({
25545
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)"),
25546
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)")
25547
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."),
25548
26249
  embedding: EmbeddingConfigSchema.default({
25549
26250
  provider: "local",
25550
26251
  model: DEFAULT_LOCAL_EMBEDDING_MODEL
@@ -25558,6 +26259,9 @@ var MagicContextConfigSchema = exports_external.object({
25558
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).'),
25559
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."),
25560
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."),
25561
26265
  todowrite: exports_external.object({
25562
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."),
25563
26267
  overlay: exports_external.boolean().default(true).describe("Pi only: show the persistent todo overlay above the editor while tasks are active.")
@@ -25604,9 +26308,6 @@ var saveStatements = new WeakMap;
25604
26308
  var loadProjectStatements = new WeakMap;
25605
26309
  var loadUnembeddedStatements = new WeakMap;
25606
26310
  var countEmbeddedStatements = new WeakMap;
25607
- var clearProjectStatements2 = new WeakMap;
25608
- var clearProjectModelStatements2 = new WeakMap;
25609
- var distinctModelIdStatements = new WeakMap;
25610
26311
  function getSaveStatement(db) {
25611
26312
  let stmt = saveStatements.get(db);
25612
26313
  if (!stmt) {
@@ -25677,7 +26378,6 @@ function countEmbeddedCommits(db, projectPath, modelId) {
25677
26378
  var insertStatements = new WeakMap;
25678
26379
  var existingShasStatements = new WeakMap;
25679
26380
  var projectCountStatements = new WeakMap;
25680
- var evictStatements = new WeakMap;
25681
26381
  var evictOverflowStatements = new WeakMap;
25682
26382
  var latestCommitTimeStatements = new WeakMap;
25683
26383
  function getInsertStatement(db) {
@@ -25919,7 +26619,7 @@ function releaseGitSweepLease(db, projectPath, holderId) {
25919
26619
  }
25920
26620
 
25921
26621
  // src/features/magic-context/memory/embedding-synapse.ts
25922
- import { createHash as createHash10 } from "node:crypto";
26622
+ import { createHash as createHash11 } from "node:crypto";
25923
26623
 
25924
26624
  // ../../node_modules/.bun/@cortexkit+subc-client@0.4.1/node_modules/@cortexkit/subc-client/dist/client.js
25925
26625
  import { promises as fs2 } from "node:fs";
@@ -28132,7 +28832,7 @@ function wait(ms) {
28132
28832
  return new Promise((resolve) => setTimeout(resolve, ms));
28133
28833
  }
28134
28834
  function sha256(value) {
28135
- return createHash10("sha256").update(value).digest("hex");
28835
+ return createHash11("sha256").update(value).digest("hex");
28136
28836
  }
28137
28837
  function stableJson(value) {
28138
28838
  if (Array.isArray(value))
@@ -28180,7 +28880,7 @@ function extractCatalogEntries(value) {
28180
28880
  const batchRecord = asRecord(rawBatch);
28181
28881
  const recommendedBatch = typeof rawBatch === "number" ? rawBatch : batchRecord ? batchRecord.rows : undefined;
28182
28882
  const recommendedTokenBudget = batchRecord ? batchRecord.token_budget : undefined;
28183
- const state = typeof record2.state === "string" ? record2.state : undefined;
28883
+ const state2 = typeof record2.state === "string" ? record2.state : undefined;
28184
28884
  return [
28185
28885
  {
28186
28886
  model,
@@ -28191,7 +28891,7 @@ function extractCatalogEntries(value) {
28191
28891
  ...typeof recommendedTokenBudget === "number" && recommendedTokenBudget > 0 ? { recommended_token_budget: Math.floor(recommendedTokenBudget) } : {},
28192
28892
  ...record2.provenance !== undefined ? { provenance: record2.provenance } : {},
28193
28893
  ...typeof record2.certified === "boolean" ? { certified: record2.certified } : {},
28194
- ...typeof record2.status === "string" ? { status: record2.status } : state ? { status: state } : {}
28894
+ ...typeof record2.status === "string" ? { status: record2.status } : state2 ? { status: state2 } : {}
28195
28895
  }
28196
28896
  ];
28197
28897
  });
@@ -28577,6 +29277,7 @@ function getEmbeddingProviderIdentity(config2) {
28577
29277
  throw new Error("Unknown embedding provider");
28578
29278
  }
28579
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;
28580
29281
  const identityInput = config2.provider === "openai-compatible" ? {
28581
29282
  provider: "openai-compatible",
28582
29283
  model: config2.model.trim(),
@@ -28588,7 +29289,8 @@ function getEmbeddingProviderIdentity(config2) {
28588
29289
  provider: "local",
28589
29290
  model: config2.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
28590
29291
  endpoint: "",
28591
- apiKeyPresent: false
29292
+ apiKeyPresent: false,
29293
+ ...localDtype ? { localDtype } : {}
28592
29294
  };
28593
29295
  return `embedding-provider:${computeNormalizedHash(JSON.stringify(identityInput))}`;
28594
29296
  }
@@ -28596,7 +29298,7 @@ function getEmbeddingProviderIdentity(config2) {
28596
29298
  // src/features/magic-context/memory/embedding-local.ts
28597
29299
  import { chmodSync as chmodSync2, mkdirSync as mkdirSync2 } from "node:fs";
28598
29300
  import { open, stat, unlink, writeFile } from "node:fs/promises";
28599
- import { dirname as dirname2, join as join3 } from "node:path";
29301
+ import { dirname as dirname2, join as join4 } from "node:path";
28600
29302
  import { pathToFileURL } from "node:url";
28601
29303
  var LOCK_POLL_MS = 150;
28602
29304
  var STALE_LOCK_MS = 3 * 60000;
@@ -28676,6 +29378,7 @@ async function injectWasmOrtForElectron() {
28676
29378
  return false;
28677
29379
  }
28678
29380
  }
29381
+ var DEFAULT_LOCAL_DTYPE = "fp32";
28679
29382
  async function withQuietConsole(fn) {
28680
29383
  const origWarn = console.warn;
28681
29384
  const origError = console.error;
@@ -28752,16 +29455,22 @@ class LocalEmbeddingProvider {
28752
29455
  modelId;
28753
29456
  maxInputTokens;
28754
29457
  model;
29458
+ dtype;
28755
29459
  pipeline = null;
28756
29460
  initPromise = null;
28757
29461
  inFlight = 0;
28758
29462
  disposing = false;
28759
29463
  disposePromise = null;
28760
29464
  inFlightWaiters = [];
28761
- constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
29465
+ constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512, dtype = DEFAULT_LOCAL_DTYPE) {
28762
29466
  this.model = model;
28763
29467
  this.maxInputTokens = maxInputTokens;
28764
- 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
+ });
28765
29474
  }
28766
29475
  async initialize() {
28767
29476
  if (this.disposing) {
@@ -28790,20 +29499,24 @@ class LocalEmbeddingProvider {
28790
29499
  if (LogLevel && "ERROR" in LogLevel) {
28791
29500
  env.logLevel = LogLevel.ERROR;
28792
29501
  }
28793
- const modelCacheDir = join3(getMagicContextStorageDir(), "models");
29502
+ const modelCacheDir = join4(getMagicContextStorageDir(), "models");
28794
29503
  try {
28795
- mkdirSync2(modelCacheDir, { recursive: true, mode: 448 });
28796
- if (process.platform !== "win32") {
28797
- try {
28798
- chmodSync2(modelCacheDir, 448);
28799
- } 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 });
28800
29513
  }
28801
29514
  env.cacheDir = modelCacheDir;
28802
29515
  } catch {
28803
29516
  log("[magic-context] could not create model cache dir, using library default");
28804
29517
  }
28805
29518
  const createPipeline = transformersModule.pipeline;
28806
- const lockPath = join3(modelCacheDir, ".load.lock");
29519
+ const lockPath = join4(modelCacheDir, ".load.lock");
28807
29520
  const releaseLock = await acquireModelLoadLock(lockPath);
28808
29521
  const stopHeartbeat = startLockHeartbeat(lockPath);
28809
29522
  try {
@@ -28812,7 +29525,7 @@ class LocalEmbeddingProvider {
28812
29525
  for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
28813
29526
  try {
28814
29527
  const pipeline = await withQuietConsole(() => createPipeline("feature-extraction", this.model, {
28815
- dtype: "fp32",
29528
+ dtype: this.dtype,
28816
29529
  ...injectedWasmOrt ? { device: "auto" } : {}
28817
29530
  }));
28818
29531
  if (this.disposing) {
@@ -29376,6 +30089,9 @@ var shadowWorker = null;
29376
30089
  var SHADOW_MAX_ITEMS_PER_TICK = 64;
29377
30090
  var SHADOW_MAX_BYTES_PER_TICK = 512 * 1024;
29378
30091
  var SHADOW_MAX_WALL_CLOCK_MS = 2000;
30092
+ var pendingShadowBackfills = new Map;
30093
+ var shadowBackfillLastIds = new Map;
30094
+ var shadowBackfillStopReasons = new Map;
29379
30095
  var loadUnembeddedMemoriesStatements = new WeakMap;
29380
30096
  var upsertActiveIdentityStatements = new WeakMap;
29381
30097
  var backfillActiveIdentityStatements = new Map;
@@ -29460,7 +30176,8 @@ function resolveEmbeddingConfig(config2) {
29460
30176
  model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
29461
30177
  ...config2?.max_input_tokens ? {
29462
30178
  max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
29463
- } : {}
30179
+ } : {},
30180
+ ...config2?.local_dtype ? { local_dtype: config2.local_dtype } : {}
29464
30181
  };
29465
30182
  }
29466
30183
  if (config2.provider === "openai-compatible") {
@@ -29519,7 +30236,7 @@ function createProvider(config2, context) {
29519
30236
  });
29520
30237
  }
29521
30238
  if (config2.provider === "local") {
29522
- return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
30239
+ return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens, config2.local_dtype);
29523
30240
  }
29524
30241
  if (config2.provider === "synapse") {
29525
30242
  const synapse = config2;
@@ -29548,10 +30265,10 @@ function stableStringify2(value) {
29548
30265
  return JSON.stringify(value);
29549
30266
  }
29550
30267
  function sha256Prefix(value, length = 16) {
29551
- return createHash11("sha256").update(value).digest("hex").slice(0, length);
30268
+ return createHash12("sha256").update(value).digest("hex").slice(0, length);
29552
30269
  }
29553
30270
  function contentSha256(value) {
29554
- return createHash11("sha256").update(value).digest("hex");
30271
+ return createHash12("sha256").update(value).digest("hex");
29555
30272
  }
29556
30273
  function getRuntimeFingerprint(config2) {
29557
30274
  if (config2.provider === "off") {
@@ -29910,6 +30627,7 @@ function registerProjectShadowEmbedding(db, projectIdentity, config2, sourceDire
29910
30627
  recordScopeActiveIdentity(db, projectIdentity, "chunk", registration.chunkModelId, now);
29911
30628
  persistShadowDescriptor(db, registration);
29912
30629
  })();
30630
+ maybeArmShadowBackfill(db, projectIdentity, registration);
29913
30631
  return {
29914
30632
  projectIdentity,
29915
30633
  sourceDirectory,
@@ -29930,7 +30648,7 @@ function startShadowWorker() {
29930
30648
  return;
29931
30649
  shadowWorker = runShadowWorker().finally(() => {
29932
30650
  shadowWorker = null;
29933
- if (shadowQueue.length > 0)
30651
+ if (shadowQueue.length > 0 || hasPendingShadowBackfill())
29934
30652
  startShadowWorker();
29935
30653
  });
29936
30654
  }
@@ -29977,6 +30695,117 @@ function enqueueShadowEmbeddingItems(projectIdentity, scope, ids) {
29977
30695
  shadowQueue.push({ projectIdentity, scope, ids: [...ids] });
29978
30696
  startShadowWorker();
29979
30697
  }
30698
+ function shadowBackfillMissingBase(scope, primaryModelId, shadowModelId, projectIdentity) {
30699
+ if (scope === "memory") {
30700
+ return {
30701
+ sql: `SELECT m.id AS id
30702
+ FROM memories m
30703
+ JOIN memory_embeddings mp ON mp.memory_id = m.id AND mp.model_id = ?
30704
+ LEFT JOIN memory_embeddings ms ON ms.memory_id = m.id AND ms.model_id = ?
30705
+ WHERE m.project_path = ? AND m.status = 'active' AND ms.memory_id IS NULL`,
30706
+ params: [primaryModelId, shadowModelId, projectIdentity],
30707
+ orderBy: " ORDER BY m.id"
30708
+ };
30709
+ }
30710
+ if (scope === "commit") {
30711
+ return {
30712
+ sql: `SELECT gc.sha AS id
30713
+ FROM git_commits gc
30714
+ JOIN git_commit_embeddings gp ON gp.sha = gc.sha AND gp.model_id = ?
30715
+ LEFT JOIN git_commit_embeddings gs ON gs.sha = gc.sha AND gs.model_id = ?
30716
+ WHERE gc.project_path = ? AND gs.sha IS NULL`,
30717
+ params: [primaryModelId, shadowModelId, projectIdentity],
30718
+ orderBy: " ORDER BY gc.committed_at DESC, gc.sha"
30719
+ };
30720
+ }
30721
+ return {
30722
+ sql: `SELECT DISTINCT cp.compartment_id AS id
30723
+ FROM compartment_chunk_embeddings cp
30724
+ WHERE cp.project_path = ? AND cp.model_id = ?
30725
+ AND NOT EXISTS (
30726
+ SELECT 1 FROM compartment_chunk_embeddings cs
30727
+ WHERE cs.compartment_id = cp.compartment_id AND cs.model_id = ?
30728
+ )`,
30729
+ params: [projectIdentity, primaryModelId, shadowModelId],
30730
+ orderBy: " ORDER BY cp.compartment_id"
30731
+ };
30732
+ }
30733
+ function shadowBackfillMissingIds(db, projectIdentity, scope, primaryModelId, shadowModelId, limit) {
30734
+ const { sql, params, orderBy } = shadowBackfillMissingBase(scope, primaryModelId, shadowModelId, projectIdentity);
30735
+ const rows = db.prepare(`${sql}${orderBy} LIMIT ?`).all(...params, limit);
30736
+ return rows.map((row) => String(row.id));
30737
+ }
30738
+ function shadowModelIdForScope(registration, scope) {
30739
+ return scope === "chunk" ? registration.chunkModelId : registration.modelId;
30740
+ }
30741
+ function hasPendingShadowBackfill(projectIdentity) {
30742
+ if (projectIdentity === undefined)
30743
+ return pendingShadowBackfills.size > 0;
30744
+ const scopes = pendingShadowBackfills.get(projectIdentity);
30745
+ return scopes !== undefined && scopes.size > 0;
30746
+ }
30747
+ function pumpShadowBackfill() {
30748
+ for (const [projectIdentity, scopes] of pendingShadowBackfills) {
30749
+ const db = dbForShadowQueue.get(projectIdentity);
30750
+ const shadow = shadowRegistrations.get(projectIdentity);
30751
+ const primary = projectRegistrations.get(projectIdentity);
30752
+ if (!db || !shadow || !primary) {
30753
+ pendingShadowBackfills.delete(projectIdentity);
30754
+ continue;
30755
+ }
30756
+ for (const scope of [...scopes]) {
30757
+ const primaryModelId = shadowModelIdForScope(primary, scope);
30758
+ const shadowModelId = shadowModelIdForScope(shadow, scope);
30759
+ const stallKey = `${projectIdentity}:${scope}`;
30760
+ if (primaryModelId === "off" || shadowModelId === "off") {
30761
+ scopes.delete(scope);
30762
+ shadowBackfillLastIds.delete(stallKey);
30763
+ continue;
30764
+ }
30765
+ const ids = shadowBackfillMissingIds(db, projectIdentity, scope, primaryModelId, shadowModelId, SHADOW_MAX_ITEMS_PER_TICK);
30766
+ if (ids.length === 0) {
30767
+ shadowBackfillStopReasons.set(stallKey, "drained");
30768
+ scopes.delete(scope);
30769
+ shadowBackfillLastIds.delete(stallKey);
30770
+ continue;
30771
+ }
30772
+ const signature = ids.join(",");
30773
+ if (shadowBackfillLastIds.get(stallKey) === signature) {
30774
+ shadowBackfillStopReasons.set(stallKey, "stalled_no_progress");
30775
+ log(`[shadow] backfill scope ${scope} for ${projectIdentity} retired without progress — ` + `the last batch produced no writes (provider failure or timeout is the usual cause); ` + `${ids.length}+ items remain and retry on the next registration or manual --shadow run`);
30776
+ scopes.delete(scope);
30777
+ shadowBackfillLastIds.delete(stallKey);
30778
+ continue;
30779
+ }
30780
+ shadowBackfillLastIds.set(stallKey, signature);
30781
+ shadowQueue.push({ projectIdentity, scope, ids });
30782
+ }
30783
+ if (scopes.size === 0)
30784
+ pendingShadowBackfills.delete(projectIdentity);
30785
+ }
30786
+ }
30787
+ function maybeArmShadowBackfill(db, projectIdentity, shadow) {
30788
+ if (untrustedLoadProjects.has(projectIdentity))
30789
+ return;
30790
+ const primary = projectRegistrations.get(projectIdentity);
30791
+ if (!primary)
30792
+ return;
30793
+ const pending = new Set;
30794
+ for (const scope of ["memory", "commit", "chunk"]) {
30795
+ const primaryModelId = shadowModelIdForScope(primary, scope);
30796
+ const shadowModelId = shadowModelIdForScope(shadow, scope);
30797
+ if (primaryModelId === "off" || shadowModelId === "off")
30798
+ continue;
30799
+ const probe = shadowBackfillMissingIds(db, projectIdentity, scope, primaryModelId, shadowModelId, 1);
30800
+ if (probe.length > 0)
30801
+ pending.add(scope);
30802
+ }
30803
+ if (pending.size === 0)
30804
+ return;
30805
+ pendingShadowBackfills.set(projectIdentity, pending);
30806
+ pumpShadowBackfill();
30807
+ startShadowWorker();
30808
+ }
29980
30809
  async function embedShadowItems(registration, items, db, scope) {
29981
30810
  const raw = registration.config;
29982
30811
  const fingerprint = typeof raw.synapse_fingerprint === "string" ? raw.synapse_fingerprint : "";
@@ -30100,7 +30929,15 @@ async function runShadowWorker() {
30100
30929
  const startedAt = Date.now();
30101
30930
  let processed = 0;
30102
30931
  let processedBytes = 0;
30103
- while (shadowQueue.length > 0 && processed < SHADOW_MAX_ITEMS_PER_TICK && Date.now() - startedAt < SHADOW_MAX_WALL_CLOCK_MS) {
30932
+ for (;; ) {
30933
+ if (shadowQueue.length === 0) {
30934
+ pumpShadowBackfill();
30935
+ if (shadowQueue.length === 0)
30936
+ break;
30937
+ }
30938
+ if (processed >= SHADOW_MAX_ITEMS_PER_TICK || Date.now() - startedAt >= SHADOW_MAX_WALL_CLOCK_MS) {
30939
+ break;
30940
+ }
30104
30941
  const item = shadowQueue.shift();
30105
30942
  if (!item)
30106
30943
  break;
@@ -30706,12 +31543,12 @@ function parseFields(json2) {
30706
31543
  }
30707
31544
 
30708
31545
  // src/hooks/magic-context/historian-state-file.ts
30709
- import { mkdirSync as mkdirSync3, unlinkSync, writeFileSync } from "node:fs";
31546
+ import { mkdirSync as mkdirSync3, unlinkSync as unlinkSync2, writeFileSync } from "node:fs";
30710
31547
  function cleanupHistorianStateFile(path3) {
30711
31548
  if (!path3)
30712
31549
  return;
30713
31550
  try {
30714
- unlinkSync(path3);
31551
+ unlinkSync2(path3);
30715
31552
  } catch {}
30716
31553
  }
30717
31554
  // src/features/magic-context/memory/cosine-similarity.ts
@@ -30754,7 +31591,7 @@ function createProvider2(config2) {
30754
31591
  });
30755
31592
  }
30756
31593
  if (config2.provider === "local") {
30757
- return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
31594
+ return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens, config2.local_dtype);
30758
31595
  }
30759
31596
  if (config2.provider === "synapse") {
30760
31597
  const synapse = config2;
@@ -31026,8 +31863,8 @@ function getMemoryVerifications(db, memoryIds) {
31026
31863
  existing.mappedAt = Math.max(existing.mappedAt, row.mapped_at ?? 0);
31027
31864
  result.set(row.memory_id, existing);
31028
31865
  }
31029
- for (const state of result.values()) {
31030
- state.files.sort();
31866
+ for (const state2 of result.values()) {
31867
+ state2.files.sort();
31031
31868
  }
31032
31869
  return result;
31033
31870
  }
@@ -31264,18 +32101,18 @@ function tallyFactsByCategory(facts) {
31264
32101
  }
31265
32102
 
31266
32103
  // src/hooks/magic-context/compaction-marker-manager.ts
31267
- import { join as join5 } from "node:path";
32104
+ import { join as join6 } from "node:path";
31268
32105
 
31269
32106
  // src/features/magic-context/compaction-marker.ts
31270
- import { createHash as createHash12 } from "node:crypto";
32107
+ import { createHash as createHash13 } from "node:crypto";
31271
32108
  import { existsSync as existsSync5 } from "node:fs";
31272
- import { join as join4 } from "node:path";
32109
+ import { join as join5 } from "node:path";
31273
32110
  var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
31274
32111
  var ID_PREFIX_HEX_LENGTH = 12;
31275
32112
  var ID_SUFFIX_LENGTH = 14;
31276
32113
  var ID_PREFIX_MASK = (1n << BigInt(ID_PREFIX_HEX_LENGTH * 4)) - 1n;
31277
32114
  function deterministicBase62(seed, length) {
31278
- let value = BigInt(`0x${createHash12("sha256").update(seed).digest("hex")}`);
32115
+ let value = BigInt(`0x${createHash13("sha256").update(seed).digest("hex")}`);
31279
32116
  const chars = Array(length);
31280
32117
  for (let index = length - 1;index >= 0; index -= 1) {
31281
32118
  chars[index] = BASE62_CHARS[Number(value % 62n)];
@@ -31295,7 +32132,7 @@ function generatePartId(timestampMs, counter = 0n, identity = "") {
31295
32132
  return generateId("prt", timestampMs, counter, identity);
31296
32133
  }
31297
32134
  function getOpenCodeDbPath() {
31298
- return join4(getDataDir(), "opencode", "opencode.db");
32135
+ return join5(getDataDir(), "opencode", "opencode.db");
31299
32136
  }
31300
32137
  var cachedWriteDb = null;
31301
32138
  var REQUIRED_MESSAGE_COLUMNS = ["id", "session_id", "time_created", "time_updated", "data"];
@@ -31508,13 +32345,223 @@ function injectCompactionMarker(args) {
31508
32345
  return null;
31509
32346
  }
31510
32347
  }
31511
- function removeCompactionMarker(state) {
32348
+ function listSessionCompactionMarkers(sessionId) {
32349
+ const db = getWritableOpenCodeDb();
32350
+ const partRows = db.prepare(`SELECT id, message_id
32351
+ FROM part
32352
+ WHERE session_id = ?
32353
+ AND COALESCE(json_extract(data, '$.type'), '') = 'compaction'`).all(sessionId);
32354
+ const markers = [];
32355
+ const summaryStmt = db.prepare(`SELECT id
32356
+ FROM message
32357
+ WHERE session_id = ?
32358
+ AND COALESCE(json_extract(data, '$.parentID'), '') = ?
32359
+ AND COALESCE(json_extract(data, '$.summary'), 0) = 1
32360
+ AND COALESCE(json_extract(data, '$.finish'), '') = 'stop'
32361
+ AND COALESCE(json_extract(data, '$.providerID'), '') = 'magic-context'`);
32362
+ for (const row of partRows) {
32363
+ if (typeof row.id !== "string" || typeof row.message_id !== "string")
32364
+ continue;
32365
+ const summaryRows = summaryStmt.all(sessionId, row.message_id);
32366
+ const summaryMessageIds = summaryRows.flatMap((summaryRow) => typeof summaryRow.id === "string" ? [summaryRow.id] : []);
32367
+ markers.push({
32368
+ compactionPartId: row.id,
32369
+ boundaryMessageId: row.message_id,
32370
+ summaryMessageIds
32371
+ });
32372
+ }
32373
+ return markers;
32374
+ }
32375
+ function removeForeignCompactionMarker(sessionId, marker, protectedSummaryMessageId) {
31512
32376
  try {
31513
32377
  const db = getWritableOpenCodeDb();
31514
32378
  db.transaction(() => {
31515
- db.prepare("DELETE FROM part WHERE id = ?").run(state.summaryPartId);
31516
- db.prepare("DELETE FROM message WHERE id = ?").run(state.summaryMessageId);
31517
- db.prepare("DELETE FROM part WHERE id = ?").run(state.compactionPartId);
32379
+ const deletePartsOfMessage = db.prepare("DELETE FROM part WHERE session_id = ? AND message_id = ?");
32380
+ const deleteMessage = db.prepare("DELETE FROM message WHERE session_id = ? AND id = ?");
32381
+ for (const summaryMessageId of marker.summaryMessageIds) {
32382
+ if (summaryMessageId === protectedSummaryMessageId)
32383
+ continue;
32384
+ deletePartsOfMessage.run(sessionId, summaryMessageId);
32385
+ deleteMessage.run(sessionId, summaryMessageId);
32386
+ }
32387
+ db.prepare("DELETE FROM part WHERE session_id = ? AND id = ?").run(sessionId, marker.compactionPartId);
32388
+ })();
32389
+ return true;
32390
+ } catch (error51) {
32391
+ log(`[magic-context] compaction-marker: foreign-marker removal failed (${sessionId}, part ${marker.compactionPartId}): ${error51 instanceof Error ? error51.message : String(error51)}`);
32392
+ return false;
32393
+ }
32394
+ }
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) {
32559
+ try {
32560
+ const db = getWritableOpenCodeDb();
32561
+ db.transaction(() => {
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);
31518
32565
  })();
31519
32566
  return true;
31520
32567
  } catch (error51) {
@@ -31530,9 +32577,9 @@ function dropMarkerSummaryTag(db, sessionId, summaryMessageId) {
31530
32577
  if (tagNumber !== null)
31531
32578
  updateTagStatus(db, sessionId, tagNumber, "dropped");
31532
32579
  }
31533
- function persistMarkerStateAndDropReplacedTag(db, sessionId, state, replacedSummaryMessageId) {
32580
+ function persistMarkerStateAndDropReplacedTag(db, sessionId, state2, replacedSummaryMessageId) {
31534
32581
  db.transaction(() => {
31535
- setPersistedCompactionMarkerState(db, sessionId, state);
32582
+ setPersistedCompactionMarkerState(db, sessionId, state2);
31536
32583
  if (replacedSummaryMessageId !== null) {
31537
32584
  dropMarkerSummaryTag(db, sessionId, replacedSummaryMessageId);
31538
32585
  }
@@ -31708,8 +32755,52 @@ function removeCompactionMarkerForSession(db, sessionId) {
31708
32755
  }
31709
32756
  }
31710
32757
  }
32758
+ function reconcileForkOrphanedCompactionMarkers(db, sessionId) {
32759
+ if (getHarness() !== "opencode") {
32760
+ return { removed: 0, failed: false };
32761
+ }
32762
+ try {
32763
+ const owned = getPersistedCompactionMarkerState(db, sessionId);
32764
+ if (!owned) {
32765
+ return { removed: 0, failed: false };
32766
+ }
32767
+ const markers = listSessionCompactionMarkers(sessionId);
32768
+ let removed = 0;
32769
+ let failed = false;
32770
+ for (const marker of markers) {
32771
+ if (marker.compactionPartId === owned.compactionPartId) {
32772
+ continue;
32773
+ }
32774
+ if (marker.summaryMessageIds.length === 0) {
32775
+ continue;
32776
+ }
32777
+ const ordering = compareOpenCodeMessagesByCanonicalOrder(sessionId, marker.boundaryMessageId, owned.boundaryMessageId);
32778
+ if (ordering === null || ordering <= 0) {
32779
+ continue;
32780
+ }
32781
+ const currentOwned = getPersistedCompactionMarkerState(db, sessionId);
32782
+ if (!currentOwned || marker.compactionPartId === currentOwned.compactionPartId) {
32783
+ continue;
32784
+ }
32785
+ const ok = removeForeignCompactionMarker(sessionId, marker, currentOwned.summaryMessageId);
32786
+ if (ok) {
32787
+ removed += 1;
32788
+ sessionLog(sessionId, `compaction-marker hygiene: removed fork-orphaned marker part=${marker.compactionPartId} boundary=${marker.boundaryMessageId} (outranked owned boundary ${currentOwned.boundaryMessageId})`);
32789
+ } else {
32790
+ failed = true;
32791
+ }
32792
+ }
32793
+ if (removed > 0) {
32794
+ log(`[magic-context][${sessionId}] compaction-marker hygiene: removed ${removed} fork-orphaned marker(s); filterCompacted will now stop at this session's own marker`);
32795
+ }
32796
+ return { removed, failed };
32797
+ } catch (error51) {
32798
+ sessionLog(sessionId, "compaction-marker hygiene: scan failed (will retry on next degraded pass):", error51);
32799
+ return { removed: 0, failed: true };
32800
+ }
32801
+ }
31711
32802
  function checkCompactionMarkerConsistency(db) {
31712
- const opencodeDbPath = join5(getDataDir(), "opencode", "opencode.db");
32803
+ const opencodeDbPath = join6(getDataDir(), "opencode", "opencode.db");
31713
32804
  let opencodeDb;
31714
32805
  try {
31715
32806
  opencodeDb = new Database(opencodeDbPath, { readonly: true });
@@ -31725,19 +32816,19 @@ function checkCompactionMarkerConsistency(db) {
31725
32816
  const checkPart = opencodeDb.prepare("SELECT 1 FROM part WHERE id = ? LIMIT 1");
31726
32817
  let reconciledCount = 0;
31727
32818
  for (const row of persistedRows) {
31728
- const state = getPersistedCompactionMarkerState(db, row.session_id);
31729
- if (!state)
32819
+ const state2 = getPersistedCompactionMarkerState(db, row.session_id);
32820
+ if (!state2)
31730
32821
  continue;
31731
- const boundaryExists = checkMessage.get(state.boundaryMessageId) != null;
31732
- const summaryMessageExists = checkMessage.get(state.summaryMessageId) != null;
31733
- const compactionPartExists = checkPart.get(state.compactionPartId) != null;
31734
- 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;
31735
32826
  const allPresent = boundaryExists && summaryMessageExists && compactionPartExists && summaryPartExists;
31736
32827
  if (allPresent)
31737
32828
  continue;
31738
32829
  let removedOk = false;
31739
32830
  try {
31740
- removedOk = removeCompactionMarker(state);
32831
+ removedOk = removeCompactionMarker(state2);
31741
32832
  } catch (error51) {
31742
32833
  sessionLog(row.session_id, "compaction-marker consistency: partial cleanup of half-written marker failed:", error51);
31743
32834
  }
@@ -32468,6 +33559,8 @@ If no candidates, omit the \`<primer_candidates>\` section entirely.
32468
33559
 
32469
33560
  Output valid XML only in this shape:
32470
33561
 
33562
+ Closing tags must match their opening tier tag (e.g. \`<p1>...</p1>\`, never \`<p1>...</p2>\`).
33563
+
32471
33564
  \`\`\`xml
32472
33565
  <output>
32473
33566
  <compartments>
@@ -32685,8 +33778,8 @@ function queueDropsForCompartmentalizedMessages(db, sessionId, upToMessageIndex)
32685
33778
  }
32686
33779
 
32687
33780
  // src/hooks/magic-context/compartment-runner-historian.ts
32688
- import { mkdirSync as mkdirSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "node:fs";
32689
- 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";
32690
33783
 
32691
33784
  // src/features/magic-context/subagent-token-capture.ts
32692
33785
  function asNumber(value) {
@@ -32778,161 +33871,6 @@ function recordChildInvocation(input) {
32778
33871
  }
32779
33872
  }
32780
33873
 
32781
- // src/hooks/magic-context/compartment-parser.ts
32782
- var COMPARTMENT_REGEX = /<compartment\s+([^>]*?)\s*>(.*?)<\/compartment>/gs;
32783
- var ATTR_START_REGEX = /\bstart="(\d+)"/;
32784
- var ATTR_END_REGEX = /\bend="(\d+)"/;
32785
- var ATTR_TITLE_REGEX = /\btitle="([^"]*)"/;
32786
- var ATTR_EPISODE_REGEX = /\bepisode_type="([^"]*)"/;
32787
- var ATTR_IMPORTANCE_REGEX = /\bimportance="(\d+)"/;
32788
- function makeTierRegex(n) {
32789
- return new RegExp(`<p${n}\\s*/>|<p${n}\\s*>(.*?)</p${n}>`, "s");
32790
- }
32791
- var TIER_REGEXES = [makeTierRegex(1), makeTierRegex(2), makeTierRegex(3), makeTierRegex(4)];
32792
- var CATEGORY_BLOCK_REGEX = /<(PROJECT_RULES|ARCHITECTURE|CONSTRAINTS|CONFIG_VALUES|NAMING)>(.*?)<\/\1>/gs;
32793
- var FACT_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
32794
- var UNPROCESSED_REGEX = /<unprocessed_from>(\d+)<\/unprocessed_from>/;
32795
- var USER_OBSERVATIONS_REGEX = /<user_observations>(.*?)<\/user_observations>/s;
32796
- var USER_OBS_ITEM_REGEX = /^\s*\*\s*(.+)$/gm;
32797
- var PRIMER_CANDIDATES_REGEX = /<primer_candidates>(.*?)<\/primer_candidates>/s;
32798
- var PRIMER_ELEMENT_REGEX = /<primer\s+at_compartment="(\d+)"\s*>(.*?)<\/primer>/gs;
32799
- var PRIMER_ITEM_REGEX = /^\s*(?:\*|-|\d+\.)\s*(.+)$/gm;
32800
- var FACTS_BLOCK_REGEX = /<facts>(.*?)<\/facts>/s;
32801
- var EVENTS_BLOCK_REGEX = /<events>(.*?)<\/events>/s;
32802
- var EVENT_ELEMENT_REGEX = /<([a-z_]+)\s+at_compartment="(\d+)"\s*>(.*?)<\/\1>/gs;
32803
- var EVENT_FIELD_REGEX = /<([a-z_]+)\s*>(.*?)<\/\1>/gs;
32804
- function extractTier(inner, index) {
32805
- const m = inner.match(TIER_REGEXES[index]);
32806
- if (!m)
32807
- return;
32808
- return unescapeXml((m[1] ?? "").trim());
32809
- }
32810
- function parseCompartmentOutput(text) {
32811
- const compartments = [];
32812
- const facts = [];
32813
- for (const match of text.matchAll(COMPARTMENT_REGEX)) {
32814
- const attrs = match[1];
32815
- const inner = match[2];
32816
- const startMatch = attrs.match(ATTR_START_REGEX);
32817
- const endMatch = attrs.match(ATTR_END_REGEX);
32818
- const titleMatch = attrs.match(ATTR_TITLE_REGEX);
32819
- if (!startMatch || !endMatch || !titleMatch)
32820
- continue;
32821
- const startMessage = parseInt(startMatch[1], 10);
32822
- const endMessage = parseInt(endMatch[1], 10);
32823
- const title = unescapeXml(titleMatch[1]);
32824
- if (Number.isNaN(startMessage) || Number.isNaN(endMessage) || !title)
32825
- continue;
32826
- const episodeMatch = attrs.match(ATTR_EPISODE_REGEX);
32827
- const importanceMatch = attrs.match(ATTR_IMPORTANCE_REGEX);
32828
- const episodeType = episodeMatch ? unescapeXml(episodeMatch[1]) : undefined;
32829
- const importance = importanceMatch ? parseInt(importanceMatch[1], 10) : undefined;
32830
- const p1 = extractTier(inner, 0);
32831
- if (typeof p1 === "string" && p1.length > 0) {
32832
- const p2 = extractTier(inner, 1);
32833
- const p3 = extractTier(inner, 2);
32834
- const p4 = extractTier(inner, 3);
32835
- compartments.push({
32836
- startMessage,
32837
- endMessage,
32838
- title,
32839
- content: p1,
32840
- p1,
32841
- p2: typeof p2 === "string" ? p2 : p1,
32842
- p3: typeof p3 === "string" ? p3 : typeof p2 === "string" ? p2 : p1,
32843
- p4: typeof p4 === "string" ? p4 : "",
32844
- importance,
32845
- episodeType
32846
- });
32847
- continue;
32848
- }
32849
- const content = unescapeXml(inner.trim());
32850
- if (content) {
32851
- compartments.push({
32852
- startMessage,
32853
- endMessage,
32854
- title,
32855
- content,
32856
- importance,
32857
- episodeType
32858
- });
32859
- }
32860
- }
32861
- const factsBlockMatch = text.match(FACTS_BLOCK_REGEX);
32862
- const factsScope = factsBlockMatch ? factsBlockMatch[1] : text.replace(EVENTS_BLOCK_REGEX, "").replace(/<compartment\s+[^>]*?\s*>.*?<\/compartment>/gs, "");
32863
- for (const categoryMatch of factsScope.matchAll(CATEGORY_BLOCK_REGEX)) {
32864
- const category = categoryMatch[1];
32865
- const blockContent = categoryMatch[2];
32866
- for (const itemMatch of blockContent.matchAll(FACT_ITEM_REGEX)) {
32867
- const content = unescapeXml(itemMatch[1].trim());
32868
- if (content) {
32869
- facts.push({ category, content });
32870
- }
32871
- }
32872
- }
32873
- const unprocessedMatch = text.match(UNPROCESSED_REGEX);
32874
- const unprocessedFrom = unprocessedMatch ? parseInt(unprocessedMatch[1], 10) : null;
32875
- const userObservations = [];
32876
- const userObsMatch = text.match(USER_OBSERVATIONS_REGEX);
32877
- if (userObsMatch) {
32878
- for (const itemMatch of userObsMatch[1].matchAll(USER_OBS_ITEM_REGEX)) {
32879
- const obs = unescapeXml(itemMatch[1].trim());
32880
- if (obs)
32881
- userObservations.push(obs);
32882
- }
32883
- }
32884
- const primerCandidates = [];
32885
- const primerMatch = text.match(PRIMER_CANDIDATES_REGEX);
32886
- if (primerMatch) {
32887
- const block = primerMatch[1];
32888
- let sawElement = false;
32889
- for (const el of block.matchAll(PRIMER_ELEMENT_REGEX)) {
32890
- sawElement = true;
32891
- const question = unescapeXml(el[2].trim());
32892
- if (question) {
32893
- primerCandidates.push({
32894
- question,
32895
- originCompartmentIndex: Number.parseInt(el[1], 10)
32896
- });
32897
- }
32898
- }
32899
- if (!sawElement) {
32900
- for (const itemMatch of block.matchAll(PRIMER_ITEM_REGEX)) {
32901
- const question = unescapeXml(itemMatch[1].trim());
32902
- if (question)
32903
- primerCandidates.push({ question });
32904
- }
32905
- }
32906
- }
32907
- const events = parseEvents(text);
32908
- compartments.sort((a, b) => a.startMessage - b.startMessage);
32909
- return { compartments, facts, events, unprocessedFrom, userObservations, primerCandidates };
32910
- }
32911
- function parseEvents(text) {
32912
- const blockMatch = text.match(EVENTS_BLOCK_REGEX);
32913
- if (!blockMatch)
32914
- return [];
32915
- const block = blockMatch[1];
32916
- const events = [];
32917
- for (const elMatch of block.matchAll(EVENT_ELEMENT_REGEX)) {
32918
- const kind = elMatch[1];
32919
- const atRaw = parseInt(elMatch[2], 10);
32920
- const atCompartment = Number.isNaN(atRaw) ? null : atRaw;
32921
- const fields = {};
32922
- for (const fieldMatch of elMatch[3].matchAll(EVENT_FIELD_REGEX)) {
32923
- const name = fieldMatch[1];
32924
- const value = unescapeXml(fieldMatch[2].trim());
32925
- if (value)
32926
- fields[name] = value;
32927
- }
32928
- events.push({ kind, atCompartment, fields });
32929
- }
32930
- return events;
32931
- }
32932
- function unescapeXml(s) {
32933
- return s.replace(/&amp;/g, "&").replace(/&apos;/g, "'").replace(/&quot;/g, '"').replace(/&lt;/g, "<").replace(/&gt;/g, ">");
32934
- }
32935
-
32936
33874
  // src/hooks/magic-context/compartment-runner-mapping.ts
32937
33875
  function tierFieldsOf(c) {
32938
33876
  return {
@@ -33137,6 +34075,24 @@ function historianResponseDumpDir(directory) {
33137
34075
  return getProjectMagicContextHistorianDir(directory);
33138
34076
  }
33139
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
+ }
33140
34096
  async function runValidatedHistorianPass(args) {
33141
34097
  const firstRun = await runHistorianPrompt({
33142
34098
  ...args,
@@ -33202,6 +34158,7 @@ async function runEditorPassOrFallback(args) {
33202
34158
  sessionLog(args.parentSessionId, "historian two-pass: running editor on draft");
33203
34159
  const editorRun = await runHistorianPrompt({
33204
34160
  client: args.client,
34161
+ db: args.db,
33205
34162
  parentSessionId: args.parentSessionId,
33206
34163
  sessionDirectory: args.sessionDirectory,
33207
34164
  prompt: buildHistorianEditorPrompt(args.draftXml),
@@ -33228,6 +34185,7 @@ async function runEditorPassOrFallback(args) {
33228
34185
  async function runHistorianPrompt(args) {
33229
34186
  const {
33230
34187
  client,
34188
+ db,
33231
34189
  parentSessionId,
33232
34190
  sessionDirectory,
33233
34191
  prompt,
@@ -33261,12 +34219,12 @@ async function runHistorianPrompt(args) {
33261
34219
  };
33262
34220
  try {
33263
34221
  sessionLog(parentSessionId, `historian: creating child session (agent=${agentId}, model=${modelOverride ? `${modelOverride.providerID}/${modelOverride.modelID}` : `agent:${agentId}`})`);
33264
- const createResponse = await client.session.create({
33265
- body: {
33266
- parentID: parentSessionId,
33267
- title: "magic-context-compartment"
33268
- },
33269
- query: { directory: sessionDirectory }
34222
+ const createResponse = await createChildSessionWithFence({
34223
+ client,
34224
+ db,
34225
+ parentSessionId,
34226
+ title: "magic-context-compartment",
34227
+ directory: sessionDirectory
33270
34228
  });
33271
34229
  const createdSession = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
33272
34230
  agentSessionId = typeof createdSession?.id === "string" ? createdSession.id : null;
@@ -33314,7 +34272,18 @@ async function runHistorianPrompt(args) {
33314
34272
  preferResponseOnMissingData: true
33315
34273
  });
33316
34274
  const invocationId = recordInvocation({ status: "completed", messages });
33317
- 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;
33318
34287
  if (!result) {
33319
34288
  return {
33320
34289
  ok: false,
@@ -33366,6 +34335,7 @@ async function runFallbackHistorianPass(args) {
33366
34335
  args.callbacks?.onModelFallback?.(modelId, i + 1, chain.length);
33367
34336
  const fallbackRun = await runHistorianPrompt({
33368
34337
  client: args.client,
34338
+ db: args.db,
33369
34339
  parentSessionId: args.parentSessionId,
33370
34340
  sessionDirectory: args.sessionDirectory,
33371
34341
  prompt: args.prompt,
@@ -33427,7 +34397,7 @@ function cleanupHistorianDump(sessionId, dumpPath) {
33427
34397
  if (!dumpPath)
33428
34398
  return;
33429
34399
  try {
33430
- unlinkSync2(dumpPath);
34400
+ unlinkSync3(dumpPath);
33431
34401
  } catch (error51) {
33432
34402
  sessionLog(sessionId, "compartment agent: failed to remove historian response dump", {
33433
34403
  dumpPath,
@@ -33442,7 +34412,7 @@ function dumpHistorianResponse(sessionId, directory, label, text) {
33442
34412
  ensureCortexKitArtifactGitignore(directory);
33443
34413
  const safeSessionId = sanitizeDumpName(sessionId);
33444
34414
  const safeLabel = sanitizeDumpName(label);
33445
- const dumpPath = join6(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
34415
+ const dumpPath = join7(dumpDir, `${safeSessionId}-${safeLabel}-${Date.now()}.xml`);
33446
34416
  writeFileSync2(dumpPath, text, "utf8");
33447
34417
  sessionLog(sessionId, "compartment agent: historian response dumped", {
33448
34418
  label,
@@ -33465,26 +34435,7 @@ function sanitizeDumpName(value) {
33465
34435
  import { Buffer as Buffer3 } from "node:buffer";
33466
34436
 
33467
34437
  // src/features/magic-context/mural/render-trigger.ts
33468
- import { createHash as createHash13 } from "node:crypto";
33469
-
33470
- // src/shared/harness-provider-map.ts
33471
- var PI_TO_CANONICAL_PROVIDER = {
33472
- "openai-codex": "openai",
33473
- "google-antigravity": "google"
33474
- };
33475
- function remapProviderPrefix(ref, map2) {
33476
- if (typeof ref !== "string")
33477
- return ref;
33478
- const slash = ref.indexOf("/");
33479
- if (slash <= 0)
33480
- return ref;
33481
- const provider2 = ref.slice(0, slash);
33482
- const mapped = map2[provider2];
33483
- return mapped ? `${mapped}${ref.slice(slash)}` : ref;
33484
- }
33485
- function piModelRefToCanonical(ref) {
33486
- return remapProviderPrefix(ref, PI_TO_CANONICAL_PROVIDER);
33487
- }
34438
+ import { createHash as createHash14 } from "node:crypto";
33488
34439
 
33489
34440
  // src/features/magic-context/mural/mural-selection.ts
33490
34441
  var DEFAULT_MURAL_MEMORY_BUDGET = 8000;
@@ -33687,6 +34638,8 @@ function naturalLineLengths(entries, roomWidth) {
33687
34638
  let currentCategory = null;
33688
34639
  for (let index = 0;index < entries.length; index++) {
33689
34640
  const entry = entries[index];
34641
+ if (!entry)
34642
+ continue;
33690
34643
  if (entry.category !== currentCategory) {
33691
34644
  currentCategory = entry.category;
33692
34645
  lengths.push(codepoints(` <${entry.category}> `));
@@ -33719,6 +34672,8 @@ function planLines(entries, roomWidth) {
33719
34672
  let currentCategory = null;
33720
34673
  for (let index = 0;index < entries.length; index++) {
33721
34674
  const entry = entries[index];
34675
+ if (!entry)
34676
+ continue;
33722
34677
  if (entry.category !== currentCategory) {
33723
34678
  currentCategory = entry.category;
33724
34679
  lines.push({
@@ -33782,8 +34737,11 @@ function renderLayout(entries, plan, roomWidth, columnCount) {
33782
34737
  const usage = {};
33783
34738
  let filledLineCount = 0;
33784
34739
  for (const [column, columnPlan] of splitPlan(plan, columnCount).entries()) {
34740
+ const columnGrid = grid[column];
34741
+ if (!columnGrid)
34742
+ continue;
33785
34743
  for (const [row, line] of columnPlan.entries()) {
33786
- grid[column][row] = line.text;
34744
+ columnGrid[row] = line.text;
33787
34745
  filledLineCount += 1;
33788
34746
  usage[line.category] = (usage[line.category] ?? 0) + 1;
33789
34747
  const placementLine = row + 1;
@@ -33894,6 +34852,7 @@ function glyph(character) {
33894
34852
  }
33895
34853
  function drawGlyph(pixels, width, height, x, y, character, color) {
33896
34854
  const glyphData = glyph(character);
34855
+ const [red, green, blue] = color;
33897
34856
  for (let row = 0;row < MURAL_CELL_HEIGHT; row++) {
33898
34857
  const pattern = glyphData.rows[row] ?? 0;
33899
34858
  for (let column = 0;column < glyphData.width; column++) {
@@ -33904,9 +34863,9 @@ function drawGlyph(pixels, width, height, x, y, character, color) {
33904
34863
  if (px < 0 || py < 0 || px >= width || py >= height)
33905
34864
  continue;
33906
34865
  const offset = (py * width + px) * 3;
33907
- pixels[offset] = color[0];
33908
- pixels[offset + 1] = color[1];
33909
- pixels[offset + 2] = color[2];
34866
+ pixels[offset] = red;
34867
+ pixels[offset + 1] = green;
34868
+ pixels[offset + 2] = blue;
33910
34869
  }
33911
34870
  }
33912
34871
  }
@@ -33918,6 +34877,7 @@ function drawText(pixels, width, height, x, y, text, color) {
33918
34877
  }
33919
34878
  }
33920
34879
  function fillRect(pixels, canvasWidth, canvasHeight, x, y, width, height, color) {
34880
+ const [red, green, blue] = color;
33921
34881
  const left = Math.max(0, x);
33922
34882
  const top = Math.max(0, y);
33923
34883
  const right = Math.min(canvasWidth, x + width);
@@ -33925,9 +34885,9 @@ function fillRect(pixels, canvasWidth, canvasHeight, x, y, width, height, color)
33925
34885
  for (let py = top;py < bottom; py++) {
33926
34886
  for (let px = left;px < right; px++) {
33927
34887
  const offset = (py * canvasWidth + px) * 3;
33928
- pixels[offset] = color[0];
33929
- pixels[offset + 1] = color[1];
33930
- pixels[offset + 2] = color[2];
34888
+ pixels[offset] = red;
34889
+ pixels[offset + 1] = green;
34890
+ pixels[offset + 2] = blue;
33931
34891
  }
33932
34892
  }
33933
34893
  }
@@ -33954,6 +34914,9 @@ function renderMural(entries) {
33954
34914
  });
33955
34915
  const fittingCandidates = candidates.filter((candidate) => candidate.layout.droppedIds.length === 0);
33956
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");
33957
34920
  const selected = candidatesToCompare.reduce((best, candidate) => {
33958
34921
  if (!best)
33959
34922
  return candidate;
@@ -33964,7 +34927,7 @@ function renderMural(entries) {
33964
34927
  return candidate.tileArea < best.tileArea ? candidate : best;
33965
34928
  }
33966
34929
  return candidate.requestedColumnCount < best.requestedColumnCount ? candidate : best;
33967
- }, candidatesToCompare[0]);
34930
+ }, firstCandidate);
33968
34931
  const { layout, width, height } = selected;
33969
34932
  const pixels = new Uint8Array(width * height * 3).fill(255);
33970
34933
  const contentWidth = layout.columnCount === 0 ? 0 : layout.columnCount * roomWidth * MURAL_CELL_WIDTH + MURAL_COLUMN_GAP * (layout.columnCount - 1) * MURAL_CELL_WIDTH;
@@ -34008,8 +34971,8 @@ function getMuralCoverage(db, projectIdentity) {
34008
34971
  const cueState = getMuralCueState(db, memories.map((memory) => memory.id));
34009
34972
  let cuedMemoryCount = 0;
34010
34973
  for (const memory of memories) {
34011
- const state = cueState.get(memory.id);
34012
- 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)) {
34013
34976
  cuedMemoryCount += 1;
34014
34977
  }
34015
34978
  }
@@ -34023,16 +34986,16 @@ function resolveMural(db, projectIdentity, budgetTokens = DEFAULT_MURAL_MEMORY_B
34023
34986
  const cueState = getMuralCueState(db, overflow.map((memory) => memory.id));
34024
34987
  const entries = [];
34025
34988
  for (const memory of overflow) {
34026
- const state = cueState.get(memory.id);
34027
- if (!state || state.cue === null || state.hash === null)
34989
+ const state2 = cueState.get(memory.id);
34990
+ if (!state2 || state2.cue === null || state2.hash === null)
34028
34991
  continue;
34029
- if (state.hash !== computeCueContentHash(memory.content))
34992
+ if (state2.hash !== computeCueContentHash(memory.content))
34030
34993
  continue;
34031
34994
  entries.push({
34032
34995
  id: memory.id,
34033
34996
  category: memory.category,
34034
34997
  importance: memory.importance ?? 50,
34035
- cue: state.cue
34998
+ cue: state2.cue
34036
34999
  });
34037
35000
  }
34038
35001
  entries.sort(compareMuralEntries);
@@ -34098,7 +35061,7 @@ function ensureMuralRendered(db, projectIdentity, budgetTokens = DEFAULT_MURAL_M
34098
35061
  return { hasMural: false, rerendered: false };
34099
35062
  }
34100
35063
  const rendered = renderMural(entries);
34101
- const textHash = createHash13("sha256").update(rendered.sha256Input).digest("hex");
35064
+ const textHash = createHash14("sha256").update(rendered.sha256Input).digest("hex");
34102
35065
  const existing = getMural(db, projectIdentity);
34103
35066
  if (existing && existing.contentHash === textHash && existing.width === rendered.width && existing.height === rendered.height) {
34104
35067
  return {
@@ -34540,6 +35503,38 @@ var INJECTION_CACHE_MAX = 100;
34540
35503
  var injectionCache = new BoundedSessionMap(INJECTION_CACHE_MAX);
34541
35504
  function clearInjectionCache(sessionId) {
34542
35505
  injectionCache.delete(sessionId);
35506
+ resetDegradedReanchorState(sessionId);
35507
+ }
35508
+ var degradedRebuildCountBySession = new BoundedSessionMap(INJECTION_CACHE_MAX);
35509
+ var reAnchorLoggedBySession = new BoundedSessionMap(INJECTION_CACHE_MAX);
35510
+ var REANCHOR_MIN_DEGRADED_PASSES = 2;
35511
+ function resetDegradedReanchorState(sessionId) {
35512
+ degradedRebuildCountBySession.delete(sessionId);
35513
+ reAnchorLoggedBySession.delete(sessionId);
35514
+ }
35515
+ function noteDegradedRebuild(sessionId) {
35516
+ const next = (degradedRebuildCountBySession.get(sessionId) ?? 0) + 1;
35517
+ degradedRebuildCountBySession.set(sessionId, next);
35518
+ return next;
35519
+ }
35520
+ function clearDegradedRebuild(sessionId) {
35521
+ degradedRebuildCountBySession.delete(sessionId);
35522
+ reAnchorLoggedBySession.delete(sessionId);
35523
+ }
35524
+ function logReanchorOnce(sessionId, message) {
35525
+ if (reAnchorLoggedBySession.get(sessionId))
35526
+ return;
35527
+ reAnchorLoggedBySession.set(sessionId, true);
35528
+ sessionLog(sessionId, message);
35529
+ }
35530
+ function findVisibleReanchorIndex(compartments, visibleMessageIds) {
35531
+ for (let index = compartments.length - 1;index >= 0; index -= 1) {
35532
+ const endMessageId = compartments[index]?.endMessageId;
35533
+ if (typeof endMessageId === "string" && endMessageId.length > 0 && visibleMessageIds.has(endMessageId)) {
35534
+ return index;
35535
+ }
35536
+ }
35537
+ return -1;
34543
35538
  }
34544
35539
  function getVisibleMemoryIds(db, sessionId) {
34545
35540
  try {
@@ -34729,24 +35724,63 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
34729
35724
  return result2;
34730
35725
  }
34731
35726
  let skippedVisibleMessages = 0;
35727
+ let needsFreshMaterialization = false;
35728
+ let resultEndMessage = lastEnd;
35729
+ let resultEndMessageId = null;
34732
35730
  const cutoffIndex = messages.findIndex((message) => message.info.id === trimEndMessageId);
34733
35731
  if (cutoffIndex >= 0) {
35732
+ clearDegradedRebuild(sessionId);
34734
35733
  skippedVisibleMessages = cutoffIndex + 1;
34735
35734
  const remaining = messages.slice(cutoffIndex + 1);
34736
35735
  messages.splice(0, messages.length, ...remaining);
35736
+ resultEndMessageId = trimEndMessageId;
34737
35737
  } else {
34738
- sessionLog(sessionId, `compartment injection entering degraded mode: boundary ${trimEndMessageId} not in visible messages`);
35738
+ const degradedCount = noteDegradedRebuild(sessionId);
35739
+ if (degradedCount === 1) {
35740
+ reconcileForkOrphanedCompactionMarkers(db, sessionId);
35741
+ }
35742
+ let reAnchored = false;
35743
+ if (degradedCount >= REANCHOR_MIN_DEGRADED_PASSES && isCacheBusting) {
35744
+ const visibleMessageIds = new Set;
35745
+ for (const message of messages) {
35746
+ if (typeof message.info.id === "string")
35747
+ visibleMessageIds.add(message.info.id);
35748
+ }
35749
+ const reAnchorIndex = findVisibleReanchorIndex(compartments, visibleMessageIds);
35750
+ if (reAnchorIndex >= 0) {
35751
+ const reAnchorCompartment = compartments[reAnchorIndex];
35752
+ const reAnchorCutoff = messages.findIndex((message) => message.info.id === reAnchorCompartment.endMessageId);
35753
+ if (reAnchorCutoff >= 0) {
35754
+ skippedVisibleMessages = reAnchorCutoff + 1;
35755
+ const remaining = messages.slice(reAnchorCutoff + 1);
35756
+ messages.splice(0, messages.length, ...remaining);
35757
+ resultEndMessage = reAnchorCompartment.endMessage;
35758
+ resultEndMessageId = reAnchorCompartment.endMessageId;
35759
+ reAnchored = true;
35760
+ logReanchorOnce(sessionId, `compartment injection re-anchored: natural boundary ${trimEndMessageId} not visible for ${degradedCount} passes; splicing at visible compartment boundary ${resultEndMessageId} (ordinal ${resultEndMessage})`);
35761
+ }
35762
+ }
35763
+ if (!reAnchored) {
35764
+ needsFreshMaterialization = true;
35765
+ logReanchorOnce(sessionId, `compartment injection degraded: boundary ${trimEndMessageId} not visible for ${degradedCount} passes and no compartment boundary is visible; requesting fresh materialization to re-cut the baseline`);
35766
+ }
35767
+ } else {
35768
+ sessionLog(sessionId, `compartment injection entering degraded mode: boundary ${trimEndMessageId} not in visible messages (consecutive degraded passes: ${degradedCount})`);
35769
+ }
34739
35770
  }
34740
35771
  const result = {
34741
35772
  block,
34742
- compartmentEndMessage: lastEnd,
34743
- compartmentEndMessageId: cutoffIndex >= 0 ? trimEndMessageId : null,
35773
+ compartmentEndMessage: resultEndMessage,
35774
+ compartmentEndMessageId: resultEndMessageId,
34744
35775
  compartmentCount: compartments.length,
34745
35776
  skippedVisibleMessages,
34746
35777
  factCount: facts.length,
34747
35778
  memoryCount,
34748
35779
  rebuiltFromDb: true
34749
35780
  };
35781
+ if (needsFreshMaterialization) {
35782
+ result.needsFreshMaterialization = true;
35783
+ }
34750
35784
  injectionCache.set(sessionId, { kind: "populated", injection: result });
34751
35785
  return result;
34752
35786
  }
@@ -35152,41 +36186,41 @@ function readCurrentM0SnapshotMarkers(args) {
35152
36186
  });
35153
36187
  return fresh.markers;
35154
36188
  }
35155
- function snapshotMarkersFromCachedM0(state) {
35156
- if (!state.cachedM0Bytes)
36189
+ function snapshotMarkersFromCachedM0(state2) {
36190
+ if (!state2.cachedM0Bytes)
35157
36191
  return null;
35158
- const cachedUpgradeIdentity = decodeCachedM0UpgradeIdentity(state.cachedM0UpgradeState);
35159
- if (state.cachedM0ProjectMemoryEpoch === null)
36192
+ const cachedUpgradeIdentity = decodeCachedM0UpgradeIdentity(state2.cachedM0UpgradeState);
36193
+ if (state2.cachedM0ProjectMemoryEpoch === null)
35160
36194
  return null;
35161
- if (state.cachedM0ProjectUserProfileVersion === null)
36195
+ if (state2.cachedM0ProjectUserProfileVersion === null)
35162
36196
  return null;
35163
- if (state.cachedM0MaxCompartmentSeq === null)
36197
+ if (state2.cachedM0MaxCompartmentSeq === null)
35164
36198
  return null;
35165
- if (state.cachedM0MaxMemoryId === null)
36199
+ if (state2.cachedM0MaxMemoryId === null)
35166
36200
  return null;
35167
- if (state.cachedM0MaxMutationId === null)
36201
+ if (state2.cachedM0MaxMutationId === null)
35168
36202
  return null;
35169
- if (state.cachedM0MaxMemoryMutationId === null)
36203
+ if (state2.cachedM0MaxMemoryMutationId === null)
35170
36204
  return null;
35171
- if (state.cachedM0SessionFactsVersion === null)
36205
+ if (state2.cachedM0SessionFactsVersion === null)
35172
36206
  return null;
35173
36207
  return {
35174
- projectMemoryEpoch: state.cachedM0ProjectMemoryEpoch,
35175
- workspaceFingerprint: state.cachedM0WorkspaceFingerprint,
35176
- projectUserProfileVersion: state.cachedM0ProjectUserProfileVersion,
35177
- maxCompartmentSeq: state.cachedM0MaxCompartmentSeq,
35178
- maxMemoryId: state.cachedM0MaxMemoryId,
35179
- maxMutationId: state.cachedM0MaxMutationId,
35180
- maxMemoryMutationId: state.cachedM0MaxMemoryMutationId,
35181
- projectDocsHash: state.cachedM0ProjectDocsHash ?? "",
35182
- materializedAt: state.cachedM0MaterializedAt ?? 0,
35183
- 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,
35184
36218
  upgradeState: cachedUpgradeIdentity.upgradeState,
35185
36219
  compartmentRenderEpoch: cachedUpgradeIdentity.compartmentRenderEpoch,
35186
- systemHash: state.cachedM0SystemHash ?? "",
35187
- modelKey: state.cachedM0ModelKey ?? "",
35188
- projectIdentity: state.cachedM0ProjectIdentity ?? null,
35189
- muralHash: state.cachedM0MuralHash ?? null
36220
+ systemHash: state2.cachedM0SystemHash ?? "",
36221
+ modelKey: state2.cachedM0ModelKey ?? "",
36222
+ projectIdentity: state2.cachedM0ProjectIdentity ?? null,
36223
+ muralHash: state2.cachedM0MuralHash ?? null
35190
36224
  };
35191
36225
  }
35192
36226
  function mustMaterialize(args) {
@@ -35502,26 +36536,26 @@ ${sessionHistory}
35502
36536
 
35503
36537
  `).trim();
35504
36538
  }
35505
- function applyMarkersToState(state, m0Bytes, markers, m1Bytes) {
35506
- state.cachedM0Bytes = m0Bytes;
36539
+ function applyMarkersToState(state2, m0Bytes, markers, m1Bytes) {
36540
+ state2.cachedM0Bytes = m0Bytes;
35507
36541
  if (m1Bytes)
35508
- state.cachedM1Bytes = m1Bytes;
35509
- state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
35510
- state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
35511
- state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
35512
- state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
35513
- state.cachedM0MaxMemoryId = markers.maxMemoryId;
35514
- state.cachedM0MaxMutationId = markers.maxMutationId;
35515
- state.cachedM0MaxMemoryMutationId = markers.maxMemoryMutationId;
35516
- state.cachedM0ProjectDocsHash = markers.projectDocsHash;
35517
- state.cachedM0MaterializedAt = markers.materializedAt;
35518
- state.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
35519
- state.cachedM0UpgradeState = encodeCachedM0UpgradeIdentity(markers.upgradeState, markers.compartmentRenderEpoch);
35520
- state.cachedM0SystemHash = markers.systemHash;
35521
- state.cachedM0ModelKey = markers.modelKey;
35522
- state.cachedM0ProjectIdentity = markers.projectIdentity;
35523
- state.cachedM0MuralHash = markers.muralHash ?? null;
35524
- 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;
35525
36559
  }
35526
36560
  function historySliceTokens(m0Text) {
35527
36561
  const slice = extractM0Block(m0Text, "session-history");
@@ -35571,7 +36605,7 @@ function materializeM0(options) {
35571
36605
  });
35572
36606
  docs = readProjectDocsForM0(projectDirectory, options.injectDocs);
35573
36607
  snapshotMarkers.projectDocsHash = docs.canonicalHash;
35574
- compartments = readM0Compartments(options.db, options.sessionId);
36608
+ compartments = options.compactionOff ? [] : readM0Compartments(options.db, options.sessionId);
35575
36609
  facts = [];
35576
36610
  memories = projectPath ? workspace.isWorkspaced ? getMemoriesByProjects(options.db, workspace.expandedIdentities, ["active", "permanent"], foldMaterializedAt, workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(options.db, projectPath, ["active", "permanent"], foldMaterializedAt) : [];
35577
36611
  userMemories = safeGetActiveUserMemories(options.db);
@@ -35936,39 +36970,39 @@ function markersFromCachedRow(row) {
35936
36970
  muralHash: row.cached_m0_mural_hash ?? null
35937
36971
  };
35938
36972
  }
35939
- function cachedRowMatchesState(row, state) {
35940
- 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);
35941
36975
  }
35942
- function applyCachedRowToState(state, row) {
36976
+ function applyCachedRowToState(state2, row) {
35943
36977
  const markers = markersFromCachedRow(row);
35944
36978
  if (!row.cached_m0_bytes || !row.cached_m1_bytes || !markers) {
35945
- throw new RenderM1InvalidMarkersError(state.sessionId);
35946
- }
35947
- state.cachedM0Bytes = toBuffer(row.cached_m0_bytes);
35948
- state.cachedM0MuralDataUrl = row.cached_m0_mural_data_url ?? null;
35949
- state.cachedM0MuralHash = row.cached_m0_mural_hash ?? null;
35950
- state.cachedM1Bytes = toBuffer(row.cached_m1_bytes);
35951
- state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
35952
- state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
35953
- state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
35954
- state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
35955
- state.cachedM0MaxMemoryId = markers.maxMemoryId;
35956
- state.cachedM0MaxMutationId = markers.maxMutationId;
35957
- state.cachedM0MaxMemoryMutationId = markers.maxMemoryMutationId;
35958
- state.cachedM0ProjectDocsHash = markers.projectDocsHash;
35959
- state.cachedM0MaterializedAt = markers.materializedAt;
35960
- state.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
35961
- state.cachedM0UpgradeState = encodeCachedM0UpgradeIdentity(markers.upgradeState, markers.compartmentRenderEpoch);
35962
- state.cachedM0SystemHash = markers.systemHash;
35963
- state.cachedM0ModelKey = markers.modelKey;
35964
- state.cachedM0ProjectIdentity = markers.projectIdentity;
35965
- state.snapshotMarkers = markers;
35966
- }
35967
- function replayCachedM1(state) {
35968
- if (!state.cachedM1Bytes) {
35969
- throw new RenderM1InvalidMarkersError(state.sessionId);
35970
- }
35971
- 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;
35972
37006
  }
35973
37007
  function softRefreshCachedM1(options) {
35974
37008
  options.db.exec("BEGIN IMMEDIATE");
@@ -36052,7 +37086,7 @@ function renderFreshM0NonPersisted(options) {
36052
37086
  const docs = readProjectDocsForM0(projectDirectory ?? "", options.injectDocs);
36053
37087
  snapshotMarkers.projectDocsHash = docs.canonicalHash;
36054
37088
  snapshotMarkers.materializedAt = options.state.cachedM0MaterializedAt ?? 0;
36055
- 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);
36056
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) : [];
36057
37091
  const userMemories = safeGetActiveUserMemories(options.db);
36058
37092
  const memoryBudget = options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
@@ -36130,7 +37164,7 @@ function injectM0M1(options) {
36130
37164
  m0Bytes: options.state.cachedM0Bytes,
36131
37165
  m1Text: null
36132
37166
  };
36133
- if (options.state.isSubagent)
37167
+ if (options.state.isSubagent && !options.compactionOff)
36134
37168
  return skipped;
36135
37169
  const decision = mustMaterialize({
36136
37170
  db: options.db,
@@ -36259,14 +37293,14 @@ function onNoteTrigger(db, sessionId, trigger) {
36259
37293
  sessionLog(sessionId, `note-nudge: trigger fired (${trigger}), triggerPending=true`);
36260
37294
  }
36261
37295
  function peekNoteNudgeText(db, sessionId, currentUserMessageId, projectIdentity, noteReadStillVisible) {
36262
- const state = getPersistedNoteNudge(db, sessionId);
36263
- if (!state.triggerPending)
37296
+ const state2 = getPersistedNoteNudge(db, sessionId);
37297
+ if (!state2.triggerPending)
36264
37298
  return null;
36265
- if (!state.triggerMessageId && currentUserMessageId) {
37299
+ if (!state2.triggerMessageId && currentUserMessageId) {
36266
37300
  setPersistedNoteNudgeTriggerMessageId(db, sessionId, currentUserMessageId);
36267
- state.triggerMessageId = currentUserMessageId;
37301
+ state2.triggerMessageId = currentUserMessageId;
36268
37302
  }
36269
- if (state.triggerMessageId && currentUserMessageId && state.triggerMessageId === currentUserMessageId) {
37303
+ if (state2.triggerMessageId && currentUserMessageId && state2.triggerMessageId === currentUserMessageId) {
36270
37304
  sessionLog(sessionId, `note-nudge: deferring — current user message ${currentUserMessageId} is same as trigger-time message`);
36271
37305
  return null;
36272
37306
  }
@@ -36468,29 +37502,29 @@ function callIdFromPart(part) {
36468
37502
  const direct = firstStringField(part, ["callID", "callId", "toolCallId", "tool_call_id", "id"]);
36469
37503
  if (direct)
36470
37504
  return direct;
36471
- const state = isRecord(part.state) ? part.state : null;
36472
- 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"]) ?? "" : "";
36473
37507
  }
36474
37508
  function toolSignalFromPart(part) {
36475
37509
  if (!isRecord(part))
36476
37510
  return null;
36477
37511
  const type = partType(part);
36478
- const state = isRecord(part.state) ? part.state : null;
37512
+ const state2 = isRecord(part.state) ? part.state : null;
36479
37513
  const callId = callIdFromPart(part);
36480
37514
  if (!callId && type !== "tool")
36481
37515
  return null;
36482
37516
  if (type === "tool") {
36483
- const hasInput = state !== null && hasOwn(state, "input");
36484
- 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;
36485
37519
  const hasOutput = outputKey !== null;
36486
- const outputValue = outputKey && state ? state[outputKey] : undefined;
37520
+ const outputValue = outputKey && state2 ? state2[outputKey] : undefined;
36487
37521
  const providerExecuted = part.providerExecuted === true;
36488
37522
  const openInvocation = !providerExecuted && !hasOutput;
36489
37523
  return {
36490
37524
  callId,
36491
37525
  hasInput: hasInput || openInvocation,
36492
37526
  hasOutput,
36493
- inputText: hasInput && state ? stringValue(state.input) : "",
37527
+ inputText: hasInput && state2 ? stringValue(state2.input) : "",
36494
37528
  outputText: hasOutput ? stringValue(outputValue) : ""
36495
37529
  };
36496
37530
  }
@@ -36718,24 +37752,27 @@ function tokenForMessage(message, options) {
36718
37752
  function buildTrueRawTokenIndex(sessionId, messages, options) {
36719
37753
  const ordered = [...messages].sort((a, b) => a.ordinal - b.ordinal);
36720
37754
  const sliceCount = ordered.length;
36721
- const maxOrdinal = ordered.length > 0 ? ordered[ordered.length - 1].ordinal : 0;
36722
- 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;
36723
37759
  const tokensByOrdinal = new Map;
36724
37760
  const idsByOrdinal = new Map;
36725
- const prefix = new Array(rawMessageCount + 1).fill(0);
37761
+ const prefix = new Array(ordinalSpan + 1).fill(0);
36726
37762
  for (const message of ordered) {
36727
37763
  const stored = options.storedTotalForMessage?.(message);
36728
37764
  const total = stored !== undefined && stored !== null ? stored : tokenForMessage(message, options).total;
36729
37765
  tokensByOrdinal.set(message.ordinal, total);
36730
37766
  idsByOrdinal.set(message.ordinal, message.id);
36731
- if (message.ordinal >= 1 && message.ordinal <= rawMessageCount) {
36732
- prefix[message.ordinal] = total;
37767
+ const relative = message.ordinal - firstOrdinal + 1;
37768
+ if (relative >= 1 && relative <= ordinalSpan) {
37769
+ prefix[relative] = total;
36733
37770
  }
36734
37771
  }
36735
- for (let k = 1;k <= rawMessageCount; k += 1) {
37772
+ for (let k = 1;k <= ordinalSpan; k += 1) {
36736
37773
  prefix[k] += prefix[k - 1];
36737
37774
  }
36738
- const ordinalToIndex = (ordinal) => Math.max(0, Math.min(rawMessageCount, ordinal - 1));
37775
+ const ordinalToIndex = (ordinal) => Math.max(0, Math.min(ordinalSpan, ordinal - firstOrdinal));
36739
37776
  return {
36740
37777
  sessionId,
36741
37778
  providerShapeVersion: options.providerShapeVersion,
@@ -36747,27 +37784,27 @@ function buildTrueRawTokenIndex(sessionId, messages, options) {
36747
37784
  return idsByOrdinal.get(ordinal) ?? null;
36748
37785
  },
36749
37786
  suffixTokensFromOrdinal(ordinal) {
36750
- if (ordinal <= 1)
36751
- return prefix[rawMessageCount];
36752
- if (ordinal > rawMessageCount)
37787
+ if (ordinal <= firstOrdinal)
37788
+ return prefix[ordinalSpan];
37789
+ if (ordinal > terminalOrdinal)
36753
37790
  return 0;
36754
- return prefix[rawMessageCount] - prefix[ordinalToIndex(ordinal)];
37791
+ return prefix[ordinalSpan] - prefix[ordinalToIndex(ordinal)];
36755
37792
  },
36756
37793
  rangeTokens(startInclusive, endExclusive) {
36757
- const start = Math.max(1, startInclusive);
36758
- const end = Math.max(start, Math.min(rawMessageCount + 1, endExclusive));
36759
- 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];
36760
37797
  },
36761
37798
  findSuffixStartForTokens(tokens) {
36762
37799
  if (!Number.isFinite(tokens) || tokens <= 0)
36763
- return rawMessageCount + 1;
37800
+ return terminalOrdinal + 1;
36764
37801
  const target = Math.max(0, Math.floor(tokens));
36765
- const total = prefix[rawMessageCount];
37802
+ const total = prefix[ordinalSpan];
36766
37803
  if (total < target)
36767
- return 1;
37804
+ return firstOrdinal;
36768
37805
  const cut = total - target;
36769
37806
  let lo = 0;
36770
- let hi = rawMessageCount;
37807
+ let hi = ordinalSpan;
36771
37808
  let best = 0;
36772
37809
  while (lo <= hi) {
36773
37810
  const mid = lo + hi >> 1;
@@ -36778,29 +37815,31 @@ function buildTrueRawTokenIndex(sessionId, messages, options) {
36778
37815
  hi = mid - 1;
36779
37816
  }
36780
37817
  }
36781
- return best + 1;
37818
+ return firstOrdinal + best;
36782
37819
  },
36783
37820
  findHeadEndForCap(startInclusive, endExclusive, capTokens) {
36784
- const start = Math.max(1, Math.min(rawMessageCount + 1, startInclusive));
36785
- 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));
36786
37823
  if (!Number.isFinite(capTokens) || capTokens <= 0)
36787
37824
  return start;
36788
- const startPrefix = prefix[start - 1];
36789
- const cut = startPrefix + Math.floor(capTokens);
36790
- let lo = start;
36791
- let hi = end - 1;
36792
- 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;
36793
37831
  while (lo <= hi) {
36794
37832
  const mid = lo + hi >> 1;
36795
37833
  if (prefix[mid] <= cut) {
36796
- bestEnd = mid + 1;
37834
+ bestEndIndex = mid;
36797
37835
  lo = mid + 1;
36798
37836
  } else {
36799
37837
  hi = mid - 1;
36800
37838
  }
36801
37839
  }
37840
+ let bestEnd = firstOrdinal + bestEndIndex;
36802
37841
  if (bestEnd === start && start < end)
36803
- return start + 1;
37842
+ bestEnd = start + 1;
36804
37843
  return Math.min(bestEnd, end);
36805
37844
  }
36806
37845
  };
@@ -37117,7 +38156,8 @@ function resolveProtectedTailBoundary(ctx) {
37117
38156
  if (ctx.migrationFloorActive)
37118
38157
  runtimeFloor = Math.max(runtimeFloor, ctx.priorBoundaryOrdinal);
37119
38158
  let protectedTailStart = Math.max(boundary, runtimeFloor);
37120
- if (!ctx.emergencyTailScale && usagePercentage < 80) {
38159
+ const forceMaterializationPercentage = escalationBands(ctx.executeThresholdPercentage).forceMaterializationPercentage;
38160
+ if (!ctx.emergencyTailScale && usagePercentage < forceMaterializationPercentage) {
37121
38161
  let lastMeaningfulUserOrdinal = 0;
37122
38162
  for (let i = messages.length - 1;i >= 0; i--) {
37123
38163
  const message = messages[i];
@@ -37358,7 +38398,8 @@ function getRawHistoryEligibility(db, sessionId) {
37358
38398
  function hasRunnableCompartmentWindow(snapshot) {
37359
38399
  if (snapshot.offset >= snapshot.protectedTailStart)
37360
38400
  return false;
37361
- if (snapshot.usagePercentage >= 80 || snapshot.emergencyTailScale) {
38401
+ const forceMaterializationPercentage = escalationBands(snapshot.executeThresholdPercentage).forceMaterializationPercentage;
38402
+ if (snapshot.usagePercentage >= forceMaterializationPercentage || snapshot.emergencyTailScale) {
37362
38403
  return snapshot.trueRawEligibleTokens >= deriveMinForceEligibleTokens(snapshot.N) || snapshot.eligibleEndOrdinal > snapshot.offset;
37363
38404
  }
37364
38405
  return snapshot.eligibleEndOrdinal > snapshot.offset;
@@ -37421,8 +38462,10 @@ function validateBoundarySnapshot(args) {
37421
38462
  return { ok: true };
37422
38463
  }
37423
38464
  function recordHighPressureNoEligibleHead(db, snapshot) {
37424
- if (snapshot.usagePercentage < 80 && !snapshot.emergencyTailScale)
38465
+ const forceMaterializationPercentage = escalationBands(snapshot.executeThresholdPercentage).forceMaterializationPercentage;
38466
+ if (snapshot.usagePercentage < forceMaterializationPercentage && !snapshot.emergencyTailScale) {
37425
38467
  return 0;
38468
+ }
37426
38469
  return recordProtectedTailNoEligibleHead(db, snapshot.sessionId);
37427
38470
  }
37428
38471
 
@@ -39453,6 +40496,7 @@ ${chunkText}`,
39453
40496
  retainDrainReservationForRetryThrottle = true;
39454
40497
  const validatedPass = await runValidatedHistorianPass({
39455
40498
  client,
40499
+ db,
39456
40500
  parentSessionId: sessionId,
39457
40501
  sessionDirectory,
39458
40502
  prompt,
@@ -39913,6 +40957,7 @@ Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${c
39913
40957
  emitProgress(`Running historian (pass ${passCount + 1})…`);
39914
40958
  const validatedPass = await runValidatedHistorianPass({
39915
40959
  client,
40960
+ db,
39916
40961
  parentSessionId: sessionId,
39917
40962
  sessionDirectory,
39918
40963
  prompt,
@@ -40332,6 +41377,7 @@ ${chunk.text}`,
40332
41377
  Historian pass ${passCount + 1}, attempt ${passAttempt} started for messages ${chunk.startIndex}-${chunk.endIndex}.`, notifParams());
40333
41378
  const validatedPass = await runValidatedHistorianPass({
40334
41379
  client,
41380
+ db,
40335
41381
  parentSessionId: sessionId,
40336
41382
  sessionDirectory,
40337
41383
  prompt,
@@ -40583,7 +41629,7 @@ async function executeContextRecomp(deps, options = {}) {
40583
41629
  }
40584
41630
 
40585
41631
  // src/hooks/magic-context/lkg-slot.ts
40586
- import { createHash as createHash14 } from "node:crypto";
41632
+ import { createHash as createHash15 } from "node:crypto";
40587
41633
  var LKG_TOTAL_BYTES = 64 * 1024 * 1024;
40588
41634
  var LKG_SINGLE_SLOT_BYTES = 24 * 1024 * 1024;
40589
41635
  var LKG_METADATA_BYTES = 256;
@@ -40594,7 +41640,7 @@ function slotBytes(slot) {
40594
41640
  return 2 * slot.jsonPrefix.length + digestBytes + LKG_METADATA_BYTES;
40595
41641
  }
40596
41642
  function lkgContentDigest(message) {
40597
- const hash2 = createHash14("sha256");
41643
+ const hash2 = createHash15("sha256");
40598
41644
  const seen = new WeakSet;
40599
41645
  const visit = (value) => {
40600
41646
  if (value === null) {
@@ -40960,4 +42006,4 @@ async function runUpgradeMemoryMigration(ctx, sessionId, migrationDirectory) {
40960
42006
  }
40961
42007
  }
40962
42008
 
40963
- 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 };