@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
package/dist/index.js CHANGED
@@ -1,7 +1,12 @@
1
1
  import {
2
+ CANONICAL_DREAM_TASKS,
2
3
  buildDreamTaskRuntimeConfigs,
4
+ compareTaskOrder,
5
+ isCanonicalDreamTask,
6
+ leaseKeyFor,
7
+ leaseKindFor,
3
8
  userMemoryCollectionEnabled
4
- } from "./index-kxz4tn6m.js";
9
+ } from "./index-56yjaeb2.js";
5
10
  import {
6
11
  AGE_RECLAIM_MIN_TOKENS,
7
12
  AdmissionClass,
@@ -17,7 +22,9 @@ import {
17
22
  GIT_SWEEP_LEASE_RENEWAL_MS,
18
23
  GLOBAL_USER_PROFILE_PROJECT_PATH,
19
24
  HISTORIAN_EDITOR_SYSTEM_PROMPT,
25
+ LATEST_SUPPORTED_VERSION,
20
26
  MARKER_SUMMARY_TEXT,
27
+ MAX_EXECUTE_THRESHOLD,
21
28
  MagicContextConfigSchema,
22
29
  ModuleMemoryAuthorityError,
23
30
  PRIMER_CANDIDATE_MAX_AGE_MS,
@@ -68,6 +75,7 @@ import {
68
75
  clearNoteNudgeTriggerAndCooldown,
69
76
  clearNoteNudgeTriggerOnly,
70
77
  clearPendingCompactionMarkerStateIf,
78
+ clearPendingOps,
71
79
  clearPersistedReasoningWatermark,
72
80
  clearPersistedTodoSyntheticAnchor,
73
81
  clearRecompStaging,
@@ -78,6 +86,7 @@ import {
78
86
  cosineSimilarity,
79
87
  countEmbeddedCommits,
80
88
  countPrimerCandidatesForProject,
89
+ createChildSessionWithFence,
81
90
  createPrimer,
82
91
  deleteTagsByMessageId,
83
92
  deleteUserMemoryCandidates,
@@ -99,6 +108,7 @@ import {
99
108
  enqueueShadowEmbeddingItems,
100
109
  ensureContextStoreUuid,
101
110
  ensureMemoryEmbeddings,
111
+ escalationBands,
102
112
  estimateTrueRawMessageTokens,
103
113
  expandWorkspaceIdentitySetWithAliases,
104
114
  exports_external,
@@ -117,6 +127,7 @@ import {
117
127
  getCandidateToolOwners,
118
128
  getChannel2NudgeClaim,
119
129
  getChannel2NudgeState,
130
+ getCompactionModeRecord,
120
131
  getCompartmentEvents,
121
132
  getCompartments,
122
133
  getContextStoreUuid,
@@ -145,6 +156,7 @@ import {
145
156
  getMemoryCountsByStatus,
146
157
  getMemoryMutationsForRenderByProjects,
147
158
  getMemoryVerifications,
159
+ getMigrationOnOpenRefusal,
148
160
  getMirrorCursor,
149
161
  getModuleNoteEvaluationBridge,
150
162
  getMural,
@@ -161,6 +173,8 @@ import {
161
173
  getPersistedCompactionMarkerState,
162
174
  getPersistedNoteNudge,
163
175
  getPersistedReasoningWatermark,
176
+ getPersistedSchemaVersion,
177
+ getPersistedTodoPermissionDenied,
164
178
  getPersistedTodoSyntheticAnchor,
165
179
  getPrimaryEmbeddingMeasurementCohort,
166
180
  getPrimerCandidatesByIds,
@@ -207,6 +221,7 @@ import {
207
221
  isDatabasePersisted,
208
222
  isEmbeddingEnabled,
209
223
  isEmergencyRecoveryArmed,
224
+ isPidAlive,
210
225
  isProviderOverflowReconfirmed,
211
226
  lkgContentDigest,
212
227
  loadCompartmentChunkEmbeddingsForSearch,
@@ -234,6 +249,7 @@ import {
234
249
  openDatabaseAsync,
235
250
  parkGitSweepNonIndexable,
236
251
  parseCron,
252
+ parseRpcPortFile,
237
253
  peekDeferredExecutePending,
238
254
  peekNoteNudgeText,
239
255
  peekProjectEmbeddings,
@@ -273,6 +289,7 @@ import {
273
289
  releaseWrapupInProgress,
274
290
  removeAutoSearchHintDecisionByMessageId,
275
291
  removeCompactionMarkerForSession,
292
+ removeMcOwnedCompactionMarkers,
276
293
  removeNoteNudgeAnchorByMessageId,
277
294
  removePendingOp,
278
295
  removeStrippedPlaceholderId,
@@ -285,6 +302,7 @@ import {
285
302
  resetLastNudgeCycleIfTailShrank,
286
303
  resetNoteNudgeCooldownOnly,
287
304
  resetProtectedTailNoEligibleHead,
305
+ resolveCompactionModeRecord,
288
306
  resolveGitTopLevel,
289
307
  resolveOpenCodeProtectedTailBoundary,
290
308
  resolveProjectIdentity,
@@ -294,6 +312,8 @@ import {
294
312
  resolveWorkspaceIdentitySet,
295
313
  resolveWorkspaceShareCategories,
296
314
  resolveWrapupProtectedTailBoundary,
315
+ rpcPortDir,
316
+ rpcPortFilePath,
297
317
  runCompartmentAgent,
298
318
  runManagedRecomp,
299
319
  runManagedUpgrade,
@@ -305,6 +325,8 @@ import {
305
325
  scheduleAfterBootQuiet,
306
326
  searchMemoriesFTS,
307
327
  searchMemoriesFTSUnion,
328
+ setChannel2NudgeState,
329
+ setCompactionModeRecord,
308
330
  setDeferredExecutePendingIfAbsent,
309
331
  setEmergencyDropSample,
310
332
  setKeepSubagents,
@@ -313,7 +335,9 @@ import {
313
335
  setMemoryClassification,
314
336
  setMuralCue,
315
337
  setNoteLastReadAt,
338
+ setPersistedCompactionMarkerState,
316
339
  setPersistedReasoningWatermark,
340
+ setPersistedTodoPermissionDenied,
317
341
  setPersistedTodoSyntheticAnchor,
318
342
  setRecompStarting,
319
343
  setRecompTerminal,
@@ -345,7 +369,7 @@ import {
345
369
  upsertCommits,
346
370
  verificationFileExists,
347
371
  withContentLanguageDirective
348
- } from "./index-h86twgsp.js";
372
+ } from "./index-s0mdn690.js";
349
373
  import {
350
374
  deriveHistorianChunkTokens,
351
375
  deriveTriggerBudget,
@@ -353,27 +377,24 @@ import {
353
377
  isSaneLimit,
354
378
  refreshModelLimitsAfterAuthOnce,
355
379
  refreshModelLimitsFromApi,
356
- resolveHistorianContextLimit
357
- } from "./index-63dq2g4d.js";
358
- import {
359
- CANONICAL_DREAM_TASKS,
360
- compareTaskOrder,
361
- isCanonicalDreamTask,
362
- leaseKeyFor,
363
- leaseKindFor
364
- } from "./index-anhrfygk.js";
380
+ resolveHistorianContextLimit,
381
+ setOutputReserveConfig,
382
+ setStoragePrivatePermissionEnforcement,
383
+ shouldEnforcePrivateStoragePermissions
384
+ } from "./index-ry8rh8cv.js";
365
385
  import {
366
386
  modelBodyField,
367
387
  resolveFallbackChain
368
388
  } from "./index-td9depx5.js";
369
389
  import {
390
+ clearIgnoredMessages,
370
391
  describeError,
392
+ flushIgnoredMessages,
371
393
  getErrorMessage,
372
394
  sendIgnoredMessage,
373
395
  sendUserPrompt
374
- } from "./index-y1c9tcm3.js";
396
+ } from "./index-cn960ffd.js";
375
397
  import {
376
- Database,
377
398
  ToolMutationBatch,
378
399
  advanceToolReclaimWatermark,
379
400
  buildFileSourceContent,
@@ -382,7 +403,6 @@ import {
382
403
  cleanUserText,
383
404
  clearIndexedMessages,
384
405
  clearSession,
385
- closeQuietly,
386
406
  createToolDropTarget,
387
407
  deleteIndexedMessage,
388
408
  estimateTokens,
@@ -390,12 +410,10 @@ import {
390
410
  extractTexts,
391
411
  extractToolCallObservation,
392
412
  extractToolCallSummaries,
393
- findLastAssistantModelFromOpenCodeDb,
394
413
  getIndexedMessageCorpusSize,
395
414
  getLastIndexedOrdinal,
396
415
  getMessageIndexReconciliationStartOrdinal,
397
416
  getMessageIndexSourceIdentity,
398
- getMessageTimesFromOpenCodeDb,
399
417
  getOrCreateSessionMeta,
400
418
  getRawSessionStoredMessageCount,
401
419
  hasMeaningfulUserText,
@@ -405,7 +423,6 @@ import {
405
423
  isFilePart,
406
424
  isMessageIndexReconciledThrough,
407
425
  isMessageIndexSourceCurrent,
408
- isMidTurn,
409
426
  isRawCompactionSummaryInfo,
410
427
  isRecord,
411
428
  isTextPart,
@@ -413,7 +430,7 @@ import {
413
430
  isToolPartWithOutput,
414
431
  markSessionCleanupPending,
415
432
  normalizeText,
416
- openCodeDbExists,
433
+ partHasCompletedResult,
417
434
  prependTag,
418
435
  primeInMemoryTailRawMessageCache,
419
436
  primeTailRawMessageCache,
@@ -430,9 +447,17 @@ import {
430
447
  sweepOrphanedOpenCodeMessageIndexes,
431
448
  textMentionsRecentCommit,
432
449
  updateSessionMeta,
433
- withRawSessionMessageCache,
450
+ withRawSessionMessageCache
451
+ } from "./index-b563sga5.js";
452
+ import {
453
+ Database,
454
+ closeQuietly,
455
+ findLastAssistantModelFromOpenCodeDb,
456
+ getMessageTimesFromOpenCodeDb,
457
+ isMidTurn,
458
+ openCodeDbExists,
434
459
  withReadOnlySessionDb
435
- } from "./index-bmkea2dq.js";
460
+ } from "./index-fcyvznch.js";
436
461
  import {
437
462
  cleanupConflictWarnings,
438
463
  detectConfigFile,
@@ -440,7 +465,7 @@ import {
440
465
  parseJsonc,
441
466
  sendConflictWarning,
442
467
  stripJsonComments
443
- } from "./index-k5y60ymm.js";
468
+ } from "./index-dtas91s5.js";
444
469
  import {
445
470
  ANNOUNCEMENT_FEATURES,
446
471
  ANNOUNCEMENT_FOOTER,
@@ -450,6 +475,13 @@ import {
450
475
  markAnnouncementSeen,
451
476
  shouldShowAnnouncement
452
477
  } from "./index-dmr999a2.js";
478
+ import {
479
+ acknowledgeNotifications,
480
+ drainNotifications,
481
+ isTuiConnected,
482
+ pushNotification,
483
+ registerNotificationSink
484
+ } from "./index-d62ypazr.js";
453
485
  import"./index-73xz0247.js";
454
486
  import {
455
487
  log,
@@ -464,13 +496,6 @@ import {
464
496
  import {
465
497
  resolvePromptContext
466
498
  } from "./index-szf8w1p5.js";
467
- import {
468
- acknowledgeNotifications,
469
- drainNotifications,
470
- isTuiConnected,
471
- pushNotification,
472
- registerNotificationSink
473
- } from "./index-d62ypazr.js";
474
499
  import {
475
500
  __commonJS,
476
501
  __require,
@@ -8489,6 +8514,7 @@ function buildHiddenAgentConfig(prompt, allowedTools, maxSteps, overrides, agent
8489
8514
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
8490
8515
 
8491
8516
  // src/config/agent-disable.ts
8517
+ var COMPACTION_ENABLED_PATH = `compaction${"."}enabled`;
8492
8518
  function isDreamerRunnable(config) {
8493
8519
  return !!config.dreamer && config.dreamer.disable !== true;
8494
8520
  }
@@ -8498,6 +8524,9 @@ function isSidekickRunnable(config) {
8498
8524
  function isHistorianRunnable(config) {
8499
8525
  return config.historian?.disable !== true;
8500
8526
  }
8527
+ function isCompactionEnabled(config) {
8528
+ return config.compaction?.enabled !== false;
8529
+ }
8501
8530
  function clonePlainObject(value) {
8502
8531
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
8503
8532
  return;
@@ -9327,6 +9356,19 @@ function stripUnsafeProjectConfigFields(projectRaw) {
9327
9356
  delete projectRaw.fail_closed_blocking;
9328
9357
  warnings.push("Ignoring fail_closed_blocking from project config (security: only user-level config may disable or force the loud inoperability gate).");
9329
9358
  }
9359
+ if ("allow_home_project" in projectRaw) {
9360
+ delete projectRaw.allow_home_project;
9361
+ warnings.push("Ignoring allow_home_project from project config (security: only user-level config may opt the user's home directory into Magic Context).");
9362
+ }
9363
+ const compaction = projectRaw.compaction;
9364
+ if (isPlainObject(compaction) && "enabled" in compaction) {
9365
+ delete compaction.enabled;
9366
+ warnings.push("Ignoring compaction.enabled from project config (security: only user-level config may disable Magic Context's context-window management; a cloned repo cannot change how the user's window is owned).");
9367
+ }
9368
+ if ("output_reserve" in projectRaw) {
9369
+ delete projectRaw.output_reserve;
9370
+ warnings.push("Ignoring output_reserve from project config (security: output-token reservation only honors user-level config).");
9371
+ }
9330
9372
  if ("language" in projectRaw) {
9331
9373
  delete projectRaw.language;
9332
9374
  warnings.push("Ignoring language from project config (security: output language is a user-level setting).");
@@ -9335,6 +9377,11 @@ function stripUnsafeProjectConfigFields(projectRaw) {
9335
9377
  delete projectRaw.sqlite;
9336
9378
  warnings.push("Ignoring sqlite.* from project config (security: SQLite cache/mmap PRAGMAs apply to the " + "process-global shared database handle; only user-level config may set them).");
9337
9379
  }
9380
+ const storage = projectRaw.storage;
9381
+ if (isPlainObject(storage) && "enforce_private_permissions" in storage) {
9382
+ delete storage.enforce_private_permissions;
9383
+ warnings.push("Ignoring storage.enforce_private_permissions from project config (security: only user-level config may opt into externally managed shared storage permissions).");
9384
+ }
9338
9385
  const pi = projectRaw.pi;
9339
9386
  if (isPlainObject(pi) && "subagent_extensions" in pi) {
9340
9387
  delete pi.subagent_extensions;
@@ -9552,8 +9599,15 @@ function pruneNestedConfigLeaf(block, relativePath) {
9552
9599
  }
9553
9600
 
9554
9601
  // src/config/transform-mode.ts
9602
+ var RUST_COMPACTION_OFF_WARNING = "compaction-off mode does not support rust transform mode; using the TypeScript transform.";
9555
9603
  var RUST_REQUIRES_USER_SUBC_WARNING = "rust mode requires user-level subc configuration; running ts.";
9556
9604
  function resolveTransformMode(args) {
9605
+ if (args.configured === "rust" && !args.compactionEnabled) {
9606
+ return {
9607
+ mode: "ts",
9608
+ warnings: [RUST_COMPACTION_OFF_WARNING]
9609
+ };
9610
+ }
9557
9611
  if (args.configured === "rust" && !args.userTierHasSubc) {
9558
9612
  return {
9559
9613
  mode: "ts",
@@ -9933,6 +9987,7 @@ function loadPluginConfigDetailed(directory) {
9933
9987
  }
9934
9988
  const recoveredTopLevelKeys = [];
9935
9989
  const config = parsePluginConfig(mergedRaw, recoveredTopLevelKeys);
9990
+ setOutputReserveConfig(config.output_reserve);
9936
9991
  if (config.configWarnings?.length) {
9937
9992
  allWarnings.push(...config.configWarnings.map((w) => {
9938
9993
  if (userLoaded && projectLoaded)
@@ -9944,7 +9999,8 @@ function loadPluginConfigDetailed(directory) {
9944
9999
  }
9945
10000
  const resolvedTransformMode = resolveTransformMode({
9946
10001
  configured: config.transform_mode,
9947
- userTierHasSubc: hasUserTierSubcConfig(userLoaded?.config)
10002
+ userTierHasSubc: hasUserTierSubcConfig(userLoaded?.config),
10003
+ compactionEnabled: isCompactionEnabled(config)
9948
10004
  });
9949
10005
  config.transform_mode = resolvedTransformMode.mode;
9950
10006
  allWarnings.push(...resolvedTransformMode.warnings.map((warning) => `[config] ${warning}`));
@@ -9971,7 +10027,9 @@ function loadPluginConfigDetailed(directory) {
9971
10027
  }
9972
10028
 
9973
10029
  // src/features/builtin-commands/commands.ts
9974
- function getMagicContextBuiltinCommands() {
10030
+ var COMPACTION_ENABLED_PATH2 = `compaction${".enabled"}`;
10031
+ function getMagicContextBuiltinCommands(compactionEnabled = true) {
10032
+ const unavailableInCompactionOff = (command) => `Unavailable when ${COMPACTION_ENABLED_PATH2} is false: /${command} manages compacted history.`;
9975
10033
  return {
9976
10034
  "ctx-status": {
9977
10035
  template: "ctx-status",
@@ -9979,11 +10037,11 @@ function getMagicContextBuiltinCommands() {
9979
10037
  },
9980
10038
  "ctx-recomp": {
9981
10039
  template: "ctx-recomp",
9982
- description: "Rebuild compartments and facts from raw history (full or <start>-<end> range)"
10040
+ description: compactionEnabled ? "Rebuild compartments and facts from raw history (full or <start>-<end> range)" : unavailableInCompactionOff("ctx-recomp")
9983
10041
  },
9984
10042
  "ctx-wrapup": {
9985
10043
  template: "ctx-wrapup",
9986
- description: "Compact older live history while keeping the newest messages raw"
10044
+ description: compactionEnabled ? "Compact older live history while keeping the newest messages raw" : unavailableInCompactionOff("ctx-wrapup")
9987
10045
  },
9988
10046
  "ctx-session-upgrade": {
9989
10047
  template: "ctx-session-upgrade",
@@ -9991,7 +10049,7 @@ function getMagicContextBuiltinCommands() {
9991
10049
  },
9992
10050
  "ctx-flush": {
9993
10051
  template: "ctx-flush",
9994
- description: "Force-process all pending magic context operations immediately"
10052
+ description: compactionEnabled ? "Force-process all pending magic context operations immediately" : unavailableInCompactionOff("ctx-flush")
9995
10053
  },
9996
10054
  "ctx-aug": {
9997
10055
  template: "ctx-aug",
@@ -10356,14 +10414,41 @@ function isMagicContextHiddenAgentName(agent) {
10356
10414
  return true;
10357
10415
  return false;
10358
10416
  }
10417
+ var MAX_FORMATTED_BLOCKING_PROCESSES = 8;
10418
+ function formatFailClosedBlockingProcesses(processes) {
10419
+ const uniqueProcesses = new Map;
10420
+ for (const process2 of processes) {
10421
+ if (!process2.harness.trim() || !Number.isInteger(process2.pid) || process2.pid <= 0)
10422
+ continue;
10423
+ uniqueProcesses.set(`${process2.harness}\x00${process2.pid}`, {
10424
+ harness: process2.harness.trim(),
10425
+ pid: process2.pid
10426
+ });
10427
+ }
10428
+ const entries = [...uniqueProcesses.values()];
10429
+ const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
10430
+ const rendered = visible.map(({ harness, pid }) => `${harness} (PID ${pid})`);
10431
+ const omitted = entries.length - visible.length;
10432
+ if (omitted > 0)
10433
+ rendered.push(`${omitted} more blocking process(es)`);
10434
+ if (rendered.length === 0)
10435
+ return "a live harness process";
10436
+ if (rendered.length === 1)
10437
+ return rendered[0];
10438
+ const last = rendered.pop();
10439
+ return `${rendered.join(", ")}, and ${last}`;
10440
+ }
10359
10441
  function formatFailClosedBlockingMessage(reason) {
10442
+ if (reason.kind === "migration_guard") {
10443
+ return [
10444
+ `Magic Context cannot migrate the shared database because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
10445
+ "Restart the blocking process (it will pick up the new build and migrate on start), or shut it down and retry.",
10446
+ `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
10447
+ ].join(" ");
10448
+ }
10360
10449
  if (reason.kind === "schema_fence") {
10361
10450
  return [
10362
- `Magic Context cannot operate: shared database schema v${reason.persistedVersion}`,
10363
- `is newer than this build supports (max v${reason.supportedVersion}).`,
10364
- "A newer OpenCode/Pi instance upgraded the database; this build fail-closed",
10365
- "so it cannot corrupt the cache or silently fall back to native compaction.",
10366
- `Update or unpin Magic Context on this harness, then restart.`,
10451
+ `Magic Context cannot operate: this Magic Context build is older than the database; upgrade/restart this harness (database schema v${reason.persistedVersion}, build supports through v${reason.supportedVersion}).`,
10367
10452
  `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
10368
10453
  ].join(" ");
10369
10454
  }
@@ -10435,7 +10520,7 @@ function createFailClosedController(options) {
10435
10520
  const shouldReprobe = typeof input.tryReopen === "function" && (blockedPassCount === 1 || blockedPassCount % reprobeEveryN === 0);
10436
10521
  if (shouldReprobe) {
10437
10522
  try {
10438
- const healed = await input.tryReopen();
10523
+ const healed = await input.tryReopen?.();
10439
10524
  if (healed) {
10440
10525
  reason = null;
10441
10526
  blockedPassCount = 0;
@@ -10753,12 +10838,12 @@ async function runSidekick(deps) {
10753
10838
  }
10754
10839
  };
10755
10840
  try {
10756
- const createResponse = await deps.client.session.create({
10757
- body: {
10758
- ...deps.sessionId ? { parentID: deps.sessionId } : {},
10759
- title: "magic-context-sidekick"
10760
- },
10761
- query: { directory: deps.sessionDirectory ?? deps.projectPath }
10841
+ const createResponse = await createChildSessionWithFence({
10842
+ client: deps.client,
10843
+ db: openDatabase(),
10844
+ parentSessionId: deps.sessionId,
10845
+ title: "magic-context-sidekick",
10846
+ directory: deps.sessionDirectory ?? deps.projectPath
10762
10847
  });
10763
10848
  const createdSession = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
10764
10849
  agentSessionId = typeof createdSession?.id === "string" ? createdSession.id : null;
@@ -12850,7 +12935,7 @@ function parseCuesManifest(text) {
12850
12935
  const body = extractCompleteManifestBody(text, "cues");
12851
12936
  const out = [];
12852
12937
  for (const match of body.matchAll(/<cue\s+id="(\d+)"\s*>([\s\S]*?)<\/cue>/g)) {
12853
- const id = Number.parseInt(match[1], 10);
12938
+ const id = Number.parseInt(match[1] ?? "", 10);
12854
12939
  if (!Number.isInteger(id))
12855
12940
  continue;
12856
12941
  out.push({ id, cue: unescapeXml(match[2] ?? "").trim() });
@@ -12951,7 +13036,10 @@ async function runCompressCues(args) {
12951
13036
  break;
12952
13037
  }
12953
13038
  const sliceMs = computeChunkSliceMs(remainingMs, chunks.length - i);
12954
- const outcome = await compressOneChunk(args, chunks[i], sliceMs, abortController.signal);
13039
+ const chunk = chunks[i];
13040
+ if (!chunk)
13041
+ break;
13042
+ const outcome = await compressOneChunk(args, chunk, sliceMs, abortController.signal);
12955
13043
  result.compressed += outcome.compressed;
12956
13044
  result.skipped += outcome.skipped;
12957
13045
  result.remaining -= outcome.compressed;
@@ -12986,12 +13074,12 @@ async function compressOneChunk(args, chunk, sliceMs, signal) {
12986
13074
  projectPath: args.projectIdentity,
12987
13075
  memories: chunk.map(toPromptMemory)
12988
13076
  });
12989
- const createResponse = await args.client.session.create({
12990
- body: {
12991
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
12992
- title: "magic-context-dream-compress-cues"
12993
- },
12994
- query: { directory: args.sessionDirectory }
13077
+ const createResponse = await createChildSessionWithFence({
13078
+ client: args.client,
13079
+ db: args.db,
13080
+ parentSessionId: args.parentSessionId,
13081
+ title: "magic-context-dream-compress-cues",
13082
+ directory: args.sessionDirectory
12995
13083
  });
12996
13084
  const created = normalizeSDKResponse(createResponse, null, {
12997
13085
  preferResponseOnMissingData: true
@@ -13170,12 +13258,12 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
13170
13258
  abortController.abort();
13171
13259
  });
13172
13260
  try {
13173
- const createResponse = await args.client.session.create({
13174
- body: {
13175
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
13176
- title: "magic-context-dream-user-memories"
13177
- },
13178
- query: { directory: args.sessionDirectory }
13261
+ const createResponse = await createChildSessionWithFence({
13262
+ client: args.client,
13263
+ db: args.db,
13264
+ parentSessionId: args.parentSessionId,
13265
+ title: "magic-context-dream-user-memories",
13266
+ directory: args.sessionDirectory
13179
13267
  });
13180
13268
  const created = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
13181
13269
  agentSessionId = typeof created?.id === "string" ? created.id : null;
@@ -13787,12 +13875,12 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
13787
13875
  recordInvocation(args, startedAt, { status: "completed" });
13788
13876
  return run2;
13789
13877
  }
13790
- const createResponse = await args.client.session.create({
13791
- body: {
13792
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
13793
- title: "magic-context-dream-classify"
13794
- },
13795
- query: { directory: args.sessionDirectory }
13878
+ const createResponse = await createChildSessionWithFence({
13879
+ client: args.client,
13880
+ db: args.db,
13881
+ parentSessionId: args.parentSessionId,
13882
+ title: "magic-context-dream-classify",
13883
+ directory: args.sessionDirectory
13796
13884
  });
13797
13885
  const created = normalizeSDKResponse(createResponse, null, {
13798
13886
  preferResponseOnMissingData: true
@@ -14574,7 +14662,7 @@ function getAsyncModule() {
14574
14662
  asyncModulePromise ??= (async () => {
14575
14663
  const [{ default: singlefileAsyncifyVariant }, { newQuickJSAsyncWASMModuleFromVariant }] = await Promise.all([
14576
14664
  import("./index-ayd60xnw.js").then((m)=>__toESM(m.default,1)),
14577
- import("./index-v7fmc1s2.js")
14665
+ import("./index-ygcng9t8.js")
14578
14666
  ]);
14579
14667
  return newQuickJSAsyncWASMModuleFromVariant(singlefileAsyncifyVariant);
14580
14668
  })();
@@ -14793,12 +14881,12 @@ Remember: output only the JSON object described by the system prompt.`;
14793
14881
  });
14794
14882
  };
14795
14883
  try {
14796
- const createResponse = await args.client.session.create({
14797
- body: {
14798
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
14799
- title: `magic-context-smart-note-compile-${args.note.id}`
14800
- },
14801
- query: { directory: args.sessionDirectory ?? args.projectIdentity }
14884
+ const createResponse = await createChildSessionWithFence({
14885
+ client: args.client,
14886
+ db: args.db ?? null,
14887
+ parentSessionId: args.parentSessionId,
14888
+ title: `magic-context-smart-note-compile-${args.note.id}`,
14889
+ directory: args.sessionDirectory ?? args.projectIdentity
14802
14890
  });
14803
14891
  const created = normalizeSDKResponse(createResponse, null, {
14804
14892
  preferResponseOnMissingData: true
@@ -15579,12 +15667,12 @@ async function confirmReadOnly(args, noteId, content, surfaceCondition, leaseSig
15579
15667
  });
15580
15668
  };
15581
15669
  try {
15582
- const createResponse = await args.client.session.create({
15583
- body: {
15584
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
15585
- title: `magic-context-smart-note-confirm-${noteId}`
15586
- },
15587
- query: { directory: args.sessionDirectory ?? args.projectIdentity }
15670
+ const createResponse = await createChildSessionWithFence({
15671
+ client: args.client,
15672
+ db: args.db,
15673
+ parentSessionId: args.parentSessionId,
15674
+ title: `magic-context-smart-note-confirm-${noteId}`,
15675
+ directory: args.sessionDirectory ?? args.projectIdentity
15588
15676
  });
15589
15677
  const created = normalizeSDKResponse(createResponse, null, {
15590
15678
  preferResponseOnMissingData: true
@@ -15929,12 +16017,12 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
15929
16017
  let agentSessionId = null;
15930
16018
  const startedAt = Date.now();
15931
16019
  try {
15932
- const createResponse = await args.client.session.create({
15933
- body: {
15934
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
15935
- title: "magic-context-dream-map-memories"
15936
- },
15937
- query: { directory: args.sessionDirectory }
16020
+ const createResponse = await createChildSessionWithFence({
16021
+ client: args.client,
16022
+ db: args.db,
16023
+ parentSessionId: args.parentSessionId,
16024
+ title: "magic-context-dream-map-memories",
16025
+ directory: args.sessionDirectory
15938
16026
  });
15939
16027
  const created = normalizeSDKResponse(createResponse, null, {
15940
16028
  preferResponseOnMissingData: true
@@ -16546,12 +16634,12 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
16546
16634
  let agentSessionId = null;
16547
16635
  const startedAt = Date.now();
16548
16636
  try {
16549
- const createResponse = await args.client.session.create({
16550
- body: {
16551
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
16552
- title: "magic-context-dream-refresh-primers"
16553
- },
16554
- query: { directory: args.sessionDirectory }
16637
+ const createResponse = await createChildSessionWithFence({
16638
+ client: args.client,
16639
+ db: args.db,
16640
+ parentSessionId: args.parentSessionId,
16641
+ title: "magic-context-dream-refresh-primers",
16642
+ directory: args.sessionDirectory
16555
16643
  });
16556
16644
  const created = normalizeSDKResponse(createResponse, null, {
16557
16645
  preferResponseOnMissingData: true
@@ -16998,12 +17086,12 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
16998
17086
  let agentSessionId = null;
16999
17087
  const startedAt = Date.now();
17000
17088
  try {
17001
- const createResponse = await args.client.session.create({
17002
- body: {
17003
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
17004
- title: "magic-context-dream-verify"
17005
- },
17006
- query: { directory: args.sessionDirectory }
17089
+ const createResponse = await createChildSessionWithFence({
17090
+ client: args.client,
17091
+ db: args.db,
17092
+ parentSessionId: args.parentSessionId,
17093
+ title: "magic-context-dream-verify",
17094
+ directory: args.sessionDirectory
17007
17095
  });
17008
17096
  const created = normalizeSDKResponse(createResponse, null, {
17009
17097
  preferResponseOnMissingData: true
@@ -17690,12 +17778,12 @@ async function runRetrospectiveTask(config, ctx, helpers) {
17690
17778
  });
17691
17779
  let childSessionId = null;
17692
17780
  try {
17693
- const createResponse = await deps.client.session.create({
17694
- body: {
17695
- ...parent ? { parentID: parent } : {},
17696
- title: "magic-context-dream-retrospective"
17697
- },
17698
- query: { directory: deps.sessionDirectory }
17781
+ const createResponse = await createChildSessionWithFence({
17782
+ client: deps.client,
17783
+ db,
17784
+ parentSessionId: parent ?? undefined,
17785
+ title: "magic-context-dream-retrospective",
17786
+ directory: deps.sessionDirectory
17699
17787
  });
17700
17788
  const created = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
17701
17789
  childSessionId = typeof created?.id === "string" ? created.id : null;
@@ -17880,12 +17968,12 @@ async function runAgenticTask(config, ctx, helpers) {
17880
17968
  });
17881
17969
  let childSessionId = null;
17882
17970
  try {
17883
- const createResponse = await deps.client.session.create({
17884
- body: {
17885
- ...parent ? { parentID: parent } : {},
17886
- title: `magic-context-dream-${task}`
17887
- },
17888
- query: { directory: docsDir }
17971
+ const createResponse = await createChildSessionWithFence({
17972
+ client: deps.client,
17973
+ db,
17974
+ parentSessionId: parent ?? undefined,
17975
+ title: `magic-context-dream-${task}`,
17976
+ directory: docsDir
17889
17977
  });
17890
17978
  const created = normalizeSDKResponse(createResponse, null, {
17891
17979
  preferResponseOnMissingData: true
@@ -19173,11 +19261,11 @@ async function resolveEmbeddingRouting(args) {
19173
19261
 
19174
19262
  // src/plugin/embedding-bootstrap.ts
19175
19263
  async function ensureProjectRegisteredFromOpenCodeDirectory(directory, db) {
19176
- const projectIdentity = resolveProjectIdentityForSession(directory);
19264
+ const detailed = loadPluginConfigDetailed(directory);
19265
+ const projectIdentity = resolveProjectIdentityForSession(directory, detailed.config.allow_home_project);
19177
19266
  if (!projectIdentity)
19178
19267
  return;
19179
19268
  invalidateProject(projectIdentity);
19180
- const detailed = loadPluginConfigDetailed(directory);
19181
19269
  if (isConfigLoadUntrusted(detailed)) {
19182
19270
  handleUntrustedLoad(db, projectIdentity, directory, detailed);
19183
19271
  return;
@@ -19231,41 +19319,45 @@ function createCompactionHandler() {
19231
19319
 
19232
19320
  // src/hooks/magic-context/event-resolvers.ts
19233
19321
  var DEFAULT_CONTEXT_LIMIT = 128000;
19234
- var MAX_EXECUTE_THRESHOLD = 80;
19235
19322
  function resolveContextLimit(providerID, modelID, ctx) {
19236
- const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID) : undefined;
19237
- const baseline = fromModelsDev ?? DEFAULT_CONTEXT_LIMIT;
19238
19323
  const modelKey = resolveModelKey(providerID, modelID);
19324
+ let detected;
19325
+ let detectedLimitProvenance = "unknown";
19239
19326
  if (ctx?.db && ctx.sessionID) {
19240
19327
  try {
19241
19328
  const overflow = getOverflowState(ctx.db, ctx.sessionID, modelKey);
19242
- if (overflow.detectedContextLimit > 0 && overflow.detectedContextLimit < baseline) {
19243
- return overflow.detectedContextLimit;
19329
+ if (overflow.detectedContextLimit > 0) {
19330
+ detected = overflow.detectedContextLimit;
19331
+ detectedLimitProvenance = overflow.detectedContextLimitProvenance;
19244
19332
  }
19245
19333
  } catch {}
19246
19334
  }
19247
- return baseline;
19335
+ const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID, detected, {
19336
+ reservation: ctx?.reservation,
19337
+ detectedLimitProvenance
19338
+ }) : undefined;
19339
+ return fromModelsDev ?? detected ?? DEFAULT_CONTEXT_LIMIT;
19248
19340
  }
19249
19341
  function resolveTrustedContextLimit(providerID, modelID, ctx) {
19250
- const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID) : undefined;
19251
19342
  const modelKey = resolveModelKey(providerID, modelID);
19252
19343
  let detected;
19344
+ let detectedLimitProvenance = "unknown";
19253
19345
  if (ctx?.db && ctx.sessionID) {
19254
19346
  try {
19255
19347
  const overflow = getOverflowState(ctx.db, ctx.sessionID, modelKey);
19256
19348
  if (overflow.detectedContextLimit > 0) {
19257
19349
  detected = overflow.detectedContextLimit;
19350
+ detectedLimitProvenance = overflow.detectedContextLimitProvenance;
19258
19351
  }
19259
19352
  } catch {}
19260
19353
  }
19261
- if (typeof fromModelsDev === "number" && fromModelsDev > 0) {
19262
- if (detected !== undefined && detected < fromModelsDev)
19263
- return detected;
19354
+ const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID, detected, {
19355
+ detectedLimitProvenance
19356
+ }) : undefined;
19357
+ if (typeof fromModelsDev === "number" && fromModelsDev > 0)
19264
19358
  return fromModelsDev;
19265
- }
19266
- if (detected !== undefined) {
19359
+ if (detected !== undefined)
19267
19360
  return detected;
19268
- }
19269
19361
  if (modelKey && ctx?.db && ctx.sessionID) {
19270
19362
  try {
19271
19363
  const persisted = loadPersistedUsage(ctx.db, ctx.sessionID);
@@ -19320,7 +19412,7 @@ function resolveExecuteThresholdDetail(config, modelKey, fallback, options) {
19320
19412
  const dedupeKey = `${options.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${tokenMatch.value}|${cap}`;
19321
19413
  if (!clampWarnSeen.has(dedupeKey)) {
19322
19414
  clampWarnSeen.add(dedupeKey);
19323
- const msg = `execute_threshold_tokens clamped: ${tokenMatch.value} → ${effectiveTokens} (80% of ${contextLimit}) for ${modelKey ?? "default"}`;
19415
+ const msg = `execute_threshold_tokens clamped: ${tokenMatch.value} → ${effectiveTokens} (${MAX_EXECUTE_THRESHOLD}% of ${contextLimit}) for ${modelKey ?? "default"}`;
19324
19416
  if (options.sessionId) {
19325
19417
  sessionLog(options.sessionId, `WARN: ${msg}`);
19326
19418
  } else {
@@ -19376,7 +19468,7 @@ function resolveExecuteThresholdDetail(config, modelKey, fallback, options) {
19376
19468
  const dedupeKey = `pct|${options?.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${resolved}`;
19377
19469
  if (!clampWarnSeen.has(dedupeKey)) {
19378
19470
  clampWarnSeen.add(dedupeKey);
19379
- const msg = `execute_threshold clamped ${resolved}% → ${MAX_EXECUTE_THRESHOLD}% for ${modelKey ?? "default"} (capped for cache safety; a large step can overflow before compaction, and 80% stays below the 85%/95% emergency bands)`;
19471
+ const msg = `execute_threshold clamped ${resolved}% → ${MAX_EXECUTE_THRESHOLD}% for ${modelKey ?? "default"} (capped against the output-reserved safe window; 10% remains for mid-turn growth before the absolute 95% wall)`;
19380
19472
  if (options?.sessionId) {
19381
19473
  sessionLog(options.sessionId, `WARN: ${msg}`);
19382
19474
  } else {
@@ -19449,6 +19541,9 @@ var UNIT_TO_MS = {
19449
19541
  };
19450
19542
  function parseCacheTtl(ttl) {
19451
19543
  const normalizedTtl = ttl.trim();
19544
+ if (normalizedTtl.toLowerCase() === "never") {
19545
+ return Number.POSITIVE_INFINITY;
19546
+ }
19452
19547
  if (NUMERIC_PATTERN.test(normalizedTtl)) {
19453
19548
  return Number(normalizedTtl);
19454
19549
  }
@@ -19847,6 +19942,75 @@ function formatThresholdClampNote(opts) {
19847
19942
  return ` [clamped: ${opts.configuredValue}% > ${opts.maxPercentage}%]`;
19848
19943
  }
19849
19944
 
19945
+ // src/hooks/magic-context/sentinel.ts
19946
+ var WHOLE_MESSAGE_PLACEHOLDER_TEXT = "[dropped]";
19947
+ function modelAcceptsEmptyContent(providerID) {
19948
+ return providerID === "anthropic";
19949
+ }
19950
+ function variantChangeBustsProviderCache(providerID) {
19951
+ if (providerID === undefined)
19952
+ return true;
19953
+ if (providerID === "anthropic")
19954
+ return true;
19955
+ if (providerID === "google-vertex-anthropic")
19956
+ return true;
19957
+ if (providerID.includes("bedrock"))
19958
+ return true;
19959
+ return false;
19960
+ }
19961
+ function makeSentinel(originalPart) {
19962
+ const sentinel = {
19963
+ type: "text",
19964
+ text: ""
19965
+ };
19966
+ if (isRecord(originalPart)) {
19967
+ if (originalPart.cache_control !== undefined) {
19968
+ sentinel.cache_control = originalPart.cache_control;
19969
+ }
19970
+ if (originalPart.cacheControl !== undefined) {
19971
+ sentinel.cacheControl = originalPart.cacheControl;
19972
+ }
19973
+ }
19974
+ return sentinel;
19975
+ }
19976
+ function makeWholeMessageSentinel(providerID) {
19977
+ return {
19978
+ type: "text",
19979
+ text: modelAcceptsEmptyContent(providerID) ? "" : WHOLE_MESSAGE_PLACEHOLDER_TEXT
19980
+ };
19981
+ }
19982
+ function isSentinel(part) {
19983
+ if (!isRecord(part))
19984
+ return false;
19985
+ if (part.type !== "text")
19986
+ return false;
19987
+ if (typeof part.text !== "string")
19988
+ return false;
19989
+ return part.text === "" || part.text === WHOLE_MESSAGE_PLACEHOLDER_TEXT;
19990
+ }
19991
+ function replaySentinelByMessageIds(messages, ids, providerID) {
19992
+ if (ids.size === 0)
19993
+ return { replayed: 0, missingIds: [] };
19994
+ const seen = new Set;
19995
+ let replayed = 0;
19996
+ for (const msg of messages) {
19997
+ const id = msg.info.id;
19998
+ if (!id || !ids.has(id))
19999
+ continue;
20000
+ seen.add(id);
20001
+ if (msg.parts.length === 1 && isSentinel(msg.parts[0]))
20002
+ continue;
20003
+ msg.parts.length = 0;
20004
+ msg.parts.push(makeWholeMessageSentinel(providerID));
20005
+ replayed++;
20006
+ }
20007
+ const missingIds = [];
20008
+ for (const id of ids)
20009
+ if (!seen.has(id))
20010
+ missingIds.push(id);
20011
+ return { replayed, missingIds };
20012
+ }
20013
+
19850
20014
  // src/hooks/magic-context/compartment-trigger.ts
19851
20015
  var PROACTIVE_TRIGGER_OFFSET_PERCENTAGE = 2;
19852
20016
  var POST_DROP_TARGET_RATIO = 0.75;
@@ -19854,9 +20018,7 @@ var MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE = 6000;
19854
20018
  var MIN_PROACTIVE_TAIL_MESSAGE_COUNT = 12;
19855
20019
  var DEFAULT_MIN_COMMIT_CLUSTERS_FOR_TRIGGER = 3;
19856
20020
  var TAIL_SIZE_TRIGGER_MULTIPLIER = 3;
19857
- var FORCE_COMPARTMENT_PERCENTAGE = 80;
19858
20021
  var BLOCK_UNTIL_DONE_PERCENTAGE = 95;
19859
- var FORCE_MATERIALIZE_PERCENTAGE = 85;
19860
20022
  var CONTENT_TAG_OWNER_SUFFIX = /:(?:p|file)\d+$/;
19861
20023
  function tagOwnerMessageId(row) {
19862
20024
  if (row.type === "tool")
@@ -19910,7 +20072,7 @@ function buildTriggerInMemoryTail(db, sessionId, messages) {
19910
20072
  function getProactiveCompartmentTriggerPercentage(executeThresholdPercentage) {
19911
20073
  return Math.max(0, executeThresholdPercentage - PROACTIVE_TRIGGER_OFFSET_PERCENTAGE);
19912
20074
  }
19913
- function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, clearReasoningAge, clearedReasoningThroughTag) {
20075
+ function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, clearReasoningAge, clearedReasoningThroughTag, canClearReasoning) {
19914
20076
  const totalActiveBytes = activeTags.reduce((sum, tag) => sum + tag.byteSize + tag.reasoningByteSize, 0);
19915
20077
  if (totalActiveBytes === 0)
19916
20078
  return null;
@@ -19921,7 +20083,7 @@ function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, c
19921
20083
  droppableBytes += activeTags.filter((tag) => pendingDropTagIds.has(tag.tagNumber)).reduce((sum, tag) => sum + tag.byteSize + tag.reasoningByteSize, 0);
19922
20084
  }
19923
20085
  const maxTag = activeTags.reduce((max, t) => Math.max(max, t.tagNumber), 0);
19924
- if (clearReasoningAge !== undefined && clearedReasoningThroughTag !== undefined) {
20086
+ if (canClearReasoning && clearReasoningAge !== undefined && clearedReasoningThroughTag !== undefined) {
19925
20087
  const reasoningAgeCutoff = maxTag - clearReasoningAge;
19926
20088
  for (const tag of activeTags) {
19927
20089
  if (tag.type !== "message")
@@ -20021,7 +20183,7 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
20021
20183
  }
20022
20184
  });
20023
20185
  }
20024
- function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride) {
20186
+ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride, reasoningProjection) {
20025
20187
  if (sessionMeta.compartmentInProgress) {
20026
20188
  sessionLog(sessionId, `compartment trigger: skipped — historian already in progress (usage=${usage.percentage.toFixed(1)}%)`);
20027
20189
  return { shouldFire: false };
@@ -20075,18 +20237,20 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
20075
20237
  }
20076
20238
  return { shouldFire: false };
20077
20239
  }
20078
- const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), clearReasoningAge, sessionMeta.clearedReasoningThroughTag);
20240
+ const canClearReasoning = reasoningProjection?.canClearReasoning ?? modelAcceptsEmptyContent(reasoningProjection?.providerID);
20241
+ const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), clearReasoningAge, sessionMeta.clearedReasoningThroughTag, canClearReasoning);
20079
20242
  const relativePostDropTarget = executeThresholdPercentage * POST_DROP_TARGET_RATIO;
20080
- if (usage.percentage >= FORCE_COMPARTMENT_PERCENTAGE) {
20243
+ const forceMaterializationPercentage = escalationBands(executeThresholdPercentage).forceMaterializationPercentage;
20244
+ if (usage.percentage >= forceMaterializationPercentage) {
20081
20245
  if (projectedPostDropPercentage !== null && projectedPostDropPercentage <= relativePostDropTarget) {
20082
- sessionLog(sessionId, `compartment trigger: skipping force-${FORCE_COMPARTMENT_PERCENTAGE} because projected post-drop usage is ${projectedPostDropPercentage.toFixed(1)}% (target ${relativePostDropTarget.toFixed(1)}%)`);
20246
+ sessionLog(sessionId, `compartment trigger: skipping force band ${forceMaterializationPercentage}% because projected post-drop usage is ${projectedPostDropPercentage.toFixed(1)}% (target ${relativePostDropTarget.toFixed(1)}%)`);
20083
20247
  return { shouldFire: false };
20084
20248
  }
20085
20249
  sessionLog(sessionId, `compartment trigger: force-firing at ${usage.percentage.toFixed(1)}% (projected post-drop ${projectedPostDropPercentage?.toFixed(1) ?? "none"}%)`);
20086
20250
  if (tailInfo.boundarySnapshot && hasRunnableCompartmentWindow(tailInfo.boundarySnapshot)) {
20087
20251
  return {
20088
20252
  shouldFire: true,
20089
- reason: "force_80",
20253
+ reason: "force_band",
20090
20254
  boundarySnapshot: tailInfo.boundarySnapshot
20091
20255
  };
20092
20256
  }
@@ -20111,9 +20275,9 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
20111
20275
  });
20112
20276
  });
20113
20277
  if (hasRunnableCompartmentWindow(scaledBoundary)) {
20114
- return { shouldFire: true, reason: "force_80", boundarySnapshot: scaledBoundary };
20278
+ return { shouldFire: true, reason: "force_band", boundarySnapshot: scaledBoundary };
20115
20279
  }
20116
- sessionLog(sessionId, "compartment trigger: force_80 skipped — raw exists but protected head genuinely empty after emergency tail scale");
20280
+ sessionLog(sessionId, "compartment trigger: force_band skipped — raw exists but protected head genuinely empty after emergency tail scale");
20117
20281
  return { shouldFire: false };
20118
20282
  }
20119
20283
  const clusterEnabled = commitClusterTrigger?.enabled ?? true;
@@ -20228,8 +20392,8 @@ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageC
20228
20392
  "### Cache TTL",
20229
20393
  `- Configured: ${meta.cacheTtl}`,
20230
20394
  `- Last response: ${meta.lastResponseTime > 0 ? `${Math.round(elapsed / 1000)}s ago` : "never"}`,
20231
- `- Remaining: ${cacheExpired ? "expired" : `${Math.round(remainingMs / 1000)}s`}`,
20232
- `- Queue will auto-execute: ${cacheExpired ? "yes (cache expired)" : `when TTL expires or context >= ${executeThresholdPercentage}%`}`,
20395
+ `- Remaining: ${cacheExpired ? "expired" : ttlMs === Number.POSITIVE_INFINITY ? "never expires (always-warm lane)" : `${Math.round(remainingMs / 1000)}s`}`,
20396
+ `- Queue will auto-execute: ${cacheExpired ? "yes (cache expired)" : ttlMs === Number.POSITIVE_INFINITY ? `when context >= ${executeThresholdPercentage}%` : `when TTL expires or context >= ${executeThresholdPercentage}%`}`,
20233
20397
  "",
20234
20398
  "### Execute Threshold",
20235
20399
  `- Execute threshold: ${formatExecuteThreshold(thresholdDetail, displayContextLimit)}`,
@@ -20580,6 +20744,11 @@ function createMagicContextCommandHandler(deps) {
20580
20744
  }
20581
20745
  const sessionId = input.sessionID;
20582
20746
  let result = "";
20747
+ if (deps.compactionOff && (isFlush || isRecomp || isWrapup)) {
20748
+ const command = `/${input.command}`;
20749
+ await deps.sendNotification(sessionId, `Magic Context compaction is disabled (${COMPACTION_ENABLED_PATH}: false) — ${command} manages compacted history and has no effect in this mode.`, {});
20750
+ throwSentinel(input.command);
20751
+ }
20583
20752
  if (isAug) {
20584
20753
  await executeAugmentation(deps, sessionId, input.arguments);
20585
20754
  return;
@@ -20669,7 +20838,10 @@ Embedding status is unavailable.`;
20669
20838
  const moduleStatus = rustStatus ? `
20670
20839
 
20671
20840
  ${formatRustStatusText(rustStatus)}` : "";
20672
- const combinedStatus = `${statusOutput}${moduleStatus}`;
20841
+ const modeStatus = deps.compactionOff ? `**Compaction:** disabled (${COMPACTION_ENABLED_PATH}: false) — native compaction owns the context window.
20842
+
20843
+ ` : "";
20844
+ const combinedStatus = `${modeStatus}${statusOutput}${moduleStatus}`;
20673
20845
  result += result ? `
20674
20846
 
20675
20847
  ${combinedStatus}` : combinedStatus;
@@ -20836,6 +21008,212 @@ ${snap.error}`;
20836
21008
  };
20837
21009
  }
20838
21010
 
21011
+ // src/hooks/magic-context/ctx-reduce-availability.ts
21012
+ var ctxReduceRegisteredGlobally = true;
21013
+ function setCtxReduceRegisteredGlobally(registered) {
21014
+ ctxReduceRegisteredGlobally = registered;
21015
+ }
21016
+ var CTX_REDUCE_TOOL = "ctx_reduce";
21017
+ var TODOWRITE_TOOL = "todowrite";
21018
+ var availabilityBySession = new BoundedSessionMap(1000);
21019
+ var permissionDeniedBySession = new BoundedSessionMap(2000);
21020
+ var ctxReducePermissionDenyLogged = new BoundedSessionMap(1000);
21021
+ function permissionCacheKey(toolName, sessionId) {
21022
+ return `${toolName}\x00${sessionId}`;
21023
+ }
21024
+ function cacheKey(toolName, sessionId) {
21025
+ return `${toolName}\x00${sessionId}`;
21026
+ }
21027
+ function verdictFromToolsMap(tools, toolName) {
21028
+ if (tools === null || typeof tools !== "object" || Array.isArray(tools))
21029
+ return null;
21030
+ const map = tools;
21031
+ if (map[toolName] === true)
21032
+ return true;
21033
+ if (map[toolName] === false)
21034
+ return false;
21035
+ if (map["*"] === false)
21036
+ return false;
21037
+ return null;
21038
+ }
21039
+ function resolveToolAvailabilityFromMessages(sessionId, toolName, messages) {
21040
+ if (toolName === CTX_REDUCE_TOOL && !ctxReduceRegisteredGlobally) {
21041
+ return { callable: false, frozen: true };
21042
+ }
21043
+ const key = cacheKey(toolName, sessionId);
21044
+ const cached = availabilityBySession.get(key);
21045
+ if (cached !== undefined)
21046
+ return { callable: cached, frozen: true };
21047
+ for (const message of messages) {
21048
+ if (message.info?.role !== "user")
21049
+ continue;
21050
+ const verdict = verdictFromToolsMap(message.info.tools, toolName) ?? true;
21051
+ availabilityBySession.set(key, verdict);
21052
+ return { callable: verdict, frozen: true };
21053
+ }
21054
+ return { callable: true, frozen: false };
21055
+ }
21056
+ function resolveToolAvailability(sessionId, toolName) {
21057
+ if (toolName === CTX_REDUCE_TOOL && !ctxReduceRegisteredGlobally) {
21058
+ return { callable: false, frozen: true };
21059
+ }
21060
+ const key = cacheKey(toolName, sessionId);
21061
+ const cached = availabilityBySession.get(key);
21062
+ if (cached !== undefined)
21063
+ return { callable: cached, frozen: true };
21064
+ if (!openCodeDbExists())
21065
+ return { callable: true, frozen: true };
21066
+ try {
21067
+ const row = withReadOnlySessionDb((db) => db.prepare(`SELECT json_extract(data, '$.tools') AS tools FROM message
21068
+ WHERE session_id = ? AND json_extract(data, '$.role') = 'user'
21069
+ ORDER BY time_created ASC LIMIT 1`).get(sessionId));
21070
+ if (!row)
21071
+ return { callable: true, frozen: false };
21072
+ const verdict = row.tools === null ? null : verdictFromToolsMap(JSON.parse(row.tools), toolName);
21073
+ const resolved = verdict ?? true;
21074
+ availabilityBySession.set(key, resolved);
21075
+ return { callable: resolved, frozen: true };
21076
+ } catch (error) {
21077
+ sessionLog(sessionId, `${toolName} availability read failed (fail-open):`, error);
21078
+ return { callable: true, frozen: false };
21079
+ }
21080
+ }
21081
+ function resolveCtxReduceAvailabilityFromMessages(sessionId, messages) {
21082
+ return resolveToolAvailabilityFromMessages(sessionId, CTX_REDUCE_TOOL, messages);
21083
+ }
21084
+ function resolveCtxReduceAvailability(sessionId) {
21085
+ return resolveToolAvailability(sessionId, CTX_REDUCE_TOOL);
21086
+ }
21087
+ function isRecord2(value) {
21088
+ return value !== null && typeof value === "object" && !Array.isArray(value);
21089
+ }
21090
+ function responseData(value) {
21091
+ if (isRecord2(value) && Object.hasOwn(value, "data"))
21092
+ return value.data;
21093
+ return value;
21094
+ }
21095
+ function escapeRegExpLiteral(value) {
21096
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
21097
+ }
21098
+ function permissionNameMatches(rulePermission, toolName) {
21099
+ if (rulePermission === "*" || rulePermission === toolName)
21100
+ return true;
21101
+ if (!rulePermission.includes("*"))
21102
+ return false;
21103
+ const pattern = rulePermission.split("*").map(escapeRegExpLiteral).join(".*");
21104
+ return new RegExp(`^${pattern}$`).test(toolName);
21105
+ }
21106
+ function permissionDisabled(toolName, rules) {
21107
+ let finalRule;
21108
+ for (let index = rules.length - 1;index >= 0; index -= 1) {
21109
+ const rule = rules[index];
21110
+ if (rule && permissionNameMatches(rule.permission, toolName)) {
21111
+ finalRule = rule;
21112
+ break;
21113
+ }
21114
+ }
21115
+ return finalRule?.action === "deny" && finalRule.pattern === "*";
21116
+ }
21117
+ function actionOf(value) {
21118
+ return value === "ask" || value === "allow" || value === "deny" ? value : null;
21119
+ }
21120
+ function appendPermissionRule(target, permission, pattern, action) {
21121
+ if (typeof permission !== "string" || permission.length === 0)
21122
+ return;
21123
+ const normalizedAction = actionOf(action);
21124
+ if (!normalizedAction)
21125
+ return;
21126
+ const patterns = Array.isArray(pattern) ? pattern : [pattern ?? "*"];
21127
+ for (const candidate of patterns) {
21128
+ if (typeof candidate === "string") {
21129
+ target.push({ permission, pattern: candidate, action: normalizedAction });
21130
+ }
21131
+ }
21132
+ }
21133
+ function permissionRules(value) {
21134
+ if (Array.isArray(value)) {
21135
+ const result2 = [];
21136
+ for (const item of value) {
21137
+ if (!isRecord2(item))
21138
+ continue;
21139
+ appendPermissionRule(result2, item.permission ?? item.tool ?? item.name, item.pattern, item.action ?? item.value);
21140
+ }
21141
+ return result2;
21142
+ }
21143
+ if (!isRecord2(value))
21144
+ return [];
21145
+ const result = [];
21146
+ if (Array.isArray(value.rules))
21147
+ result.push(...permissionRules(value.rules));
21148
+ for (const [permission, configured] of Object.entries(value)) {
21149
+ if (permission === "rules")
21150
+ continue;
21151
+ const simpleAction = actionOf(configured);
21152
+ if (simpleAction) {
21153
+ appendPermissionRule(result, permission, "*", simpleAction);
21154
+ continue;
21155
+ }
21156
+ if (!isRecord2(configured))
21157
+ continue;
21158
+ for (const [pattern, action] of Object.entries(configured)) {
21159
+ appendPermissionRule(result, permission, pattern, action);
21160
+ }
21161
+ }
21162
+ return result;
21163
+ }
21164
+ function activeAgentNameFromSession(value) {
21165
+ if (!isRecord2(value))
21166
+ return;
21167
+ const agent = value.agent;
21168
+ return typeof agent === "string" && agent.length > 0 ? agent : undefined;
21169
+ }
21170
+ async function resolveToolPermissionDenied(client, sessionId, toolName, activeAgent) {
21171
+ const sdk = client;
21172
+ if (!sdk.app?.agents || !sdk.session?.get) {
21173
+ throw new Error("OpenCode permission APIs are unavailable");
21174
+ }
21175
+ const [agentsResponse, sessionResponse] = await Promise.all([
21176
+ sdk.app.agents(),
21177
+ sdk.session.get({ path: { id: sessionId } })
21178
+ ]);
21179
+ const agents = responseData(agentsResponse);
21180
+ const session = responseData(sessionResponse);
21181
+ const agentName = activeAgent ?? activeAgentNameFromSession(session);
21182
+ const agent = Array.isArray(agents) ? agents.find((candidate) => isRecord2(candidate) && candidate.name === agentName) : undefined;
21183
+ const agentRules = permissionRules(isRecord2(agent) ? agent.permission : undefined);
21184
+ const sessionRules = permissionRules(isRecord2(session) ? session.permission ?? session.permissions : undefined);
21185
+ const denied = permissionDisabled(toolName, [...agentRules, ...sessionRules]);
21186
+ permissionDeniedBySession.set(permissionCacheKey(toolName, sessionId), denied);
21187
+ return denied;
21188
+ }
21189
+ function todowritePermissionDenied(client, sessionId, activeAgent) {
21190
+ return resolveToolPermissionDenied(client, sessionId, TODOWRITE_TOOL, activeAgent);
21191
+ }
21192
+ function cachedToolPermissionDenied(sessionId, toolName) {
21193
+ return permissionDeniedBySession.get(permissionCacheKey(toolName, sessionId));
21194
+ }
21195
+ function clearToolPermissionDenied(sessionId, toolName) {
21196
+ if (toolName) {
21197
+ permissionDeniedBySession.delete(permissionCacheKey(toolName, sessionId));
21198
+ } else {
21199
+ permissionDeniedBySession.delete(permissionCacheKey(TODOWRITE_TOOL, sessionId));
21200
+ permissionDeniedBySession.delete(permissionCacheKey(CTX_REDUCE_TOOL, sessionId));
21201
+ }
21202
+ ctxReducePermissionDenyLogged.delete(sessionId);
21203
+ }
21204
+ function hasLoggedCtxReducePermissionDeny(sessionId) {
21205
+ return ctxReducePermissionDenyLogged.get(sessionId) === true;
21206
+ }
21207
+ function markCtxReducePermissionDenyLogged(sessionId) {
21208
+ ctxReducePermissionDenyLogged.set(sessionId, true);
21209
+ }
21210
+ function resolveTodowriteAvailabilityFromMessages(sessionId, messages) {
21211
+ return resolveToolAvailabilityFromMessages(sessionId, TODOWRITE_TOOL, messages);
21212
+ }
21213
+ function resolveTodowriteAvailability(sessionId) {
21214
+ return resolveToolAvailability(sessionId, TODOWRITE_TOOL);
21215
+ }
21216
+
20839
21217
  // src/hooks/magic-context/embed-session-state.ts
20840
21218
  var embedPauseBySession = new Set;
20841
21219
  var embedRunStateBySession = new Map;
@@ -21390,6 +21768,35 @@ ${body}${hintText}
21390
21768
  }
21391
21769
 
21392
21770
  // src/hooks/magic-context/channel2-delivery.ts
21771
+ function subagentRunIsActive(deps, sessionId) {
21772
+ try {
21773
+ const meta = getOrCreateSessionMeta(deps.db, sessionId);
21774
+ if (!meta.isSubagent)
21775
+ return true;
21776
+ return isMidTurn(deps, sessionId);
21777
+ } catch (error) {
21778
+ sessionLog(sessionId, "channel2 subagent run-state check failed; refusing delivery:", error);
21779
+ return false;
21780
+ }
21781
+ }
21782
+ function clearPendingChannel2Intent(db, sessionId) {
21783
+ try {
21784
+ if (casChannel2NudgeState(db, sessionId, "pending", "")) {
21785
+ sessionLog(sessionId, "channel2 intent cleared because the subagent run is terminal");
21786
+ }
21787
+ } catch (error) {
21788
+ sessionLog(sessionId, "channel2 terminal-run intent clear failed; leaving lease to heal:", error);
21789
+ }
21790
+ }
21791
+ function releaseClaimWithoutDelivery(db, sessionId, claimToken) {
21792
+ try {
21793
+ if (casChannel2NudgeClaim(db, sessionId, "", claimToken)) {
21794
+ sessionLog(sessionId, "channel2 claim released because the subagent run completed before delivery");
21795
+ }
21796
+ } catch (error) {
21797
+ sessionLog(sessionId, "channel2 terminal-run claim release failed; lease will heal:", error);
21798
+ }
21799
+ }
21393
21800
  async function maybeDeliverChannel2(sessionId, deps) {
21394
21801
  let state;
21395
21802
  try {
@@ -21399,6 +21806,10 @@ async function maybeDeliverChannel2(sessionId, deps) {
21399
21806
  }
21400
21807
  if (state !== "pending")
21401
21808
  return false;
21809
+ if (!subagentRunIsActive(deps, sessionId)) {
21810
+ clearPendingChannel2Intent(deps.db, sessionId);
21811
+ return false;
21812
+ }
21402
21813
  if (deps.directiveText === undefined && (deps.reclaimableTokens === undefined || deps.usableTokens === undefined)) {
21403
21814
  return false;
21404
21815
  }
@@ -21419,6 +21830,10 @@ async function maybeDeliverChannel2(sessionId, deps) {
21419
21830
  if (!claimChannel2NudgeState(deps.db, sessionId, claimToken)) {
21420
21831
  return false;
21421
21832
  }
21833
+ if (!subagentRunIsActive(deps, sessionId)) {
21834
+ releaseClaimWithoutDelivery(deps.db, sessionId, claimToken);
21835
+ return false;
21836
+ }
21422
21837
  try {
21423
21838
  const promptContext = await resolvePromptContext(client, sessionId);
21424
21839
  const reminder = deps.directiveText ?? buildChannel2Reminder(deps.reclaimableTokens, deps.oldestReclaimableToolTags);
@@ -21445,6 +21860,10 @@ async function maybeDeliverChannel2(sessionId, deps) {
21445
21860
  sessionLog(sessionId, `channel2 ceiling nudge delivery skipped: claim no longer owned before send (state=${claim.state || "empty"})`);
21446
21861
  return false;
21447
21862
  }
21863
+ if (!subagentRunIsActive(deps, sessionId)) {
21864
+ releaseClaimWithoutDelivery(deps.db, sessionId, claimToken);
21865
+ return false;
21866
+ }
21448
21867
  await session.promptAsync({ path: { id: sessionId }, body });
21449
21868
  } catch (error) {
21450
21869
  try {
@@ -21575,9 +21994,9 @@ function getMessageRemovedInfo(properties) {
21575
21994
  import * as crypto3 from "node:crypto";
21576
21995
 
21577
21996
  // src/hooks/magic-context/boundary-execution.ts
21578
- var FORCE_MATERIALIZE_PERCENTAGE2 = 85;
21579
21997
  function detectMidTurnBypassReason(input) {
21580
- if (input.contextUsage.percentage >= FORCE_MATERIALIZE_PERCENTAGE2)
21998
+ const { forceMaterializationPercentage } = escalationBands(input.effectiveExecuteThresholdPercentage);
21999
+ if (input.contextUsage.percentage >= forceMaterializationPercentage)
21581
22000
  return "force-materialize";
21582
22001
  if (input.historyRefreshSessions.has(input.sessionId))
21583
22002
  return "explicit-bust";
@@ -21604,7 +22023,7 @@ function canConsumeDeferredOnThisPass(args) {
21604
22023
  return true;
21605
22024
  if (args.activeRunBlocksMaterialization)
21606
22025
  return false;
21607
- return args.schedulerDecision === "execute" || args.contextPercentage >= FORCE_MATERIALIZE_PERCENTAGE;
22026
+ return args.schedulerDecision === "execute" || args.contextPercentage >= (args.forceMaterializationPercentage ?? escalationBands(65).forceMaterializationPercentage);
21608
22027
  }
21609
22028
 
21610
22029
  // src/hooks/magic-context/caveman.ts
@@ -21948,72 +22367,157 @@ function replayCavemanCompression(sessionId, db, targets, tags) {
21948
22367
  return replayed;
21949
22368
  }
21950
22369
 
21951
- // src/hooks/magic-context/ctx-reduce-availability.ts
21952
- var CTX_REDUCE_TOOL = "ctx_reduce";
21953
- var TODOWRITE_TOOL = "todowrite";
21954
- var availabilityBySession = new BoundedSessionMap(1000);
21955
- function cacheKey(toolName, sessionId) {
21956
- return `${toolName}\x00${sessionId}`;
21957
- }
21958
- function verdictFromToolsMap(tools, toolName) {
21959
- if (tools === null || typeof tools !== "object" || Array.isArray(tools))
21960
- return null;
21961
- const map = tools;
21962
- if (map[toolName] === true)
21963
- return true;
21964
- if (map[toolName] === false)
21965
- return false;
21966
- if (map["*"] === false)
21967
- return false;
21968
- return null;
21969
- }
21970
- function resolveToolAvailabilityFromMessages(sessionId, toolName, messages) {
21971
- const key = cacheKey(toolName, sessionId);
21972
- const cached = availabilityBySession.get(key);
21973
- if (cached !== undefined)
21974
- return { callable: cached, frozen: true };
21975
- for (const message of messages) {
21976
- if (message.info?.role !== "user")
21977
- continue;
21978
- const verdict = verdictFromToolsMap(message.info.tools, toolName) ?? true;
21979
- availabilityBySession.set(key, verdict);
21980
- return { callable: verdict, frozen: true };
22370
+ // src/hooks/magic-context/compaction-off-transition.ts
22371
+ import { existsSync as existsSync11 } from "node:fs";
22372
+ var loggedUnverifiedMarkerCleanupRetry = false;
22373
+ var COMPACTION_OFF_FLIP_NOTICE = [
22374
+ "## Magic Context — compaction-off mode is now active",
22375
+ "",
22376
+ "Magic Context no longer manages this session's context window; native compaction (or nothing) owns it. Memory, dreamer, notes and ctx_search stay live.",
22377
+ "",
22378
+ "Magic Context's compaction markers for this session were removed, so history previously hidden by them becomes visible again — the first turn after disabling may trigger one native compaction cycle on long sessions."
22379
+ ].join(`
22380
+ `);
22381
+ var COMPACTION_ON_WRAPUP_SUGGESTION = [
22382
+ "## Magic Context — compaction re-enabled",
22383
+ "",
22384
+ "Context-window management resumed for this session. History that grew while compaction was off will be picked up by the historian automatically; run `/ctx-wrapup` to digest the backlog now in bounded chunks."
22385
+ ].join(`
22386
+ `);
22387
+ var NO_TRANSITION = {
22388
+ recordToWrite: null,
22389
+ notice: null,
22390
+ invalidatedM0Baseline: false,
22391
+ historianCatchUpSignaled: false,
22392
+ clearedCompartmentInProgress: false,
22393
+ clearedSomething: false,
22394
+ markerCleanup: {
22395
+ verified: true,
22396
+ removedLineages: 0,
22397
+ removedRows: 0,
22398
+ retainedLineages: 0
21981
22399
  }
21982
- return { callable: true, frozen: false };
22400
+ };
22401
+ function clearCachedM0Baseline(db, sessionId) {
22402
+ const result = db.prepare("UPDATE session_meta SET cached_m0_bytes = NULL, cached_m1_bytes = NULL, cached_m0_mural_data_url = NULL WHERE session_id = ?").run(sessionId);
22403
+ return (result.changes ?? 0) > 0;
21983
22404
  }
21984
- function resolveToolAvailability(sessionId, toolName) {
21985
- const key = cacheKey(toolName, sessionId);
21986
- const cached = availabilityBySession.get(key);
21987
- if (cached !== undefined)
21988
- return { callable: cached, frozen: true };
21989
- if (!openCodeDbExists())
21990
- return { callable: true, frozen: true };
21991
- try {
21992
- const row = withReadOnlySessionDb((db) => db.prepare(`SELECT json_extract(data, '$.tools') AS tools FROM message
21993
- WHERE session_id = ? AND json_extract(data, '$.role') = 'user'
21994
- ORDER BY time_created ASC LIMIT 1`).get(sessionId));
21995
- if (!row)
21996
- return { callable: true, frozen: false };
21997
- const verdict = row.tools === null ? null : verdictFromToolsMap(JSON.parse(row.tools), toolName);
21998
- const resolved = verdict ?? true;
21999
- availabilityBySession.set(key, resolved);
22000
- return { callable: resolved, frozen: true };
22001
- } catch (error) {
22002
- sessionLog(sessionId, `${toolName} availability read failed (fail-open):`, error);
22003
- return { callable: true, frozen: false };
22405
+ function cleanupOffMarkers(sessionId) {
22406
+ if (!existsSync11(getOpenCodeDbPath())) {
22407
+ return { verified: true, removedLineages: 0, removedRows: 0, retainedLineages: 0 };
22004
22408
  }
22409
+ return removeMcOwnedCompactionMarkers(sessionId, MARKER_SUMMARY_TEXT);
22005
22410
  }
22006
- function resolveCtxReduceAvailabilityFromMessages(sessionId, messages) {
22007
- return resolveToolAvailabilityFromMessages(sessionId, CTX_REDUCE_TOOL, messages);
22008
- }
22009
- function resolveCtxReduceAvailability(sessionId) {
22010
- return resolveToolAvailability(sessionId, CTX_REDUCE_TOOL);
22011
- }
22012
- function resolveTodowriteAvailabilityFromMessages(sessionId, messages) {
22013
- return resolveToolAvailabilityFromMessages(sessionId, TODOWRITE_TOOL, messages);
22411
+ function reconcileCompactionMode(args) {
22412
+ const { db, sessionId } = args;
22413
+ const stored = getCompactionModeRecord(db, sessionId);
22414
+ if (stored === "on_notice_pending") {
22415
+ return {
22416
+ ...NO_TRANSITION,
22417
+ recordToWrite: "on",
22418
+ notice: COMPACTION_ON_WRAPUP_SUGGESTION
22419
+ };
22420
+ }
22421
+ if (stored === "off_notice_pending") {
22422
+ const markerCleanup2 = cleanupOffMarkers(sessionId);
22423
+ return {
22424
+ ...NO_TRANSITION,
22425
+ recordToWrite: markerCleanup2.verified ? "off" : "off_cleanup_pending",
22426
+ notice: COMPACTION_OFF_FLIP_NOTICE,
22427
+ markerCleanup: markerCleanup2
22428
+ };
22429
+ }
22430
+ if (!args.compactionOff) {
22431
+ if (stored === null || resolveCompactionModeRecord(stored) === "on") {
22432
+ return stored === null ? { ...NO_TRANSITION, recordToWrite: "on" } : NO_TRANSITION;
22433
+ }
22434
+ const invalidatedM0Baseline2 = clearCachedM0Baseline(db, sessionId);
22435
+ let historianCatchUpSignaled = false;
22436
+ if (args.historianRunnable) {
22437
+ updateSessionMeta(db, sessionId, { compartmentInProgress: true });
22438
+ historianCatchUpSignaled = true;
22439
+ }
22440
+ if (!historianCatchUpSignaled) {
22441
+ return {
22442
+ ...NO_TRANSITION,
22443
+ recordToWrite: "on",
22444
+ invalidatedM0Baseline: invalidatedM0Baseline2
22445
+ };
22446
+ }
22447
+ setCompactionModeRecord(db, sessionId, "on_notice_pending");
22448
+ return {
22449
+ ...NO_TRANSITION,
22450
+ recordToWrite: "on",
22451
+ notice: COMPACTION_ON_WRAPUP_SUGGESTION,
22452
+ invalidatedM0Baseline: invalidatedM0Baseline2,
22453
+ historianCatchUpSignaled
22454
+ };
22455
+ }
22456
+ if (stored === "off")
22457
+ return NO_TRANSITION;
22458
+ if (stored === "off_cleanup_pending") {
22459
+ const markerCleanup2 = cleanupOffMarkers(sessionId);
22460
+ return {
22461
+ ...NO_TRANSITION,
22462
+ recordToWrite: markerCleanup2.verified ? "off" : null,
22463
+ markerCleanup: markerCleanup2
22464
+ };
22465
+ }
22466
+ let clearedSomething = false;
22467
+ const markerCleanup = cleanupOffMarkers(sessionId);
22468
+ if (markerCleanup.removedRows > 0)
22469
+ clearedSomething = true;
22470
+ if (getPersistedCompactionMarkerState(db, sessionId) !== null) {
22471
+ setPersistedCompactionMarkerState(db, sessionId, null);
22472
+ clearedSomething = true;
22473
+ }
22474
+ const pendingMarker = getPendingCompactionMarkerState(db, sessionId);
22475
+ if (pendingMarker !== null) {
22476
+ clearPendingCompactionMarkerStateIf(db, sessionId, pendingMarker);
22477
+ clearedSomething = true;
22478
+ }
22479
+ if (getOverflowState(db, sessionId).needsEmergencyRecovery) {
22480
+ clearEmergencyRecovery(db, sessionId);
22481
+ clearedSomething = true;
22482
+ }
22483
+ const channel2State = getChannel2NudgeState(db, sessionId);
22484
+ if (channel2State === "pending" || channel2State === "claimed") {
22485
+ setChannel2NudgeState(db, sessionId, "");
22486
+ clearedSomething = true;
22487
+ }
22488
+ if (getPendingOps(db, sessionId).length > 0) {
22489
+ clearPendingOps(db, sessionId);
22490
+ clearedSomething = true;
22491
+ }
22492
+ const invalidatedM0Baseline = clearCachedM0Baseline(db, sessionId);
22493
+ let clearedCompartmentInProgress = false;
22494
+ if (args.compartmentInProgress) {
22495
+ updateSessionMeta(db, sessionId, { compartmentInProgress: false });
22496
+ clearedCompartmentInProgress = true;
22497
+ }
22498
+ sessionLog(sessionId, `compaction-off transition: marker cleanup verified=${markerCleanup.verified}, removed=${markerCleanup.removedLineages} lineage(s)/${markerCleanup.removedRows} row(s), retained=${markerCleanup.retainedLineages}, clearedSomething=${clearedSomething}`);
22499
+ if (!markerCleanup.verified && !loggedUnverifiedMarkerCleanupRetry) {
22500
+ loggedUnverifiedMarkerCleanupRetry = true;
22501
+ sessionLog(sessionId, "compaction-off transition could not verify complete marker cleanup; durable cleanup retry will run on the next pass");
22502
+ }
22503
+ const notice = clearedSomething ? COMPACTION_OFF_FLIP_NOTICE : null;
22504
+ if (notice) {
22505
+ setCompactionModeRecord(db, sessionId, "off_notice_pending");
22506
+ } else if (!markerCleanup.verified) {
22507
+ setCompactionModeRecord(db, sessionId, "off_cleanup_pending");
22508
+ }
22509
+ return {
22510
+ recordToWrite: notice ? markerCleanup.verified ? "off" : "off_cleanup_pending" : markerCleanup.verified ? "off" : null,
22511
+ notice,
22512
+ invalidatedM0Baseline,
22513
+ historianCatchUpSignaled: false,
22514
+ clearedCompartmentInProgress,
22515
+ clearedSomething,
22516
+ markerCleanup
22517
+ };
22014
22518
  }
22015
- function resolveTodowriteAvailability(sessionId) {
22016
- return resolveToolAvailability(sessionId, TODOWRITE_TOOL);
22519
+ function commitCompactionModeRecord(db, sessionId, record) {
22520
+ setCompactionModeRecord(db, sessionId, record);
22017
22521
  }
22018
22522
 
22019
22523
  // src/hooks/magic-context/emergency-fail-closed.ts
@@ -22364,6 +22868,29 @@ function calibrateBuckets(input) {
22364
22868
  }
22365
22869
 
22366
22870
  // src/hooks/magic-context/final-wire-token-estimate.ts
22871
+ function compactWireLabel(value, fallback) {
22872
+ if (typeof value !== "string" || value.length === 0)
22873
+ return fallback;
22874
+ return value.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 32) || fallback;
22875
+ }
22876
+ function wirePartKind(part, role) {
22877
+ const rawType = part !== null && typeof part === "object" && typeof part.type === "string" ? part.type : "unknown";
22878
+ if (rawType === "tool_result" || rawType === "tool-result")
22879
+ return "toolresult";
22880
+ if (rawType === "tool_use" || rawType === "tool-use" || rawType === "tool-invocation") {
22881
+ return "tool";
22882
+ }
22883
+ if (role === "user" && rawType === "tool")
22884
+ return "toolresult";
22885
+ return compactWireLabel(rawType, "unknown");
22886
+ }
22887
+ function describeFinalWireTail(messages) {
22888
+ return `[${messages.slice(-3).map((message) => {
22889
+ const role = compactWireLabel(message.info.role, "unknown");
22890
+ const kinds = message.parts.map((part) => wirePartKind(part, role)).join("+") || "none";
22891
+ return `${role}:${kinds}`;
22892
+ }).join(", ")}]`;
22893
+ }
22367
22894
  function serializedTokens(value) {
22368
22895
  if (value === undefined)
22369
22896
  return 0;
@@ -25886,64 +26413,6 @@ ${hintText}`;
25886
26413
  }
25887
26414
  function clearAutoSearchForSession(_sessionId) {}
25888
26415
 
25889
- // src/hooks/magic-context/sentinel.ts
25890
- var WHOLE_MESSAGE_PLACEHOLDER_TEXT = "[dropped]";
25891
- function modelAcceptsEmptyContent(providerID) {
25892
- return providerID === "anthropic";
25893
- }
25894
- function makeSentinel(originalPart) {
25895
- const sentinel = {
25896
- type: "text",
25897
- text: ""
25898
- };
25899
- if (isRecord(originalPart)) {
25900
- if (originalPart.cache_control !== undefined) {
25901
- sentinel.cache_control = originalPart.cache_control;
25902
- }
25903
- if (originalPart.cacheControl !== undefined) {
25904
- sentinel.cacheControl = originalPart.cacheControl;
25905
- }
25906
- }
25907
- return sentinel;
25908
- }
25909
- function makeWholeMessageSentinel(providerID) {
25910
- return {
25911
- type: "text",
25912
- text: modelAcceptsEmptyContent(providerID) ? "" : WHOLE_MESSAGE_PLACEHOLDER_TEXT
25913
- };
25914
- }
25915
- function isSentinel(part) {
25916
- if (!isRecord(part))
25917
- return false;
25918
- if (part.type !== "text")
25919
- return false;
25920
- if (typeof part.text !== "string")
25921
- return false;
25922
- return part.text === "" || part.text === WHOLE_MESSAGE_PLACEHOLDER_TEXT;
25923
- }
25924
- function replaySentinelByMessageIds(messages, ids, providerID) {
25925
- if (ids.size === 0)
25926
- return { replayed: 0, missingIds: [] };
25927
- const seen = new Set;
25928
- let replayed = 0;
25929
- for (const msg of messages) {
25930
- const id = msg.info.id;
25931
- if (!id || !ids.has(id))
25932
- continue;
25933
- seen.add(id);
25934
- if (msg.parts.length === 1 && isSentinel(msg.parts[0]))
25935
- continue;
25936
- msg.parts.length = 0;
25937
- msg.parts.push(makeWholeMessageSentinel(providerID));
25938
- replayed++;
25939
- }
25940
- const missingIds = [];
25941
- for (const id of ids)
25942
- if (!seen.has(id))
25943
- missingIds.push(id);
25944
- return { replayed, missingIds };
25945
- }
25946
-
25947
26416
  // src/hooks/magic-context/drop-stale-reduce-calls.ts
25948
26417
  var STALE_TOOL_NAMES = new Set(["ctx_reduce"]);
25949
26418
  function isReduceToolPart(part) {
@@ -26988,6 +27457,14 @@ function computeSyntheticCallId(stateJson) {
26988
27457
  const hash = createHash10("sha256").update(stateJson).digest("hex").slice(0, 16);
26989
27458
  return `${SYNTHETIC_CALL_ID_PREFIX}${hash}`;
26990
27459
  }
27460
+ function isSyntheticTodoPart(part) {
27461
+ if (part === null || typeof part !== "object")
27462
+ return false;
27463
+ const p = part;
27464
+ if (p.syntheticTodoMarker === true)
27465
+ return true;
27466
+ return p.type === "tool" && p.tool === "todowrite" && typeof p.callID === "string" && p.callID.startsWith(SYNTHETIC_CALL_ID_PREFIX);
27467
+ }
26991
27468
  function parseTodoState(stateJson) {
26992
27469
  if (stateJson.length === 0)
26993
27470
  return null;
@@ -27475,7 +27952,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
27475
27952
  hasResult: false
27476
27953
  };
27477
27954
  entry.occurrences.push({ message, part, kind: toolObservation.kind });
27478
- if (toolObservation.kind === "result")
27955
+ if (toolObservation.kind === "result" && partHasCompletedResult(part))
27479
27956
  entry.hasResult = true;
27480
27957
  toolCallIndex.set(compositeKey, entry);
27481
27958
  const _tGetTool = performance.now();
@@ -27727,6 +28204,74 @@ function injectPersistedTodoAnchor(messages, sessionId, messageId2, part) {
27727
28204
  }
27728
28205
  return injectSyntheticTodoAtHead(messages, sessionId, part);
27729
28206
  }
28207
+ function removeSyntheticTodoParts(messages) {
28208
+ for (let index = messages.length - 1;index >= 0; index -= 1) {
28209
+ const message = messages[index];
28210
+ if (!message)
28211
+ continue;
28212
+ const retainedParts = message.parts.filter((part) => !isSyntheticTodoPart(part));
28213
+ if (retainedParts.length === message.parts.length)
28214
+ continue;
28215
+ message.parts = retainedParts;
28216
+ if (message.info.id === TODO_HEAD_ANCHOR_ID && retainedParts.length === 0) {
28217
+ messages.splice(index, 1);
28218
+ }
28219
+ }
28220
+ }
28221
+ async function applyTodoSynthesis(args) {
28222
+ if (!args.fullFeatureMode || args.compactionOff)
28223
+ return 0;
28224
+ const persistedAnchor = getPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28225
+ let permissionDenied = cachedToolPermissionDenied(args.sessionId, "todowrite") ?? getPersistedTodoPermissionDenied(args.db, args.sessionId) ?? false;
28226
+ const toolsMapUnavailable = args.todowriteAvailability.frozen && !args.todowriteAvailability.callable;
28227
+ if (args.isCacheBustingPass && args.client && !toolsMapUnavailable) {
28228
+ try {
28229
+ permissionDenied = await todowritePermissionDenied(args.client, args.sessionId, args.activeAgent);
28230
+ setPersistedTodoPermissionDenied(args.db, args.sessionId, permissionDenied);
28231
+ } catch (error) {
28232
+ sessionLog(args.sessionId, "todowrite permission read failed; retaining the last successful verdict:", error);
28233
+ }
28234
+ }
28235
+ const todowriteUnavailable = toolsMapUnavailable || permissionDenied;
28236
+ if (args.isCacheBustingPass && todowriteUnavailable) {
28237
+ removeSyntheticTodoParts(args.messages);
28238
+ clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28239
+ if (persistedAnchor) {
28240
+ sessionLog(args.sessionId, "todowrite synthetic pair cleared on a cache-busting pass because the tool is denied");
28241
+ }
28242
+ return 0;
28243
+ }
28244
+ if (args.isCacheBustingPass) {
28245
+ const part = buildSyntheticTodoPart(args.sessionMeta.lastTodoState);
28246
+ const persistedInjection = part !== null && persistedAnchor && persistedAnchor.callId === part.callID ? injectPersistedTodoAnchor(args.messages, args.sessionId, persistedAnchor.messageId, part) : null;
28247
+ if (part === null) {
28248
+ if (persistedAnchor)
28249
+ clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28250
+ return 0;
28251
+ }
28252
+ if (persistedAnchor && persistedInjection?.injected) {
28253
+ if (persistedAnchor.stateJson.length === 0) {
28254
+ setPersistedTodoSyntheticAnchor(args.db, args.sessionId, persistedAnchor.callId, persistedAnchor.messageId, args.sessionMeta.lastTodoState);
28255
+ }
28256
+ return persistedInjection.prependedMessageCount;
28257
+ }
28258
+ const existingAssistantId = injectToolPartIntoLatestAssistant(args.messages, part);
28259
+ const injection = existingAssistantId === null ? injectSyntheticTodoAtHead(args.messages, args.sessionId, part) : {
28260
+ injected: true,
28261
+ messageId: existingAssistantId,
28262
+ prependedMessageCount: 0
28263
+ };
28264
+ setPersistedTodoSyntheticAnchor(args.db, args.sessionId, part.callID, injection.messageId, args.sessionMeta.lastTodoState);
28265
+ return injection.prependedMessageCount;
28266
+ }
28267
+ if (persistedAnchor && persistedAnchor.stateJson.length > 0) {
28268
+ const part = buildSyntheticTodoPart(persistedAnchor.stateJson);
28269
+ if (part !== null && part.callID === persistedAnchor.callId) {
28270
+ return injectPersistedTodoAnchor(args.messages, args.sessionId, persistedAnchor.messageId, part).prependedMessageCount;
28271
+ }
28272
+ }
28273
+ return 0;
28274
+ }
27730
28275
  function runRustModePostprocess(args) {
27731
28276
  if (!args.fullFeatureMode)
27732
28277
  return;
@@ -27883,18 +28428,19 @@ function finalizeMessageRepresentation(messages, resolvedProviderID, options) {
27883
28428
  return { clearedParts, mergedReasoningParts };
27884
28429
  }
27885
28430
  async function runPostTransformPhase(args) {
28431
+ const compactionOff = args.compactionOff === true;
27886
28432
  const pendingMaterializationAtPassStart = args.pendingMaterializationSessions.has(args.sessionId);
27887
28433
  const deferredMaterializationAtPassStart = args.deferredMaterializationSessions.has(args.sessionId);
27888
28434
  const isExplicitFlush = pendingMaterializationAtPassStart;
27889
28435
  const deferredMaterializationWasPending = deferredMaterializationAtPassStart;
27890
28436
  const alreadyRanThisTurn = args.currentTurnId !== null && args.lastHeuristicsTurnId.get(args.sessionId) === args.currentTurnId;
27891
- const forceMaterialization = args.fullFeatureMode && args.contextUsage.percentage >= args.forceMaterializationPercentage;
27892
- const emergencyDropEligible = args.contextUsage.percentage >= args.forceMaterializationPercentage;
28437
+ const forceMaterialization = args.fullFeatureMode && !compactionOff && args.contextUsage.percentage >= args.forceMaterializationPercentage;
28438
+ const emergencyDropEligible = !compactionOff && args.contextUsage.percentage >= args.forceMaterializationPercentage;
27893
28439
  const activeCompartmentRun = args.canRunCompartments ? getActiveCompartmentRun(args.sessionId) : undefined;
27894
28440
  const compartmentRunning = args.canRunCompartments && !args.awaitedCompartmentRun && activeCompartmentRun !== undefined;
27895
28441
  const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
27896
28442
  const materializationRequested = isExplicitFlush || deferredMaterialize;
27897
- const m0M1EnabledForFold = args.fullFeatureMode && args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory);
28443
+ const m0M1EnabledForFold = args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory) && (args.fullFeatureMode || compactionOff);
27898
28444
  const m0HardFoldThisPass = m0M1EnabledForFold && args.m0M1 ? mustMaterialize({
27899
28445
  db: args.db,
27900
28446
  sessionId: args.sessionId,
@@ -27904,12 +28450,23 @@ async function runPostTransformPhase(args) {
27904
28450
  hardSignals: args.m0M1.hardSignals
27905
28451
  }).value : false;
27906
28452
  const bypassCompartmentGate = forceMaterialization || m0HardFoldThisPass;
27907
- const shouldReadPendingOps = materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning;
28453
+ const shouldReadPendingOps = !compactionOff && (materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning);
27908
28454
  const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
27909
28455
  const hasPendingUserOps = pendingOps.length > 0;
27910
- const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || bypassCompartmentGate);
27911
- const shouldRunHeuristics = (!compartmentRunning || bypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
28456
+ const shouldApplyPendingOps = !compactionOff && (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || bypassCompartmentGate);
28457
+ const shouldRunHeuristics = !compactionOff && (!compartmentRunning || bypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
27912
28458
  const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
28459
+ if (isCacheBustingPass && args.client && args.ctxReduceAvailability.callable && !hasLoggedCtxReducePermissionDeny(args.sessionId)) {
28460
+ try {
28461
+ const denied = await resolveToolPermissionDenied(args.client, args.sessionId, "ctx_reduce", args.activeAgent);
28462
+ if (denied) {
28463
+ markCtxReducePermissionDenyLogged(args.sessionId);
28464
+ sessionLog(args.sessionId, "ctx_reduce permission is denied by OpenCode; frozen guidance remains until session restart");
28465
+ }
28466
+ } catch (error) {
28467
+ sessionLog(args.sessionId, "ctx_reduce permission read failed (ignored):", error);
28468
+ }
28469
+ }
27913
28470
  const canUseEmptySentinels = modelAcceptsEmptyContent(args.resolvedProviderID);
27914
28471
  if (shouldRunHeuristics) {
27915
28472
  const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
@@ -27921,7 +28478,7 @@ async function runPostTransformPhase(args) {
27921
28478
  }
27922
28479
  if (compartmentRunning && hasPendingUserOps) {
27923
28480
  if (bypassCompartmentGate) {
27924
- const bypassReason = forceMaterialization ? "emergency >=85%" : "m0 hard fold";
28481
+ const bypassReason = forceMaterialization ? `emergency >=${args.forceMaterializationPercentage}%` : "m0 hard fold";
27925
28482
  sessionLog(args.sessionId, `transform: compartment-gate bypass (${bypassReason}) — applying ${pendingOps.length} pending ops while compartment agent runs (${args.contextUsage.percentage.toFixed(1)}%)`);
27926
28483
  } else {
27927
28484
  sessionLog(args.sessionId, "transform: deferring pending ops — compartment agent in progress");
@@ -28027,7 +28584,7 @@ async function runPostTransformPhase(args) {
28027
28584
  if (args.schedulerDecision === "execute" && !materializationRequested) {
28028
28585
  updateSessionMeta(args.db, args.sessionId, { lastResponseTime: Date.now() });
28029
28586
  }
28030
- const toolReclaimExecutePass = args.schedulerDecision === "execute";
28587
+ const toolReclaimExecutePass = !compactionOff && args.schedulerDecision === "execute";
28031
28588
  const alreadyMutatingThisPass = pendingOpsDidMutate || heuristicOrReasoningDidMutate;
28032
28589
  let autoReclaimTargetCount = 0;
28033
28590
  let autoReclaimDidMutate = false;
@@ -28111,7 +28668,7 @@ async function runPostTransformPhase(args) {
28111
28668
  sessionLog(args.sessionId, "transform failed applying pending operations:", error);
28112
28669
  updateSessionMeta(args.db, args.sessionId, { lastTransformError: getErrorMessage(error) });
28113
28670
  }
28114
- if (canUseEmptySentinels) {
28671
+ if (canUseEmptySentinels && !compactionOff) {
28115
28672
  try {
28116
28673
  const t8 = performance.now();
28117
28674
  const frozenStaleReduceIds = getStaleReduceStrippedIds(args.db, args.sessionId);
@@ -28128,7 +28685,7 @@ async function runPostTransformPhase(args) {
28128
28685
  sessionLog(args.sessionId, "transform failed dropping stale ctx_reduce calls:", error);
28129
28686
  }
28130
28687
  }
28131
- if (canUseEmptySentinels) {
28688
+ if (canUseEmptySentinels && !compactionOff) {
28132
28689
  try {
28133
28690
  const tImg = performance.now();
28134
28691
  const frozenImageIds = getProcessedImageStrippedIds(args.db, args.sessionId);
@@ -28163,7 +28720,8 @@ async function runPostTransformPhase(args) {
28163
28720
  temporalAwareness: args.m0M1.temporalAwareness,
28164
28721
  isCacheBustingPass,
28165
28722
  hardSignals: args.m0M1.hardSignals,
28166
- muralEnabled: args.m0M1.muralEnabled
28723
+ muralEnabled: args.m0M1.muralEnabled,
28724
+ compactionOff
28167
28725
  });
28168
28726
  if (result.injected) {
28169
28727
  m0M1InjectedThisPass = true;
@@ -28188,7 +28746,7 @@ async function runPostTransformPhase(args) {
28188
28746
  clearInjectionCache(args.sessionId);
28189
28747
  }
28190
28748
  logTransformTiming(args.sessionId, "pp.injectM0M1", tInjectM0M1);
28191
- } else if (args.fullFeatureMode && args.pendingCompartmentInjection) {
28749
+ } else if (args.fullFeatureMode && !compactionOff && args.pendingCompartmentInjection) {
28192
28750
  const compartmentResult = renderCompartmentInjection(args.sessionId, args.messages, args.pendingCompartmentInjection);
28193
28751
  if (compartmentResult.injected) {
28194
28752
  prependedMessageCount += compartmentResult.prependedMessageCount;
@@ -28199,7 +28757,7 @@ async function runPostTransformPhase(args) {
28199
28757
  }
28200
28758
  }
28201
28759
  }
28202
- {
28760
+ if (!compactionOff) {
28203
28761
  const tPlaceholder = performance.now();
28204
28762
  const persistedIds = getStrippedPlaceholderIds(args.db, args.sessionId);
28205
28763
  if (persistedIds.size > 0) {
@@ -28232,7 +28790,7 @@ async function runPostTransformPhase(args) {
28232
28790
  logTransformTiming(args.sessionId, "pp.placeholderNeutralize", tPlaceholder);
28233
28791
  }
28234
28792
  const tNudgeBlock = performance.now();
28235
- if (args.fullFeatureMode) {
28793
+ if (args.fullFeatureMode && !compactionOff) {
28236
28794
  for (const anchor of getNoteNudgeAnchors(args.db, args.sessionId)) {
28237
28795
  appendReminderToUserMessageById(args.messages, anchor.messageId, anchor.text);
28238
28796
  }
@@ -28277,12 +28835,14 @@ async function runPostTransformPhase(args) {
28277
28835
  }
28278
28836
  }
28279
28837
  }
28280
- reconcileMarkerRepresentation(args.messages, getPersistedCompactionMarkerState(args.db, args.sessionId), {
28281
- db: args.db,
28282
- sessionId: args.sessionId,
28283
- tagger: args.tagger,
28284
- ctxReduceAvailability: args.ctxReduceAvailability
28285
- });
28838
+ if (!compactionOff) {
28839
+ reconcileMarkerRepresentation(args.messages, getPersistedCompactionMarkerState(args.db, args.sessionId), {
28840
+ db: args.db,
28841
+ sessionId: args.sessionId,
28842
+ tagger: args.tagger,
28843
+ ctxReduceAvailability: args.ctxReduceAvailability
28844
+ });
28845
+ }
28286
28846
  const deferredHistoryDrainEligible = historyWasConsumedThisPass && args.deferredHistoryWasPendingAtPassStart && !suppressV12HistoryDrain;
28287
28847
  if (deferredHistoryDrainEligible) {
28288
28848
  args.deferredHistoryRefreshSessions.delete(args.sessionId);
@@ -28306,42 +28866,19 @@ async function runPostTransformPhase(args) {
28306
28866
  sessionLog(args.sessionId, `note-nudge delivery skipped wire append: ${outcome.kind}`);
28307
28867
  }
28308
28868
  }
28309
- if (args.fullFeatureMode) {
28310
- const persistedAnchor = getPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28311
- const todowriteUnavailable = args.todowriteAvailability.frozen && !args.todowriteAvailability.callable;
28312
- if (isCacheBustingPass && todowriteUnavailable) {
28313
- if (persistedAnchor) {
28314
- clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28315
- }
28316
- } else if (isCacheBustingPass) {
28317
- const part = buildSyntheticTodoPart(args.sessionMeta.lastTodoState);
28318
- const persistedInjection = part !== null && persistedAnchor && persistedAnchor.callId === part.callID ? injectPersistedTodoAnchor(args.messages, args.sessionId, persistedAnchor.messageId, part) : null;
28319
- if (part === null) {
28320
- if (persistedAnchor) {
28321
- clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28322
- }
28323
- } else if (persistedAnchor && persistedInjection?.injected) {
28324
- prependedMessageCount += persistedInjection.prependedMessageCount;
28325
- if (persistedAnchor.stateJson.length === 0) {
28326
- setPersistedTodoSyntheticAnchor(args.db, args.sessionId, persistedAnchor.callId, persistedAnchor.messageId, args.sessionMeta.lastTodoState);
28327
- }
28328
- } else {
28329
- const existingAssistantId = injectToolPartIntoLatestAssistant(args.messages, part);
28330
- const injection = existingAssistantId === null ? injectSyntheticTodoAtHead(args.messages, args.sessionId, part) : {
28331
- injected: true,
28332
- messageId: existingAssistantId,
28333
- prependedMessageCount: 0
28334
- };
28335
- prependedMessageCount += injection.prependedMessageCount;
28336
- setPersistedTodoSyntheticAnchor(args.db, args.sessionId, part.callID, injection.messageId, args.sessionMeta.lastTodoState);
28337
- }
28338
- } else if (persistedAnchor && persistedAnchor.stateJson.length > 0) {
28339
- const part = buildSyntheticTodoPart(persistedAnchor.stateJson);
28340
- if (part !== null && part.callID === persistedAnchor.callId) {
28341
- const injection = injectPersistedTodoAnchor(args.messages, args.sessionId, persistedAnchor.messageId, part);
28342
- prependedMessageCount += injection.prependedMessageCount;
28343
- }
28344
- }
28869
+ if (args.fullFeatureMode && !compactionOff) {
28870
+ prependedMessageCount += await applyTodoSynthesis({
28871
+ db: args.db,
28872
+ sessionId: args.sessionId,
28873
+ messages: args.messages,
28874
+ fullFeatureMode: args.fullFeatureMode,
28875
+ compactionOff,
28876
+ isCacheBustingPass,
28877
+ sessionMeta: args.sessionMeta,
28878
+ todowriteAvailability: args.todowriteAvailability,
28879
+ client: args.client,
28880
+ activeAgent: args.activeAgent
28881
+ });
28345
28882
  }
28346
28883
  logTransformTiming(args.sessionId, "pp.noteAndTodoSynthesis", tNoteAndTodo);
28347
28884
  if (args.compartmentInjectionRebuiltFromDb && args.pendingCompartmentInjection) {
@@ -28478,7 +29015,7 @@ class MemoryAuthorityUnavailableError extends Error {
28478
29015
  var RUST_FAILURE_PARK_THRESHOLD = 3;
28479
29016
  var RUST_PROBE_INTERVAL = 5;
28480
29017
  var RUST_SEND_TIMEOUT_MS = 15000;
28481
- function isRecord2(value) {
29018
+ function isRecord3(value) {
28482
29019
  return value !== null && typeof value === "object";
28483
29020
  }
28484
29021
  function replaceMessagesInPlace(output, next) {
@@ -28488,9 +29025,9 @@ function replaceMessagesInPlace(output, next) {
28488
29025
  return target;
28489
29026
  }
28490
29027
  function messageInfo2(value) {
28491
- if (!isRecord2(value))
29028
+ if (!isRecord3(value))
28492
29029
  return {};
28493
- return isRecord2(value.info) ? value.info : value;
29030
+ return isRecord3(value.info) ? value.info : value;
28494
29031
  }
28495
29032
  function messageIdOf(message) {
28496
29033
  const id = messageInfo2(message).id;
@@ -28684,7 +29221,7 @@ function isSyntheticUserMessage(message) {
28684
29221
  if (!message || messageInfo2(message).role !== "user" || !Array.isArray(message.parts)) {
28685
29222
  return false;
28686
29223
  }
28687
- return message.parts.length > 0 && message.parts.every((part) => isRecord2(part) && (part.synthetic === true || part.ignored === true));
29224
+ return message.parts.length > 0 && message.parts.every((part) => isRecord3(part) && (part.synthetic === true || part.ignored === true));
28688
29225
  }
28689
29226
  function observeSyntheticTurn(state, messages) {
28690
29227
  const newest = newestUserMessage(messages);
@@ -28704,16 +29241,16 @@ function observeSyntheticTurn(state, messages) {
28704
29241
  function assertNativeBoundary(output, sessionId, boundaryId) {
28705
29242
  const first = output.find((message) => messageInfo2(message).role !== "system");
28706
29243
  const info = messageInfo2(first);
28707
- const parts = isRecord2(first) && Array.isArray(first.parts) ? first.parts : [];
28708
- const synthetic = parts.length > 0 && parts.every((part) => isRecord2(part) && part.synthetic === true);
29244
+ const parts = isRecord3(first) && Array.isArray(first.parts) ? first.parts : [];
29245
+ const synthetic = parts.length > 0 && parts.every((part) => isRecord3(part) && part.synthetic === true);
28709
29246
  if (info.role === "user" && info.sessionID === sessionId && synthetic)
28710
29247
  return;
28711
29248
  throw new Error(`rust transform wire invariant failed: boundary=${boundaryId} expected a synthetic m0 user message scoped to session ${sessionId}`);
28712
29249
  }
28713
29250
  function responseValue(response) {
28714
- if (isRecord2(response) && isRecord2(response.result))
29251
+ if (isRecord3(response) && isRecord3(response.result))
28715
29252
  return response.result;
28716
- if (isRecord2(response))
29253
+ if (isRecord3(response))
28717
29254
  return response;
28718
29255
  throw new Error("module transform returned a non-object response");
28719
29256
  }
@@ -28722,7 +29259,7 @@ function noteDeliveryPassIds(response) {
28722
29259
  return [];
28723
29260
  return [
28724
29261
  ...new Set(response.note_deliveries.flatMap((delivery) => {
28725
- if (!isRecord2(delivery))
29262
+ if (!isRecord3(delivery))
28726
29263
  return [];
28727
29264
  const passId = delivery.transform_pass_id;
28728
29265
  return typeof passId === "string" && passId.length > 0 ? [passId] : [];
@@ -28732,7 +29269,7 @@ function noteDeliveryPassIds(response) {
28732
29269
  function modelFromMessages(messages) {
28733
29270
  for (let index = messages.length - 1;index >= 0; index -= 1) {
28734
29271
  const info = messages[index]?.info;
28735
- const model = isRecord2(info?.model) ? info.model : undefined;
29272
+ const model = isRecord3(info?.model) ? info.model : undefined;
28736
29273
  if (typeof model?.providerID === "string" && typeof model.modelID === "string") {
28737
29274
  return { providerID: model.providerID, modelID: model.modelID };
28738
29275
  }
@@ -28756,6 +29293,7 @@ function ensureState(states, sessionId) {
28756
29293
  ordinalMemoAnchor: null,
28757
29294
  ordinalMemoStoredCount: null,
28758
29295
  ordinalMemoCanonicalCount: 0,
29296
+ ordinalContinuationBase: null,
28759
29297
  seedPassPending: true,
28760
29298
  failureCount: 0,
28761
29299
  parkCount: 0,
@@ -28810,8 +29348,8 @@ function passUsage(usage, limit) {
28810
29348
  };
28811
29349
  }
28812
29350
  function directiveTextOf(response) {
28813
- const directives = isRecord2(response.host_directives) ? response.host_directives : undefined;
28814
- const channel2 = isRecord2(directives?.channel2_nudge) ? directives.channel2_nudge : undefined;
29351
+ const directives = isRecord3(response.host_directives) ? response.host_directives : undefined;
29352
+ const channel2 = isRecord3(directives?.channel2_nudge) ? directives.channel2_nudge : undefined;
28815
29353
  return typeof channel2?.text === "string" && channel2.text.length > 0 ? channel2.text : undefined;
28816
29354
  }
28817
29355
  function isNeedFullSync(response) {
@@ -28820,7 +29358,7 @@ function isNeedFullSync(response) {
28820
29358
  function canonicalizeForChecksum(value) {
28821
29359
  if (Array.isArray(value))
28822
29360
  return value.map(canonicalizeForChecksum);
28823
- if (!isRecord2(value))
29361
+ if (!isRecord3(value))
28824
29362
  return value;
28825
29363
  return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalizeForChecksum(value[key])]));
28826
29364
  }
@@ -28836,7 +29374,7 @@ function authoritySeedRows(db, projectPath, domain) {
28836
29374
  WHERE sp.session_id = n.session_id AND sp.project_path = ?
28837
29375
  ))
28838
29376
  ORDER BY n.id ASC`).all(projectPath, projectPath);
28839
- const memoryRows = snapshots.filter(isRecord2);
29377
+ const memoryRows = snapshots.filter(isRecord3);
28840
29378
  const mappings = domain === "memories" ? getMemoryVerifications(db, memoryRows.map((row) => Number(row.id))) : new Map;
28841
29379
  return memoryRows.map((snapshot) => {
28842
29380
  const id = Number(snapshot.id);
@@ -28861,11 +29399,36 @@ async function prepareRustMemoryAuthority(args) {
28861
29399
  throw new MemoryAuthorityUnavailableError("the module does not expose authority.status, authority.prepare, and authority.seed");
28862
29400
  }
28863
29401
  const authorityModule = {
28864
- authorityStatus: (request2) => module.authorityStatus({ ...request2, projectRoot }),
28865
- authorityPrepare: (request2) => module.authorityPrepare({ ...request2, projectRoot }),
28866
- authoritySeed: (request2) => module.authoritySeed({ ...request2, projectRoot }),
28867
- authorityDrain: module.authorityDrain ? (request2) => module.authorityDrain({ ...request2, projectRoot }) : undefined,
28868
- mirrorPull: module.mirrorPull ? (request2) => module.mirrorPull({ ...request2, projectRoot }) : undefined
29402
+ authorityStatus: (request2) => {
29403
+ const method = module.authorityStatus;
29404
+ if (!method)
29405
+ throw new MemoryAuthorityUnavailableError("authority.status unavailable");
29406
+ return method.call(module, { ...request2, projectRoot });
29407
+ },
29408
+ authorityPrepare: (request2) => {
29409
+ const method = module.authorityPrepare;
29410
+ if (!method)
29411
+ throw new MemoryAuthorityUnavailableError("authority.prepare unavailable");
29412
+ return method.call(module, { ...request2, projectRoot });
29413
+ },
29414
+ authoritySeed: (request2) => {
29415
+ const method = module.authoritySeed;
29416
+ if (!method)
29417
+ throw new MemoryAuthorityUnavailableError("authority.seed unavailable");
29418
+ return method.call(module, { ...request2, projectRoot });
29419
+ },
29420
+ authorityDrain: module.authorityDrain ? (request2) => {
29421
+ const method = module.authorityDrain;
29422
+ if (!method)
29423
+ throw new MemoryAuthorityUnavailableError("authority.drain unavailable");
29424
+ return method.call(module, { ...request2, projectRoot });
29425
+ } : undefined,
29426
+ mirrorPull: module.mirrorPull ? (request2) => {
29427
+ const method = module.mirrorPull;
29428
+ if (!method)
29429
+ throw new MemoryAuthorityUnavailableError("mirror.pull unavailable");
29430
+ return method.call(module, { ...request2, projectRoot });
29431
+ } : undefined
28869
29432
  };
28870
29433
  const contextStoreUuid = ensureContextStoreUuid(db);
28871
29434
  const domains = ["memories", "notes"];
@@ -28891,7 +29454,7 @@ async function prepareRustMemoryAuthority(args) {
28891
29454
  projectPath,
28892
29455
  domain,
28893
29456
  module: authorityModule,
28894
- checksum: () => checksumSeedRows(db.prepare(`SELECT * FROM ${domain === "memories" ? "memories" : "notes"} WHERE project_path = ? ORDER BY id ASC`).all(projectPath).filter(isRecord2))
29457
+ checksum: () => checksumSeedRows(db.prepare(`SELECT * FROM ${domain === "memories" ? "memories" : "notes"} WHERE project_path = ? ORDER BY id ASC`).all(projectPath).filter(isRecord3))
28895
29458
  });
28896
29459
  if (!("code" in drained))
28897
29460
  break;
@@ -29000,6 +29563,13 @@ function buildTransformBody(args) {
29000
29563
  caveman_enabled: args.passInputs.caveman_enabled === true,
29001
29564
  caveman_min_chars: args.passInputs.caveman_min_chars ?? 500,
29002
29565
  cache_ttl: args.passInputs.cache_ttl,
29566
+ lineage_switched: args.passInputs.lineage_switched === true,
29567
+ descent_edge_id: args.passInputs.descent_edge_id,
29568
+ prior_conversation_key: args.passInputs.prior_conversation_key,
29569
+ prior_epoch: args.passInputs.prior_epoch,
29570
+ new_epoch: args.passInputs.new_epoch,
29571
+ constituents: args.passInputs.constituents,
29572
+ compaction_observed: args.passInputs.compaction_observed === true,
29003
29573
  pass_inputs: args.passInputs,
29004
29574
  declared_trim: args.declaredTrim
29005
29575
  };
@@ -29231,7 +29801,7 @@ function createRustModeTransform(deps, options) {
29231
29801
  decision = typeof response.decision === "string" ? response.decision : typeof response.action === "string" ? response.action : typeof response.status === "string" ? response.status : "unknown";
29232
29802
  servedFrom = typeof response.served_from === "string" ? response.served_from : "unknown";
29233
29803
  materializeReason = typeof response.materialize_reason === "string" && response.materialize_reason.length > 0 ? response.materialize_reason : "none";
29234
- const timings2 = isRecord2(response.timings) ? response.timings : undefined;
29804
+ const timings2 = isRecord3(response.timings) ? response.timings : undefined;
29235
29805
  const total = timings2?.total;
29236
29806
  moduleElapsedMs = typeof total === "number" && Number.isFinite(total) ? total : 0;
29237
29807
  if (timings2 && moduleElapsedMs >= 1000) {
@@ -29332,10 +29902,10 @@ function createRustModeTransform(deps, options) {
29332
29902
  continue;
29333
29903
  const prior = state.idOrdinalMemo.get(priorId);
29334
29904
  if (prior !== undefined)
29335
- return prior;
29905
+ return Math.max(prior, state.ordinalContinuationBase ?? 0);
29336
29906
  }
29337
- return state.ordinalMemoCanonicalCount;
29338
- })() : undefined;
29907
+ return Math.max(state.ordinalMemoCanonicalCount, state.ordinalContinuationBase ?? 0);
29908
+ })() : state.ordinalContinuationBase ?? undefined;
29339
29909
  const ordinalStartedAt = performance.now();
29340
29910
  let resolved = await resolveOrdinalsForModule({
29341
29911
  sessionId,
@@ -29361,7 +29931,8 @@ function createRustModeTransform(deps, options) {
29361
29931
  memo: state.idOrdinalMemo,
29362
29932
  memoAnchor: state.ordinalMemoAnchor,
29363
29933
  memoStoredCount: state.ordinalMemoStoredCount,
29364
- memoCanonicalCount: state.ordinalMemoCanonicalCount
29934
+ memoCanonicalCount: state.ordinalMemoCanonicalCount,
29935
+ provisionalBase: state.ordinalContinuationBase ?? undefined
29365
29936
  });
29366
29937
  logStage(sessionId, "ordinalResolve", fullOrdinalStartedAt, timings, "fallback=clean_full");
29367
29938
  }
@@ -29403,10 +29974,11 @@ function createRustModeTransform(deps, options) {
29403
29974
  };
29404
29975
  }
29405
29976
  }
29977
+ const stateSyncCapabilities = options.moduleClient.stateSyncCapabilities;
29406
29978
  const stateSyncResult = await syncModuleState({
29407
29979
  client: {
29408
29980
  call: callModule,
29409
- stateSyncCapabilities: options.moduleClient.stateSyncCapabilities ? (capabilityArgs) => options.moduleClient.stateSyncCapabilities(capabilityArgs) : undefined
29981
+ stateSyncCapabilities: stateSyncCapabilities ? (capabilityArgs) => stateSyncCapabilities.call(options.moduleClient, capabilityArgs) : undefined
29410
29982
  },
29411
29983
  state,
29412
29984
  pass: syncPass,
@@ -29540,7 +30112,8 @@ function createRustModeTransform(deps, options) {
29540
30112
  memo: state.idOrdinalMemo,
29541
30113
  memoAnchor: state.ordinalMemoAnchor,
29542
30114
  memoStoredCount: state.ordinalMemoStoredCount,
29543
- memoCanonicalCount: state.ordinalMemoCanonicalCount
30115
+ memoCanonicalCount: state.ordinalMemoCanonicalCount,
30116
+ provisionalBase: state.ordinalContinuationBase ?? undefined
29544
30117
  });
29545
30118
  logStage(sessionId, "ordinalResolve", retryOrdinalStartedAt, timings, "retry=full");
29546
30119
  if (!retryResolved.ok) {
@@ -29690,6 +30263,16 @@ function createRustModeTransform(deps, options) {
29690
30263
  sessionLog(sessionId, "rust note delivery ack failed (will retry):", ackError);
29691
30264
  }
29692
30265
  }
30266
+ const ordinalContinuationBase = response.ordinal_continuation_base;
30267
+ if (typeof ordinalContinuationBase === "number" && Number.isSafeInteger(ordinalContinuationBase) && ordinalContinuationBase > 0) {
30268
+ if (state.ordinalContinuationBase === null) {
30269
+ for (const [messageId2, ordinal] of state.idOrdinalMemo) {
30270
+ state.idOrdinalMemo.set(messageId2, ordinal + ordinalContinuationBase);
30271
+ }
30272
+ state.ordinalMemoCanonicalCount += ordinalContinuationBase;
30273
+ }
30274
+ state.ordinalContinuationBase = ordinalContinuationBase;
30275
+ }
29693
30276
  if (!stateSyncRetryBusy) {
29694
30277
  state.initialized = true;
29695
30278
  state.seedPassPending = false;
@@ -29723,13 +30306,14 @@ function createRustModeTransform(deps, options) {
29723
30306
  sessionLog(sessionId, "rust memory mirror-back failed (ignored):", error);
29724
30307
  }
29725
30308
  }
29726
- if (options.moduleClient.getCompartmentsAfter) {
30309
+ const getCompartmentsAfter = options.moduleClient.getCompartmentsAfter;
30310
+ if (getCompartmentsAfter) {
29727
30311
  try {
29728
30312
  await mirrorModuleCompartments({
29729
30313
  db: deps.db,
29730
30314
  sessionId,
29731
30315
  reader: {
29732
- getCompartmentsAfter: (mirroredSessionId, afterSequence) => options.moduleClient.getCompartmentsAfter(mirroredSessionId, afterSequence)
30316
+ getCompartmentsAfter: (mirroredSessionId, afterSequence) => getCompartmentsAfter.call(options.moduleClient, mirroredSessionId, afterSequence)
29733
30317
  }
29734
30318
  });
29735
30319
  } catch (error) {
@@ -29787,7 +30371,7 @@ function createRustModeTransform(deps, options) {
29787
30371
  // src/hooks/magic-context/transform-compartment-phase.ts
29788
30372
  function runCompartmentPhase(args) {
29789
30373
  const historianRunnable = args.historianRunnable !== false;
29790
- const willReadRawHistory = historianRunnable && args.canRunCompartments && getActiveCompartmentRun(args.sessionId) === undefined && (args.sessionMeta.compartmentInProgress || !args.skipAwaitForThisPass && args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE);
30374
+ const willReadRawHistory = historianRunnable && !args.compactionOff && args.canRunCompartments && getActiveCompartmentRun(args.sessionId) === undefined && (args.sessionMeta.compartmentInProgress || !args.skipAwaitForThisPass && args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE);
29791
30375
  if (!willReadRawHistory) {
29792
30376
  return runCompartmentPhaseImpl(args);
29793
30377
  }
@@ -29811,6 +30395,21 @@ async function runCompartmentPhaseImpl(args) {
29811
30395
  let justAwaitedPublication = false;
29812
30396
  let rebuiltHistoryThisPass = false;
29813
30397
  const historianRunnable = args.historianRunnable !== false;
30398
+ if (args.compactionOff) {
30399
+ if (args.sessionMeta.compartmentInProgress) {
30400
+ sessionLog(args.sessionId, "transform: compaction off; clearing stale compartmentInProgress flag");
30401
+ updateSessionMeta(args.db, args.sessionId, { compartmentInProgress: false });
30402
+ compartmentInProgress = false;
30403
+ }
30404
+ return {
30405
+ pendingCompartmentInjection,
30406
+ awaitedCompartmentRun: false,
30407
+ compartmentInProgress,
30408
+ published,
30409
+ justAwaitedPublication,
30410
+ rebuiltHistoryThisPass
30411
+ };
30412
+ }
29814
30413
  let rawEligibility = null;
29815
30414
  let lastObservedCompartmentEnd = -1;
29816
30415
  let cachedBoundarySnapshot = null;
@@ -29996,12 +30595,31 @@ function clearMessageTokensCache(sessionId, messageId2) {
29996
30595
  cache.delete(messageId2);
29997
30596
  }
29998
30597
  var recordedSessionProjectIdentity = new BoundedSessionMap(MESSAGE_TOKENS_CACHE_MAX);
30598
+ function activeAgentFromMessages(messages) {
30599
+ for (let index = messages.length - 1;index >= 0; index -= 1) {
30600
+ const info = messages[index]?.info;
30601
+ if (info?.role !== "user")
30602
+ continue;
30603
+ return typeof info.agent === "string" && info.agent.length > 0 ? info.agent : undefined;
30604
+ }
30605
+ return;
30606
+ }
29999
30607
  function deriveTaggerLoadFloor(messages, sessionId, db) {
30000
30608
  return deriveTagLoadFloor(db, sessionId, function* () {
30001
30609
  for (const message of messages)
30002
30610
  yield message.info?.id;
30003
30611
  }());
30004
30612
  }
30613
+ function computeHardCacheExpired(cacheTtl, lastResponseTime, now, onInvalid) {
30614
+ let ttlMs;
30615
+ try {
30616
+ ttlMs = parseCacheTtl(cacheTtl);
30617
+ } catch (error) {
30618
+ onInvalid?.(error);
30619
+ ttlMs = 5 * 60 * 1000;
30620
+ }
30621
+ return lastResponseTime > 0 && now - lastResponseTime > ttlMs;
30622
+ }
30005
30623
  function findLastAssistantModel(messages) {
30006
30624
  for (let i = messages.length - 1;i >= 0; i--) {
30007
30625
  const info = messages[i].info;
@@ -30027,19 +30645,22 @@ var tsAuthorityRecoveryStateByProject = new Map;
30027
30645
  var tsAuthorityMismatchLoggedProjects = new Set;
30028
30646
  var tsAuthorityUnreachableLoggedProjects = new Set;
30029
30647
  function authorityModuleForProject(module, projectRoot) {
30030
- if (!module.authorityStatus || !module.authorityDrain || !module.mirrorPull) {
30648
+ const authorityStatus = module.authorityStatus;
30649
+ const authorityDrain = module.authorityDrain;
30650
+ const mirrorPull = module.mirrorPull;
30651
+ if (!authorityStatus || !authorityDrain || !mirrorPull) {
30031
30652
  throw new Error("the module does not expose authority.status, authority.drain, and mirror.pull");
30032
30653
  }
30033
30654
  return {
30034
- authorityStatus: (request2) => module.authorityStatus({ ...request2, projectRoot }),
30655
+ authorityStatus: (request2) => authorityStatus.call(module, { ...request2, projectRoot }),
30035
30656
  authorityPrepare: (request2) => {
30036
30657
  if (!module.authorityPrepare) {
30037
30658
  throw new Error("the module does not expose authority.prepare");
30038
30659
  }
30039
30660
  return module.authorityPrepare({ ...request2, projectRoot });
30040
30661
  },
30041
- authorityDrain: (request2) => module.authorityDrain({ ...request2, projectRoot }),
30042
- mirrorPull: (request2) => module.mirrorPull({ ...request2, projectRoot })
30662
+ authorityDrain: (request2) => authorityDrain.call(module, { ...request2, projectRoot }),
30663
+ mirrorPull: (request2) => mirrorPull.call(module, { ...request2, projectRoot })
30043
30664
  };
30044
30665
  }
30045
30666
  async function recoverTsAuthorityProject(args) {
@@ -30091,11 +30712,12 @@ function scheduleTsAuthorityRecovery(args) {
30091
30712
  return;
30092
30713
  if (tsAuthorityRecoveryStateByProject.has(args.projectPath))
30093
30714
  return;
30715
+ const module = args.module;
30094
30716
  if (!tsAuthorityMismatchLoggedProjects.has(args.projectPath)) {
30095
30717
  tsAuthorityMismatchLoggedProjects.add(args.projectPath);
30096
30718
  log(`[magic-context] project ${args.projectPath} is module-authority-managed but transform_mode is TS; draining authority back to TypeScript`);
30097
30719
  }
30098
- if (!args.module) {
30720
+ if (!module) {
30099
30721
  tsAuthorityRecoveryStateByProject.set(args.projectPath, "complete");
30100
30722
  if (!tsAuthorityUnreachableLoggedProjects.has(args.projectPath)) {
30101
30723
  tsAuthorityUnreachableLoggedProjects.add(args.projectPath);
@@ -30104,7 +30726,7 @@ function scheduleTsAuthorityRecovery(args) {
30104
30726
  return;
30105
30727
  }
30106
30728
  tsAuthorityRecoveryStateByProject.set(args.projectPath, "running");
30107
- Promise.resolve().then(() => recoverTsAuthorityProject({ ...args, module: args.module })).then((outcome) => {
30729
+ Promise.resolve().then(() => recoverTsAuthorityProject({ ...args, module })).then((outcome) => {
30108
30730
  if (outcome === "completed") {
30109
30731
  tsAuthorityRecoveryStateByProject.set(args.projectPath, "complete");
30110
30732
  log(`[magic-context] authority drain complete for project ${args.projectPath}`);
@@ -30150,6 +30772,7 @@ function createTransform(deps) {
30150
30772
  }
30151
30773
  const tUserMsg = performance.now();
30152
30774
  const currentTurnId = findLastUserMessageId(messages);
30775
+ const activeAgent = activeAgentFromMessages(messages);
30153
30776
  logTransformTiming(sessionId, "findLastUserMessageId", tUserMsg);
30154
30777
  const tMeta = performance.now();
30155
30778
  let sessionMeta;
@@ -30175,6 +30798,47 @@ function createTransform(deps) {
30175
30798
  }
30176
30799
  const reducedMode = sessionMeta.isSubagent;
30177
30800
  const fullFeatureMode = !reducedMode;
30801
+ const compactionOff = deps.compactionOff === true;
30802
+ try {
30803
+ const transition = reconcileCompactionMode({
30804
+ db,
30805
+ sessionId,
30806
+ compactionOff,
30807
+ historianRunnable: deps.historianRunnable !== false,
30808
+ compartmentInProgress: sessionMeta.compartmentInProgress
30809
+ });
30810
+ const hasTransitionEffects = transition.recordToWrite !== null || transition.notice !== null || transition.invalidatedM0Baseline || transition.clearedCompartmentInProgress || transition.historianCatchUpSignaled;
30811
+ if (hasTransitionEffects) {
30812
+ if (transition.invalidatedM0Baseline) {
30813
+ sessionMeta = {
30814
+ ...sessionMeta,
30815
+ cachedM0Bytes: null,
30816
+ cachedM1Bytes: null,
30817
+ cachedM0MuralDataUrl: null,
30818
+ cachedM0MuralHash: null
30819
+ };
30820
+ }
30821
+ if (transition.clearedCompartmentInProgress) {
30822
+ sessionMeta = { ...sessionMeta, compartmentInProgress: false };
30823
+ }
30824
+ if (transition.historianCatchUpSignaled) {
30825
+ sessionMeta = { ...sessionMeta, compartmentInProgress: true };
30826
+ }
30827
+ const notice = transition.notice;
30828
+ let noticeDelivered = notice === null || deps.client === undefined;
30829
+ if (notice && deps.client) {
30830
+ noticeDelivered = await sendIgnoredMessage(deps.client, sessionId, notice, deps.getNotificationParams?.(sessionId) ?? {}) === "sent";
30831
+ }
30832
+ if (noticeDelivered && transition.recordToWrite !== null) {
30833
+ commitCompactionModeRecord(db, sessionId, transition.recordToWrite);
30834
+ } else if (!noticeDelivered) {
30835
+ sessionLog(sessionId, "compaction mode notice was not delivered; durable pending record will retry on the next pass");
30836
+ }
30837
+ }
30838
+ } catch (error) {
30839
+ passOutcome.record("compaction-mode-transition-failure");
30840
+ sessionLog(sessionId, "compaction mode transition failed (retrying next pass):", error);
30841
+ }
30178
30842
  const ctxReduceAvailability = resolveCtxReduceAvailabilityFromMessages(sessionId, messages);
30179
30843
  const ctxReduceCallable = ctxReduceAvailability.callable;
30180
30844
  const todowriteAvailability = resolveTodowriteAvailabilityFromMessages(sessionId, messages);
@@ -30202,7 +30866,7 @@ function createTransform(deps) {
30202
30866
  }
30203
30867
  const compartmentDirectory = sessionDirectory;
30204
30868
  const historianRunnable = deps.historianRunnable !== false;
30205
- const canRunCompartments = fullFeatureMode && historianRunnable && deps.client !== undefined && compartmentDirectory.length > 0;
30869
+ const canRunCompartments = fullFeatureMode && !compactionOff && historianRunnable && deps.client !== undefined && compartmentDirectory.length > 0;
30206
30870
  const fallbackModelId = deps.getFallbackModelId?.(sessionId);
30207
30871
  const tModelDetect = performance.now();
30208
30872
  const persistedUsageBeforeResets = loadPersistedUsage(db, sessionId);
@@ -30262,7 +30926,7 @@ function createTransform(deps) {
30262
30926
  let emergencyRecoveryArmed = false;
30263
30927
  let emergencyRecoveryOrigin = null;
30264
30928
  let usagePercentageSynthetic = false;
30265
- if (fullFeatureMode) {
30929
+ if (fullFeatureMode && !compactionOff) {
30266
30930
  try {
30267
30931
  const armModel = deps.liveModelBySession?.get(sessionId);
30268
30932
  const armModelKey = deps.getModelKey?.(sessionId);
@@ -30315,25 +30979,27 @@ function createTransform(deps) {
30315
30979
  sessionID: sessionId
30316
30980
  }) : undefined;
30317
30981
  const currentModelKeyForBoundary = deps.getModelKey?.(sessionId);
30982
+ const thresholdContextLimit = resolvedContextLimit && resolvedContextLimit > 0 ? resolvedContextLimit : contextUsageEarly.percentage > 0 ? contextUsageEarly.inputTokens / (contextUsageEarly.percentage / 100) : undefined;
30983
+ const effectiveExecuteThresholdPercentage = resolveExecuteThreshold(deps.executeThresholdPercentage ?? 65, currentModelKeyForBoundary, 65, {
30984
+ tokensConfig: deps.executeThresholdTokens,
30985
+ contextLimit: thresholdContextLimit,
30986
+ sessionId
30987
+ });
30988
+ const { forceMaterializationPercentage } = escalationBands(effectiveExecuteThresholdPercentage);
30318
30989
  const persistedUsageFreshForBoundary = persistedUsageBeforeResets && Date.now() - persistedUsageBeforeResets.updatedAt <= 10 * 60 * 1000 && (persistedUsageBeforeResets.lastObservedModelKey === null || currentModelKeyForBoundary === undefined || persistedUsageBeforeResets.lastObservedModelKey === currentModelKeyForBoundary) && (resolvedContextLimit === undefined || persistedUsageBeforeResets.lastUsageContextLimit === 0 || persistedUsageBeforeResets.lastUsageContextLimit === resolvedContextLimit) ? persistedUsageBeforeResets.usage : null;
30319
30990
  const boundaryUsageForProtectedTail = persistedUsageFreshForBoundary ?? contextUsageEarly;
30320
30991
  const boundaryUsageSource = persistedUsageFreshForBoundary ? "persisted" : "live";
30321
30992
  const historyBudgetTokens = resolveHistoryBudgetTokens(deps.historyBudgetPercentage, contextUsageEarly, deps.executeThresholdPercentage, deps.getModelKey?.(sessionId), deps.executeThresholdTokens, resolvedContextLimit);
30322
- let emergencyCeilingLimit = resolvedContextLimit && resolvedContextLimit > 0 ? resolvedContextLimit : 0;
30323
- if (emergencyCeilingLimit <= 0 && contextUsageEarly.percentage > 0) {
30324
- emergencyCeilingLimit = contextUsageEarly.inputTokens / (contextUsageEarly.percentage / 100);
30325
- }
30326
- const emergencyCeilingTokens = Number.isFinite(emergencyCeilingLimit) && emergencyCeilingLimit > 0 ? Math.floor(emergencyCeilingLimit * (resolveExecuteThreshold(deps.executeThresholdPercentage ?? 65, deps.getModelKey?.(sessionId), 65, {
30327
- tokensConfig: deps.executeThresholdTokens,
30328
- contextLimit: emergencyCeilingLimit
30329
- }) / 100)) : undefined;
30330
- const schedulerDecisionEarly = resolveSchedulerDecision(deps.scheduler, sessionMeta, contextUsageEarly, sessionId, deps.getModelKey?.(sessionId), resolvedContextLimit);
30993
+ const emergencyCeilingLimit = thresholdContextLimit ?? 0;
30994
+ const emergencyCeilingTokens = Number.isFinite(emergencyCeilingLimit) && emergencyCeilingLimit > 0 ? Math.floor(emergencyCeilingLimit * (effectiveExecuteThresholdPercentage / 100)) : undefined;
30995
+ const schedulerDecisionEarly = compactionOff ? "defer" : resolveSchedulerDecision(deps.scheduler, sessionMeta, contextUsageEarly, sessionId, deps.getModelKey?.(sessionId), resolvedContextLimit);
30331
30996
  const midTurn = isMidTurn(deps, resolvedSessionId);
30332
30997
  const bypassReason = detectMidTurnBypassReason({
30333
30998
  contextUsage: contextUsageEarly,
30334
30999
  sessionMeta,
30335
31000
  historyRefreshSessions: deps.historyRefreshSessions,
30336
- sessionId
31001
+ sessionId,
31002
+ effectiveExecuteThresholdPercentage
30337
31003
  });
30338
31004
  const { midTurnAdjustedSchedulerDecision, sideEffect } = applyMidTurnDeferral({
30339
31005
  base: schedulerDecisionEarly,
@@ -30351,12 +31017,13 @@ function createTransform(deps) {
30351
31017
  sessionLog(sessionId, `[boundary-exec] base=${schedulerDecisionEarly} bypass=${bypassReason} midTurn=${midTurn} effective=${midTurnAdjustedSchedulerDecision} sideEffect=${sideEffect}`);
30352
31018
  const historyRefreshExplicitBeforePrepare = deps.historyRefreshSessions.has(sessionId);
30353
31019
  const deferredHistoryWasPendingAtPassStart = deferredHistoryRefreshSessions.has(sessionId);
30354
- const earlyActiveRunBlocksMaterialization = (getActiveCompartmentRun(sessionId) !== undefined || sessionMeta.compartmentInProgress) && contextUsageEarly.percentage < FORCE_MATERIALIZE_PERCENTAGE;
31020
+ const earlyActiveRunBlocksMaterialization = (getActiveCompartmentRun(sessionId) !== undefined || sessionMeta.compartmentInProgress) && contextUsageEarly.percentage < forceMaterializationPercentage;
30355
31021
  const canConsumeDeferredEarly = canConsumeDeferredOnThisPass({
30356
31022
  schedulerDecision: midTurnAdjustedSchedulerDecision,
30357
31023
  contextPercentage: contextUsageEarly.percentage,
30358
31024
  justAwaitedPublication: false,
30359
- activeRunBlocksMaterialization: earlyActiveRunBlocksMaterialization
31025
+ activeRunBlocksMaterialization: earlyActiveRunBlocksMaterialization,
31026
+ forceMaterializationPercentage
30360
31027
  });
30361
31028
  const consumingDeferredEarly = canConsumeDeferredEarly && deferredHistoryWasPendingAtPassStart;
30362
31029
  const isCacheBusting = historyRefreshExplicitBeforePrepare || consumingDeferredEarly;
@@ -30437,7 +31104,7 @@ function createTransform(deps) {
30437
31104
  skipCompartmentAwaitForThisPass = true;
30438
31105
  return true;
30439
31106
  };
30440
- if (fullFeatureMode && historianFailureState.failureCount > 0 && contextUsageEarly.percentage >= 95 && !recoveryNoHeadEscapeActive) {
31107
+ if (fullFeatureMode && !compactionOff && historianFailureState.failureCount > 0 && contextUsageEarly.percentage >= 95 && !recoveryNoHeadEscapeActive) {
30441
31108
  skipCompartmentAwaitForThisPass = true;
30442
31109
  const emergencyPercentage = contextUsageEarly.percentage.toFixed(1);
30443
31110
  const recoveryStarted = startRecoveryRun();
@@ -30449,7 +31116,7 @@ function createTransform(deps) {
30449
31116
  sessionLog(sessionId, "transform: emergency recovery remains armed — no complete eligible head before protected tail");
30450
31117
  }
30451
31118
  sessionLog(sessionId, `EMERGENCY: historian recovery requested at ${emergencyPercentage}%, failures: ${historianFailureState.failureCount}`);
30452
- } else if (fullFeatureMode && isFirstTransformPassForSession && historianFailureState.failureCount > 0 && getEligibleHistoryForCompartment() && startRecoveryRun()) {
31119
+ } else if (fullFeatureMode && !compactionOff && isFirstTransformPassForSession && historianFailureState.failureCount > 0 && getEligibleHistoryForCompartment() && startRecoveryRun()) {
30453
31120
  sessionLog(sessionId, `transform: historian recovery triggered on session load after ${historianFailureState.failureCount} failure(s)`);
30454
31121
  if (deps.client) {
30455
31122
  sendIgnoredMessage(deps.client, sessionId, `## Historian recovery
@@ -30464,7 +31131,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30464
31131
  maybeSendProjectIdentityWarning(deps, sessionId, memoryProjectDirectory, notificationParams);
30465
31132
  }
30466
31133
  const sessionProjectIdentity = projectIdentity ?? (sessionDirectory ? resolveProjectIdentity(sessionDirectory) : deps.projectPath);
30467
- const sessionIdentityForBinding = sessionDirectory ? resolveProjectIdentityForSession(sessionDirectory) : undefined;
31134
+ const sessionIdentityForBinding = sessionDirectory ? resolveProjectIdentityForSession(sessionDirectory, deps.allowHomeProject) : undefined;
30468
31135
  if (sessionDirectory) {
30469
31136
  maybeSendProjectIdentityWarning(deps, sessionId, sessionDirectory, notificationParams);
30470
31137
  }
@@ -30481,16 +31148,16 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30481
31148
  recordSessionProjectIdentity(db, sessionId, sessionIdentityForBinding);
30482
31149
  recordedSessionProjectIdentity.set(sessionId, sessionIdentityForBinding);
30483
31150
  }
30484
- const taggerFloor = deriveTaggerLoadFloor(messages, sessionId, db);
30485
- if (taggerFloor === 0 && messages.length > 0) {
31151
+ const taggerFloor = compactionOff ? 0 : deriveTaggerLoadFloor(messages, sessionId, db);
31152
+ if (!compactionOff && taggerFloor === 0 && messages.length > 0) {
30486
31153
  sessionLog(sessionId, `tag floor: 0 (full-scan fallback) — no leading wire message resolved a tag across ${messages.length} msgs`);
30487
31154
  }
30488
31155
  let triggerBoundarySnapshot;
30489
- if (fullFeatureMode && historianRunnable && !sessionMeta.compartmentInProgress) {
31156
+ if (fullFeatureMode && !compactionOff && historianRunnable && !sessionMeta.compartmentInProgress) {
30490
31157
  const tTrigger = performance.now();
30491
31158
  try {
30492
31159
  const inMemoryTail = buildTriggerInMemoryTail(db, sessionId, extractInMemoryMessageViews(messages));
30493
- const triggerResult = checkCompartmentTrigger(db, sessionId, sessionMeta, boundaryUsageForProtectedTail, sessionMeta.lastContextPercentage, boundaryExecuteThreshold, deriveTriggerBudget(boundaryContextLimit, boundaryExecuteThreshold), deps.clearReasoningAge, deps.commitClusterTrigger, undefined, boundaryContextLimit, inMemoryTail, taggerFloor);
31160
+ const triggerResult = checkCompartmentTrigger(db, sessionId, sessionMeta, boundaryUsageForProtectedTail, sessionMeta.lastContextPercentage, boundaryExecuteThreshold, deriveTriggerBudget(boundaryContextLimit, boundaryExecuteThreshold), deps.clearReasoningAge, deps.commitClusterTrigger, undefined, boundaryContextLimit, inMemoryTail, taggerFloor, { providerID: resolvedProviderID });
30494
31161
  if (triggerResult.shouldFire) {
30495
31162
  sessionLog(sessionId, `compartment trigger: firing (reason=${triggerResult.reason})`);
30496
31163
  updateSessionMeta(db, sessionId, { compartmentInProgress: true });
@@ -30505,7 +31172,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30505
31172
  }
30506
31173
  let pendingCompartmentInjection = null;
30507
31174
  let rebuiltHistoryFromInitialPrepare = false;
30508
- if (fullFeatureMode) {
31175
+ if (fullFeatureMode && !compactionOff) {
30509
31176
  const tInj = performance.now();
30510
31177
  pendingCompartmentInjection = prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectIdentity, deps.memoryConfig?.injectionBudgetTokens, deps.experimentalTemporalAwareness);
30511
31178
  logTransformTiming(sessionId, "prepareCompartmentInjection", tInj);
@@ -30519,10 +31186,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30519
31186
  let targets = new Map;
30520
31187
  let reasoningByMessage = new Map;
30521
31188
  let messageTagNumbers = new Map;
30522
- let tagNormalizationTargets = [];
30523
31189
  let batch = null;
30524
31190
  let hasRecentReduceCall = false;
30525
- if (deps.experimentalTemporalAwareness) {
31191
+ if (deps.experimentalTemporalAwareness && !compactionOff) {
30526
31192
  const tTemporal = performance.now();
30527
31193
  const injected = injectTemporalMarkers(messages);
30528
31194
  if (injected > 0) {
@@ -30531,44 +31197,45 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30531
31197
  logTransformTiming(sessionId, "injectTemporalMarkers", tTemporal);
30532
31198
  }
30533
31199
  let taggingSucceeded = false;
30534
- try {
30535
- const t0 = performance.now();
30536
- const tInitFromDb = performance.now();
30537
- deps.tagger.initFromDb(sessionId, db, taggerFloor);
30538
- logTransformTiming(sessionId, "tag.initFromDb", tInitFromDb);
30539
- const skipPrefixInjection = !ctxReduceCallable;
30540
- const result = tagMessages(sessionId, messages, deps.tagger, db, {
30541
- skipPrefixInjection
30542
- });
30543
- targets = result.targets;
30544
- reasoningByMessage = result.reasoningByMessage;
30545
- messageTagNumbers = result.messageTagNumbers;
30546
- tagNormalizationTargets = result.normalizationTargets;
30547
- batch = result.batch;
30548
- hasRecentReduceCall = result.hasRecentReduceCall;
30549
- const hadPriorCommitState = deps.commitSeenLastPass?.has(sessionId) ?? false;
30550
- const sawCommitLastPass = deps.commitSeenLastPass?.get(sessionId) ?? false;
30551
- if (fullFeatureMode && hadPriorCommitState && result.hasRecentCommit && !sawCommitLastPass) {
30552
- onNoteTrigger(db, sessionId, "commit_detected");
30553
- }
30554
- deps.commitSeenLastPass?.set(sessionId, result.hasRecentCommit);
30555
- logTransformTiming(sessionId, "tagMessages", t0);
30556
- taggingSucceeded = true;
30557
- } catch (error) {
30558
- passOutcome.record("tagging-persistence-failure");
30559
- sessionLog(sessionId, "transform tag persistence failed; continuing without tagging:", error);
31200
+ if (!compactionOff) {
30560
31201
  try {
30561
- deps.tagger.cleanup(sessionId);
30562
- } catch (cleanupError) {
30563
- sessionLog(sessionId, "tagger cleanup after failure threw:", cleanupError);
31202
+ const t0 = performance.now();
31203
+ const tInitFromDb = performance.now();
31204
+ deps.tagger.initFromDb(sessionId, db, taggerFloor);
31205
+ logTransformTiming(sessionId, "tag.initFromDb", tInitFromDb);
31206
+ const skipPrefixInjection = !ctxReduceCallable;
31207
+ const result = tagMessages(sessionId, messages, deps.tagger, db, {
31208
+ skipPrefixInjection
31209
+ });
31210
+ targets = result.targets;
31211
+ reasoningByMessage = result.reasoningByMessage;
31212
+ messageTagNumbers = result.messageTagNumbers;
31213
+ batch = result.batch;
31214
+ hasRecentReduceCall = result.hasRecentReduceCall;
31215
+ const hadPriorCommitState = deps.commitSeenLastPass?.has(sessionId) ?? false;
31216
+ const sawCommitLastPass = deps.commitSeenLastPass?.get(sessionId) ?? false;
31217
+ if (fullFeatureMode && hadPriorCommitState && result.hasRecentCommit && !sawCommitLastPass) {
31218
+ onNoteTrigger(db, sessionId, "commit_detected");
31219
+ }
31220
+ deps.commitSeenLastPass?.set(sessionId, result.hasRecentCommit);
31221
+ logTransformTiming(sessionId, "tagMessages", t0);
31222
+ taggingSucceeded = true;
31223
+ } catch (error) {
31224
+ passOutcome.record("tagging-persistence-failure");
31225
+ sessionLog(sessionId, "transform tag persistence failed; continuing without tagging:", error);
31226
+ try {
31227
+ deps.tagger.cleanup(sessionId);
31228
+ } catch (cleanupError) {
31229
+ sessionLog(sessionId, "tagger cleanup after failure threw:", cleanupError);
31230
+ }
30564
31231
  }
30565
31232
  }
30566
31233
  const t1 = performance.now();
30567
- const activeTags = getActiveTagsBySession(db, sessionId);
31234
+ const activeTags = compactionOff ? [] : getActiveTagsBySession(db, sessionId);
30568
31235
  logTransformTiming(sessionId, "getActiveTagsBySession", t1, `count=${activeTags.length}`);
30569
31236
  const t1b = performance.now();
30570
31237
  const targetTagNumbers = [...targets.keys()];
30571
- const targetsSliceTags = getTagsByNumbers(db, sessionId, targetTagNumbers);
31238
+ const targetsSliceTags = compactionOff ? [] : getTagsByNumbers(db, sessionId, targetTagNumbers);
30572
31239
  logTransformTiming(sessionId, "getTagsByNumbers", t1b, `targets=${targetTagNumbers.length} fetched=${targetsSliceTags.length}`);
30573
31240
  let didMutateFromFlushedStatuses = false;
30574
31241
  if (taggingSucceeded) {
@@ -30584,10 +31251,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30584
31251
  }
30585
31252
  }
30586
31253
  const t3 = performance.now();
30587
- const strippedStructuralNoise = canUseEmptySentinels ? stripStructuralNoise(messages) : 0;
31254
+ const strippedStructuralNoise = canUseEmptySentinels && !compactionOff ? stripStructuralNoise(messages) : 0;
30588
31255
  logTransformTiming(sessionId, "stripStructuralNoise", t3, `strippedParts=${strippedStructuralNoise}`);
30589
31256
  const persistedReasoningWatermark = sessionMeta?.clearedReasoningThroughTag ?? 0;
30590
- if (persistedReasoningWatermark > 0) {
31257
+ if (persistedReasoningWatermark > 0 && !compactionOff) {
30591
31258
  const tReplay = performance.now();
30592
31259
  const replayed = canUseEmptySentinels ? replayClearedReasoning(messages, reasoningByMessage, messageTagNumbers, persistedReasoningWatermark) : 0;
30593
31260
  const replayedInline = replayStrippedInlineThinking(messages, messageTagNumbers, persistedReasoningWatermark);
@@ -30596,7 +31263,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30596
31263
  }
30597
31264
  logTransformTiming(sessionId, "replayReasoningClearing", tReplay);
30598
31265
  }
30599
- if (!reducedMode && deps.cavemanTextCompression?.enabled) {
31266
+ if (!reducedMode && !compactionOff && deps.cavemanTextCompression?.enabled) {
30600
31267
  const tCavemanReplay = performance.now();
30601
31268
  const replayedCaveman = replayCavemanCompression(sessionId, db, targets, targetsSliceTags);
30602
31269
  if (replayedCaveman > 0) {
@@ -30605,7 +31272,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30605
31272
  logTransformTiming(sessionId, "replayCavemanCompression", tCavemanReplay);
30606
31273
  }
30607
31274
  const t4 = performance.now();
30608
- const strippedClearedReasoning = canUseEmptySentinels ? stripClearedReasoning(messages) : 0;
31275
+ const strippedClearedReasoning = canUseEmptySentinels && !compactionOff ? stripClearedReasoning(messages) : 0;
30609
31276
  logTransformTiming(sessionId, "stripClearedReasoning", t4, `strippedParts=${strippedClearedReasoning}`);
30610
31277
  const watermark = getMaxDroppedTagNumber(db, sessionId);
30611
31278
  const contextUsage = contextUsageEarly;
@@ -30615,6 +31282,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30615
31282
  const compartmentPhase = await runCompartmentPhase({
30616
31283
  canRunCompartments,
30617
31284
  fullFeatureMode,
31285
+ compactionOff,
30618
31286
  historianRunnable,
30619
31287
  sessionMeta,
30620
31288
  contextUsage,
@@ -30657,31 +31325,32 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30657
31325
  const compartmentInProgress = compartmentPhase.compartmentInProgress;
30658
31326
  sessionMeta = { ...sessionMeta, compartmentInProgress };
30659
31327
  logTransformTiming(sessionId, "compartmentPhase", tCompartmentPhase);
31328
+ if (pendingCompartmentInjection?.needsFreshMaterialization) {
31329
+ deps.pendingMaterializationSessions.add(sessionId);
31330
+ deferredMaterializationSessions.add(sessionId);
31331
+ }
30660
31332
  const hardModel = deps.liveModelBySession?.get(sessionId);
30661
31333
  const hardModelKey = hardModel ? `${hardModel.providerID}/${hardModel.modelID}` : "";
30662
31334
  const hardSystemHash = typeof sessionMeta.systemPromptHash === "string" ? sessionMeta.systemPromptHash : "";
30663
- let hardTtlMs = 5 * 60 * 1000;
30664
- try {
30665
- hardTtlMs = parseCacheTtl(sessionMeta.cacheTtl);
30666
- } catch (error) {
31335
+ const hardCacheExpired = computeHardCacheExpired(sessionMeta.cacheTtl, sessionMeta.lastResponseTime, Date.now(), (error) => {
30667
31336
  passOutcome.record("invalid-cache-ttl-fallback");
30668
31337
  sessionLog(sessionId, "invalid cache_ttl; using the 5m default:", error);
30669
- }
30670
- const hardCacheExpired = sessionMeta.lastResponseTime > 0 && Date.now() - sessionMeta.lastResponseTime >= hardTtlMs;
31338
+ });
30671
31339
  const m0HardSignals = {
30672
31340
  systemHash: hardSystemHash,
30673
31341
  modelKey: hardModelKey,
30674
31342
  cacheExpired: hardCacheExpired,
30675
31343
  lastResponseTime: sessionMeta.lastResponseTime
30676
31344
  };
30677
- const lateActiveRunBlocksMaterialization = getActiveCompartmentRun(sessionId) !== undefined && contextUsageEarly.percentage < FORCE_MATERIALIZE_PERCENTAGE;
31345
+ const lateActiveRunBlocksMaterialization = getActiveCompartmentRun(sessionId) !== undefined && contextUsageEarly.percentage < forceMaterializationPercentage;
30678
31346
  const canConsumeDeferredLate = canConsumeDeferredOnThisPass({
30679
31347
  schedulerDecision: midTurnAdjustedSchedulerDecision,
30680
31348
  contextPercentage: contextUsageEarly.percentage,
30681
31349
  justAwaitedPublication: compartmentPhase.justAwaitedPublication,
30682
- activeRunBlocksMaterialization: lateActiveRunBlocksMaterialization
31350
+ activeRunBlocksMaterialization: lateActiveRunBlocksMaterialization,
31351
+ forceMaterializationPercentage
30683
31352
  });
30684
- const wasEmergencyBlock = contextUsageEarly.percentage >= FORCE_MATERIALIZE_PERCENTAGE && compartmentPhase.justAwaitedPublication;
31353
+ const wasEmergencyBlock = contextUsageEarly.percentage >= forceMaterializationPercentage && compartmentPhase.justAwaitedPublication;
30685
31354
  const historyRebuiltThisPass = wasEmergencyBlock ? compartmentPhase.rebuiltHistoryThisPass : rebuiltHistoryFromInitialPrepare || compartmentPhase.rebuiltHistoryThisPass;
30686
31355
  const tPostProcess = performance.now();
30687
31356
  const postTransformResult = await runPostTransformPhase({
@@ -30695,10 +31364,13 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30695
31364
  tagger: deps.tagger,
30696
31365
  ctxReduceAvailability,
30697
31366
  todowriteAvailability,
31367
+ client: deps.client,
31368
+ activeAgent,
30698
31369
  batch,
30699
31370
  contextUsage,
30700
31371
  schedulerDecision,
30701
31372
  fullFeatureMode,
31373
+ compactionOff,
30702
31374
  canRunCompartments,
30703
31375
  awaitedCompartmentRun,
30704
31376
  phaseJustAwaitedPublication: compartmentPhase.justAwaitedPublication,
@@ -30721,7 +31393,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30721
31393
  pendingCompartmentInjection,
30722
31394
  didMutateFromFlushedStatuses,
30723
31395
  watermark,
30724
- forceMaterializationPercentage: FORCE_MATERIALIZE_PERCENTAGE,
31396
+ forceMaterializationPercentage,
30725
31397
  hasRecentReduceCall,
30726
31398
  projectPath: sessionProjectIdentity,
30727
31399
  sessionDirectory,
@@ -30743,63 +31415,70 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30743
31415
  }
30744
31416
  });
30745
31417
  passOutcome.markFinalized();
30746
- const finalWireEstimate = contextUsage.percentage >= 95 ? estimateFinalWireInputTokens({
30747
- messages,
30748
- systemPromptTokens: sessionMeta.systemPromptTokens,
30749
- providerID: modelForBudget?.providerID,
30750
- modelID: modelForBudget?.modelID,
30751
- agentName: notificationParams.agent
30752
- }) : undefined;
30753
- if (finalWireEstimate) {
30754
- sessionLog(sessionId, `transform: final-wire telemetry estimate=${finalWireEstimate.tokens} trusted=${finalWireEstimate.trusted} conversation=${finalWireEstimate.messageTokens.conversation} tools=${finalWireEstimate.messageTokens.toolCall} system=${finalWireEstimate.systemTokens} toolDefinitions=${finalWireEstimate.toolDefinitionTokens ?? "unknown"}`);
30755
- }
30756
- const currentModelKeyForRecovery = deps.getModelKey?.(sessionId);
30757
- const overflowStateForFinalWire = getOverflowState(db, sessionId, currentModelKeyForRecovery);
30758
- const providerProvenLimitTokens = typeof currentModelKeyForRecovery === "string" && currentModelKeyForRecovery.length > 0 && overflowStateForFinalWire.detectedContextLimit > 0 && overflowStateForFinalWire.detectedContextLimitModelKey === currentModelKeyForRecovery ? overflowStateForFinalWire.detectedContextLimit : undefined;
30759
- const emergencyFailClosed = evaluateEmergencyFailClosed({
30760
- usagePercentage: contextUsage.percentage,
30761
- emergencyRecoveryArmed,
30762
- emergencyRecoveryOrigin,
30763
- foldMaterializedThisPass: postTransformResult.historianFoldMaterializedThisPass,
30764
- finalWireEstimate,
30765
- providerProvenLimitTokens
30766
- });
30767
- if (emergencyFailClosed.disarm) {
30768
- clearEmergencyRecovery(db, sessionId);
30769
- sessionLog(sessionId, `emergency disarm: trusted final-wire ${emergencyFailClosed.disarm.finalWireTokens} under limit ${emergencyFailClosed.disarm.provenLimitTokens}`);
30770
- }
30771
- if (emergencyFailClosed.shouldAbort) {
30772
- if (!deps.client) {
30773
- throw new EmergencyFailClosedError("Cannot fail closed: OpenCode client is unavailable");
30774
- }
30775
- let notification;
30776
- try {
30777
- notification = await sendIgnoredMessage(deps.client, sessionId, "Context full — /ctx-flush or /clear to continue.", notificationParams);
30778
- } catch (error) {
30779
- throw new EmergencyFailClosedError("Emergency recovery notification failed", {
30780
- cause: error
30781
- });
30782
- }
30783
- if (notification !== "sent") {
30784
- throw new EmergencyFailClosedError(`Emergency recovery notification was ${notification}`);
30785
- }
30786
- try {
30787
- await abortSessionFailClosed(deps.client, sessionId);
30788
- } catch (error) {
30789
- sessionLog(sessionId, "transform: emergency fail-closed abort failed; refusing to return a sendable prompt:", getErrorMessage(error));
30790
- throw new EmergencyFailClosedError("Emergency recovery abort failed", {
30791
- cause: error
30792
- });
31418
+ const finalWireTail = describeFinalWireTail(messages);
31419
+ let finalWireEstimate;
31420
+ if (!compactionOff) {
31421
+ finalWireEstimate = contextUsage.percentage >= 95 ? estimateFinalWireInputTokens({
31422
+ messages,
31423
+ systemPromptTokens: sessionMeta.systemPromptTokens,
31424
+ providerID: modelForBudget?.providerID,
31425
+ modelID: modelForBudget?.modelID,
31426
+ agentName: notificationParams.agent
31427
+ }) : undefined;
31428
+ if (finalWireEstimate) {
31429
+ sessionLog(sessionId, `transform: final-wire telemetry estimate=${finalWireEstimate.tokens} trusted=${finalWireEstimate.trusted} conversation=${finalWireEstimate.messageTokens.conversation} tools=${finalWireEstimate.messageTokens.toolCall} system=${finalWireEstimate.systemTokens} toolDefinitions=${finalWireEstimate.toolDefinitionTokens ?? "unknown"} tail=${finalWireTail}`);
31430
+ }
31431
+ const currentModelKeyForRecovery = deps.getModelKey?.(sessionId);
31432
+ const overflowStateForFinalWire = getOverflowState(db, sessionId, currentModelKeyForRecovery);
31433
+ const providerProvenLimitTokens = typeof currentModelKeyForRecovery === "string" && currentModelKeyForRecovery.length > 0 && overflowStateForFinalWire.detectedContextLimit > 0 && overflowStateForFinalWire.detectedContextLimitModelKey === currentModelKeyForRecovery ? overflowStateForFinalWire.detectedContextLimit : undefined;
31434
+ const emergencyFailClosed = evaluateEmergencyFailClosed({
31435
+ usagePercentage: contextUsage.percentage,
31436
+ emergencyRecoveryArmed,
31437
+ emergencyRecoveryOrigin,
31438
+ foldMaterializedThisPass: postTransformResult.historianFoldMaterializedThisPass,
31439
+ finalWireEstimate,
31440
+ providerProvenLimitTokens
31441
+ });
31442
+ if (emergencyFailClosed.disarm) {
31443
+ clearEmergencyRecovery(db, sessionId);
31444
+ sessionLog(sessionId, `emergency disarm: trusted final-wire ${emergencyFailClosed.disarm.finalWireTokens} under limit ${emergencyFailClosed.disarm.provenLimitTokens}`);
30793
31445
  }
30794
- try {
30795
- clearEmergencyDropSample(db, sessionId);
30796
- } catch (error) {
30797
- throw new EmergencyFailClosedError("Emergency recovery cleanup failed", {
30798
- cause: error
30799
- });
31446
+ if (emergencyFailClosed.shouldAbort) {
31447
+ if (!deps.client) {
31448
+ throw new EmergencyFailClosedError("Cannot fail closed: OpenCode client is unavailable");
31449
+ }
31450
+ let notification;
31451
+ try {
31452
+ notification = await sendIgnoredMessage(deps.client, sessionId, "Context full — /ctx-flush or /clear to continue.", notificationParams);
31453
+ } catch (error) {
31454
+ throw new EmergencyFailClosedError("Emergency recovery notification failed", {
31455
+ cause: error
31456
+ });
31457
+ }
31458
+ if (notification !== "sent" && notification !== "queued") {
31459
+ throw new EmergencyFailClosedError(`Emergency recovery notification was ${notification}`);
31460
+ }
31461
+ try {
31462
+ await abortSessionFailClosed(deps.client, sessionId);
31463
+ } catch (error) {
31464
+ sessionLog(sessionId, "transform: emergency fail-closed abort failed; refusing to return a sendable prompt:", getErrorMessage(error));
31465
+ throw new EmergencyFailClosedError("Emergency recovery abort failed", {
31466
+ cause: error
31467
+ });
31468
+ }
31469
+ try {
31470
+ clearEmergencyDropSample(db, sessionId);
31471
+ } catch (error) {
31472
+ throw new EmergencyFailClosedError("Emergency recovery cleanup failed", {
31473
+ cause: error
31474
+ });
31475
+ }
31476
+ sessionLog(sessionId, `EMERGENCY: fail-closed (reason=${emergencyFailClosed.reason}, recoveryOrigin=${emergencyRecoveryOrigin ?? "unknown"}, finalEstimate=${finalWireEstimate?.tokens ?? "unavailable"}, estimateTrusted=${finalWireEstimate?.trusted ?? false}, syntheticUsage=${usagePercentageSynthetic})`);
31477
+ return;
30800
31478
  }
30801
- sessionLog(sessionId, `EMERGENCY: fail-closed (reason=${emergencyFailClosed.reason}, recoveryOrigin=${emergencyRecoveryOrigin ?? "unknown"}, finalEstimate=${finalWireEstimate?.tokens ?? "unavailable"}, estimateTrusted=${finalWireEstimate?.trusted ?? false}, syntheticUsage=${usagePercentageSynthetic})`);
30802
- return;
31479
+ }
31480
+ if (!finalWireEstimate) {
31481
+ sessionLog(sessionId, `transform: final-wire telemetry estimate=unavailable trusted=false conversation=unknown tools=unknown system=unknown toolDefinitions=unknown tail=${finalWireTail}`);
30803
31482
  }
30804
31483
  if (passOutcome.captureEligible) {
30805
31484
  const keys = resolveLkgModelKeys(messages);
@@ -30875,7 +31554,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30875
31554
  sessionLog(sessionId, "conversation_tokens UPDATE failed:", error);
30876
31555
  }
30877
31556
  }
30878
- if (ctxReduceCallable && deps.channel1StateBySession) {
31557
+ if (ctxReduceCallable && !compactionOff && deps.channel1StateBySession) {
30879
31558
  try {
30880
31559
  const resolvedExecuteThresholdPct = resolveExecuteThreshold(deps.executeThresholdPercentage ?? 65, deps.getModelKey?.(sessionId), 65, {
30881
31560
  tokensConfig: deps.executeThresholdTokens,
@@ -31064,15 +31743,22 @@ function createEventHandler2(deps) {
31064
31743
  const sessionMeta = getOrCreateSessionMeta(deps.db, errInfo.sessionID);
31065
31744
  if (sessionMeta.isSubagent) {
31066
31745
  if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
31067
- recordDetectedContextLimit(deps.db, errInfo.sessionID, detection.reportedLimit);
31746
+ recordDetectedContextLimit(deps.db, errInfo.sessionID, detection.reportedLimit, undefined, detection.reportedLimitProvenance);
31068
31747
  }
31069
- sessionLog(errInfo.sessionID, `overflow detected on subagent: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only (subagents cannot run historian)`);
31748
+ sessionLog(errInfo.sessionID, `overflow detected on subagent: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only (subagents cannot run historian)`);
31070
31749
  return;
31071
31750
  }
31072
31751
  const existing = getOverflowState(deps.db, errInfo.sessionID);
31752
+ if (deps.compactionOff) {
31753
+ if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
31754
+ recordDetectedContextLimit(deps.db, errInfo.sessionID, detection.reportedLimit, undefined, detection.reportedLimitProvenance);
31755
+ }
31756
+ sessionLog(errInfo.sessionID, `overflow detected in compaction-off mode: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only (recovery disarmed; native compaction owns the window)`);
31757
+ return;
31758
+ }
31073
31759
  dropSlot(errInfo.sessionID, "overflow-recovery-arm");
31074
- recordOverflowDetected(deps.db, errInfo.sessionID, detection.reportedLimit);
31075
- sessionLog(errInfo.sessionID, `overflow detected via session.error: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"} (previousRecovery=${existing.needsEmergencyRecovery})`);
31760
+ recordOverflowDetected(deps.db, errInfo.sessionID, detection.reportedLimit, undefined, "provider_overflow", detection.reportedLimitProvenance);
31761
+ sessionLog(errInfo.sessionID, `overflow detected via session.error: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"} (previousRecovery=${existing.needsEmergencyRecovery})`);
31076
31762
  deps.onSessionCacheInvalidated?.(errInfo.sessionID);
31077
31763
  } catch (error) {
31078
31764
  sessionLog(errInfo.sessionID, "event session.error handling failed:", error);
@@ -31114,13 +31800,18 @@ function createEventHandler2(deps) {
31114
31800
  const metaForOverflow = getOrCreateSessionMeta(deps.db, info.sessionID);
31115
31801
  if (metaForOverflow.isSubagent) {
31116
31802
  if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
31117
- recordDetectedContextLimit(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey);
31803
+ recordDetectedContextLimit(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey, detection.reportedLimitProvenance);
31804
+ }
31805
+ sessionLog(info.sessionID, `overflow detected on subagent via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only`);
31806
+ } else if (deps.compactionOff) {
31807
+ if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
31808
+ recordDetectedContextLimit(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey, detection.reportedLimitProvenance);
31118
31809
  }
31119
- sessionLog(info.sessionID, `overflow detected on subagent via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only`);
31810
+ sessionLog(info.sessionID, `overflow detected in compaction-off mode via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only`);
31120
31811
  } else {
31121
31812
  dropSlot(info.sessionID, "overflow-recovery-arm");
31122
- recordOverflowDetected(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey);
31123
- sessionLog(info.sessionID, `overflow detected via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"}`);
31813
+ recordOverflowDetected(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey, "provider_overflow", detection.reportedLimitProvenance);
31814
+ sessionLog(info.sessionID, `overflow detected via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"}`);
31124
31815
  deps.onSessionCacheInvalidated?.(info.sessionID);
31125
31816
  }
31126
31817
  } catch (error) {
@@ -31219,7 +31910,7 @@ function createEventHandler2(deps) {
31219
31910
  } catch (error) {
31220
31911
  sessionLog(info.sessionID, "event message.updated persistence failed:", error);
31221
31912
  }
31222
- if ((info.finish === "stop" || info.finish === "tool-calls") && deps.client && deps.channel1StateBySession) {
31913
+ if ((info.finish === "stop" || info.finish === "tool-calls") && deps.client && deps.channel1StateBySession && !deps.compactionOff) {
31223
31914
  deliverChannel2IfPending(deps, info.sessionID);
31224
31915
  }
31225
31916
  return;
@@ -31794,11 +32485,16 @@ function createChatMessageHook(args) {
31794
32485
  args.agentBySession.set(sessionId, input.agent);
31795
32486
  }
31796
32487
  if (previousVariant !== undefined && input.variant !== undefined && previousVariant !== input.variant) {
31797
- sessionLog(sessionId, `variant changed (${previousVariant} -> ${input.variant}), triggering flush`);
31798
- args.historyRefreshSessions.add(sessionId);
31799
- args.systemPromptRefreshSessions.add(sessionId);
31800
- args.pendingMaterializationSessions.add(sessionId);
31801
- args.lastHeuristicsTurnId.delete(sessionId);
32488
+ const providerID = input.model?.providerID ?? args.liveModelBySession.get(sessionId)?.providerID;
32489
+ if (variantChangeBustsProviderCache(providerID)) {
32490
+ sessionLog(sessionId, `variant changed (${previousVariant} -> ${input.variant}), triggering flush`);
32491
+ args.historyRefreshSessions.add(sessionId);
32492
+ args.systemPromptRefreshSessions.add(sessionId);
32493
+ args.pendingMaterializationSessions.add(sessionId);
32494
+ args.lastHeuristicsTurnId.delete(sessionId);
32495
+ } else {
32496
+ sessionLog(sessionId, `variant changed (${previousVariant} -> ${input.variant}) on provider ${providerID} whose cache ignores request params; deferring flush to next natural bust`);
32497
+ }
31802
32498
  }
31803
32499
  };
31804
32500
  }
@@ -31856,11 +32552,15 @@ function createEventHook(args) {
31856
32552
  args.deferredMaterializationSessions.delete(sessionId);
31857
32553
  args.lastHeuristicsTurnId.delete(sessionId);
31858
32554
  args.commitSeenLastPass?.delete(sessionId);
32555
+ clearIgnoredMessages(sessionId);
31859
32556
  resetNoteNudgeCooldownOnly(sessionId);
31860
32557
  clearAutoSearchForSession(sessionId);
31861
32558
  clearSidebarSnapshotCache(sessionId);
31862
32559
  clearSessionTracking(sessionId);
31863
32560
  }
32561
+ if (input.event.type !== "session.deleted") {
32562
+ await flushIgnoredMessages(sessionId);
32563
+ }
31864
32564
  };
31865
32565
  }
31866
32566
  function createCommandExecuteBeforeHook(commandHandler) {
@@ -31920,6 +32620,7 @@ function createToolExecuteAfterHook(args) {
31920
32620
  if (!typedInput.sessionID || !typedInput.tool) {
31921
32621
  return;
31922
32622
  }
32623
+ await flushIgnoredMessages(typedInput.sessionID);
31923
32624
  if (typedInput.tool === "ctx_reduce") {
31924
32625
  const state = args.channel1StateBySession.get(typedInput.sessionID);
31925
32626
  if (state)
@@ -31940,6 +32641,19 @@ function createToolExecuteAfterHook(args) {
31940
32641
  const todowriteVerdict = resolveTodowriteAvailability(typedInput.sessionID);
31941
32642
  if (todowriteVerdict.frozen && !todowriteVerdict.callable)
31942
32643
  return;
32644
+ const activeAgent = typedInput.agent;
32645
+ if (args.client) {
32646
+ try {
32647
+ if (await todowritePermissionDenied(args.client, typedInput.sessionID, activeAgent)) {
32648
+ return;
32649
+ }
32650
+ } catch (error) {
32651
+ if (cachedToolPermissionDenied(typedInput.sessionID, "todowrite")) {
32652
+ return;
32653
+ }
32654
+ sessionLog(typedInput.sessionID, "todowrite permission read failed during capture (ignored):", error);
32655
+ }
32656
+ }
31943
32657
  const todoArgs = typedInput.args;
31944
32658
  const todos = todoArgs?.todos;
31945
32659
  const sessionMeta = Array.isArray(todos) ? getOrCreateSessionMeta(args.db, typedInput.sessionID) : null;
@@ -32364,14 +33078,24 @@ function createMagicContextHook(deps) {
32364
33078
  const reason = (opened ? getDatabasePersistenceError(opened) : null) ?? "Failed to initialize the persistent SQLite database.";
32365
33079
  log("[magic-context] disabling feature because persistent storage is unavailable:", reason);
32366
33080
  notifyMagicContextDisabled(deps.client, reason);
33081
+ const migration = getMigrationOnOpenRefusal();
33082
+ const blockingProcesses = migration?.serverPids.map((pid) => ({ harness: "OpenCode server", pid })) ?? [];
32367
33083
  const fence = getSchemaFenceRejection();
32368
33084
  recordHookInitFailure({
32369
33085
  type: "storage",
32370
- reason: fence ? {
33086
+ reason: migration && blockingProcesses.length > 0 ? {
33087
+ kind: "migration_guard",
33088
+ persistedVersion: migration.persistedVersion,
33089
+ supportedVersion: migration.supportedVersion,
33090
+ blockingProcesses
33091
+ } : fence ? {
32371
33092
  kind: "schema_fence",
32372
33093
  persistedVersion: fence.persistedVersion,
32373
33094
  supportedVersion: fence.supportedVersion
32374
- } : { kind: "storage_failure", cause: reason }
33095
+ } : {
33096
+ kind: "storage_failure",
33097
+ cause: migration?.unreadableFile ? `migration guard could not read RPC discovery file ${migration.unreadableFile}` : reason
33098
+ }
32375
33099
  });
32376
33100
  return null;
32377
33101
  }
@@ -32387,9 +33111,9 @@ function createMagicContextHook(deps) {
32387
33111
  });
32388
33112
  return null;
32389
33113
  }
32390
- const projectPath = resolveProjectIdentityForSession(deps.directory);
33114
+ const projectPath = resolveProjectIdentityForSession(deps.directory, deps.config.allow_home_project);
32391
33115
  if (!projectPath) {
32392
- log("[magic-context] not binding a project identity for the user's home directory");
33116
+ log("[magic-context] not binding a project identity for this directory");
32393
33117
  clearHookInitFailure();
32394
33118
  recordHookInitFailure({ type: "no_project" });
32395
33119
  return null;
@@ -32453,6 +33177,7 @@ function createMagicContextHook(deps) {
32453
33177
  const dreamerRunnable = isDreamerRunnable(deps.config);
32454
33178
  const dreamerConfig = dreamerRunnable ? deps.config.dreamer : undefined;
32455
33179
  const historianRunnable = isHistorianRunnable(deps.config);
33180
+ const compactionOff = !isCompactionEnabled(deps.config);
32456
33181
  const buildManagedRecompCtx = (sessionId) => ({
32457
33182
  client: deps.client,
32458
33183
  db,
@@ -32513,7 +33238,7 @@ function createMagicContextHook(deps) {
32513
33238
  return "Embedding is already running for this session.";
32514
33239
  }
32515
33240
  await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
32516
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33241
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32517
33242
  if (!sessionProjectIdentity)
32518
33243
  return "No project identity is bound for the home directory.";
32519
33244
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32581,7 +33306,7 @@ function createMagicContextHook(deps) {
32581
33306
  if (ctrl)
32582
33307
  ctrl.abort();
32583
33308
  const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
32584
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33309
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32585
33310
  if (!sessionProjectIdentity)
32586
33311
  return "No project identity is bound for the home directory.";
32587
33312
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32590,7 +33315,7 @@ function createMagicContextHook(deps) {
32590
33315
  };
32591
33316
  const getEmbedStatusText = (sessionId) => {
32592
33317
  const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
32593
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33318
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32594
33319
  if (!sessionProjectIdentity)
32595
33320
  return "No project identity is bound for the home directory.";
32596
33321
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32616,7 +33341,7 @@ function createMagicContextHook(deps) {
32616
33341
  try {
32617
33342
  await new Promise((resolve3) => setTimeout(resolve3, 0));
32618
33343
  await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
32619
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33344
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32620
33345
  if (!sessionProjectIdentity)
32621
33346
  return;
32622
33347
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32849,6 +33574,7 @@ function createMagicContextHook(deps) {
32849
33574
  internalChildSessions,
32850
33575
  client: deps.client,
32851
33576
  directory: deps.directory,
33577
+ allowHomeProject: deps.config.allow_home_project,
32852
33578
  injectDocs: deps.config.dreamer?.inject_docs !== false,
32853
33579
  memoryConfig: deps.config.memory ? {
32854
33580
  enabled: deps.config.memory.enabled,
@@ -32873,6 +33599,7 @@ function createMagicContextHook(deps) {
32873
33599
  },
32874
33600
  projectPath,
32875
33601
  historianRunnable,
33602
+ compactionOff,
32876
33603
  experimentalUserMemories: userMemoryCollectionEnabled(dreamerConfig),
32877
33604
  experimentalTemporalAwareness: deps.config.temporal_awareness === true,
32878
33605
  experimentalMuralEnabled: deps.config.experimental?.mural?.enabled === true,
@@ -32886,7 +33613,7 @@ function createMagicContextHook(deps) {
32886
33613
  directory: deps.directory,
32887
33614
  ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory
32888
33615
  } : undefined,
32889
- cavemanTextCompression: deps.config.caveman_text_compression?.enabled === true ? {
33616
+ cavemanTextCompression: compactionOff ? undefined : deps.config.caveman_text_compression?.enabled === true ? {
32890
33617
  enabled: true,
32891
33618
  minChars: deps.config.caveman_text_compression.min_chars ?? 500
32892
33619
  } : undefined,
@@ -32902,6 +33629,7 @@ function createMagicContextHook(deps) {
32902
33629
  contextUsageMap,
32903
33630
  compactionHandler: deps.compactionHandler,
32904
33631
  config: deps.config,
33632
+ compactionOff,
32905
33633
  tagger: deps.tagger,
32906
33634
  db,
32907
33635
  client: deps.client,
@@ -32922,6 +33650,7 @@ function createMagicContextHook(deps) {
32922
33650
  transform.clearRustSession(sessionId);
32923
33651
  systemPromptHash.clearSession(sessionId);
32924
33652
  lastHeuristicsTurnId.delete(sessionId);
33653
+ clearToolPermissionDenied(sessionId);
32925
33654
  commitSeenLastPass.delete(sessionId);
32926
33655
  variantBySession.delete(sessionId);
32927
33656
  liveModelBySession.delete(sessionId);
@@ -32981,6 +33710,7 @@ function createMagicContextHook(deps) {
32981
33710
  const commandHandler = createMagicContextCommandHandler({
32982
33711
  db,
32983
33712
  protectedTags: deps.config.protected_tags,
33713
+ compactionOff,
32984
33714
  toastDurationMs: deps.config.toast_duration_ms,
32985
33715
  executeThresholdPercentage: deps.config.execute_threshold_percentage ?? 65,
32986
33716
  executeThresholdTokens: deps.config.execute_threshold_tokens,
@@ -33124,6 +33854,7 @@ function createMagicContextHook(deps) {
33124
33854
  "tool.execute.after": createToolExecuteAfterHook({
33125
33855
  db,
33126
33856
  channel1StateBySession,
33857
+ client: deps.client,
33127
33858
  transformMode: deps.config.transform_mode,
33128
33859
  todoStateSet: deps.config.transform_mode === "rust" && rustModeModuleClient ? ({ sessionId, stateJson, ownerMessageId }) => rustModeModuleClient.call({
33129
33860
  sessionId,
@@ -33219,15 +33950,30 @@ function createMessagesTransformHandler(args) {
33219
33950
  const sessionId = resolveSessionId2(output);
33220
33951
  const agent = resolveAgentNameFromMessages(output.messages);
33221
33952
  const isInternalChild = typeof sessionId === "string" && sessionId.length > 0 && args.internalChildSessions?.has(sessionId) === true;
33953
+ const compactionOffInputSnapshot = args.compactionOff ? [...output.messages] : null;
33954
+ const restoreCompactionOffInput = () => {
33955
+ if (compactionOffInputSnapshot && output.messages !== compactionOffInputSnapshot) {
33956
+ output.messages.splice(0, output.messages.length, ...compactionOffInputSnapshot);
33957
+ }
33958
+ };
33222
33959
  if (args.failClosed) {
33223
- await args.failClosed.enforce({
33224
- blockingEnabled: args.failClosedBlockingEnabled !== false,
33225
- exempt: shouldBypassFailClosedBlock({
33226
- agent,
33227
- isInternalChildSession: isInternalChild
33228
- }),
33229
- tryReopen: args.tryReopenStorage
33230
- });
33960
+ try {
33961
+ await args.failClosed.enforce({
33962
+ blockingEnabled: args.failClosedBlockingEnabled !== false,
33963
+ exempt: shouldBypassFailClosedBlock({
33964
+ agent,
33965
+ isInternalChildSession: isInternalChild
33966
+ }),
33967
+ tryReopen: args.tryReopenStorage
33968
+ });
33969
+ } catch (error) {
33970
+ if (args.compactionOff && isFailClosedBlockingError(error)) {
33971
+ log(`[magic-context] compaction-off: fail-closed inert, passing through: ${error.message}`);
33972
+ restoreCompactionOffInput();
33973
+ return output.messages;
33974
+ }
33975
+ throw error;
33976
+ }
33231
33977
  }
33232
33978
  const magicContext = args.getMagicContext ? args.getMagicContext() : args.magicContext;
33233
33979
  const slotAtEntry = sessionId ? getSlot(sessionId) : undefined;
@@ -33244,9 +33990,15 @@ function createMessagesTransformHandler(args) {
33244
33990
  return output.messages;
33245
33991
  } catch (error) {
33246
33992
  if (error instanceof EmergencyFailClosedError || isFailClosedBlockingError(error)) {
33247
- throw error;
33993
+ if (!args.compactionOff)
33994
+ throw error;
33995
+ log(`[magic-context] compaction-off: fail-closed inert, passing through: ${error instanceof Error ? error.message : String(error)}`);
33996
+ restoreCompactionOffInput();
33997
+ return output.messages;
33248
33998
  }
33249
- if (sessionId && slotAtEntry && !entry) {
33999
+ if (args.compactionOff) {
34000
+ restoreCompactionOffInput();
34001
+ } else if (sessionId && slotAtEntry && !entry) {
33250
34002
  dropSlot(sessionId, "lkg_invalidated_reshape");
33251
34003
  sessionLog(sessionId, "lkg_invalidated_reshape");
33252
34004
  } else if (sessionId && entry) {
@@ -33288,6 +34040,7 @@ function createMessagesTransformHandler(args) {
33288
34040
  const isTransient = typeof code === "string" && TRANSIENT_SQLITE_CODES.has(code);
33289
34041
  if (isTransient) {
33290
34042
  log(`[magic-context] transform skipped this pass — ${code} (transient; retrying next pass): ${message}`);
34043
+ restoreCompactionOffInput();
33291
34044
  return output.messages;
33292
34045
  }
33293
34046
  log(`[magic-context] transform FAILED code=${code ?? "none"} name=${name ?? "none"}: ${message}. Continuing with unmodified messages for this pass.`, error);
@@ -33309,6 +34062,7 @@ function createMessagesTransformHandler(args) {
33309
34062
  }
33310
34063
  }
33311
34064
  }
34065
+ restoreCompactionOffInput();
33312
34066
  return output.messages;
33313
34067
  };
33314
34068
  }
@@ -33541,21 +34295,11 @@ async function loadRustSessionStatus(client, sessionId, directory) {
33541
34295
  return;
33542
34296
  }
33543
34297
  }
33544
- function parseTtlString(ttl) {
33545
- const match = ttl.match(/^(\d+)(s|m|h)$/);
33546
- if (!match)
34298
+ function safeParseTtl(ttl) {
34299
+ try {
34300
+ return parseCacheTtl(ttl);
34301
+ } catch {
33547
34302
  return 5 * 60 * 1000;
33548
- const val = Number.parseInt(match[1], 10);
33549
- const unit = match[2];
33550
- switch (unit) {
33551
- case "s":
33552
- return val * 1000;
33553
- case "m":
33554
- return val * 60 * 1000;
33555
- case "h":
33556
- return val * 3600 * 1000;
33557
- default:
33558
- return 5 * 60 * 1000;
33559
34303
  }
33560
34304
  }
33561
34305
  function resolveConfigValue(cfg, key, modelKey, defaultValue) {
@@ -33578,7 +34322,7 @@ function resolveConfigValue(cfg, key, modelKey, defaultValue) {
33578
34322
  }
33579
34323
  return defaultValue;
33580
34324
  }
33581
- function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus) {
34325
+ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled = true) {
33582
34326
  try {
33583
34327
  const projectIdentity = resolveProjectIdentity(directory);
33584
34328
  const meta = db.prepare("SELECT * FROM session_meta WHERE session_id = ?").get(sessionId);
@@ -33599,7 +34343,8 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33599
34343
  const cacheTtl = meta ? String(meta.cache_ttl ?? "5m") : "5m";
33600
34344
  const memoryBlockCount = meta ? Number(meta.memory_block_count ?? 0) : 0;
33601
34345
  const compartmentRow = db.prepare("SELECT COUNT(*) as count FROM compartments WHERE session_id = ?").get(sessionId);
33602
- const compartmentCount = typeof moduleStatus?.compartment_count === "number" ? moduleStatus.compartment_count : compartmentRow?.count ?? 0;
34346
+ const archivedCompartmentCount = compartmentRow?.count ?? 0;
34347
+ const compartmentCount = typeof moduleStatus?.compartment_count === "number" ? moduleStatus.compartment_count : archivedCompartmentCount;
33603
34348
  let memoryCount = 0;
33604
34349
  if (projectIdentity) {
33605
34350
  const memRow = db.prepare("SELECT COUNT(*) as count FROM memories WHERE project_path = ? AND status = 'active'").get(projectIdentity);
@@ -33694,6 +34439,12 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33694
34439
  executeThreshold = thresholdDetail.percentage;
33695
34440
  executeThresholdClamped = thresholdDetail.clamped === true;
33696
34441
  }
34442
+ const nativeContextLimit = activeProviderID && activeModelID ? resolveContextLimit(activeProviderID, activeModelID, {
34443
+ db,
34444
+ sessionID: sessionId,
34445
+ reservation: "none"
34446
+ }) : contextLimit;
34447
+ const nativeContextUsagePercentage = nativeContextLimit > 0 ? effectiveInputTokens / nativeContextLimit * 100 : undefined;
33697
34448
  const calibration = resolveModelCalibration(activeProviderID, activeModelID);
33698
34449
  const calibrated = calibrateBuckets({
33699
34450
  inputTokens: effectiveInputTokens,
@@ -33713,8 +34464,11 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33713
34464
  usagePercentage: effectiveUsagePercentage,
33714
34465
  inputTokens: effectiveInputTokens,
33715
34466
  contextLimit,
34467
+ native_context_usage_percentage: nativeContextUsagePercentage,
34468
+ compaction_enabled: compactionEnabled,
33716
34469
  systemPromptTokens: calibrated.systemTokens,
33717
34470
  compartmentCount,
34471
+ archivedCompartmentCount,
33718
34472
  memoryCount,
33719
34473
  memoryBlockCount,
33720
34474
  pendingOpsCount,
@@ -33723,6 +34477,7 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33723
34477
  sessionNoteCount,
33724
34478
  readySmartNoteCount,
33725
34479
  cacheTtl,
34480
+ lastTransformError: meta?.last_transform_error ? String(meta.last_transform_error) : null,
33726
34481
  lastDreamerRunAt,
33727
34482
  projectIdentity,
33728
34483
  compartmentTokens: calibrated.compartmentTokens,
@@ -33761,15 +34516,15 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33761
34516
  throw err;
33762
34517
  }
33763
34518
  }
33764
- function buildSidebarSnapshotRpcResponse(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus) {
34519
+ function buildSidebarSnapshotRpcResponse(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled = true) {
33765
34520
  try {
33766
- return buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus);
34521
+ return buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled);
33767
34522
  } catch {
33768
34523
  return { error: "sidebar snapshot unavailable" };
33769
34524
  }
33770
34525
  }
33771
- function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessionState, injectionBudgetTokens, moduleStatus) {
33772
- const base = buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus);
34526
+ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessionState, injectionBudgetTokens, moduleStatus, compactionEnabled = true) {
34527
+ const base = buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled);
33773
34528
  const detail = {
33774
34529
  ...base,
33775
34530
  tagCounter: 0,
@@ -33786,6 +34541,7 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessi
33786
34541
  cacheTtlMs: 0,
33787
34542
  cacheRemainingMs: 0,
33788
34543
  cacheExpired: false,
34544
+ cacheNeverExpires: false,
33789
34545
  executeThreshold: 65,
33790
34546
  executeThresholdMode: "percentage",
33791
34547
  protectedTagCount: 20,
@@ -33794,9 +34550,17 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessi
33794
34550
  compressionBudget: null,
33795
34551
  compressionUsage: null,
33796
34552
  toastDurationMs: 5000,
33797
- mural: undefined
34553
+ mural: undefined,
34554
+ storage_versions: {
34555
+ context_db_schema_version: null,
34556
+ plugin_supported_version: LATEST_SUPPORTED_VERSION
34557
+ }
33798
34558
  };
33799
34559
  try {
34560
+ detail.storage_versions = {
34561
+ context_db_schema_version: getPersistedSchemaVersion(db),
34562
+ plugin_supported_version: LATEST_SUPPORTED_VERSION
34563
+ };
33800
34564
  const muralConfig = config?.experimental?.mural;
33801
34565
  if (muralConfig?.enabled && base.projectIdentity) {
33802
34566
  const row = getMural(db, base.projectIdentity);
@@ -33855,11 +34619,20 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessi
33855
34619
  } else if (base.usagePercentage > 0) {
33856
34620
  detail.contextLimit = Math.round(base.inputTokens / (base.usagePercentage / 100));
33857
34621
  }
33858
- detail.cacheTtlMs = parseTtlString(detail.cacheTtl);
34622
+ detail.cacheTtlMs = safeParseTtl(detail.cacheTtl);
34623
+ if (detail.cacheTtlMs === Number.POSITIVE_INFINITY) {
34624
+ detail.cacheNeverExpires = true;
34625
+ detail.cacheTtlMs = -1;
34626
+ }
33859
34627
  if (detail.lastResponseTime > 0) {
33860
34628
  const elapsed = Date.now() - detail.lastResponseTime;
33861
- detail.cacheRemainingMs = Math.max(0, detail.cacheTtlMs - elapsed);
33862
- detail.cacheExpired = detail.cacheRemainingMs === 0;
34629
+ if (detail.cacheNeverExpires) {
34630
+ detail.cacheRemainingMs = -1;
34631
+ detail.cacheExpired = false;
34632
+ } else {
34633
+ detail.cacheRemainingMs = Math.max(0, detail.cacheTtlMs - elapsed);
34634
+ detail.cacheExpired = detail.cacheRemainingMs === 0;
34635
+ }
33863
34636
  }
33864
34637
  try {
33865
34638
  const histTokens = base.compartmentTokens + base.factTokens;
@@ -33897,6 +34670,7 @@ function buildEmbedDetail(db, sessionId, dir, liveSessionState) {
33897
34670
  }
33898
34671
  function registerRpcHandlers(rpcServer, args) {
33899
34672
  const { directory, config, liveSessionState, rustModeModuleClient } = args;
34673
+ const compactionEnabled = isCompactionEnabled(config);
33900
34674
  const rawConfig = config;
33901
34675
  const getNotificationParams = (sessionId) => getLiveNotificationParams(sessionId, liveSessionState.liveModelBySession, liveSessionState.variantBySession, liveSessionState.agentBySession, config.toast_duration_ms);
33902
34676
  const injectionBudgetTokens = config.memory?.injection_budget_tokens;
@@ -33907,7 +34681,7 @@ function registerRpcHandlers(rpcServer, args) {
33907
34681
  if (!db || !sessionId)
33908
34682
  return { error: "unavailable" };
33909
34683
  const moduleStatus = config.transform_mode === "rust" ? await loadRustSessionStatus(rustModeModuleClient, sessionId, dir) : undefined;
33910
- return buildSidebarSnapshotRpcResponse(db, sessionId, dir, liveSessionState, injectionBudgetTokens, rawConfig, moduleStatus);
34684
+ return buildSidebarSnapshotRpcResponse(db, sessionId, dir, liveSessionState, injectionBudgetTokens, rawConfig, moduleStatus, compactionEnabled);
33911
34685
  });
33912
34686
  rpcServer.handle("status-detail", async (params) => {
33913
34687
  const sessionId = String(params.sessionId ?? "");
@@ -33917,7 +34691,7 @@ function registerRpcHandlers(rpcServer, args) {
33917
34691
  if (!db || !sessionId)
33918
34692
  return { error: "unavailable" };
33919
34693
  const moduleStatus = config.transform_mode === "rust" ? await loadRustSessionStatus(rustModeModuleClient, sessionId, dir) : undefined;
33920
- return buildStatusDetail(db, sessionId, dir, modelKey, rawConfig, liveSessionState, injectionBudgetTokens, moduleStatus);
34694
+ return buildStatusDetail(db, sessionId, dir, modelKey, rawConfig, liveSessionState, injectionBudgetTokens, moduleStatus, compactionEnabled);
33921
34695
  });
33922
34696
  rpcServer.handle("embed-detail", async (params) => {
33923
34697
  const sessionId = String(params.sessionId ?? "");
@@ -33945,9 +34719,9 @@ function registerRpcHandlers(rpcServer, args) {
33945
34719
  }
33946
34720
  });
33947
34721
  const buildManagedCtx = async (db) => {
33948
- const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await import("./derive-budgets-e9j09sjr.js");
34722
+ const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await import("./derive-budgets-9crp0cvd.js");
33949
34723
  const { resolveFallbackChain: resolveFallbackChain2 } = await import("./resolve-fallbacks-5n5tvge1.js");
33950
- const { userMemoryCollectionEnabled: userMemoryCollectionEnabled2 } = await import("./task-config-dn9k9szr.js");
34724
+ const { userMemoryCollectionEnabled: userMemoryCollectionEnabled2 } = await import("./task-config-5nx3qfz8.js");
33951
34725
  const DEFAULT_HISTORIAN_TIMEOUT_MS2 = 600000;
33952
34726
  return {
33953
34727
  client: args.client,
@@ -33972,8 +34746,8 @@ function registerRpcHandlers(rpcServer, args) {
33972
34746
  const db = getDb();
33973
34747
  if (!db)
33974
34748
  return { ok: false, error: "db unavailable" };
33975
- const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-yh7pepvx.js");
33976
- const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-tghq9gnh.js");
34749
+ const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-8e82vmvb.js");
34750
+ const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-6njqewzk.js");
33977
34751
  log(`[rpc] recomp requested for session ${sessionId}`);
33978
34752
  const ctx = await buildManagedCtx(db);
33979
34753
  runManagedRecomp2(ctx, sessionId).then((message) => {
@@ -33988,8 +34762,8 @@ function registerRpcHandlers(rpcServer, args) {
33988
34762
  const db = getDb();
33989
34763
  if (!db)
33990
34764
  return { ok: false, error: "db unavailable" };
33991
- const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-yh7pepvx.js");
33992
- const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-tghq9gnh.js");
34765
+ const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-8e82vmvb.js");
34766
+ const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-6njqewzk.js");
33993
34767
  log(`[rpc] session-upgrade requested for session ${sessionId}`);
33994
34768
  const ctx = await buildManagedCtx(db);
33995
34769
  runManagedUpgrade2(ctx, sessionId).then((message) => {
@@ -34005,7 +34779,7 @@ function registerRpcHandlers(rpcServer, args) {
34005
34779
  if (!db)
34006
34780
  return { ok: false, error: "db unavailable" };
34007
34781
  try {
34008
- const { updateSessionMeta: updateSessionMeta2 } = await import("./storage-meta-session-1phy0b1z.js");
34782
+ const { updateSessionMeta: updateSessionMeta2 } = await import("./storage-meta-session-xt41zbw4.js");
34009
34783
  updateSessionMeta2(db, sessionId, { upgradeRemindedAt: Date.now() });
34010
34784
  return { ok: true };
34011
34785
  } catch (error) {
@@ -34109,7 +34883,7 @@ Two recovery modes for finer detail:
34109
34883
  var CTX_EXPAND_TOKEN_BUDGET = 15000;
34110
34884
 
34111
34885
  // src/tools/ctx-expand/render.ts
34112
- function isRecord3(value) {
34886
+ function isRecord4(value) {
34113
34887
  return value !== null && typeof value === "object" && !Array.isArray(value);
34114
34888
  }
34115
34889
  function roleLabel(role) {
@@ -34138,15 +34912,15 @@ function keyArg(input) {
34138
34912
  function asToolPart(part) {
34139
34913
  const type = typeof part.type === "string" ? part.type : "";
34140
34914
  if (type === "tool") {
34141
- const state = isRecord3(part.state) ? part.state : null;
34915
+ const state = isRecord4(part.state) ? part.state : null;
34142
34916
  const output = state && typeof state.output === "string" ? state.output : state && state.output != null ? JSON.stringify(state.output) : null;
34143
- const metadata = state && isRecord3(state.metadata) ? state.metadata : null;
34917
+ const metadata = state && isRecord4(state.metadata) ? state.metadata : null;
34144
34918
  const title = state && typeof state.title === "string" && state.title || metadata && typeof metadata.title === "string" && metadata.title || null;
34145
34919
  return {
34146
34920
  name: typeof part.tool === "string" ? part.tool : "tool",
34147
34921
  callId: typeof part.callID === "string" ? part.callID : "",
34148
34922
  title,
34149
- input: state && isRecord3(state.input) ? state.input : null,
34923
+ input: state && isRecord4(state.input) ? state.input : null,
34150
34924
  output
34151
34925
  };
34152
34926
  }
@@ -34155,7 +34929,7 @@ function asToolPart(part) {
34155
34929
  name: typeof part.name === "string" ? part.name : "tool",
34156
34930
  callId: typeof part.id === "string" ? part.id : "",
34157
34931
  title: null,
34158
- input: isRecord3(part.input) ? part.input : null,
34932
+ input: isRecord4(part.input) ? part.input : null,
34159
34933
  output: null
34160
34934
  };
34161
34935
  }
@@ -34184,7 +34958,7 @@ function reasoningOf(part) {
34184
34958
  return null;
34185
34959
  }
34186
34960
  function renderPartPreview(part) {
34187
- if (!isRecord3(part))
34961
+ if (!isRecord4(part))
34188
34962
  return null;
34189
34963
  const text = textOf(part);
34190
34964
  if (text !== null) {
@@ -34208,7 +34982,7 @@ function renderPartPreview(part) {
34208
34982
  return ` • [${type}]`;
34209
34983
  }
34210
34984
  function renderPartFull(part) {
34211
- if (!isRecord3(part))
34985
+ if (!isRecord4(part))
34212
34986
  return null;
34213
34987
  const text = textOf(part);
34214
34988
  if (text !== null) {
@@ -35714,6 +36488,8 @@ function createToolRegistry(args) {
35714
36488
  if (pluginConfig.enabled !== true) {
35715
36489
  return {};
35716
36490
  }
36491
+ const compactionOff = !isCompactionEnabled(pluginConfig);
36492
+ setCtxReduceRegisteredGlobally(!compactionOff);
35717
36493
  let db;
35718
36494
  try {
35719
36495
  const opened = openDatabase();
@@ -35731,10 +36507,10 @@ function createToolRegistry(args) {
35731
36507
  ensureProjectRegisteredFromOpenCodeDirectory(ctx.directory, db).catch((error) => {
35732
36508
  log(`[magic-context] embedding registration skipped: ${getErrorMessage(error)}`);
35733
36509
  });
35734
- const resolveProjectPath = (directory) => resolveProjectIdentityForSession(directory);
36510
+ const resolveProjectPath = (directory) => resolveProjectIdentityForSession(directory, pluginConfig.allow_home_project);
35735
36511
  const memoryEnabled = pluginConfig.memory?.enabled !== false;
35736
36512
  const allTools = {
35737
- ...createCtxReduceTools({
36513
+ ...compactionOff ? {} : createCtxReduceTools({
35738
36514
  db,
35739
36515
  protectedTags: pluginConfig.protected_tags ?? DEFAULT_PROTECTED_TAGS,
35740
36516
  rustToolBackends
@@ -35799,64 +36575,6 @@ import {
35799
36575
  writeFileSync as writeFileSync5
35800
36576
  } from "node:fs";
35801
36577
  import { dirname as dirname5 } from "node:path";
35802
-
35803
- // src/shared/rpc-utils.ts
35804
- import { createHash as createHash14 } from "node:crypto";
35805
- import { join as join7 } from "node:path";
35806
- function projectHash(directory) {
35807
- const normalized = directory.replace(/\/+$/, "");
35808
- return createHash14("sha256").update(normalized).digest("hex").slice(0, 16);
35809
- }
35810
- function rpcPortDir(storageDir, directory) {
35811
- return join7(storageDir, "rpc", projectHash(directory));
35812
- }
35813
- function rpcPortFilePath(storageDir, directory, pid = process.pid, instanceId) {
35814
- const suffix = instanceId ? `-${instanceId}` : "";
35815
- return join7(rpcPortDir(storageDir, directory), `port-${pid}${suffix}.json`);
35816
- }
35817
- function isPidAlive(pid) {
35818
- if (!Number.isInteger(pid) || pid <= 0)
35819
- return false;
35820
- try {
35821
- process.kill(pid, 0);
35822
- return true;
35823
- } catch (err) {
35824
- return err.code === "EPERM";
35825
- }
35826
- }
35827
- function parseRpcPortFile(content, fallbackPid = 0) {
35828
- const trimmed = content.trim();
35829
- if (!trimmed)
35830
- return null;
35831
- if (trimmed.startsWith("{")) {
35832
- try {
35833
- const parsed = JSON.parse(trimmed);
35834
- const port2 = Number(parsed.port);
35835
- const pid = Number(parsed.pid);
35836
- const startedAt = Number(parsed.started_at);
35837
- if (!isValidPort(port2) || !Number.isInteger(pid) || pid <= 0)
35838
- return null;
35839
- return {
35840
- port: port2,
35841
- pid,
35842
- started_at: Number.isFinite(startedAt) ? startedAt : 0,
35843
- token: typeof parsed.token === "string" ? parsed.token : undefined,
35844
- instance_id: typeof parsed.instance_id === "string" ? parsed.instance_id : undefined
35845
- };
35846
- } catch {
35847
- return null;
35848
- }
35849
- }
35850
- const port = Number.parseInt(trimmed, 10);
35851
- if (!isValidPort(port))
35852
- return null;
35853
- return { port, pid: fallbackPid, started_at: 0 };
35854
- }
35855
- function isValidPort(port) {
35856
- return Number.isInteger(port) && port > 0 && port <= 65535;
35857
- }
35858
-
35859
- // src/shared/rpc-server.ts
35860
36578
  var MAX_BODY_BYTES = 1048576;
35861
36579
  var WS_AUTH_TIMEOUT_MS = 5000;
35862
36580
  var WS_CLOSE_UNAUTHORIZED = 4401;
@@ -35931,10 +36649,15 @@ class MagicContextRpcServer {
35931
36649
  try {
35932
36650
  this.warnIfOtherLiveInstance();
35933
36651
  const dir = dirname5(this.portFilePath);
35934
- mkdirSync3(dir, { recursive: true, mode: 448 });
35935
- try {
35936
- chmodSync(dir, 448);
35937
- } catch {}
36652
+ const enforcePrivatePermissions = shouldEnforcePrivateStoragePermissions();
36653
+ if (enforcePrivatePermissions) {
36654
+ mkdirSync3(dir, { recursive: true, mode: 448 });
36655
+ try {
36656
+ chmodSync(dir, 448);
36657
+ } catch {}
36658
+ } else {
36659
+ mkdirSync3(dir, { recursive: true });
36660
+ }
35938
36661
  const tmpPath = `${this.portFilePath}.tmp`;
35939
36662
  try {
35940
36663
  rmSync3(tmpPath, { force: true });
@@ -35945,11 +36668,13 @@ class MagicContextRpcServer {
35945
36668
  started_at: this.startedAt,
35946
36669
  token: this.token,
35947
36670
  instance_id: this.instanceId
35948
- }), { encoding: "utf-8", mode: 384 });
36671
+ }), enforcePrivatePermissions ? { encoding: "utf-8", mode: 384 } : { encoding: "utf-8" });
35949
36672
  renameSync4(tmpPath, this.portFilePath);
35950
- try {
35951
- chmodSync(this.portFilePath, 384);
35952
- } catch {}
36673
+ if (enforcePrivatePermissions) {
36674
+ try {
36675
+ chmodSync(this.portFilePath, 384);
36676
+ } catch {}
36677
+ }
35953
36678
  log(`[rpc] server listening on 127.0.0.1:${this.port}`);
35954
36679
  } catch (err) {
35955
36680
  log(`[rpc] failed to write port file: ${err}`);
@@ -36126,6 +36851,7 @@ var server = async (ctx) => {
36126
36851
  ...pluginConfig.configWarnings ?? []
36127
36852
  ];
36128
36853
  }
36854
+ setStoragePrivatePermissionEnforcement(pluginConfig.storage.enforce_private_permissions);
36129
36855
  setSqlitePragmaConfig({
36130
36856
  cacheSizeMb: pluginConfig.sqlite.cache_size_mb,
36131
36857
  mmapSizeMb: pluginConfig.sqlite.mmap_size_mb
@@ -36149,7 +36875,7 @@ var server = async (ctx) => {
36149
36875
  `);
36150
36876
  setTimeout(async () => {
36151
36877
  try {
36152
- const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-tghq9gnh.js");
36878
+ const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-6njqewzk.js");
36153
36879
  const clientWithSessions = ctx.client;
36154
36880
  const sessions = await Promise.resolve(clientWithSessions.session?.list?.()).catch(() => null);
36155
36881
  const sessionList = Array.isArray(sessions) ? sessions : sessions?.data;
@@ -36162,7 +36888,9 @@ var server = async (ctx) => {
36162
36888
  }
36163
36889
  let conflictResult = null;
36164
36890
  if (pluginConfig.enabled) {
36165
- conflictResult = detectConflicts(ctx.directory);
36891
+ conflictResult = detectConflicts(ctx.directory, {
36892
+ compactionEnabled: isCompactionEnabled(pluginConfig)
36893
+ });
36166
36894
  if (conflictResult.hasConflict) {
36167
36895
  pluginConfig.enabled = false;
36168
36896
  log(`[magic-context] disabled due to conflicts: ${conflictResult.reasons.join("; ")}`);
@@ -36272,9 +37000,9 @@ var server = async (ctx) => {
36272
37000
  if (pluginConfig.enabled) {
36273
37001
  const dreamerRunnable = isDreamerRunnable(pluginConfig);
36274
37002
  const classifyModuleClient = createDreamTimerModuleClient(rustModeModuleClient);
36275
- const timerProjectIdentity = resolveProjectIdentityForSession(ctx.directory);
37003
+ const timerProjectIdentity = resolveProjectIdentityForSession(ctx.directory, pluginConfig.allow_home_project);
36276
37004
  if (!timerProjectIdentity) {
36277
- log("[magic-context] dream timer skipped: cwd is the user's home directory");
37005
+ log("[magic-context] dream timer skipped: no project identity is bound for this directory");
36278
37006
  } else {
36279
37007
  const timerRegistration = {
36280
37008
  directory: ctx.directory,
@@ -36317,7 +37045,7 @@ var server = async (ctx) => {
36317
37045
  {
36318
37046
  const fence = getSchemaFenceRejection();
36319
37047
  if (fence) {
36320
- import("./conflict-warning-hook-bwa99a04.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
37048
+ import("./conflict-warning-hook-fvpfvt0w.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
36321
37049
  }
36322
37050
  }
36323
37051
  if (conflictResult?.hasConflict) {
@@ -36338,7 +37066,7 @@ var server = async (ctx) => {
36338
37066
  } = await import("./announcement-gms2nhya.js");
36339
37067
  if (shouldShowAnnouncement2()) {
36340
37068
  setTimeout(() => {
36341
- import("./conflict-warning-hook-bwa99a04.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION2, ANNOUNCEMENT_FEATURES2, ANNOUNCEMENT_FOOTER2, markAnnouncementSeen2)).catch(() => {});
37069
+ import("./conflict-warning-hook-fvpfvt0w.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION2, ANNOUNCEMENT_FEATURES2, ANNOUNCEMENT_FOOTER2, markAnnouncementSeen2)).catch(() => {});
36342
37070
  }, 8000);
36343
37071
  }
36344
37072
  } catch {}
@@ -36379,6 +37107,7 @@ var server = async (ctx) => {
36379
37107
  getMagicContext: () => magicContextRuntime.magicContext,
36380
37108
  failClosed,
36381
37109
  failClosedBlockingEnabled,
37110
+ compactionOff: !isCompactionEnabled(pluginConfig),
36382
37111
  internalChildSessions: liveSessionState.internalChildSessions,
36383
37112
  tryReopenStorage
36384
37113
  }),
@@ -36420,7 +37149,7 @@ var server = async (ctx) => {
36420
37149
  }
36421
37150
  const commandConfig = {
36422
37151
  ...config.command ?? {},
36423
- ...getMagicContextBuiltinCommands(),
37152
+ ...getMagicContextBuiltinCommands(isCompactionEnabled(pluginConfig)),
36424
37153
  ...pluginConfig.command ?? {}
36425
37154
  };
36426
37155
  config.command = commandConfig;