@cortexkit/opencode-magic-context 0.33.1 → 0.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +20 -3
  2. package/dist/config/agent-disable.d.ts +22 -0
  3. package/dist/config/agent-disable.d.ts.map +1 -1
  4. package/dist/config/index.d.ts.map +1 -1
  5. package/dist/config/migrate-experimental.d.ts +2 -1
  6. package/dist/config/migrate-experimental.d.ts.map +1 -1
  7. package/dist/config/project-security.d.ts +9 -0
  8. package/dist/config/project-security.d.ts.map +1 -1
  9. package/dist/config/schema/magic-context.d.ts +90 -17
  10. package/dist/config/schema/magic-context.d.ts.map +1 -1
  11. package/dist/config/transform-mode.d.ts +2 -0
  12. package/dist/config/transform-mode.d.ts.map +1 -1
  13. package/dist/{conflict-warning-hook-n48c783v.js → conflict-warning-hook-fvpfvt0w.js} +1 -1
  14. package/dist/{derive-budgets-e9j09sjr.js → derive-budgets-9crp0cvd.js} +1 -1
  15. package/dist/features/builtin-commands/commands.d.ts +1 -1
  16. package/dist/features/builtin-commands/commands.d.ts.map +1 -1
  17. package/dist/features/magic-context/compaction-marker.d.ts +57 -0
  18. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  19. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/classify.d.ts +1 -0
  21. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  23. package/dist/features/magic-context/dreamer/map-memories.d.ts +1 -0
  24. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  25. package/dist/features/magic-context/dreamer/refresh-primers.d.ts +1 -0
  26. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  27. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +2 -0
  28. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  29. package/dist/features/magic-context/dreamer/task-executor.d.ts +4 -1
  30. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  31. package/dist/features/magic-context/dreamer/task-gates.d.ts +19 -1
  32. package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -1
  33. package/dist/features/magic-context/dreamer/task-registry.d.ts +28 -0
  34. package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
  35. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +7 -1
  36. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  37. package/dist/features/magic-context/dreamer/verify.d.ts +1 -0
  38. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  39. package/dist/features/magic-context/fail-closed-block.d.ts +10 -0
  40. package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
  41. package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -1
  42. package/dist/features/magic-context/git-commits/storage-git-commits.d.ts.map +1 -1
  43. package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -1
  44. package/dist/features/magic-context/memory/embedding-local.d.ts +7 -1
  45. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  46. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
  47. package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
  48. package/dist/features/magic-context/memory/project-identity.d.ts +2 -6
  49. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  50. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
  51. package/dist/features/magic-context/migrations.d.ts +23 -1
  52. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  53. package/dist/features/magic-context/mural/compress-cues.d.ts +1 -0
  54. package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
  55. package/dist/features/magic-context/mural/render-mural.d.ts.map +1 -1
  56. package/dist/features/magic-context/overflow-detection.d.ts +8 -1
  57. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  58. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  59. package/dist/features/magic-context/scheduler.d.ts.map +1 -1
  60. package/dist/features/magic-context/schema-fence-probe.d.ts +28 -0
  61. package/dist/features/magic-context/schema-fence-probe.d.ts.map +1 -0
  62. package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
  63. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
  64. package/dist/features/magic-context/storage-db.d.ts +37 -2
  65. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  66. package/dist/features/magic-context/storage-meta-persisted.d.ts +38 -4
  67. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  68. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  69. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  70. package/dist/features/magic-context/storage.d.ts +2 -2
  71. package/dist/features/magic-context/storage.d.ts.map +1 -1
  72. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
  73. package/dist/hooks/magic-context/boundary-execution.d.ts +1 -1
  74. package/dist/hooks/magic-context/boundary-execution.d.ts.map +1 -1
  75. package/dist/hooks/magic-context/cache-busting-signals.d.ts +1 -0
  76. package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
  77. package/dist/hooks/magic-context/child-session-spawn.d.ts +26 -0
  78. package/dist/hooks/magic-context/child-session-spawn.d.ts.map +1 -0
  79. package/dist/hooks/magic-context/command-handler.d.ts +3 -0
  80. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  81. package/dist/hooks/magic-context/compaction-off-transition.d.ts +96 -0
  82. package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -0
  83. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +2 -0
  84. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  85. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  86. package/dist/hooks/magic-context/compartment-runner-mapping.d.ts.map +1 -1
  87. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  88. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  89. package/dist/hooks/magic-context/compartment-trigger.d.ts +12 -5
  90. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  91. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +47 -1
  92. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
  93. package/dist/hooks/magic-context/emergency-drop.d.ts +2 -2
  94. package/dist/hooks/magic-context/event-handler.d.ts +7 -0
  95. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  96. package/dist/hooks/magic-context/event-resolvers.d.ts +13 -21
  97. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  98. package/dist/hooks/magic-context/execute-status.d.ts +5 -1
  99. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
  100. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
  101. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  102. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +1 -1
  103. package/dist/hooks/magic-context/hook-handlers.d.ts +1 -0
  104. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  105. package/dist/hooks/magic-context/hook.d.ts +14 -6
  106. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  107. package/dist/hooks/magic-context/inject-compartments.d.ts +10 -1
  108. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  109. package/dist/hooks/magic-context/live-session-state.d.ts +3 -0
  110. package/dist/hooks/magic-context/live-session-state.d.ts.map +1 -1
  111. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  112. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  113. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  114. package/dist/hooks/magic-context/rust-mode-transform.d.ts +3 -0
  115. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  116. package/dist/hooks/magic-context/send-session-notification.d.ts +20 -1
  117. package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
  118. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +3 -0
  119. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  120. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +31 -1
  121. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  122. package/dist/hooks/magic-context/transform.d.ts +29 -2
  123. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  124. package/dist/{index-56yjaeb2.js → index-2y0ybv5x.js} +11 -1
  125. package/dist/{index-ey1bc14z.js → index-b563sga5.js} +7 -264
  126. package/dist/{index-y1c9tcm3.js → index-cn960ffd.js} +101 -20
  127. package/dist/{index-xyaekybw.js → index-dtas91s5.js} +6 -4
  128. package/dist/index-fcyvznch.js +279 -0
  129. package/dist/{index-63dq2g4d.js → index-ry8rh8cv.js} +138 -24
  130. package/dist/{index-c2gahrks.js → index-x8spt5wy.js} +1682 -893
  131. package/dist/index.d.ts.map +1 -1
  132. package/dist/index.js +1677 -723
  133. package/dist/plugin/dream-timer.d.ts +4 -2
  134. package/dist/plugin/dream-timer.d.ts.map +1 -1
  135. package/dist/plugin/embedding-bootstrap.d.ts.map +1 -1
  136. package/dist/plugin/hooks/create-session-hooks.d.ts +12 -1
  137. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  138. package/dist/plugin/messages-transform.d.ts +10 -0
  139. package/dist/plugin/messages-transform.d.ts.map +1 -1
  140. package/dist/plugin/rpc-handlers.d.ts +3 -7
  141. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  142. package/dist/plugin/tool-registry.d.ts +8 -0
  143. package/dist/plugin/tool-registry.d.ts.map +1 -1
  144. package/dist/{recomp-orchestrator-2yb2hfh2.js → recomp-orchestrator-k72ejkkh.js} +6 -4
  145. package/dist/send-session-notification-6njqewzk.js +20 -0
  146. package/dist/shared/conflict-detector.d.ts +38 -1
  147. package/dist/shared/conflict-detector.d.ts.map +1 -1
  148. package/dist/shared/conflict-fixer.d.ts +18 -1
  149. package/dist/shared/conflict-fixer.d.ts.map +1 -1
  150. package/dist/shared/context-limit-provenance.d.ts +3 -0
  151. package/dist/shared/context-limit-provenance.d.ts.map +1 -0
  152. package/dist/shared/escalation-bands.d.ts +9 -0
  153. package/dist/shared/escalation-bands.d.ts.map +1 -0
  154. package/dist/shared/format-threshold.d.ts +1 -1
  155. package/dist/shared/models-dev-cache.d.ts +29 -3
  156. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  157. package/dist/shared/rpc-server.d.ts.map +1 -1
  158. package/dist/shared/rpc-types.d.ts +51 -1
  159. package/dist/shared/rpc-types.d.ts.map +1 -1
  160. package/dist/shared/rpc-utils.d.ts +19 -0
  161. package/dist/shared/rpc-utils.d.ts.map +1 -1
  162. package/dist/shared/storage-permissions.d.ts +5 -0
  163. package/dist/shared/storage-permissions.d.ts.map +1 -0
  164. package/dist/shared/tui-runtime-specifiers.d.ts +20 -0
  165. package/dist/shared/tui-runtime-specifiers.d.ts.map +1 -0
  166. package/dist/{storage-meta-session-td6bwtky.js → storage-meta-session-xt41zbw4.js} +2 -1
  167. package/dist/{task-config-5nx3qfz8.js → task-config-gbp7r23g.js} +1 -1
  168. package/dist/tui/compaction-off.d.ts +13 -0
  169. package/dist/tui/compaction-off.d.ts.map +1 -0
  170. package/dist/tui/data/context-db.d.ts.map +1 -1
  171. package/dist/tui-compiled/compaction-off.d.ts +13 -0
  172. package/dist/tui-compiled/compaction-off.d.ts.map +1 -0
  173. package/dist/tui-compiled/data/context-db.d.ts.map +1 -1
  174. package/package.json +6 -1
  175. package/src/agents/dreamer.ts +68 -0
  176. package/src/agents/hidden-agent-registrations.ts +331 -0
  177. package/src/agents/historian.ts +3 -0
  178. package/src/agents/language-directive.test.ts +138 -0
  179. package/src/agents/language-directive.ts +121 -0
  180. package/src/agents/magic-context-prompt.language.test.ts +35 -0
  181. package/src/agents/magic-context-prompt.test.ts +292 -0
  182. package/src/agents/magic-context-prompt.ts +182 -0
  183. package/src/agents/permissions.test.ts +252 -0
  184. package/src/agents/permissions.ts +186 -0
  185. package/src/agents/sidekick.ts +1 -0
  186. package/src/agents/smart-note-compiler.ts +1 -0
  187. package/src/config/agent-disable.ts +106 -0
  188. package/src/config/compaction-accessor-guard.test.ts +82 -0
  189. package/src/config/compaction-backcompat.test.ts +52 -0
  190. package/src/config/index.test.ts +936 -0
  191. package/src/config/index.ts +601 -0
  192. package/src/config/migrate-config-location.test.ts +332 -0
  193. package/src/config/migrate-config-location.ts +635 -0
  194. package/src/config/migrate-dreamer-v2.test.ts +287 -0
  195. package/src/config/migrate-dreamer-v2.ts +336 -0
  196. package/src/config/migrate-experimental.test.ts +41 -0
  197. package/src/config/migrate-experimental.ts +185 -0
  198. package/src/config/project-security.test.ts +388 -0
  199. package/src/config/project-security.ts +611 -0
  200. package/src/config/prune-config-leaf.test.ts +78 -0
  201. package/src/config/prune-config-leaf.ts +68 -0
  202. package/src/config/removed-config-keys.test.ts +116 -0
  203. package/src/config/schema/agent-overrides.ts +45 -0
  204. package/src/config/schema/magic-context.test.ts +359 -0
  205. package/src/config/schema/magic-context.ts +991 -0
  206. package/src/config/transform-mode.test.ts +62 -0
  207. package/src/config/transform-mode.ts +34 -0
  208. package/src/config/variable.test.ts +323 -0
  209. package/src/config/variable.ts +192 -0
  210. package/src/features/magic-context/defaults.ts +1 -0
  211. package/src/features/magic-context/dreamer/cron.ts +243 -0
  212. package/src/features/magic-context/dreamer/task-registry.ts +151 -0
  213. package/src/shared/conflict-detector.test.ts +121 -0
  214. package/src/shared/conflict-detector.ts +50 -3
  215. package/src/shared/conflict-fixer.test.ts +309 -0
  216. package/src/shared/conflict-fixer.ts +82 -5
  217. package/src/shared/context-limit-provenance.ts +6 -0
  218. package/src/shared/escalation-bands.test.ts +23 -0
  219. package/src/shared/escalation-bands.ts +18 -0
  220. package/src/shared/format-threshold.ts +1 -1
  221. package/src/shared/models-dev-cache.test.ts +171 -0
  222. package/src/shared/models-dev-cache.ts +195 -38
  223. package/src/shared/rpc-server.ts +27 -18
  224. package/src/shared/rpc-types.ts +55 -1
  225. package/src/shared/rpc-utils.test.ts +157 -0
  226. package/src/shared/rpc-utils.ts +137 -0
  227. package/src/shared/storage-permissions.ts +20 -0
  228. package/src/shared/tui-runtime-specifiers.ts +32 -0
  229. package/src/tui/compaction-off.test.ts +56 -0
  230. package/src/tui/compaction-off.ts +29 -0
  231. package/src/tui/data/context-db.ts +6 -0
  232. package/src/tui/index.tsx +113 -65
  233. package/src/tui/slots/sidebar-content.tsx +189 -91
  234. package/src/tui/tui-compiled-runtime-imports.test.ts +151 -0
  235. package/src/tui-compiled/compaction-off.ts +29 -0
  236. package/src/tui-compiled/data/context-db.ts +6 -0
  237. package/src/tui-compiled/index.tsx +558 -455
  238. package/src/tui-compiled/slots/sidebar-content.tsx +334 -169
  239. package/dist/send-session-notification-tghq9gnh.js +0 -11
  240. /package/dist/{index-v7fmc1s2.js → index-ygcng9t8.js} +0 -0
package/dist/index.js CHANGED
@@ -2,11 +2,13 @@ import {
2
2
  CANONICAL_DREAM_TASKS,
3
3
  buildDreamTaskRuntimeConfigs,
4
4
  compareTaskOrder,
5
+ formatDreamTaskBacklogs,
5
6
  isCanonicalDreamTask,
6
7
  leaseKeyFor,
7
8
  leaseKindFor,
9
+ processedDreamTaskItems,
8
10
  userMemoryCollectionEnabled
9
- } from "./index-56yjaeb2.js";
11
+ } from "./index-2y0ybv5x.js";
10
12
  import {
11
13
  AGE_RECLAIM_MIN_TOKENS,
12
14
  AdmissionClass,
@@ -22,7 +24,9 @@ import {
22
24
  GIT_SWEEP_LEASE_RENEWAL_MS,
23
25
  GLOBAL_USER_PROFILE_PROJECT_PATH,
24
26
  HISTORIAN_EDITOR_SYSTEM_PROMPT,
27
+ LATEST_SUPPORTED_VERSION,
25
28
  MARKER_SUMMARY_TEXT,
29
+ MAX_EXECUTE_THRESHOLD,
26
30
  MagicContextConfigSchema,
27
31
  ModuleMemoryAuthorityError,
28
32
  PRIMER_CANDIDATE_MAX_AGE_MS,
@@ -73,6 +77,7 @@ import {
73
77
  clearNoteNudgeTriggerAndCooldown,
74
78
  clearNoteNudgeTriggerOnly,
75
79
  clearPendingCompactionMarkerStateIf,
80
+ clearPendingOps,
76
81
  clearPersistedReasoningWatermark,
77
82
  clearPersistedTodoSyntheticAnchor,
78
83
  clearRecompStaging,
@@ -83,6 +88,7 @@ import {
83
88
  cosineSimilarity,
84
89
  countEmbeddedCommits,
85
90
  countPrimerCandidatesForProject,
91
+ createChildSessionWithFence,
86
92
  createPrimer,
87
93
  deleteTagsByMessageId,
88
94
  deleteUserMemoryCandidates,
@@ -104,6 +110,7 @@ import {
104
110
  enqueueShadowEmbeddingItems,
105
111
  ensureContextStoreUuid,
106
112
  ensureMemoryEmbeddings,
113
+ escalationBands,
107
114
  estimateTrueRawMessageTokens,
108
115
  expandWorkspaceIdentitySetWithAliases,
109
116
  exports_external,
@@ -122,6 +129,7 @@ import {
122
129
  getCandidateToolOwners,
123
130
  getChannel2NudgeClaim,
124
131
  getChannel2NudgeState,
132
+ getCompactionModeRecord,
125
133
  getCompartmentEvents,
126
134
  getCompartments,
127
135
  getContextStoreUuid,
@@ -150,6 +158,7 @@ import {
150
158
  getMemoryCountsByStatus,
151
159
  getMemoryMutationsForRenderByProjects,
152
160
  getMemoryVerifications,
161
+ getMigrationOnOpenRefusal,
153
162
  getMirrorCursor,
154
163
  getModuleNoteEvaluationBridge,
155
164
  getMural,
@@ -166,6 +175,8 @@ import {
166
175
  getPersistedCompactionMarkerState,
167
176
  getPersistedNoteNudge,
168
177
  getPersistedReasoningWatermark,
178
+ getPersistedSchemaVersion,
179
+ getPersistedTodoPermissionDenied,
169
180
  getPersistedTodoSyntheticAnchor,
170
181
  getPrimaryEmbeddingMeasurementCohort,
171
182
  getPrimerCandidatesByIds,
@@ -197,6 +208,7 @@ import {
197
208
  hasLengthCappedOutput,
198
209
  hasMemoryClassifiedAtColumn,
199
210
  hasMemoryShareableColumn,
211
+ hasMuralCueColumns,
200
212
  hasRunnableCompartmentWindow,
201
213
  injectM0M1,
202
214
  injectTemporalMarkers,
@@ -212,6 +224,7 @@ import {
212
224
  isDatabasePersisted,
213
225
  isEmbeddingEnabled,
214
226
  isEmergencyRecoveryArmed,
227
+ isPidAlive,
215
228
  isProviderOverflowReconfirmed,
216
229
  lkgContentDigest,
217
230
  loadCompartmentChunkEmbeddingsForSearch,
@@ -239,6 +252,7 @@ import {
239
252
  openDatabaseAsync,
240
253
  parkGitSweepNonIndexable,
241
254
  parseCron,
255
+ parseRpcPortFile,
242
256
  peekDeferredExecutePending,
243
257
  peekNoteNudgeText,
244
258
  peekProjectEmbeddings,
@@ -278,6 +292,7 @@ import {
278
292
  releaseWrapupInProgress,
279
293
  removeAutoSearchHintDecisionByMessageId,
280
294
  removeCompactionMarkerForSession,
295
+ removeMcOwnedCompactionMarkers,
281
296
  removeNoteNudgeAnchorByMessageId,
282
297
  removePendingOp,
283
298
  removeStrippedPlaceholderId,
@@ -290,6 +305,7 @@ import {
290
305
  resetLastNudgeCycleIfTailShrank,
291
306
  resetNoteNudgeCooldownOnly,
292
307
  resetProtectedTailNoEligibleHead,
308
+ resolveCompactionModeRecord,
293
309
  resolveGitTopLevel,
294
310
  resolveOpenCodeProtectedTailBoundary,
295
311
  resolveProjectIdentity,
@@ -299,6 +315,8 @@ import {
299
315
  resolveWorkspaceIdentitySet,
300
316
  resolveWorkspaceShareCategories,
301
317
  resolveWrapupProtectedTailBoundary,
318
+ rpcPortDir,
319
+ rpcPortFilePath,
302
320
  runCompartmentAgent,
303
321
  runManagedRecomp,
304
322
  runManagedUpgrade,
@@ -310,6 +328,8 @@ import {
310
328
  scheduleAfterBootQuiet,
311
329
  searchMemoriesFTS,
312
330
  searchMemoriesFTSUnion,
331
+ setChannel2NudgeState,
332
+ setCompactionModeRecord,
313
333
  setDeferredExecutePendingIfAbsent,
314
334
  setEmergencyDropSample,
315
335
  setKeepSubagents,
@@ -318,7 +338,9 @@ import {
318
338
  setMemoryClassification,
319
339
  setMuralCue,
320
340
  setNoteLastReadAt,
341
+ setPersistedCompactionMarkerState,
321
342
  setPersistedReasoningWatermark,
343
+ setPersistedTodoPermissionDenied,
322
344
  setPersistedTodoSyntheticAnchor,
323
345
  setRecompStarting,
324
346
  setRecompTerminal,
@@ -350,7 +372,7 @@ import {
350
372
  upsertCommits,
351
373
  verificationFileExists,
352
374
  withContentLanguageDirective
353
- } from "./index-c2gahrks.js";
375
+ } from "./index-x8spt5wy.js";
354
376
  import {
355
377
  deriveHistorianChunkTokens,
356
378
  deriveTriggerBudget,
@@ -358,20 +380,24 @@ import {
358
380
  isSaneLimit,
359
381
  refreshModelLimitsAfterAuthOnce,
360
382
  refreshModelLimitsFromApi,
361
- resolveHistorianContextLimit
362
- } from "./index-63dq2g4d.js";
383
+ resolveHistorianContextLimit,
384
+ setOutputReserveConfig,
385
+ setStoragePrivatePermissionEnforcement,
386
+ shouldEnforcePrivateStoragePermissions
387
+ } from "./index-ry8rh8cv.js";
363
388
  import {
364
389
  modelBodyField,
365
390
  resolveFallbackChain
366
391
  } from "./index-td9depx5.js";
367
392
  import {
393
+ clearIgnoredMessages,
368
394
  describeError,
395
+ flushIgnoredMessages,
369
396
  getErrorMessage,
370
397
  sendIgnoredMessage,
371
398
  sendUserPrompt
372
- } from "./index-y1c9tcm3.js";
399
+ } from "./index-cn960ffd.js";
373
400
  import {
374
- Database,
375
401
  ToolMutationBatch,
376
402
  advanceToolReclaimWatermark,
377
403
  buildFileSourceContent,
@@ -380,7 +406,6 @@ import {
380
406
  cleanUserText,
381
407
  clearIndexedMessages,
382
408
  clearSession,
383
- closeQuietly,
384
409
  createToolDropTarget,
385
410
  deleteIndexedMessage,
386
411
  estimateTokens,
@@ -388,12 +413,10 @@ import {
388
413
  extractTexts,
389
414
  extractToolCallObservation,
390
415
  extractToolCallSummaries,
391
- findLastAssistantModelFromOpenCodeDb,
392
416
  getIndexedMessageCorpusSize,
393
417
  getLastIndexedOrdinal,
394
418
  getMessageIndexReconciliationStartOrdinal,
395
419
  getMessageIndexSourceIdentity,
396
- getMessageTimesFromOpenCodeDb,
397
420
  getOrCreateSessionMeta,
398
421
  getRawSessionStoredMessageCount,
399
422
  hasMeaningfulUserText,
@@ -403,7 +426,6 @@ import {
403
426
  isFilePart,
404
427
  isMessageIndexReconciledThrough,
405
428
  isMessageIndexSourceCurrent,
406
- isMidTurn,
407
429
  isRawCompactionSummaryInfo,
408
430
  isRecord,
409
431
  isTextPart,
@@ -411,7 +433,6 @@ import {
411
433
  isToolPartWithOutput,
412
434
  markSessionCleanupPending,
413
435
  normalizeText,
414
- openCodeDbExists,
415
436
  partHasCompletedResult,
416
437
  prependTag,
417
438
  primeInMemoryTailRawMessageCache,
@@ -429,9 +450,17 @@ import {
429
450
  sweepOrphanedOpenCodeMessageIndexes,
430
451
  textMentionsRecentCommit,
431
452
  updateSessionMeta,
432
- withRawSessionMessageCache,
453
+ withRawSessionMessageCache
454
+ } from "./index-b563sga5.js";
455
+ import {
456
+ Database,
457
+ closeQuietly,
458
+ findLastAssistantModelFromOpenCodeDb,
459
+ getMessageTimesFromOpenCodeDb,
460
+ isMidTurn,
461
+ openCodeDbExists,
433
462
  withReadOnlySessionDb
434
- } from "./index-ey1bc14z.js";
463
+ } from "./index-fcyvznch.js";
435
464
  import {
436
465
  cleanupConflictWarnings,
437
466
  detectConfigFile,
@@ -439,7 +468,7 @@ import {
439
468
  parseJsonc,
440
469
  sendConflictWarning,
441
470
  stripJsonComments
442
- } from "./index-xyaekybw.js";
471
+ } from "./index-dtas91s5.js";
443
472
  import {
444
473
  ANNOUNCEMENT_FEATURES,
445
474
  ANNOUNCEMENT_FOOTER,
@@ -449,6 +478,13 @@ import {
449
478
  markAnnouncementSeen,
450
479
  shouldShowAnnouncement
451
480
  } from "./index-dmr999a2.js";
481
+ import {
482
+ acknowledgeNotifications,
483
+ drainNotifications,
484
+ isTuiConnected,
485
+ pushNotification,
486
+ registerNotificationSink
487
+ } from "./index-d62ypazr.js";
452
488
  import"./index-73xz0247.js";
453
489
  import {
454
490
  log,
@@ -463,13 +499,6 @@ import {
463
499
  import {
464
500
  resolvePromptContext
465
501
  } from "./index-szf8w1p5.js";
466
- import {
467
- acknowledgeNotifications,
468
- drainNotifications,
469
- isTuiConnected,
470
- pushNotification,
471
- registerNotificationSink
472
- } from "./index-d62ypazr.js";
473
502
  import {
474
503
  __commonJS,
475
504
  __require,
@@ -8488,6 +8517,7 @@ function buildHiddenAgentConfig(prompt, allowedTools, maxSteps, overrides, agent
8488
8517
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
8489
8518
 
8490
8519
  // src/config/agent-disable.ts
8520
+ var COMPACTION_ENABLED_PATH = `compaction${"."}enabled`;
8491
8521
  function isDreamerRunnable(config) {
8492
8522
  return !!config.dreamer && config.dreamer.disable !== true;
8493
8523
  }
@@ -8497,6 +8527,9 @@ function isSidekickRunnable(config) {
8497
8527
  function isHistorianRunnable(config) {
8498
8528
  return config.historian?.disable !== true;
8499
8529
  }
8530
+ function isCompactionEnabled(config) {
8531
+ return config.compaction?.enabled !== false;
8532
+ }
8500
8533
  function clonePlainObject(value) {
8501
8534
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
8502
8535
  return;
@@ -9135,9 +9168,10 @@ function migrateLegacyExperimental(rawConfig, warnings) {
9135
9168
  const exp = experimental;
9136
9169
  const hasUM = "user_memories" in exp;
9137
9170
  const hasPKF = "pin_key_files" in exp;
9171
+ const hasMural = "mural" in exp;
9138
9172
  const TOP_LEVEL_GRADUATED = ["temporal_awareness", "caveman_text_compression"];
9139
9173
  const MEMORY_GRADUATED = ["auto_search", "git_commit_indexing"];
9140
- const hasGraduated = TOP_LEVEL_GRADUATED.some((k) => (k in exp)) || MEMORY_GRADUATED.some((k) => (k in exp));
9174
+ const hasGraduated = TOP_LEVEL_GRADUATED.some((k) => (k in exp)) || MEMORY_GRADUATED.some((k) => (k in exp)) || hasMural;
9141
9175
  if (!hasUM && !hasPKF && !hasGraduated) {
9142
9176
  return rawConfig;
9143
9177
  }
@@ -9145,6 +9179,15 @@ function migrateLegacyExperimental(rawConfig, warnings) {
9145
9179
  const dreamer = typeof patched.dreamer === "object" && patched.dreamer !== null ? { ...patched.dreamer } : {};
9146
9180
  const memory = typeof patched.memory === "object" && patched.memory !== null ? { ...patched.memory } : {};
9147
9181
  const newExperimental = { ...exp };
9182
+ const coerceToObject = (value) => {
9183
+ if (typeof value === "boolean") {
9184
+ return { enabled: value };
9185
+ }
9186
+ if (typeof value === "object" && value !== null) {
9187
+ return { ...value };
9188
+ }
9189
+ return;
9190
+ };
9148
9191
  const relocate = (key, dest, destLabel) => {
9149
9192
  if (!(key in exp))
9150
9193
  return;
@@ -9165,15 +9208,20 @@ function migrateLegacyExperimental(rawConfig, warnings) {
9165
9208
  relocate(key, patched, "");
9166
9209
  for (const key of MEMORY_GRADUATED)
9167
9210
  relocate(key, memory, "memory.");
9168
- const coerceToObject = (value) => {
9169
- if (typeof value === "boolean") {
9170
- return { enabled: value };
9171
- }
9172
- if (typeof value === "object" && value !== null) {
9173
- return { ...value };
9211
+ if (hasMural) {
9212
+ const oldMural = coerceToObject(exp.mural);
9213
+ const existingMural = patched.mural;
9214
+ if (existingMural === undefined) {
9215
+ patched.mural = oldMural ?? exp.mural;
9216
+ warnings.push('Deprecated "experimental.mural"; use top-level "mural" instead (migrated in memory; run `doctor` to persist).');
9217
+ } else if (oldMural !== undefined && typeof existingMural === "object" && existingMural !== null && !Array.isArray(existingMural)) {
9218
+ patched.mural = {
9219
+ ...oldMural,
9220
+ ...existingMural
9221
+ };
9174
9222
  }
9175
- return;
9176
- };
9223
+ delete newExperimental.mural;
9224
+ }
9177
9225
  if (hasUM) {
9178
9226
  const oldUM = coerceToObject(exp.user_memories);
9179
9227
  if (oldUM !== undefined) {
@@ -9326,6 +9374,19 @@ function stripUnsafeProjectConfigFields(projectRaw) {
9326
9374
  delete projectRaw.fail_closed_blocking;
9327
9375
  warnings.push("Ignoring fail_closed_blocking from project config (security: only user-level config may disable or force the loud inoperability gate).");
9328
9376
  }
9377
+ if ("allow_home_project" in projectRaw) {
9378
+ delete projectRaw.allow_home_project;
9379
+ warnings.push("Ignoring allow_home_project from project config (security: only user-level config may opt the user's home directory into Magic Context).");
9380
+ }
9381
+ const compaction = projectRaw.compaction;
9382
+ if (isPlainObject(compaction) && "enabled" in compaction) {
9383
+ delete compaction.enabled;
9384
+ 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).");
9385
+ }
9386
+ if ("output_reserve" in projectRaw) {
9387
+ delete projectRaw.output_reserve;
9388
+ warnings.push("Ignoring output_reserve from project config (security: output-token reservation only honors user-level config).");
9389
+ }
9329
9390
  if ("language" in projectRaw) {
9330
9391
  delete projectRaw.language;
9331
9392
  warnings.push("Ignoring language from project config (security: output language is a user-level setting).");
@@ -9334,6 +9395,11 @@ function stripUnsafeProjectConfigFields(projectRaw) {
9334
9395
  delete projectRaw.sqlite;
9335
9396
  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).");
9336
9397
  }
9398
+ const storage = projectRaw.storage;
9399
+ if (isPlainObject(storage) && "enforce_private_permissions" in storage) {
9400
+ delete storage.enforce_private_permissions;
9401
+ warnings.push("Ignoring storage.enforce_private_permissions from project config (security: only user-level config may opt into externally managed shared storage permissions).");
9402
+ }
9337
9403
  const pi = projectRaw.pi;
9338
9404
  if (isPlainObject(pi) && "subagent_extensions" in pi) {
9339
9405
  delete pi.subagent_extensions;
@@ -9371,6 +9437,17 @@ function stripUnsafeProjectConfigFields(projectRaw) {
9371
9437
  warnings.push(`Ignoring historian.${removed.join("/")} from project config ` + "(security: historian model selection is user-level only; a repository cannot force extra compaction cost).");
9372
9438
  }
9373
9439
  }
9440
+ const mural = projectRaw.mural;
9441
+ if (isPlainObject(mural) && "model" in mural) {
9442
+ delete mural.model;
9443
+ warnings.push("Ignoring mural.model from project config (security: the mural cue-compressor model is a user-level setting; a repository cannot choose where project memory is sent).");
9444
+ }
9445
+ const experimental = projectRaw.experimental;
9446
+ const legacyMural = isPlainObject(experimental) ? experimental.mural : undefined;
9447
+ if (isPlainObject(legacyMural) && "model" in legacyMural) {
9448
+ delete legacyMural.model;
9449
+ warnings.push("Ignoring experimental.mural.model from project config (security: the mural cue-compressor model is a user-level setting; use user-level mural.model).");
9450
+ }
9374
9451
  for (const agentKey of HIDDEN_AGENT_KEYS) {
9375
9452
  const block = projectRaw[agentKey];
9376
9453
  if (!isPlainObject(block))
@@ -9551,8 +9628,15 @@ function pruneNestedConfigLeaf(block, relativePath) {
9551
9628
  }
9552
9629
 
9553
9630
  // src/config/transform-mode.ts
9631
+ var RUST_COMPACTION_OFF_WARNING = "compaction-off mode does not support rust transform mode; using the TypeScript transform.";
9554
9632
  var RUST_REQUIRES_USER_SUBC_WARNING = "rust mode requires user-level subc configuration; running ts.";
9555
9633
  function resolveTransformMode(args) {
9634
+ if (args.configured === "rust" && !args.compactionEnabled) {
9635
+ return {
9636
+ mode: "ts",
9637
+ warnings: [RUST_COMPACTION_OFF_WARNING]
9638
+ };
9639
+ }
9556
9640
  if (args.configured === "rust" && !args.userTierHasSubc) {
9557
9641
  return {
9558
9642
  mode: "ts",
@@ -9932,6 +10016,7 @@ function loadPluginConfigDetailed(directory) {
9932
10016
  }
9933
10017
  const recoveredTopLevelKeys = [];
9934
10018
  const config = parsePluginConfig(mergedRaw, recoveredTopLevelKeys);
10019
+ setOutputReserveConfig(config.output_reserve);
9935
10020
  if (config.configWarnings?.length) {
9936
10021
  allWarnings.push(...config.configWarnings.map((w) => {
9937
10022
  if (userLoaded && projectLoaded)
@@ -9943,7 +10028,8 @@ function loadPluginConfigDetailed(directory) {
9943
10028
  }
9944
10029
  const resolvedTransformMode = resolveTransformMode({
9945
10030
  configured: config.transform_mode,
9946
- userTierHasSubc: hasUserTierSubcConfig(userLoaded?.config)
10031
+ userTierHasSubc: hasUserTierSubcConfig(userLoaded?.config),
10032
+ compactionEnabled: isCompactionEnabled(config)
9947
10033
  });
9948
10034
  config.transform_mode = resolvedTransformMode.mode;
9949
10035
  allWarnings.push(...resolvedTransformMode.warnings.map((warning) => `[config] ${warning}`));
@@ -9970,7 +10056,9 @@ function loadPluginConfigDetailed(directory) {
9970
10056
  }
9971
10057
 
9972
10058
  // src/features/builtin-commands/commands.ts
9973
- function getMagicContextBuiltinCommands() {
10059
+ var COMPACTION_ENABLED_PATH2 = `compaction${".enabled"}`;
10060
+ function getMagicContextBuiltinCommands(compactionEnabled = true) {
10061
+ const unavailableInCompactionOff = (command) => `Unavailable when ${COMPACTION_ENABLED_PATH2} is false: /${command} manages compacted history.`;
9974
10062
  return {
9975
10063
  "ctx-status": {
9976
10064
  template: "ctx-status",
@@ -9978,11 +10066,11 @@ function getMagicContextBuiltinCommands() {
9978
10066
  },
9979
10067
  "ctx-recomp": {
9980
10068
  template: "ctx-recomp",
9981
- description: "Rebuild compartments and facts from raw history (full or <start>-<end> range)"
10069
+ description: compactionEnabled ? "Rebuild compartments and facts from raw history (full or <start>-<end> range)" : unavailableInCompactionOff("ctx-recomp")
9982
10070
  },
9983
10071
  "ctx-wrapup": {
9984
10072
  template: "ctx-wrapup",
9985
- description: "Compact older live history while keeping the newest messages raw"
10073
+ description: compactionEnabled ? "Compact older live history while keeping the newest messages raw" : unavailableInCompactionOff("ctx-wrapup")
9986
10074
  },
9987
10075
  "ctx-session-upgrade": {
9988
10076
  template: "ctx-session-upgrade",
@@ -9990,7 +10078,7 @@ function getMagicContextBuiltinCommands() {
9990
10078
  },
9991
10079
  "ctx-flush": {
9992
10080
  template: "ctx-flush",
9993
- description: "Force-process all pending magic context operations immediately"
10081
+ description: compactionEnabled ? "Force-process all pending magic context operations immediately" : unavailableInCompactionOff("ctx-flush")
9994
10082
  },
9995
10083
  "ctx-aug": {
9996
10084
  template: "ctx-aug",
@@ -10355,14 +10443,41 @@ function isMagicContextHiddenAgentName(agent) {
10355
10443
  return true;
10356
10444
  return false;
10357
10445
  }
10446
+ var MAX_FORMATTED_BLOCKING_PROCESSES = 8;
10447
+ function formatFailClosedBlockingProcesses(processes) {
10448
+ const uniqueProcesses = new Map;
10449
+ for (const process2 of processes) {
10450
+ if (!process2.harness.trim() || !Number.isInteger(process2.pid) || process2.pid <= 0)
10451
+ continue;
10452
+ uniqueProcesses.set(`${process2.harness}\x00${process2.pid}`, {
10453
+ harness: process2.harness.trim(),
10454
+ pid: process2.pid
10455
+ });
10456
+ }
10457
+ const entries = [...uniqueProcesses.values()];
10458
+ const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
10459
+ const rendered = visible.map(({ harness, pid }) => `${harness} (PID ${pid})`);
10460
+ const omitted = entries.length - visible.length;
10461
+ if (omitted > 0)
10462
+ rendered.push(`${omitted} more blocking process(es)`);
10463
+ if (rendered.length === 0)
10464
+ return "a live harness process";
10465
+ if (rendered.length === 1)
10466
+ return rendered[0];
10467
+ const last = rendered.pop();
10468
+ return `${rendered.join(", ")}, and ${last}`;
10469
+ }
10358
10470
  function formatFailClosedBlockingMessage(reason) {
10471
+ if (reason.kind === "migration_guard") {
10472
+ return [
10473
+ `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.`,
10474
+ "Restart the blocking process (it will pick up the new build and migrate on start), or shut it down and retry.",
10475
+ `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
10476
+ ].join(" ");
10477
+ }
10359
10478
  if (reason.kind === "schema_fence") {
10360
10479
  return [
10361
- `Magic Context cannot operate: shared database schema v${reason.persistedVersion}`,
10362
- `is newer than this build supports (max v${reason.supportedVersion}).`,
10363
- "A newer OpenCode/Pi instance upgraded the database; this build fail-closed",
10364
- "so it cannot corrupt the cache or silently fall back to native compaction.",
10365
- `Update or unpin Magic Context on this harness, then restart.`,
10480
+ `Magic Context cannot operate: this Magic Context build is older than the database; upgrade/restart this harness (upstream migration lane v${reason.persistedVersion}, build supports through v${reason.supportedVersion}).`,
10366
10481
  `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
10367
10482
  ].join(" ");
10368
10483
  }
@@ -10434,7 +10549,7 @@ function createFailClosedController(options) {
10434
10549
  const shouldReprobe = typeof input.tryReopen === "function" && (blockedPassCount === 1 || blockedPassCount % reprobeEveryN === 0);
10435
10550
  if (shouldReprobe) {
10436
10551
  try {
10437
- const healed = await input.tryReopen();
10552
+ const healed = await input.tryReopen?.();
10438
10553
  if (healed) {
10439
10554
  reason = null;
10440
10555
  blockedPassCount = 0;
@@ -10752,12 +10867,12 @@ async function runSidekick(deps) {
10752
10867
  }
10753
10868
  };
10754
10869
  try {
10755
- const createResponse = await deps.client.session.create({
10756
- body: {
10757
- ...deps.sessionId ? { parentID: deps.sessionId } : {},
10758
- title: "magic-context-sidekick"
10759
- },
10760
- query: { directory: deps.sessionDirectory ?? deps.projectPath }
10870
+ const createResponse = await createChildSessionWithFence({
10871
+ client: deps.client,
10872
+ db: openDatabase(),
10873
+ parentSessionId: deps.sessionId,
10874
+ title: "magic-context-sidekick",
10875
+ directory: deps.sessionDirectory ?? deps.projectPath
10761
10876
  });
10762
10877
  const createdSession = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
10763
10878
  agentSessionId = typeof createdSession?.id === "string" ? createdSession.id : null;
@@ -11700,6 +11815,7 @@ function createLiveSessionState() {
11700
11815
  deferredMaterializationSessions: new Set,
11701
11816
  sessionDirectoryBySession: new Map,
11702
11817
  recompProgressBySession: new Map,
11818
+ dreamerProgressByProject: new Map,
11703
11819
  internalChildSessions: new Set
11704
11820
  };
11705
11821
  }
@@ -12849,7 +12965,7 @@ function parseCuesManifest(text) {
12849
12965
  const body = extractCompleteManifestBody(text, "cues");
12850
12966
  const out = [];
12851
12967
  for (const match of body.matchAll(/<cue\s+id="(\d+)"\s*>([\s\S]*?)<\/cue>/g)) {
12852
- const id = Number.parseInt(match[1], 10);
12968
+ const id = Number.parseInt(match[1] ?? "", 10);
12853
12969
  if (!Number.isInteger(id))
12854
12970
  continue;
12855
12971
  out.push({ id, cue: unescapeXml(match[2] ?? "").trim() });
@@ -12950,11 +13066,15 @@ async function runCompressCues(args) {
12950
13066
  break;
12951
13067
  }
12952
13068
  const sliceMs = computeChunkSliceMs(remainingMs, chunks.length - i);
12953
- const outcome = await compressOneChunk(args, chunks[i], sliceMs, abortController.signal);
13069
+ const chunk = chunks[i];
13070
+ if (!chunk)
13071
+ break;
13072
+ const outcome = await compressOneChunk(args, chunk, sliceMs, abortController.signal);
12954
13073
  result.compressed += outcome.compressed;
12955
13074
  result.skipped += outcome.skipped;
12956
13075
  result.remaining -= outcome.compressed;
12957
13076
  result.chunks += 1;
13077
+ args.onProgress?.(result.compressed + result.skipped);
12958
13078
  if (outcome.failure?.class === "timeout") {
12959
13079
  consecutiveTimeouts += 1;
12960
13080
  timeoutStreakElapsedMs.push(outcome.failure.elapsedMs);
@@ -12985,12 +13105,12 @@ async function compressOneChunk(args, chunk, sliceMs, signal) {
12985
13105
  projectPath: args.projectIdentity,
12986
13106
  memories: chunk.map(toPromptMemory)
12987
13107
  });
12988
- const createResponse = await args.client.session.create({
12989
- body: {
12990
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
12991
- title: "magic-context-dream-compress-cues"
12992
- },
12993
- query: { directory: args.sessionDirectory }
13108
+ const createResponse = await createChildSessionWithFence({
13109
+ client: args.client,
13110
+ db: args.db,
13111
+ parentSessionId: args.parentSessionId,
13112
+ title: "magic-context-dream-compress-cues",
13113
+ directory: args.sessionDirectory
12994
13114
  });
12995
13115
  const created = normalizeSDKResponse(createResponse, null, {
12996
13116
  preferResponseOnMissingData: true
@@ -13169,12 +13289,12 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
13169
13289
  abortController.abort();
13170
13290
  });
13171
13291
  try {
13172
- const createResponse = await args.client.session.create({
13173
- body: {
13174
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
13175
- title: "magic-context-dream-user-memories"
13176
- },
13177
- query: { directory: args.sessionDirectory }
13292
+ const createResponse = await createChildSessionWithFence({
13293
+ client: args.client,
13294
+ db: args.db,
13295
+ parentSessionId: args.parentSessionId,
13296
+ title: "magic-context-dream-user-memories",
13297
+ directory: args.sessionDirectory
13178
13298
  });
13179
13299
  const created = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
13180
13300
  agentSessionId = typeof created?.id === "string" ? created.id : null;
@@ -13763,6 +13883,7 @@ async function runClassify(args) {
13763
13883
  result.changed += counts.changed;
13764
13884
  result.remaining -= counts.classified;
13765
13885
  result.chunks += 1;
13886
+ args.onProgress?.(result.classified);
13766
13887
  }
13767
13888
  result.complete = result.remaining === 0;
13768
13889
  log(`[dreamer] classify: stage=${stage} classified=${result.classified} changed=${result.changed} chunks=${result.chunks} remaining=${result.remaining} complete=${result.complete}`);
@@ -13786,12 +13907,12 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
13786
13907
  recordInvocation(args, startedAt, { status: "completed" });
13787
13908
  return run2;
13788
13909
  }
13789
- const createResponse = await args.client.session.create({
13790
- body: {
13791
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
13792
- title: "magic-context-dream-classify"
13793
- },
13794
- query: { directory: args.sessionDirectory }
13910
+ const createResponse = await createChildSessionWithFence({
13911
+ client: args.client,
13912
+ db: args.db,
13913
+ parentSessionId: args.parentSessionId,
13914
+ title: "magic-context-dream-classify",
13915
+ directory: args.sessionDirectory
13795
13916
  });
13796
13917
  const created = normalizeSDKResponse(createResponse, null, {
13797
13918
  preferResponseOnMissingData: true
@@ -14573,7 +14694,7 @@ function getAsyncModule() {
14573
14694
  asyncModulePromise ??= (async () => {
14574
14695
  const [{ default: singlefileAsyncifyVariant }, { newQuickJSAsyncWASMModuleFromVariant }] = await Promise.all([
14575
14696
  import("./index-ayd60xnw.js").then((m)=>__toESM(m.default,1)),
14576
- import("./index-v7fmc1s2.js")
14697
+ import("./index-ygcng9t8.js")
14577
14698
  ]);
14578
14699
  return newQuickJSAsyncWASMModuleFromVariant(singlefileAsyncifyVariant);
14579
14700
  })();
@@ -14792,12 +14913,12 @@ Remember: output only the JSON object described by the system prompt.`;
14792
14913
  });
14793
14914
  };
14794
14915
  try {
14795
- const createResponse = await args.client.session.create({
14796
- body: {
14797
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
14798
- title: `magic-context-smart-note-compile-${args.note.id}`
14799
- },
14800
- query: { directory: args.sessionDirectory ?? args.projectIdentity }
14916
+ const createResponse = await createChildSessionWithFence({
14917
+ client: args.client,
14918
+ db: args.db ?? null,
14919
+ parentSessionId: args.parentSessionId,
14920
+ title: `magic-context-smart-note-compile-${args.note.id}`,
14921
+ directory: args.sessionDirectory ?? args.projectIdentity
14801
14922
  });
14802
14923
  const created = normalizeSDKResponse(createResponse, null, {
14803
14924
  preferResponseOnMissingData: true
@@ -15578,12 +15699,12 @@ async function confirmReadOnly(args, noteId, content, surfaceCondition, leaseSig
15578
15699
  });
15579
15700
  };
15580
15701
  try {
15581
- const createResponse = await args.client.session.create({
15582
- body: {
15583
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
15584
- title: `magic-context-smart-note-confirm-${noteId}`
15585
- },
15586
- query: { directory: args.sessionDirectory ?? args.projectIdentity }
15702
+ const createResponse = await createChildSessionWithFence({
15703
+ client: args.client,
15704
+ db: args.db,
15705
+ parentSessionId: args.parentSessionId,
15706
+ title: `magic-context-smart-note-confirm-${noteId}`,
15707
+ directory: args.sessionDirectory ?? args.projectIdentity
15587
15708
  });
15588
15709
  const created = normalizeSDKResponse(createResponse, null, {
15589
15710
  preferResponseOnMissingData: true
@@ -15916,6 +16037,7 @@ async function mapMemories(args) {
15916
16037
  result.independent += counts.independent;
15917
16038
  result.remaining -= counts.mapped + counts.independent;
15918
16039
  result.batches += 1;
16040
+ args.onProgress?.(result.mapped + result.independent);
15919
16041
  }
15920
16042
  result.complete = result.remaining === 0;
15921
16043
  log(`[dreamer] map-memories: mapped=${result.mapped} independent=${result.independent} batches=${result.batches} remaining=${result.remaining} complete=${result.complete}`);
@@ -15928,12 +16050,12 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
15928
16050
  let agentSessionId = null;
15929
16051
  const startedAt = Date.now();
15930
16052
  try {
15931
- const createResponse = await args.client.session.create({
15932
- body: {
15933
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
15934
- title: "magic-context-dream-map-memories"
15935
- },
15936
- query: { directory: args.sessionDirectory }
16053
+ const createResponse = await createChildSessionWithFence({
16054
+ client: args.client,
16055
+ db: args.db,
16056
+ parentSessionId: args.parentSessionId,
16057
+ title: "magic-context-dream-map-memories",
16058
+ directory: args.sessionDirectory
15937
16059
  });
15938
16060
  const created = normalizeSDKResponse(createResponse, null, {
15939
16061
  preferResponseOnMissingData: true
@@ -16517,6 +16639,7 @@ async function refreshPrimers(args) {
16517
16639
  result.refreshed += 1;
16518
16640
  else
16519
16641
  result.skipped += 1;
16642
+ args.onProgress?.(result.refreshed + result.skipped);
16520
16643
  }
16521
16644
  log(`[dreamer] refresh-primers: refreshed=${result.refreshed} skipped=${result.skipped}`);
16522
16645
  return result;
@@ -16545,12 +16668,12 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
16545
16668
  let agentSessionId = null;
16546
16669
  const startedAt = Date.now();
16547
16670
  try {
16548
- const createResponse = await args.client.session.create({
16549
- body: {
16550
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
16551
- title: "magic-context-dream-refresh-primers"
16552
- },
16553
- query: { directory: args.sessionDirectory }
16671
+ const createResponse = await createChildSessionWithFence({
16672
+ client: args.client,
16673
+ db: args.db,
16674
+ parentSessionId: args.parentSessionId,
16675
+ title: "magic-context-dream-refresh-primers",
16676
+ directory: args.sessionDirectory
16554
16677
  });
16555
16678
  const created = normalizeSDKResponse(createResponse, null, {
16556
16679
  preferResponseOnMissingData: true
@@ -16786,6 +16909,191 @@ function insertDreamRun(db, run) {
16786
16909
  getInsertDreamRunStatement(db).run(run.projectPath, run.startedAt, run.finishedAt, run.holderId, JSON.stringify(run.tasks), run.tasksSucceeded, run.tasksFailed, run.smartNotesSurfaced, run.smartNotesPending, run.memoryChanges ? JSON.stringify(run.memoryChanges) : null, run.parentSessionId ?? null);
16787
16910
  }
16788
16911
 
16912
+ // src/features/magic-context/dreamer/task-gates.ts
16913
+ function countActiveMemories(db, projectPath) {
16914
+ const row = db.prepare("SELECT COUNT(*) AS cnt FROM memories WHERE project_path = ? AND status IN ('active','permanent')").get(projectPath);
16915
+ return row?.cnt ?? 0;
16916
+ }
16917
+ function countUnmappedActiveMemories(db, projectPath) {
16918
+ const row = db.prepare(`SELECT COUNT(*) AS cnt
16919
+ FROM memories m
16920
+ WHERE m.project_path = ?
16921
+ AND m.status IN ('active','permanent')
16922
+ AND NOT EXISTS (
16923
+ SELECT 1 FROM memory_verifications v WHERE v.memory_id = m.id
16924
+ )`).get(projectPath);
16925
+ return row?.cnt ?? 0;
16926
+ }
16927
+ function countCompartmentsSince(db, projectPath, since) {
16928
+ const row = db.prepare(`SELECT COUNT(*) AS cnt
16929
+ FROM compartments c
16930
+ JOIN session_projects sp ON sp.session_id = c.session_id
16931
+ WHERE sp.project_path = ? AND c.created_at > ?`).get(projectPath, since);
16932
+ return row?.cnt ?? 0;
16933
+ }
16934
+ function countProjectSessionsSince(db, projectPath, since) {
16935
+ const row = since === null ? db.prepare("SELECT COUNT(*) AS cnt FROM session_projects WHERE project_path = ?").get(projectPath) : db.prepare("SELECT COUNT(*) AS cnt FROM session_projects WHERE project_path = ? AND updated_at > ?").get(projectPath, since);
16936
+ return row?.cnt ?? 0;
16937
+ }
16938
+ function countMappedMemories(db, projectPath) {
16939
+ const row = db.prepare(`SELECT COUNT(DISTINCT m.id) AS cnt
16940
+ FROM memories m
16941
+ JOIN memory_verifications v ON v.memory_id = m.id
16942
+ WHERE m.project_path = ?
16943
+ AND m.status IN ('active','permanent')
16944
+ AND v.file_path <> ''`).get(projectPath);
16945
+ return row?.cnt ?? 0;
16946
+ }
16947
+ function countUnverifiedMappedMemories(db, projectPath) {
16948
+ const row = db.prepare(`SELECT COUNT(DISTINCT m.id) AS cnt
16949
+ FROM memories m
16950
+ JOIN memory_verifications v ON v.memory_id = m.id
16951
+ WHERE m.project_path = ?
16952
+ AND m.status IN ('active','permanent')
16953
+ AND v.file_path <> ''
16954
+ AND v.verified_at = 0`).get(projectPath);
16955
+ return row?.cnt ?? 0;
16956
+ }
16957
+ function countCueCandidates(db, projectPath) {
16958
+ if (!hasMuralCueColumns(db))
16959
+ return countActiveMemories(db, projectPath);
16960
+ const row = db.prepare(`SELECT COUNT(*) AS cnt
16961
+ FROM memories
16962
+ WHERE project_path = ?
16963
+ AND status IN ('active','permanent')
16964
+ AND (mural_cue IS NULL OR mural_cue_hash IS NULL OR updated_at > mural_cue_at)`).get(projectPath);
16965
+ return row?.cnt ?? 0;
16966
+ }
16967
+ function countStalePrimers(db, projectPath) {
16968
+ const row = db.prepare(`SELECT COUNT(*) AS cnt
16969
+ FROM primers
16970
+ WHERE project_path = ?
16971
+ AND status = 'active'
16972
+ AND (answer IS NULL OR TRIM(answer) = '' OR answer_refreshed_at IS NULL
16973
+ OR last_observed_at > answer_refreshed_at)`).get(projectPath);
16974
+ return row?.cnt ?? 0;
16975
+ }
16976
+ function countUnclassifiedActiveMemories(db, projectPath) {
16977
+ if (!hasMemoryClassifiedAtColumn(db))
16978
+ return countActiveMemories(db, projectPath);
16979
+ const row = db.prepare(`SELECT COUNT(*) AS cnt
16980
+ FROM memories
16981
+ WHERE project_path = ?
16982
+ AND status IN ('active','permanent')
16983
+ AND classified_at IS NULL`).get(projectPath);
16984
+ return row?.cnt ?? 0;
16985
+ }
16986
+ function countPendingSmartNotes(db, projectPath) {
16987
+ const row = db.prepare("SELECT COUNT(*) AS cnt FROM notes WHERE project_path = ? AND type = 'smart' AND status = 'pending'").get(projectPath);
16988
+ return row?.cnt ?? 0;
16989
+ }
16990
+ function countUserMemoryCandidates(db) {
16991
+ const row = db.prepare("SELECT COUNT(*) AS cnt FROM user_memory_candidates").get();
16992
+ return row?.cnt ?? 0;
16993
+ }
16994
+ function countActivePrimers(db, projectPath) {
16995
+ const row = db.prepare("SELECT COUNT(*) AS cnt FROM primers WHERE project_path = ? AND status = 'active'").get(projectPath);
16996
+ return row?.cnt ?? 0;
16997
+ }
16998
+ function getDreamTaskBacklog(db, projectPath, task, options = {}) {
16999
+ switch (task) {
17000
+ case "map-memories": {
17001
+ const total = countActiveMemories(db, projectPath);
17002
+ return { pending: countUnmappedActiveMemories(db, projectPath), total };
17003
+ }
17004
+ case "verify": {
17005
+ return {
17006
+ pending: countUnverifiedMappedMemories(db, projectPath),
17007
+ total: countMappedMemories(db, projectPath)
17008
+ };
17009
+ }
17010
+ case "verify-broad": {
17011
+ const total = countMappedMemories(db, projectPath);
17012
+ return { pending: total, total };
17013
+ }
17014
+ case "curate": {
17015
+ const total = countActiveMemories(db, projectPath);
17016
+ return { pending: total, total };
17017
+ }
17018
+ case "compress-cues": {
17019
+ const total = countActiveMemories(db, projectPath);
17020
+ return { pending: countCueCandidates(db, projectPath), total };
17021
+ }
17022
+ case "classify-memories": {
17023
+ const total = countActiveMemories(db, projectPath);
17024
+ return { pending: countUnclassifiedActiveMemories(db, projectPath), total };
17025
+ }
17026
+ case "retrospective": {
17027
+ const pending = countProjectSessionsSince(db, projectPath, options.retrospectiveWatermarkMs ?? null);
17028
+ return { pending, total: pending };
17029
+ }
17030
+ case "maintain-docs": {
17031
+ const total = countCompartmentsSince(db, projectPath, 0);
17032
+ const pending = countCompartmentsSince(db, projectPath, options.lastRunAt ?? 0);
17033
+ return { pending, total };
17034
+ }
17035
+ case "evaluate-smart-notes": {
17036
+ const pending = countPendingSmartNotes(db, projectPath);
17037
+ return { pending, total: pending };
17038
+ }
17039
+ case "review-user-memories": {
17040
+ const pending = countUserMemoryCandidates(db);
17041
+ return { pending, total: pending };
17042
+ }
17043
+ case "promote-primers": {
17044
+ const pending = countPrimerCandidatesForProject(db, projectPath);
17045
+ return { pending, total: pending };
17046
+ }
17047
+ case "refresh-primers": {
17048
+ const total = countActivePrimers(db, projectPath);
17049
+ return { pending: countStalePrimers(db, projectPath), total };
17050
+ }
17051
+ default: {
17052
+ const _exhaustive = task;
17053
+ return _exhaustive;
17054
+ }
17055
+ }
17056
+ }
17057
+ function getDreamTaskBacklogs(db, projectPath, tasks = CANONICAL_DREAM_TASKS, options = {}) {
17058
+ const result = {};
17059
+ for (const task of tasks)
17060
+ result[task] = getDreamTaskBacklog(db, projectPath, task, options);
17061
+ return result;
17062
+ }
17063
+ function evaluateTaskGate(task, ctx) {
17064
+ const { db, projectIdentity: project, lastRunAt } = ctx;
17065
+ switch (task) {
17066
+ case "map-memories":
17067
+ return countUnmappedActiveMemories(db, project) > 0;
17068
+ case "verify":
17069
+ return countActiveMemories(db, project) > 0;
17070
+ case "verify-broad":
17071
+ return countActiveMemories(db, project) > 0;
17072
+ case "curate":
17073
+ return countActiveMemories(db, project) > 0;
17074
+ case "compress-cues":
17075
+ return countActiveMemories(db, project) > 0;
17076
+ case "classify-memories":
17077
+ return countActiveMemories(db, project) > 0;
17078
+ case "retrospective":
17079
+ return countProjectSessionsSince(db, project, ctx.retrospectiveWatermarkMs ?? null) > 0;
17080
+ case "maintain-docs":
17081
+ return countCompartmentsSince(db, project, lastRunAt ?? 0) > 0;
17082
+ case "evaluate-smart-notes":
17083
+ return getSmartNotesNeedingCompilation(db, project, Date.now(), 1).length > 0 || getStaleCompiledSmartNotes(db, project, Date.now(), 1).length > 0 || getPendingSmartNotes(db, project).some((note) => note.checkStatus === "fallback");
17084
+ case "review-user-memories":
17085
+ return getUserMemoryCandidates(db).length >= ctx.promotionThreshold;
17086
+ case "promote-primers":
17087
+ return countPrimerCandidatesForProject(db, project) >= (ctx.promotionThreshold ?? 2);
17088
+ case "refresh-primers":
17089
+ return getActivePrimers(db, project).some((primer) => !primer.answer.trim() || primer.answerRefreshedAt == null || (primer.lastObservedAt ?? 0) > primer.answerRefreshedAt);
17090
+ default: {
17091
+ const _exhaustive = task;
17092
+ return Boolean(_exhaustive);
17093
+ }
17094
+ }
17095
+ }
17096
+
16789
17097
  // src/features/magic-context/dreamer/verify.ts
16790
17098
  import { createHash as createHash5 } from "node:crypto";
16791
17099
 
@@ -16985,6 +17293,7 @@ async function runVerify(args) {
16985
17293
  result.archived += counts.archived;
16986
17294
  result.remaining -= counts.verified + counts.updated + counts.archived;
16987
17295
  result.batches += 1;
17296
+ args.onProgress?.(result.verified + result.updated + result.archived);
16988
17297
  }
16989
17298
  result.complete = result.remaining === 0;
16990
17299
  log(`[dreamer] ${args.forceBroad ? "verify-broad" : "verify"}: verified=${result.verified} updated=${result.updated} archived=${result.archived} batches=${result.batches} remaining=${result.remaining} complete=${result.complete}`);
@@ -16997,12 +17306,12 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
16997
17306
  let agentSessionId = null;
16998
17307
  const startedAt = Date.now();
16999
17308
  try {
17000
- const createResponse = await args.client.session.create({
17001
- body: {
17002
- ...args.parentSessionId ? { parentID: args.parentSessionId } : {},
17003
- title: "magic-context-dream-verify"
17004
- },
17005
- query: { directory: args.sessionDirectory }
17309
+ const createResponse = await createChildSessionWithFence({
17310
+ client: args.client,
17311
+ db: args.db,
17312
+ parentSessionId: args.parentSessionId,
17313
+ title: "magic-context-dream-verify",
17314
+ directory: args.sessionDirectory
17006
17315
  });
17007
17316
  const created = normalizeSDKResponse(createResponse, null, {
17008
17317
  preferResponseOnMissingData: true
@@ -17276,6 +17585,20 @@ function createDreamTaskExecutor(deps) {
17276
17585
  const { db, projectIdentity, holderId, leaseKey } = ctx;
17277
17586
  const startedAt = Date.now();
17278
17587
  const deadline = startedAt + config.timeoutMinutes * 60 * 1000;
17588
+ const backlogAtStart = getDreamTaskBacklog(db, projectIdentity, config.task);
17589
+ const reportProgress = (processed) => {
17590
+ deps.onProgress?.({
17591
+ task: config.task,
17592
+ processed: Math.max(0, processed),
17593
+ total: backlogAtStart.pending,
17594
+ startedAt
17595
+ });
17596
+ };
17597
+ reportProgress(0);
17598
+ const incompleteMessage = (remaining) => {
17599
+ const processed = processedDreamTaskItems(backlogAtStart.pending, remaining);
17600
+ return `${config.task} incomplete: ${remaining} remain (was ${backlogAtStart.pending} at run start; processed ${processed} this run)`;
17601
+ };
17279
17602
  const parent = await resolveParentSessionId();
17280
17603
  let moduleRoute;
17281
17604
  if (config.task === "map-memories" || config.task === "compress-cues" || config.task === "verify" || config.task === "verify-broad" || config.task === "retrospective") {
@@ -17304,7 +17627,19 @@ function createDreamTaskExecutor(deps) {
17304
17627
  name: config.task,
17305
17628
  durationMs: Date.now() - startedAt,
17306
17629
  resultChars: 0,
17307
- ...error ? { error } : {}
17630
+ ...error ? { error } : {},
17631
+ backlog: (() => {
17632
+ const end = getDreamTaskBacklog(db, projectIdentity, config.task);
17633
+ const processed = processedDreamTaskItems(backlogAtStart.pending, end.pending);
17634
+ const value = {
17635
+ pendingAtStart: backlogAtStart.pending,
17636
+ totalAtStart: backlogAtStart.total,
17637
+ pendingAtEnd: end.pending,
17638
+ totalAtEnd: end.total,
17639
+ processed
17640
+ };
17641
+ return value;
17642
+ })()
17308
17643
  }
17309
17644
  ],
17310
17645
  tasksSucceeded: status === "completed" ? 1 : 0,
@@ -17338,8 +17673,8 @@ function createDreamTaskExecutor(deps) {
17338
17673
  }
17339
17674
  try {
17340
17675
  if (config.task === "compress-cues") {
17341
- if (deps.experimentalMural?.enabled !== true) {
17342
- log("[dreamer] compress-cues: skipped (experimental.mural is not enabled)");
17676
+ if (deps.mural?.enabled !== true) {
17677
+ log("[dreamer] compress-cues: skipped (mural is not enabled)");
17343
17678
  recordRun("completed", null);
17344
17679
  return { status: "completed" };
17345
17680
  }
@@ -17358,12 +17693,13 @@ function createDreamTaskExecutor(deps) {
17358
17693
  holderId,
17359
17694
  leaseKey,
17360
17695
  deadline,
17361
- model: config.model ?? deps.experimentalMural.model ?? deps.dreamerModel,
17362
- fallbackModels: config.fallbackModels
17696
+ model: config.model ?? deps.mural.model ?? deps.dreamerModel,
17697
+ fallbackModels: config.fallbackModels,
17698
+ onProgress: (processed) => reportProgress(processed)
17363
17699
  });
17364
17700
  log(`[dreamer] compress-cues: compressed=${result.compressed} skipped=${result.skipped} chunks=${result.chunks} remaining=${result.remaining}`);
17365
17701
  if (!result.complete) {
17366
- const error = `compress-cues incomplete: ${result.remaining} selected memories remain`;
17702
+ const error = incompleteMessage(result.remaining);
17367
17703
  recordRun("failed", error);
17368
17704
  return { status: "failed", transient: true, error };
17369
17705
  }
@@ -17400,11 +17736,12 @@ function createDreamTaskExecutor(deps) {
17400
17736
  deadline,
17401
17737
  model: config.model,
17402
17738
  fallbackModels: config.fallbackModels,
17403
- moduleRoute
17739
+ moduleRoute,
17740
+ onProgress: (processed) => reportProgress(processed)
17404
17741
  });
17405
17742
  log(`[dreamer] map-memories: mapped=${result.mapped} independent=${result.independent} batches=${result.batches} remaining=${result.remaining}`);
17406
17743
  if (!result.complete) {
17407
- const error = `map-memories incomplete: ${result.remaining} selected memories remain`;
17744
+ const error = incompleteMessage(result.remaining);
17408
17745
  recordRun("failed", error);
17409
17746
  return { status: "failed", transient: true, error };
17410
17747
  }
@@ -17426,10 +17763,11 @@ function createDreamTaskExecutor(deps) {
17426
17763
  model: config.model,
17427
17764
  fallbackModels: config.fallbackModels,
17428
17765
  language: config.language ?? deps.language,
17429
- moduleRoute
17766
+ moduleRoute,
17767
+ onProgress: (processed) => reportProgress(processed)
17430
17768
  });
17431
17769
  if (!result.complete) {
17432
- const error = `${config.task} incomplete: ${result.remaining} selected memories remain`;
17770
+ const error = incompleteMessage(result.remaining);
17433
17771
  recordRun("failed", error, {
17434
17772
  memoryChanges: computeMemoryDelta(memoryBefore)
17435
17773
  });
@@ -17488,11 +17826,12 @@ function createDreamTaskExecutor(deps) {
17488
17826
  deadline,
17489
17827
  model: config.model,
17490
17828
  fallbackModels: config.fallbackModels,
17491
- ...moduleArgs
17829
+ ...moduleArgs,
17830
+ onProgress: (processed) => reportProgress(processed)
17492
17831
  });
17493
17832
  log(`[dreamer] classify-memories: stage=${result.stage} classified=${result.classified} changed=${result.changed} chunks=${result.chunks} remaining=${result.remaining}`);
17494
17833
  if (!result.complete) {
17495
- const error = `classify-memories incomplete: ${result.remaining} selected memories remain`;
17834
+ const error = incompleteMessage(result.remaining);
17496
17835
  recordRun("failed", error);
17497
17836
  return { status: "failed", transient: true, error };
17498
17837
  }
@@ -17528,7 +17867,8 @@ function createDreamTaskExecutor(deps) {
17528
17867
  model: config.model,
17529
17868
  fallbackModels: config.fallbackModels,
17530
17869
  language: config.language ?? deps.language,
17531
- rawProviderFactory: deps.primerRawProviderFactory
17870
+ rawProviderFactory: deps.primerRawProviderFactory,
17871
+ onProgress: (processed) => reportProgress(processed)
17532
17872
  });
17533
17873
  recordRun("completed", null);
17534
17874
  log(`[dreamer] refresh-primers: refreshed=${result.refreshed} skipped=${result.skipped}`);
@@ -17582,6 +17922,8 @@ function createDreamTaskExecutor(deps) {
17582
17922
  recordRun("failed", brief);
17583
17923
  log(`[dreamer] task ${config.task} failed (transient=${transient}): ${brief}`);
17584
17924
  return { status: "failed", transient, error: brief };
17925
+ } finally {
17926
+ deps.onProgress?.(null, config.task);
17585
17927
  }
17586
17928
  };
17587
17929
  }
@@ -17689,12 +18031,12 @@ async function runRetrospectiveTask(config, ctx, helpers) {
17689
18031
  });
17690
18032
  let childSessionId = null;
17691
18033
  try {
17692
- const createResponse = await deps.client.session.create({
17693
- body: {
17694
- ...parent ? { parentID: parent } : {},
17695
- title: "magic-context-dream-retrospective"
17696
- },
17697
- query: { directory: deps.sessionDirectory }
18034
+ const createResponse = await createChildSessionWithFence({
18035
+ client: deps.client,
18036
+ db,
18037
+ parentSessionId: parent ?? undefined,
18038
+ title: "magic-context-dream-retrospective",
18039
+ directory: deps.sessionDirectory
17698
18040
  });
17699
18041
  const created = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
17700
18042
  childSessionId = typeof created?.id === "string" ? created.id : null;
@@ -17879,12 +18221,12 @@ async function runAgenticTask(config, ctx, helpers) {
17879
18221
  });
17880
18222
  let childSessionId = null;
17881
18223
  try {
17882
- const createResponse = await deps.client.session.create({
17883
- body: {
17884
- ...parent ? { parentID: parent } : {},
17885
- title: `magic-context-dream-${task}`
17886
- },
17887
- query: { directory: docsDir }
18224
+ const createResponse = await createChildSessionWithFence({
18225
+ client: deps.client,
18226
+ db,
18227
+ parentSessionId: parent ?? undefined,
18228
+ title: `magic-context-dream-${task}`,
18229
+ directory: docsDir
17888
18230
  });
17889
18231
  const created = normalizeSDKResponse(createResponse, null, {
17890
18232
  preferResponseOnMissingData: true
@@ -17957,66 +18299,6 @@ async function runAgenticTask(config, ctx, helpers) {
17957
18299
  }
17958
18300
  }
17959
18301
 
17960
- // src/features/magic-context/dreamer/task-gates.ts
17961
- function countActiveMemories(db, projectPath) {
17962
- const row = db.prepare("SELECT COUNT(*) AS cnt FROM memories WHERE project_path = ? AND status IN ('active','permanent')").get(projectPath);
17963
- return row?.cnt ?? 0;
17964
- }
17965
- function countUnmappedActiveMemories(db, projectPath) {
17966
- const row = db.prepare(`SELECT COUNT(*) AS cnt
17967
- FROM memories m
17968
- WHERE m.project_path = ?
17969
- AND m.status IN ('active','permanent')
17970
- AND NOT EXISTS (
17971
- SELECT 1 FROM memory_verifications v WHERE v.memory_id = m.id
17972
- )`).get(projectPath);
17973
- return row?.cnt ?? 0;
17974
- }
17975
- function countCompartmentsSince(db, projectPath, since) {
17976
- const row = db.prepare(`SELECT COUNT(*) AS cnt
17977
- FROM compartments c
17978
- JOIN session_projects sp ON sp.session_id = c.session_id
17979
- WHERE sp.project_path = ? AND c.created_at > ?`).get(projectPath, since);
17980
- return row?.cnt ?? 0;
17981
- }
17982
- function countProjectSessionsSince(db, projectPath, since) {
17983
- const row = since === null ? db.prepare("SELECT COUNT(*) AS cnt FROM session_projects WHERE project_path = ?").get(projectPath) : db.prepare("SELECT COUNT(*) AS cnt FROM session_projects WHERE project_path = ? AND updated_at > ?").get(projectPath, since);
17984
- return row?.cnt ?? 0;
17985
- }
17986
- function evaluateTaskGate(task, ctx) {
17987
- const { db, projectIdentity: project, lastRunAt } = ctx;
17988
- switch (task) {
17989
- case "map-memories":
17990
- return countUnmappedActiveMemories(db, project) > 0;
17991
- case "verify":
17992
- return countActiveMemories(db, project) > 0;
17993
- case "verify-broad":
17994
- return countActiveMemories(db, project) > 0;
17995
- case "curate":
17996
- return countActiveMemories(db, project) > 0;
17997
- case "compress-cues":
17998
- return countActiveMemories(db, project) > 0;
17999
- case "classify-memories":
18000
- return countActiveMemories(db, project) > 0;
18001
- case "retrospective":
18002
- return countProjectSessionsSince(db, project, ctx.retrospectiveWatermarkMs ?? null) > 0;
18003
- case "maintain-docs":
18004
- return countCompartmentsSince(db, project, lastRunAt ?? 0) > 0;
18005
- case "evaluate-smart-notes":
18006
- return getSmartNotesNeedingCompilation(db, project, Date.now(), 1).length > 0 || getStaleCompiledSmartNotes(db, project, Date.now(), 1).length > 0 || getPendingSmartNotes(db, project).some((note) => note.checkStatus === "fallback");
18007
- case "review-user-memories":
18008
- return getUserMemoryCandidates(db).length >= ctx.promotionThreshold;
18009
- case "promote-primers":
18010
- return countPrimerCandidatesForProject(db, project) >= (ctx.promotionThreshold ?? 2);
18011
- case "refresh-primers":
18012
- return getActivePrimers(db, project).some((primer) => !primer.answer.trim() || primer.answerRefreshedAt == null || (primer.lastObservedAt ?? 0) > primer.answerRefreshedAt);
18013
- default: {
18014
- const _exhaustive = task;
18015
- return Boolean(_exhaustive);
18016
- }
18017
- }
18018
- }
18019
-
18020
18302
  // src/features/magic-context/dreamer/task-scheduler.ts
18021
18303
  var MAX_TASK_RETRIES = 3;
18022
18304
  function ensureSeeded(db, projectIdentity, config, now) {
@@ -18164,10 +18446,10 @@ async function runDomainGroup(deps, group, cb) {
18164
18446
  cb?.onRan?.(due.config.task);
18165
18447
  } else if (outcome.transient) {
18166
18448
  recordTransientFailure(db, projectIdentity, due, finishedAt, outcome.error ?? null);
18167
- cb?.onFailed?.(due.config.task);
18449
+ cb?.onFailed?.(due.config.task, outcome.error);
18168
18450
  } else {
18169
18451
  advanceAfterRun(db, projectIdentity, due, finishedAt, "failed", outcome.error ?? null);
18170
- cb?.onFailed?.(due.config.task);
18452
+ cb?.onFailed?.(due.config.task, outcome.error);
18171
18453
  }
18172
18454
  }
18173
18455
  } finally {
@@ -18176,7 +18458,15 @@ async function runDomainGroup(deps, group, cb) {
18176
18458
  }
18177
18459
  async function runManualDream(deps) {
18178
18460
  const now = Date.now();
18179
- const result = { ran: [], skippedNoWork: [], deferredBusy: [], failed: [] };
18461
+ const result = {
18462
+ ran: [],
18463
+ skippedNoWork: [],
18464
+ deferredBusy: [],
18465
+ failed: [],
18466
+ failureDetails: [],
18467
+ backlogBefore: {},
18468
+ backlogAfter: {}
18469
+ };
18180
18470
  let selected;
18181
18471
  let forceGate = false;
18182
18472
  if (deps.task) {
@@ -18190,6 +18480,9 @@ async function runManualDream(deps) {
18190
18480
  }
18191
18481
  if (selected.length === 0)
18192
18482
  return result;
18483
+ const selectedTaskNames = selected.map((config) => config.task);
18484
+ result.backlogBefore = getDreamTaskBacklogs(deps.db, deps.projectIdentity, selectedTaskNames);
18485
+ result.backlogAfter = { ...result.backlogBefore };
18193
18486
  for (const cfg of selected)
18194
18487
  ensureSeeded(deps.db, deps.projectIdentity, cfg, now);
18195
18488
  const dueAll = selected.map((config) => ({ config, scheduledAt: now }));
@@ -18211,8 +18504,10 @@ async function runManualDream(deps) {
18211
18504
  else
18212
18505
  result.skippedNoWork.push(d.config.task);
18213
18506
  }
18214
- if (gated.length === 0)
18507
+ if (gated.length === 0) {
18508
+ result.backlogAfter = getDreamTaskBacklogs(deps.db, deps.projectIdentity, selectedTaskNames);
18215
18509
  return result;
18510
+ }
18216
18511
  const groups = new Map;
18217
18512
  for (const d of gated) {
18218
18513
  const kind = leaseKindFor(d.config.task);
@@ -18224,9 +18519,14 @@ async function runManualDream(deps) {
18224
18519
  forceGate,
18225
18520
  leaseWaitMs: MANUAL_RUN_LEASE_WAIT_MS,
18226
18521
  onRan: (t) => result.ran.push(t),
18227
- onFailed: (t) => result.failed.push(t),
18522
+ onFailed: (task, error) => {
18523
+ result.failed.push(task);
18524
+ if (error)
18525
+ result.failureDetails?.push(`${task}: ${error}`);
18526
+ },
18228
18527
  onBusy: (t) => result.deferredBusy.push(t)
18229
18528
  })));
18529
+ result.backlogAfter = getDreamTaskBacklogs(deps.db, deps.projectIdentity, selectedTaskNames);
18230
18530
  return result;
18231
18531
  }
18232
18532
  async function runDueTasksForProject(deps) {
@@ -18799,10 +19099,11 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
18799
19099
  ensureProjectRegistered: reg.ensureRegistered,
18800
19100
  language: reg.language,
18801
19101
  dreamerModel: dreamerConfig.model,
18802
- experimentalMural: reg.experimentalMural,
19102
+ mural: reg.mural,
18803
19103
  memoryInjectionBudgetTokens: reg.memoryInjectionBudgetTokens,
18804
19104
  transformMode: reg.transformMode,
18805
- moduleClient: reg.moduleClient
19105
+ moduleClient: reg.moduleClient,
19106
+ onProgress: (progress, completedTask) => reg.onDreamerProgress?.(progress, completedTask)
18806
19107
  });
18807
19108
  const ran = await runDueTasksForProject({
18808
19109
  db,
@@ -19172,11 +19473,11 @@ async function resolveEmbeddingRouting(args) {
19172
19473
 
19173
19474
  // src/plugin/embedding-bootstrap.ts
19174
19475
  async function ensureProjectRegisteredFromOpenCodeDirectory(directory, db) {
19175
- const projectIdentity = resolveProjectIdentityForSession(directory);
19476
+ const detailed = loadPluginConfigDetailed(directory);
19477
+ const projectIdentity = resolveProjectIdentityForSession(directory, detailed.config.allow_home_project);
19176
19478
  if (!projectIdentity)
19177
19479
  return;
19178
19480
  invalidateProject(projectIdentity);
19179
- const detailed = loadPluginConfigDetailed(directory);
19180
19481
  if (isConfigLoadUntrusted(detailed)) {
19181
19482
  handleUntrustedLoad(db, projectIdentity, directory, detailed);
19182
19483
  return;
@@ -19230,41 +19531,45 @@ function createCompactionHandler() {
19230
19531
 
19231
19532
  // src/hooks/magic-context/event-resolvers.ts
19232
19533
  var DEFAULT_CONTEXT_LIMIT = 128000;
19233
- var MAX_EXECUTE_THRESHOLD = 80;
19234
19534
  function resolveContextLimit(providerID, modelID, ctx) {
19235
- const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID) : undefined;
19236
- const baseline = fromModelsDev ?? DEFAULT_CONTEXT_LIMIT;
19237
19535
  const modelKey = resolveModelKey(providerID, modelID);
19536
+ let detected;
19537
+ let detectedLimitProvenance = "unknown";
19238
19538
  if (ctx?.db && ctx.sessionID) {
19239
19539
  try {
19240
19540
  const overflow = getOverflowState(ctx.db, ctx.sessionID, modelKey);
19241
- if (overflow.detectedContextLimit > 0 && overflow.detectedContextLimit < baseline) {
19242
- return overflow.detectedContextLimit;
19541
+ if (overflow.detectedContextLimit > 0) {
19542
+ detected = overflow.detectedContextLimit;
19543
+ detectedLimitProvenance = overflow.detectedContextLimitProvenance;
19243
19544
  }
19244
19545
  } catch {}
19245
19546
  }
19246
- return baseline;
19547
+ const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID, detected, {
19548
+ reservation: ctx?.reservation,
19549
+ detectedLimitProvenance
19550
+ }) : undefined;
19551
+ return fromModelsDev ?? detected ?? DEFAULT_CONTEXT_LIMIT;
19247
19552
  }
19248
19553
  function resolveTrustedContextLimit(providerID, modelID, ctx) {
19249
- const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID) : undefined;
19250
19554
  const modelKey = resolveModelKey(providerID, modelID);
19251
19555
  let detected;
19556
+ let detectedLimitProvenance = "unknown";
19252
19557
  if (ctx?.db && ctx.sessionID) {
19253
19558
  try {
19254
19559
  const overflow = getOverflowState(ctx.db, ctx.sessionID, modelKey);
19255
19560
  if (overflow.detectedContextLimit > 0) {
19256
19561
  detected = overflow.detectedContextLimit;
19562
+ detectedLimitProvenance = overflow.detectedContextLimitProvenance;
19257
19563
  }
19258
19564
  } catch {}
19259
19565
  }
19260
- if (typeof fromModelsDev === "number" && fromModelsDev > 0) {
19261
- if (detected !== undefined && detected < fromModelsDev)
19262
- return detected;
19566
+ const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID, detected, {
19567
+ detectedLimitProvenance
19568
+ }) : undefined;
19569
+ if (typeof fromModelsDev === "number" && fromModelsDev > 0)
19263
19570
  return fromModelsDev;
19264
- }
19265
- if (detected !== undefined) {
19571
+ if (detected !== undefined)
19266
19572
  return detected;
19267
- }
19268
19573
  if (modelKey && ctx?.db && ctx.sessionID) {
19269
19574
  try {
19270
19575
  const persisted = loadPersistedUsage(ctx.db, ctx.sessionID);
@@ -19319,7 +19624,7 @@ function resolveExecuteThresholdDetail(config, modelKey, fallback, options) {
19319
19624
  const dedupeKey = `${options.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${tokenMatch.value}|${cap}`;
19320
19625
  if (!clampWarnSeen.has(dedupeKey)) {
19321
19626
  clampWarnSeen.add(dedupeKey);
19322
- const msg = `execute_threshold_tokens clamped: ${tokenMatch.value} → ${effectiveTokens} (80% of ${contextLimit}) for ${modelKey ?? "default"}`;
19627
+ const msg = `execute_threshold_tokens clamped: ${tokenMatch.value} → ${effectiveTokens} (${MAX_EXECUTE_THRESHOLD}% of ${contextLimit}) for ${modelKey ?? "default"}`;
19323
19628
  if (options.sessionId) {
19324
19629
  sessionLog(options.sessionId, `WARN: ${msg}`);
19325
19630
  } else {
@@ -19375,7 +19680,7 @@ function resolveExecuteThresholdDetail(config, modelKey, fallback, options) {
19375
19680
  const dedupeKey = `pct|${options?.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${resolved}`;
19376
19681
  if (!clampWarnSeen.has(dedupeKey)) {
19377
19682
  clampWarnSeen.add(dedupeKey);
19378
- 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)`;
19683
+ 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)`;
19379
19684
  if (options?.sessionId) {
19380
19685
  sessionLog(options.sessionId, `WARN: ${msg}`);
19381
19686
  } else {
@@ -19448,6 +19753,9 @@ var UNIT_TO_MS = {
19448
19753
  };
19449
19754
  function parseCacheTtl(ttl) {
19450
19755
  const normalizedTtl = ttl.trim();
19756
+ if (normalizedTtl.toLowerCase() === "never") {
19757
+ return Number.POSITIVE_INFINITY;
19758
+ }
19451
19759
  if (NUMERIC_PATTERN.test(normalizedTtl)) {
19452
19760
  return Number(normalizedTtl);
19453
19761
  }
@@ -19846,6 +20154,75 @@ function formatThresholdClampNote(opts) {
19846
20154
  return ` [clamped: ${opts.configuredValue}% > ${opts.maxPercentage}%]`;
19847
20155
  }
19848
20156
 
20157
+ // src/hooks/magic-context/sentinel.ts
20158
+ var WHOLE_MESSAGE_PLACEHOLDER_TEXT = "[dropped]";
20159
+ function modelAcceptsEmptyContent(providerID) {
20160
+ return providerID === "anthropic";
20161
+ }
20162
+ function variantChangeBustsProviderCache(providerID) {
20163
+ if (providerID === undefined)
20164
+ return true;
20165
+ if (providerID === "anthropic")
20166
+ return true;
20167
+ if (providerID === "google-vertex-anthropic")
20168
+ return true;
20169
+ if (providerID.includes("bedrock"))
20170
+ return true;
20171
+ return false;
20172
+ }
20173
+ function makeSentinel(originalPart) {
20174
+ const sentinel = {
20175
+ type: "text",
20176
+ text: ""
20177
+ };
20178
+ if (isRecord(originalPart)) {
20179
+ if (originalPart.cache_control !== undefined) {
20180
+ sentinel.cache_control = originalPart.cache_control;
20181
+ }
20182
+ if (originalPart.cacheControl !== undefined) {
20183
+ sentinel.cacheControl = originalPart.cacheControl;
20184
+ }
20185
+ }
20186
+ return sentinel;
20187
+ }
20188
+ function makeWholeMessageSentinel(providerID) {
20189
+ return {
20190
+ type: "text",
20191
+ text: modelAcceptsEmptyContent(providerID) ? "" : WHOLE_MESSAGE_PLACEHOLDER_TEXT
20192
+ };
20193
+ }
20194
+ function isSentinel(part) {
20195
+ if (!isRecord(part))
20196
+ return false;
20197
+ if (part.type !== "text")
20198
+ return false;
20199
+ if (typeof part.text !== "string")
20200
+ return false;
20201
+ return part.text === "" || part.text === WHOLE_MESSAGE_PLACEHOLDER_TEXT;
20202
+ }
20203
+ function replaySentinelByMessageIds(messages, ids, providerID) {
20204
+ if (ids.size === 0)
20205
+ return { replayed: 0, missingIds: [] };
20206
+ const seen = new Set;
20207
+ let replayed = 0;
20208
+ for (const msg of messages) {
20209
+ const id = msg.info.id;
20210
+ if (!id || !ids.has(id))
20211
+ continue;
20212
+ seen.add(id);
20213
+ if (msg.parts.length === 1 && isSentinel(msg.parts[0]))
20214
+ continue;
20215
+ msg.parts.length = 0;
20216
+ msg.parts.push(makeWholeMessageSentinel(providerID));
20217
+ replayed++;
20218
+ }
20219
+ const missingIds = [];
20220
+ for (const id of ids)
20221
+ if (!seen.has(id))
20222
+ missingIds.push(id);
20223
+ return { replayed, missingIds };
20224
+ }
20225
+
19849
20226
  // src/hooks/magic-context/compartment-trigger.ts
19850
20227
  var PROACTIVE_TRIGGER_OFFSET_PERCENTAGE = 2;
19851
20228
  var POST_DROP_TARGET_RATIO = 0.75;
@@ -19853,9 +20230,7 @@ var MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE = 6000;
19853
20230
  var MIN_PROACTIVE_TAIL_MESSAGE_COUNT = 12;
19854
20231
  var DEFAULT_MIN_COMMIT_CLUSTERS_FOR_TRIGGER = 3;
19855
20232
  var TAIL_SIZE_TRIGGER_MULTIPLIER = 3;
19856
- var FORCE_COMPARTMENT_PERCENTAGE = 80;
19857
20233
  var BLOCK_UNTIL_DONE_PERCENTAGE = 95;
19858
- var FORCE_MATERIALIZE_PERCENTAGE = 85;
19859
20234
  var CONTENT_TAG_OWNER_SUFFIX = /:(?:p|file)\d+$/;
19860
20235
  function tagOwnerMessageId(row) {
19861
20236
  if (row.type === "tool")
@@ -19909,7 +20284,7 @@ function buildTriggerInMemoryTail(db, sessionId, messages) {
19909
20284
  function getProactiveCompartmentTriggerPercentage(executeThresholdPercentage) {
19910
20285
  return Math.max(0, executeThresholdPercentage - PROACTIVE_TRIGGER_OFFSET_PERCENTAGE);
19911
20286
  }
19912
- function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, clearReasoningAge, clearedReasoningThroughTag) {
20287
+ function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, clearReasoningAge, clearedReasoningThroughTag, canClearReasoning) {
19913
20288
  const totalActiveBytes = activeTags.reduce((sum, tag) => sum + tag.byteSize + tag.reasoningByteSize, 0);
19914
20289
  if (totalActiveBytes === 0)
19915
20290
  return null;
@@ -19920,7 +20295,7 @@ function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, c
19920
20295
  droppableBytes += activeTags.filter((tag) => pendingDropTagIds.has(tag.tagNumber)).reduce((sum, tag) => sum + tag.byteSize + tag.reasoningByteSize, 0);
19921
20296
  }
19922
20297
  const maxTag = activeTags.reduce((max, t) => Math.max(max, t.tagNumber), 0);
19923
- if (clearReasoningAge !== undefined && clearedReasoningThroughTag !== undefined) {
20298
+ if (canClearReasoning && clearReasoningAge !== undefined && clearedReasoningThroughTag !== undefined) {
19924
20299
  const reasoningAgeCutoff = maxTag - clearReasoningAge;
19925
20300
  for (const tag of activeTags) {
19926
20301
  if (tag.type !== "message")
@@ -20020,7 +20395,7 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
20020
20395
  }
20021
20396
  });
20022
20397
  }
20023
- function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride) {
20398
+ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride, reasoningProjection) {
20024
20399
  if (sessionMeta.compartmentInProgress) {
20025
20400
  sessionLog(sessionId, `compartment trigger: skipped — historian already in progress (usage=${usage.percentage.toFixed(1)}%)`);
20026
20401
  return { shouldFire: false };
@@ -20074,18 +20449,20 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
20074
20449
  }
20075
20450
  return { shouldFire: false };
20076
20451
  }
20077
- const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), clearReasoningAge, sessionMeta.clearedReasoningThroughTag);
20452
+ const canClearReasoning = reasoningProjection?.canClearReasoning ?? modelAcceptsEmptyContent(reasoningProjection?.providerID);
20453
+ const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), clearReasoningAge, sessionMeta.clearedReasoningThroughTag, canClearReasoning);
20078
20454
  const relativePostDropTarget = executeThresholdPercentage * POST_DROP_TARGET_RATIO;
20079
- if (usage.percentage >= FORCE_COMPARTMENT_PERCENTAGE) {
20455
+ const forceMaterializationPercentage = escalationBands(executeThresholdPercentage).forceMaterializationPercentage;
20456
+ if (usage.percentage >= forceMaterializationPercentage) {
20080
20457
  if (projectedPostDropPercentage !== null && projectedPostDropPercentage <= relativePostDropTarget) {
20081
- sessionLog(sessionId, `compartment trigger: skipping force-${FORCE_COMPARTMENT_PERCENTAGE} because projected post-drop usage is ${projectedPostDropPercentage.toFixed(1)}% (target ${relativePostDropTarget.toFixed(1)}%)`);
20458
+ sessionLog(sessionId, `compartment trigger: skipping force band ${forceMaterializationPercentage}% because projected post-drop usage is ${projectedPostDropPercentage.toFixed(1)}% (target ${relativePostDropTarget.toFixed(1)}%)`);
20082
20459
  return { shouldFire: false };
20083
20460
  }
20084
20461
  sessionLog(sessionId, `compartment trigger: force-firing at ${usage.percentage.toFixed(1)}% (projected post-drop ${projectedPostDropPercentage?.toFixed(1) ?? "none"}%)`);
20085
20462
  if (tailInfo.boundarySnapshot && hasRunnableCompartmentWindow(tailInfo.boundarySnapshot)) {
20086
20463
  return {
20087
20464
  shouldFire: true,
20088
- reason: "force_80",
20465
+ reason: "force_band",
20089
20466
  boundarySnapshot: tailInfo.boundarySnapshot
20090
20467
  };
20091
20468
  }
@@ -20110,9 +20487,9 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
20110
20487
  });
20111
20488
  });
20112
20489
  if (hasRunnableCompartmentWindow(scaledBoundary)) {
20113
- return { shouldFire: true, reason: "force_80", boundarySnapshot: scaledBoundary };
20490
+ return { shouldFire: true, reason: "force_band", boundarySnapshot: scaledBoundary };
20114
20491
  }
20115
- sessionLog(sessionId, "compartment trigger: force_80 skipped — raw exists but protected head genuinely empty after emergency tail scale");
20492
+ sessionLog(sessionId, "compartment trigger: force_band skipped — raw exists but protected head genuinely empty after emergency tail scale");
20116
20493
  return { shouldFire: false };
20117
20494
  }
20118
20495
  const clusterEnabled = commitClusterTrigger?.enabled ?? true;
@@ -20182,7 +20559,7 @@ function formatExecuteThreshold(detail, contextLimit) {
20182
20559
  }
20183
20560
  return `${percentage}%${clampNote}`;
20184
20561
  }
20185
- function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageConfig = DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, liveModelKey, historyBudgetPercentage, commitClusterTrigger, executeThresholdTokens, contextLimit) {
20562
+ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageConfig = DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, liveModelKey, historyBudgetPercentage, commitClusterTrigger, executeThresholdTokens, contextLimit, dreamer) {
20186
20563
  const thresholdDetail = resolveExecuteThresholdDetail(executeThresholdPercentageConfig, liveModelKey, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, {
20187
20564
  tokensConfig: executeThresholdTokens,
20188
20565
  contextLimit,
@@ -20227,8 +20604,8 @@ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageC
20227
20604
  "### Cache TTL",
20228
20605
  `- Configured: ${meta.cacheTtl}`,
20229
20606
  `- Last response: ${meta.lastResponseTime > 0 ? `${Math.round(elapsed / 1000)}s ago` : "never"}`,
20230
- `- Remaining: ${cacheExpired ? "expired" : `${Math.round(remainingMs / 1000)}s`}`,
20231
- `- Queue will auto-execute: ${cacheExpired ? "yes (cache expired)" : `when TTL expires or context >= ${executeThresholdPercentage}%`}`,
20607
+ `- Remaining: ${cacheExpired ? "expired" : ttlMs === Number.POSITIVE_INFINITY ? "never expires (always-warm lane)" : `${Math.round(remainingMs / 1000)}s`}`,
20608
+ `- Queue will auto-execute: ${cacheExpired ? "yes (cache expired)" : ttlMs === Number.POSITIVE_INFINITY ? `when context >= ${executeThresholdPercentage}%` : `when TTL expires or context >= ${executeThresholdPercentage}%`}`,
20232
20609
  "",
20233
20610
  "### Execute Threshold",
20234
20611
  `- Execute threshold: ${formatExecuteThreshold(thresholdDetail, displayContextLimit)}`,
@@ -20237,6 +20614,11 @@ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageC
20237
20614
  `**Protected tags:** ${protectedTags}`,
20238
20615
  `**Subagent session:** ${meta.isSubagent}`
20239
20616
  ];
20617
+ if (dreamer?.backlog && Object.keys(dreamer.backlog).length > 0) {
20618
+ lines.push("", "### Dreamer", ...dreamer.progress ? [
20619
+ `- Running: ${dreamer.progress.task} — ${dreamer.progress.processed}/${dreamer.progress.total} processed`
20620
+ ] : [], ...formatDreamTaskBacklogs(dreamer.backlog).split("\\n"));
20621
+ }
20240
20622
  if (meta.lastContextPercentage > 0 || meta.lastInputTokens > 0) {
20241
20623
  lines.push("", "### Context Usage", `- Last percentage: ${meta.lastContextPercentage.toFixed(1)}%`, `- Last input tokens: ${meta.lastInputTokens.toLocaleString()}`, `- Resolved context limit: ${displayContextLimit > 0 ? displayContextLimit.toLocaleString() : "unknown"}`, `- Proactive compartment evaluation: ${proactiveCompartmentTrigger}%`, `- Post-drop target for historian: ${(executeThresholdPercentage * POST_DROP_TARGET_RATIO).toFixed(0)}% (${executeThresholdPercentage}% * ${POST_DROP_TARGET_RATIO})`, `- Commit cluster trigger: ${commitClusterTrigger?.enabled !== false ? `enabled (min ${commitClusterTrigger?.min_clusters ?? 3} clusters)` : "disabled"}, tail-size trigger: > 3x compartment budget`);
20242
20624
  }
@@ -20259,6 +20641,12 @@ ${c.content}
20259
20641
  lines.push(`- §${op.tagId}§ → ${op.operation}`);
20260
20642
  }
20261
20643
  }
20644
+ if (dreamer?.backlog && Object.keys(dreamer.backlog).length > 0) {
20645
+ lines.push("", "### Dreamer Backlog", formatDreamTaskBacklogs(dreamer.backlog));
20646
+ }
20647
+ if (dreamer?.progress) {
20648
+ lines.push("", "### Dreamer Progress", `- ${dreamer.progress.task}: ${dreamer.progress.processed}/${dreamer.progress.total} processed this run`);
20649
+ }
20262
20650
  return lines.join(`
20263
20651
  `);
20264
20652
  } catch (error) {
@@ -20494,16 +20882,32 @@ ${sidekickResult}
20494
20882
  await sendUserPrompt(deps.sidekick.client, sessionId, augmentedPrompt);
20495
20883
  throwSentinel("CTX-AUG");
20496
20884
  }
20885
+ function readDreamTaskBacklogsSafely(db, projectPath, tasks) {
20886
+ try {
20887
+ return getDreamTaskBacklogs(db, projectPath, tasks);
20888
+ } catch {
20889
+ return {};
20890
+ }
20891
+ }
20497
20892
  function summarizeManualDream(s) {
20498
20893
  const lines = ["## /ctx-dream", ""];
20499
20894
  if (s.ran.length > 0)
20500
20895
  lines.push(`Ran: ${s.ran.join(", ")}`);
20501
20896
  if (s.failed.length > 0)
20502
20897
  lines.push(`Failed: ${s.failed.join(", ")}`);
20898
+ if ((s.failureDetails?.length ?? 0) > 0) {
20899
+ lines.push("Failure details:", ...(s.failureDetails ?? []).map((detail) => `- ${detail}`));
20900
+ }
20503
20901
  if (s.skippedNoWork.length > 0)
20504
20902
  lines.push(`Skipped (no work): ${s.skippedNoWork.join(", ")}`);
20505
20903
  if (s.deferredBusy.length > 0)
20506
20904
  lines.push(`Busy: ${s.deferredBusy.join(", ")} — another dream task holds this domain's lease; retry in a minute`);
20905
+ if (Object.keys(s.backlogBefore ?? {}).length > 0) {
20906
+ lines.push("", "Backlog at run start:", formatDreamTaskBacklogs(s.backlogBefore ?? {}));
20907
+ }
20908
+ if (Object.keys(s.backlogAfter ?? {}).length > 0) {
20909
+ lines.push("", "Backlog at run end:", formatDreamTaskBacklogs(s.backlogAfter ?? {}));
20910
+ }
20507
20911
  if (s.ran.length === 0 && s.failed.length === 0 && s.skippedNoWork.length === 0 && s.deferredBusy.length === 0) {
20508
20912
  lines.push("No enabled dream tasks to run.");
20509
20913
  }
@@ -20531,7 +20935,17 @@ Unknown task "${requested}". Valid tasks: ${CANONICAL_DREAM_TASKS.join(", ")}.`,
20531
20935
  }
20532
20936
  task = requested;
20533
20937
  }
20534
- await deps.sendNotification(sessionId, task ? `Running dream task "${task}"...` : "Starting dream run...", dreamNotificationParams);
20938
+ const backlogTasks = task ? [task] : CANONICAL_DREAM_TASKS;
20939
+ const backlogBefore = readDreamTaskBacklogsSafely(deps.db, deps.dreamer.projectPath, backlogTasks);
20940
+ await deps.sendNotification(sessionId, [
20941
+ "## /ctx-dream",
20942
+ "",
20943
+ task ? `Running dream task "${task}"...` : "Starting dream run...",
20944
+ "",
20945
+ "Backlog before starting:",
20946
+ formatDreamTaskBacklogs(backlogBefore, backlogTasks)
20947
+ ].join(`
20948
+ `), dreamNotificationParams);
20535
20949
  const summary = await deps.dreamer.runManual(task);
20536
20950
  await deps.sendNotification(sessionId, summarizeManualDream(summary), dreamNotificationParams);
20537
20951
  throwSentinel("CTX-DREAM");
@@ -20579,6 +20993,11 @@ function createMagicContextCommandHandler(deps) {
20579
20993
  }
20580
20994
  const sessionId = input.sessionID;
20581
20995
  let result = "";
20996
+ if (deps.compactionOff && (isFlush || isRecomp || isWrapup)) {
20997
+ const command = `/${input.command}`;
20998
+ await deps.sendNotification(sessionId, `Magic Context compaction is disabled (${COMPACTION_ENABLED_PATH}: false) — ${command} manages compacted history and has no effect in this mode.`, {});
20999
+ throwSentinel(input.command);
21000
+ }
20582
21001
  if (isAug) {
20583
21002
  await executeAugmentation(deps, sessionId, input.arguments);
20584
21003
  return;
@@ -20664,11 +21083,17 @@ Embedding status is unavailable.`;
20664
21083
  }
20665
21084
  const liveModelKey = deps.getLiveModelKey?.(sessionId);
20666
21085
  const liveContextLimit = deps.getContextLimit?.(sessionId);
20667
- const statusOutput = executeStatus(deps.db, sessionId, deps.protectedTags, deps.executeThresholdPercentage, liveModelKey, deps.historyBudgetPercentage, deps.commitClusterTrigger, deps.executeThresholdTokens, liveContextLimit);
21086
+ const statusOutput = executeStatus(deps.db, sessionId, deps.protectedTags, deps.executeThresholdPercentage, liveModelKey, deps.historyBudgetPercentage, deps.commitClusterTrigger, deps.executeThresholdTokens, liveContextLimit, deps.dreamer ? {
21087
+ backlog: readDreamTaskBacklogsSafely(deps.db, deps.dreamer.projectPath, CANONICAL_DREAM_TASKS),
21088
+ progress: deps.getDreamerProgress?.() ?? null
21089
+ } : undefined);
20668
21090
  const moduleStatus = rustStatus ? `
20669
21091
 
20670
21092
  ${formatRustStatusText(rustStatus)}` : "";
20671
- const combinedStatus = `${statusOutput}${moduleStatus}`;
21093
+ const modeStatus = deps.compactionOff ? `**Compaction:** disabled (${COMPACTION_ENABLED_PATH}: false) — native compaction owns the context window.
21094
+
21095
+ ` : "";
21096
+ const combinedStatus = `${modeStatus}${statusOutput}${moduleStatus}`;
20672
21097
  result += result ? `
20673
21098
 
20674
21099
  ${combinedStatus}` : combinedStatus;
@@ -20835,6 +21260,212 @@ ${snap.error}`;
20835
21260
  };
20836
21261
  }
20837
21262
 
21263
+ // src/hooks/magic-context/ctx-reduce-availability.ts
21264
+ var ctxReduceRegisteredGlobally = true;
21265
+ function setCtxReduceRegisteredGlobally(registered) {
21266
+ ctxReduceRegisteredGlobally = registered;
21267
+ }
21268
+ var CTX_REDUCE_TOOL = "ctx_reduce";
21269
+ var TODOWRITE_TOOL = "todowrite";
21270
+ var availabilityBySession = new BoundedSessionMap(1000);
21271
+ var permissionDeniedBySession = new BoundedSessionMap(2000);
21272
+ var ctxReducePermissionDenyLogged = new BoundedSessionMap(1000);
21273
+ function permissionCacheKey(toolName, sessionId) {
21274
+ return `${toolName}\x00${sessionId}`;
21275
+ }
21276
+ function cacheKey(toolName, sessionId) {
21277
+ return `${toolName}\x00${sessionId}`;
21278
+ }
21279
+ function verdictFromToolsMap(tools, toolName) {
21280
+ if (tools === null || typeof tools !== "object" || Array.isArray(tools))
21281
+ return null;
21282
+ const map = tools;
21283
+ if (map[toolName] === true)
21284
+ return true;
21285
+ if (map[toolName] === false)
21286
+ return false;
21287
+ if (map["*"] === false)
21288
+ return false;
21289
+ return null;
21290
+ }
21291
+ function resolveToolAvailabilityFromMessages(sessionId, toolName, messages) {
21292
+ if (toolName === CTX_REDUCE_TOOL && !ctxReduceRegisteredGlobally) {
21293
+ return { callable: false, frozen: true };
21294
+ }
21295
+ const key = cacheKey(toolName, sessionId);
21296
+ const cached = availabilityBySession.get(key);
21297
+ if (cached !== undefined)
21298
+ return { callable: cached, frozen: true };
21299
+ for (const message of messages) {
21300
+ if (message.info?.role !== "user")
21301
+ continue;
21302
+ const verdict = verdictFromToolsMap(message.info.tools, toolName) ?? true;
21303
+ availabilityBySession.set(key, verdict);
21304
+ return { callable: verdict, frozen: true };
21305
+ }
21306
+ return { callable: true, frozen: false };
21307
+ }
21308
+ function resolveToolAvailability(sessionId, toolName) {
21309
+ if (toolName === CTX_REDUCE_TOOL && !ctxReduceRegisteredGlobally) {
21310
+ return { callable: false, frozen: true };
21311
+ }
21312
+ const key = cacheKey(toolName, sessionId);
21313
+ const cached = availabilityBySession.get(key);
21314
+ if (cached !== undefined)
21315
+ return { callable: cached, frozen: true };
21316
+ if (!openCodeDbExists())
21317
+ return { callable: true, frozen: true };
21318
+ try {
21319
+ const row = withReadOnlySessionDb((db) => db.prepare(`SELECT json_extract(data, '$.tools') AS tools FROM message
21320
+ WHERE session_id = ? AND json_extract(data, '$.role') = 'user'
21321
+ ORDER BY time_created ASC LIMIT 1`).get(sessionId));
21322
+ if (!row)
21323
+ return { callable: true, frozen: false };
21324
+ const verdict = row.tools === null ? null : verdictFromToolsMap(JSON.parse(row.tools), toolName);
21325
+ const resolved = verdict ?? true;
21326
+ availabilityBySession.set(key, resolved);
21327
+ return { callable: resolved, frozen: true };
21328
+ } catch (error) {
21329
+ sessionLog(sessionId, `${toolName} availability read failed (fail-open):`, error);
21330
+ return { callable: true, frozen: false };
21331
+ }
21332
+ }
21333
+ function resolveCtxReduceAvailabilityFromMessages(sessionId, messages) {
21334
+ return resolveToolAvailabilityFromMessages(sessionId, CTX_REDUCE_TOOL, messages);
21335
+ }
21336
+ function resolveCtxReduceAvailability(sessionId) {
21337
+ return resolveToolAvailability(sessionId, CTX_REDUCE_TOOL);
21338
+ }
21339
+ function isRecord2(value) {
21340
+ return value !== null && typeof value === "object" && !Array.isArray(value);
21341
+ }
21342
+ function responseData(value) {
21343
+ if (isRecord2(value) && Object.hasOwn(value, "data"))
21344
+ return value.data;
21345
+ return value;
21346
+ }
21347
+ function escapeRegExpLiteral(value) {
21348
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
21349
+ }
21350
+ function permissionNameMatches(rulePermission, toolName) {
21351
+ if (rulePermission === "*" || rulePermission === toolName)
21352
+ return true;
21353
+ if (!rulePermission.includes("*"))
21354
+ return false;
21355
+ const pattern = rulePermission.split("*").map(escapeRegExpLiteral).join(".*");
21356
+ return new RegExp(`^${pattern}$`).test(toolName);
21357
+ }
21358
+ function permissionDisabled(toolName, rules) {
21359
+ let finalRule;
21360
+ for (let index = rules.length - 1;index >= 0; index -= 1) {
21361
+ const rule = rules[index];
21362
+ if (rule && permissionNameMatches(rule.permission, toolName)) {
21363
+ finalRule = rule;
21364
+ break;
21365
+ }
21366
+ }
21367
+ return finalRule?.action === "deny" && finalRule.pattern === "*";
21368
+ }
21369
+ function actionOf(value) {
21370
+ return value === "ask" || value === "allow" || value === "deny" ? value : null;
21371
+ }
21372
+ function appendPermissionRule(target, permission, pattern, action) {
21373
+ if (typeof permission !== "string" || permission.length === 0)
21374
+ return;
21375
+ const normalizedAction = actionOf(action);
21376
+ if (!normalizedAction)
21377
+ return;
21378
+ const patterns = Array.isArray(pattern) ? pattern : [pattern ?? "*"];
21379
+ for (const candidate of patterns) {
21380
+ if (typeof candidate === "string") {
21381
+ target.push({ permission, pattern: candidate, action: normalizedAction });
21382
+ }
21383
+ }
21384
+ }
21385
+ function permissionRules(value) {
21386
+ if (Array.isArray(value)) {
21387
+ const result2 = [];
21388
+ for (const item of value) {
21389
+ if (!isRecord2(item))
21390
+ continue;
21391
+ appendPermissionRule(result2, item.permission ?? item.tool ?? item.name, item.pattern, item.action ?? item.value);
21392
+ }
21393
+ return result2;
21394
+ }
21395
+ if (!isRecord2(value))
21396
+ return [];
21397
+ const result = [];
21398
+ if (Array.isArray(value.rules))
21399
+ result.push(...permissionRules(value.rules));
21400
+ for (const [permission, configured] of Object.entries(value)) {
21401
+ if (permission === "rules")
21402
+ continue;
21403
+ const simpleAction = actionOf(configured);
21404
+ if (simpleAction) {
21405
+ appendPermissionRule(result, permission, "*", simpleAction);
21406
+ continue;
21407
+ }
21408
+ if (!isRecord2(configured))
21409
+ continue;
21410
+ for (const [pattern, action] of Object.entries(configured)) {
21411
+ appendPermissionRule(result, permission, pattern, action);
21412
+ }
21413
+ }
21414
+ return result;
21415
+ }
21416
+ function activeAgentNameFromSession(value) {
21417
+ if (!isRecord2(value))
21418
+ return;
21419
+ const agent = value.agent;
21420
+ return typeof agent === "string" && agent.length > 0 ? agent : undefined;
21421
+ }
21422
+ async function resolveToolPermissionDenied(client, sessionId, toolName, activeAgent) {
21423
+ const sdk = client;
21424
+ if (!sdk.app?.agents || !sdk.session?.get) {
21425
+ throw new Error("OpenCode permission APIs are unavailable");
21426
+ }
21427
+ const [agentsResponse, sessionResponse] = await Promise.all([
21428
+ sdk.app.agents(),
21429
+ sdk.session.get({ path: { id: sessionId } })
21430
+ ]);
21431
+ const agents = responseData(agentsResponse);
21432
+ const session = responseData(sessionResponse);
21433
+ const agentName = activeAgent ?? activeAgentNameFromSession(session);
21434
+ const agent = Array.isArray(agents) ? agents.find((candidate) => isRecord2(candidate) && candidate.name === agentName) : undefined;
21435
+ const agentRules = permissionRules(isRecord2(agent) ? agent.permission : undefined);
21436
+ const sessionRules = permissionRules(isRecord2(session) ? session.permission ?? session.permissions : undefined);
21437
+ const denied = permissionDisabled(toolName, [...agentRules, ...sessionRules]);
21438
+ permissionDeniedBySession.set(permissionCacheKey(toolName, sessionId), denied);
21439
+ return denied;
21440
+ }
21441
+ function todowritePermissionDenied(client, sessionId, activeAgent) {
21442
+ return resolveToolPermissionDenied(client, sessionId, TODOWRITE_TOOL, activeAgent);
21443
+ }
21444
+ function cachedToolPermissionDenied(sessionId, toolName) {
21445
+ return permissionDeniedBySession.get(permissionCacheKey(toolName, sessionId));
21446
+ }
21447
+ function clearToolPermissionDenied(sessionId, toolName) {
21448
+ if (toolName) {
21449
+ permissionDeniedBySession.delete(permissionCacheKey(toolName, sessionId));
21450
+ } else {
21451
+ permissionDeniedBySession.delete(permissionCacheKey(TODOWRITE_TOOL, sessionId));
21452
+ permissionDeniedBySession.delete(permissionCacheKey(CTX_REDUCE_TOOL, sessionId));
21453
+ }
21454
+ ctxReducePermissionDenyLogged.delete(sessionId);
21455
+ }
21456
+ function hasLoggedCtxReducePermissionDeny(sessionId) {
21457
+ return ctxReducePermissionDenyLogged.get(sessionId) === true;
21458
+ }
21459
+ function markCtxReducePermissionDenyLogged(sessionId) {
21460
+ ctxReducePermissionDenyLogged.set(sessionId, true);
21461
+ }
21462
+ function resolveTodowriteAvailabilityFromMessages(sessionId, messages) {
21463
+ return resolveToolAvailabilityFromMessages(sessionId, TODOWRITE_TOOL, messages);
21464
+ }
21465
+ function resolveTodowriteAvailability(sessionId) {
21466
+ return resolveToolAvailability(sessionId, TODOWRITE_TOOL);
21467
+ }
21468
+
20838
21469
  // src/hooks/magic-context/embed-session-state.ts
20839
21470
  var embedPauseBySession = new Set;
20840
21471
  var embedRunStateBySession = new Map;
@@ -21615,9 +22246,9 @@ function getMessageRemovedInfo(properties) {
21615
22246
  import * as crypto3 from "node:crypto";
21616
22247
 
21617
22248
  // src/hooks/magic-context/boundary-execution.ts
21618
- var FORCE_MATERIALIZE_PERCENTAGE2 = 85;
21619
22249
  function detectMidTurnBypassReason(input) {
21620
- if (input.contextUsage.percentage >= FORCE_MATERIALIZE_PERCENTAGE2)
22250
+ const { forceMaterializationPercentage } = escalationBands(input.effectiveExecuteThresholdPercentage);
22251
+ if (input.contextUsage.percentage >= forceMaterializationPercentage)
21621
22252
  return "force-materialize";
21622
22253
  if (input.historyRefreshSessions.has(input.sessionId))
21623
22254
  return "explicit-bust";
@@ -21644,7 +22275,7 @@ function canConsumeDeferredOnThisPass(args) {
21644
22275
  return true;
21645
22276
  if (args.activeRunBlocksMaterialization)
21646
22277
  return false;
21647
- return args.schedulerDecision === "execute" || args.contextPercentage >= FORCE_MATERIALIZE_PERCENTAGE;
22278
+ return args.schedulerDecision === "execute" || args.contextPercentage >= (args.forceMaterializationPercentage ?? escalationBands(65).forceMaterializationPercentage);
21648
22279
  }
21649
22280
 
21650
22281
  // src/hooks/magic-context/caveman.ts
@@ -21988,72 +22619,157 @@ function replayCavemanCompression(sessionId, db, targets, tags) {
21988
22619
  return replayed;
21989
22620
  }
21990
22621
 
21991
- // src/hooks/magic-context/ctx-reduce-availability.ts
21992
- var CTX_REDUCE_TOOL = "ctx_reduce";
21993
- var TODOWRITE_TOOL = "todowrite";
21994
- var availabilityBySession = new BoundedSessionMap(1000);
21995
- function cacheKey(toolName, sessionId) {
21996
- return `${toolName}\x00${sessionId}`;
21997
- }
21998
- function verdictFromToolsMap(tools, toolName) {
21999
- if (tools === null || typeof tools !== "object" || Array.isArray(tools))
22000
- return null;
22001
- const map = tools;
22002
- if (map[toolName] === true)
22003
- return true;
22004
- if (map[toolName] === false)
22005
- return false;
22006
- if (map["*"] === false)
22007
- return false;
22008
- return null;
22009
- }
22010
- function resolveToolAvailabilityFromMessages(sessionId, toolName, messages) {
22011
- const key = cacheKey(toolName, sessionId);
22012
- const cached = availabilityBySession.get(key);
22013
- if (cached !== undefined)
22014
- return { callable: cached, frozen: true };
22015
- for (const message of messages) {
22016
- if (message.info?.role !== "user")
22017
- continue;
22018
- const verdict = verdictFromToolsMap(message.info.tools, toolName) ?? true;
22019
- availabilityBySession.set(key, verdict);
22020
- return { callable: verdict, frozen: true };
22622
+ // src/hooks/magic-context/compaction-off-transition.ts
22623
+ import { existsSync as existsSync11 } from "node:fs";
22624
+ var loggedUnverifiedMarkerCleanupRetry = false;
22625
+ var COMPACTION_OFF_FLIP_NOTICE = [
22626
+ "## Magic Context — compaction-off mode is now active",
22627
+ "",
22628
+ "Magic Context no longer manages this session's context window; native compaction (or nothing) owns it. Memory, dreamer, notes and ctx_search stay live.",
22629
+ "",
22630
+ "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."
22631
+ ].join(`
22632
+ `);
22633
+ var COMPACTION_ON_WRAPUP_SUGGESTION = [
22634
+ "## Magic Context — compaction re-enabled",
22635
+ "",
22636
+ "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."
22637
+ ].join(`
22638
+ `);
22639
+ var NO_TRANSITION = {
22640
+ recordToWrite: null,
22641
+ notice: null,
22642
+ invalidatedM0Baseline: false,
22643
+ historianCatchUpSignaled: false,
22644
+ clearedCompartmentInProgress: false,
22645
+ clearedSomething: false,
22646
+ markerCleanup: {
22647
+ verified: true,
22648
+ removedLineages: 0,
22649
+ removedRows: 0,
22650
+ retainedLineages: 0
22021
22651
  }
22022
- return { callable: true, frozen: false };
22652
+ };
22653
+ function clearCachedM0Baseline(db, sessionId) {
22654
+ 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);
22655
+ return (result.changes ?? 0) > 0;
22023
22656
  }
22024
- function resolveToolAvailability(sessionId, toolName) {
22025
- const key = cacheKey(toolName, sessionId);
22026
- const cached = availabilityBySession.get(key);
22027
- if (cached !== undefined)
22028
- return { callable: cached, frozen: true };
22029
- if (!openCodeDbExists())
22030
- return { callable: true, frozen: true };
22031
- try {
22032
- const row = withReadOnlySessionDb((db) => db.prepare(`SELECT json_extract(data, '$.tools') AS tools FROM message
22033
- WHERE session_id = ? AND json_extract(data, '$.role') = 'user'
22034
- ORDER BY time_created ASC LIMIT 1`).get(sessionId));
22035
- if (!row)
22036
- return { callable: true, frozen: false };
22037
- const verdict = row.tools === null ? null : verdictFromToolsMap(JSON.parse(row.tools), toolName);
22038
- const resolved = verdict ?? true;
22039
- availabilityBySession.set(key, resolved);
22040
- return { callable: resolved, frozen: true };
22041
- } catch (error) {
22042
- sessionLog(sessionId, `${toolName} availability read failed (fail-open):`, error);
22043
- return { callable: true, frozen: false };
22657
+ function cleanupOffMarkers(sessionId) {
22658
+ if (!existsSync11(getOpenCodeDbPath())) {
22659
+ return { verified: true, removedLineages: 0, removedRows: 0, retainedLineages: 0 };
22044
22660
  }
22661
+ return removeMcOwnedCompactionMarkers(sessionId, MARKER_SUMMARY_TEXT);
22045
22662
  }
22046
- function resolveCtxReduceAvailabilityFromMessages(sessionId, messages) {
22047
- return resolveToolAvailabilityFromMessages(sessionId, CTX_REDUCE_TOOL, messages);
22048
- }
22049
- function resolveCtxReduceAvailability(sessionId) {
22050
- return resolveToolAvailability(sessionId, CTX_REDUCE_TOOL);
22051
- }
22052
- function resolveTodowriteAvailabilityFromMessages(sessionId, messages) {
22053
- return resolveToolAvailabilityFromMessages(sessionId, TODOWRITE_TOOL, messages);
22663
+ function reconcileCompactionMode(args) {
22664
+ const { db, sessionId } = args;
22665
+ const stored = getCompactionModeRecord(db, sessionId);
22666
+ if (stored === "on_notice_pending") {
22667
+ return {
22668
+ ...NO_TRANSITION,
22669
+ recordToWrite: "on",
22670
+ notice: COMPACTION_ON_WRAPUP_SUGGESTION
22671
+ };
22672
+ }
22673
+ if (stored === "off_notice_pending") {
22674
+ const markerCleanup2 = cleanupOffMarkers(sessionId);
22675
+ return {
22676
+ ...NO_TRANSITION,
22677
+ recordToWrite: markerCleanup2.verified ? "off" : "off_cleanup_pending",
22678
+ notice: COMPACTION_OFF_FLIP_NOTICE,
22679
+ markerCleanup: markerCleanup2
22680
+ };
22681
+ }
22682
+ if (!args.compactionOff) {
22683
+ if (stored === null || resolveCompactionModeRecord(stored) === "on") {
22684
+ return stored === null ? { ...NO_TRANSITION, recordToWrite: "on" } : NO_TRANSITION;
22685
+ }
22686
+ const invalidatedM0Baseline2 = clearCachedM0Baseline(db, sessionId);
22687
+ let historianCatchUpSignaled = false;
22688
+ if (args.historianRunnable) {
22689
+ updateSessionMeta(db, sessionId, { compartmentInProgress: true });
22690
+ historianCatchUpSignaled = true;
22691
+ }
22692
+ if (!historianCatchUpSignaled) {
22693
+ return {
22694
+ ...NO_TRANSITION,
22695
+ recordToWrite: "on",
22696
+ invalidatedM0Baseline: invalidatedM0Baseline2
22697
+ };
22698
+ }
22699
+ setCompactionModeRecord(db, sessionId, "on_notice_pending");
22700
+ return {
22701
+ ...NO_TRANSITION,
22702
+ recordToWrite: "on",
22703
+ notice: COMPACTION_ON_WRAPUP_SUGGESTION,
22704
+ invalidatedM0Baseline: invalidatedM0Baseline2,
22705
+ historianCatchUpSignaled
22706
+ };
22707
+ }
22708
+ if (stored === "off")
22709
+ return NO_TRANSITION;
22710
+ if (stored === "off_cleanup_pending") {
22711
+ const markerCleanup2 = cleanupOffMarkers(sessionId);
22712
+ return {
22713
+ ...NO_TRANSITION,
22714
+ recordToWrite: markerCleanup2.verified ? "off" : null,
22715
+ markerCleanup: markerCleanup2
22716
+ };
22717
+ }
22718
+ let clearedSomething = false;
22719
+ const markerCleanup = cleanupOffMarkers(sessionId);
22720
+ if (markerCleanup.removedRows > 0)
22721
+ clearedSomething = true;
22722
+ if (getPersistedCompactionMarkerState(db, sessionId) !== null) {
22723
+ setPersistedCompactionMarkerState(db, sessionId, null);
22724
+ clearedSomething = true;
22725
+ }
22726
+ const pendingMarker = getPendingCompactionMarkerState(db, sessionId);
22727
+ if (pendingMarker !== null) {
22728
+ clearPendingCompactionMarkerStateIf(db, sessionId, pendingMarker);
22729
+ clearedSomething = true;
22730
+ }
22731
+ if (getOverflowState(db, sessionId).needsEmergencyRecovery) {
22732
+ clearEmergencyRecovery(db, sessionId);
22733
+ clearedSomething = true;
22734
+ }
22735
+ const channel2State = getChannel2NudgeState(db, sessionId);
22736
+ if (channel2State === "pending" || channel2State === "claimed") {
22737
+ setChannel2NudgeState(db, sessionId, "");
22738
+ clearedSomething = true;
22739
+ }
22740
+ if (getPendingOps(db, sessionId).length > 0) {
22741
+ clearPendingOps(db, sessionId);
22742
+ clearedSomething = true;
22743
+ }
22744
+ const invalidatedM0Baseline = clearCachedM0Baseline(db, sessionId);
22745
+ let clearedCompartmentInProgress = false;
22746
+ if (args.compartmentInProgress) {
22747
+ updateSessionMeta(db, sessionId, { compartmentInProgress: false });
22748
+ clearedCompartmentInProgress = true;
22749
+ }
22750
+ sessionLog(sessionId, `compaction-off transition: marker cleanup verified=${markerCleanup.verified}, removed=${markerCleanup.removedLineages} lineage(s)/${markerCleanup.removedRows} row(s), retained=${markerCleanup.retainedLineages}, clearedSomething=${clearedSomething}`);
22751
+ if (!markerCleanup.verified && !loggedUnverifiedMarkerCleanupRetry) {
22752
+ loggedUnverifiedMarkerCleanupRetry = true;
22753
+ sessionLog(sessionId, "compaction-off transition could not verify complete marker cleanup; durable cleanup retry will run on the next pass");
22754
+ }
22755
+ const notice = clearedSomething ? COMPACTION_OFF_FLIP_NOTICE : null;
22756
+ if (notice) {
22757
+ setCompactionModeRecord(db, sessionId, "off_notice_pending");
22758
+ } else if (!markerCleanup.verified) {
22759
+ setCompactionModeRecord(db, sessionId, "off_cleanup_pending");
22760
+ }
22761
+ return {
22762
+ recordToWrite: notice ? markerCleanup.verified ? "off" : "off_cleanup_pending" : markerCleanup.verified ? "off" : null,
22763
+ notice,
22764
+ invalidatedM0Baseline,
22765
+ historianCatchUpSignaled: false,
22766
+ clearedCompartmentInProgress,
22767
+ clearedSomething,
22768
+ markerCleanup
22769
+ };
22054
22770
  }
22055
- function resolveTodowriteAvailability(sessionId) {
22056
- return resolveToolAvailability(sessionId, TODOWRITE_TOOL);
22771
+ function commitCompactionModeRecord(db, sessionId, record) {
22772
+ setCompactionModeRecord(db, sessionId, record);
22057
22773
  }
22058
22774
 
22059
22775
  // src/hooks/magic-context/emergency-fail-closed.ts
@@ -22404,6 +23120,29 @@ function calibrateBuckets(input) {
22404
23120
  }
22405
23121
 
22406
23122
  // src/hooks/magic-context/final-wire-token-estimate.ts
23123
+ function compactWireLabel(value, fallback) {
23124
+ if (typeof value !== "string" || value.length === 0)
23125
+ return fallback;
23126
+ return value.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 32) || fallback;
23127
+ }
23128
+ function wirePartKind(part, role) {
23129
+ const rawType = part !== null && typeof part === "object" && typeof part.type === "string" ? part.type : "unknown";
23130
+ if (rawType === "tool_result" || rawType === "tool-result")
23131
+ return "toolresult";
23132
+ if (rawType === "tool_use" || rawType === "tool-use" || rawType === "tool-invocation") {
23133
+ return "tool";
23134
+ }
23135
+ if (role === "user" && rawType === "tool")
23136
+ return "toolresult";
23137
+ return compactWireLabel(rawType, "unknown");
23138
+ }
23139
+ function describeFinalWireTail(messages) {
23140
+ return `[${messages.slice(-3).map((message) => {
23141
+ const role = compactWireLabel(message.info.role, "unknown");
23142
+ const kinds = message.parts.map((part) => wirePartKind(part, role)).join("+") || "none";
23143
+ return `${role}:${kinds}`;
23144
+ }).join(", ")}]`;
23145
+ }
22407
23146
  function serializedTokens(value) {
22408
23147
  if (value === undefined)
22409
23148
  return 0;
@@ -25926,75 +26665,6 @@ ${hintText}`;
25926
26665
  }
25927
26666
  function clearAutoSearchForSession(_sessionId) {}
25928
26667
 
25929
- // src/hooks/magic-context/sentinel.ts
25930
- var WHOLE_MESSAGE_PLACEHOLDER_TEXT = "[dropped]";
25931
- function modelAcceptsEmptyContent(providerID) {
25932
- return providerID === "anthropic";
25933
- }
25934
- function variantChangeBustsProviderCache(providerID) {
25935
- if (providerID === undefined)
25936
- return true;
25937
- if (providerID === "anthropic")
25938
- return true;
25939
- if (providerID === "google-vertex-anthropic")
25940
- return true;
25941
- if (providerID.includes("bedrock"))
25942
- return true;
25943
- return false;
25944
- }
25945
- function makeSentinel(originalPart) {
25946
- const sentinel = {
25947
- type: "text",
25948
- text: ""
25949
- };
25950
- if (isRecord(originalPart)) {
25951
- if (originalPart.cache_control !== undefined) {
25952
- sentinel.cache_control = originalPart.cache_control;
25953
- }
25954
- if (originalPart.cacheControl !== undefined) {
25955
- sentinel.cacheControl = originalPart.cacheControl;
25956
- }
25957
- }
25958
- return sentinel;
25959
- }
25960
- function makeWholeMessageSentinel(providerID) {
25961
- return {
25962
- type: "text",
25963
- text: modelAcceptsEmptyContent(providerID) ? "" : WHOLE_MESSAGE_PLACEHOLDER_TEXT
25964
- };
25965
- }
25966
- function isSentinel(part) {
25967
- if (!isRecord(part))
25968
- return false;
25969
- if (part.type !== "text")
25970
- return false;
25971
- if (typeof part.text !== "string")
25972
- return false;
25973
- return part.text === "" || part.text === WHOLE_MESSAGE_PLACEHOLDER_TEXT;
25974
- }
25975
- function replaySentinelByMessageIds(messages, ids, providerID) {
25976
- if (ids.size === 0)
25977
- return { replayed: 0, missingIds: [] };
25978
- const seen = new Set;
25979
- let replayed = 0;
25980
- for (const msg of messages) {
25981
- const id = msg.info.id;
25982
- if (!id || !ids.has(id))
25983
- continue;
25984
- seen.add(id);
25985
- if (msg.parts.length === 1 && isSentinel(msg.parts[0]))
25986
- continue;
25987
- msg.parts.length = 0;
25988
- msg.parts.push(makeWholeMessageSentinel(providerID));
25989
- replayed++;
25990
- }
25991
- const missingIds = [];
25992
- for (const id of ids)
25993
- if (!seen.has(id))
25994
- missingIds.push(id);
25995
- return { replayed, missingIds };
25996
- }
25997
-
25998
26668
  // src/hooks/magic-context/drop-stale-reduce-calls.ts
25999
26669
  var STALE_TOOL_NAMES = new Set(["ctx_reduce"]);
26000
26670
  function isReduceToolPart(part) {
@@ -27039,6 +27709,14 @@ function computeSyntheticCallId(stateJson) {
27039
27709
  const hash = createHash10("sha256").update(stateJson).digest("hex").slice(0, 16);
27040
27710
  return `${SYNTHETIC_CALL_ID_PREFIX}${hash}`;
27041
27711
  }
27712
+ function isSyntheticTodoPart(part) {
27713
+ if (part === null || typeof part !== "object")
27714
+ return false;
27715
+ const p = part;
27716
+ if (p.syntheticTodoMarker === true)
27717
+ return true;
27718
+ return p.type === "tool" && p.tool === "todowrite" && typeof p.callID === "string" && p.callID.startsWith(SYNTHETIC_CALL_ID_PREFIX);
27719
+ }
27042
27720
  function parseTodoState(stateJson) {
27043
27721
  if (stateJson.length === 0)
27044
27722
  return null;
@@ -27778,6 +28456,74 @@ function injectPersistedTodoAnchor(messages, sessionId, messageId2, part) {
27778
28456
  }
27779
28457
  return injectSyntheticTodoAtHead(messages, sessionId, part);
27780
28458
  }
28459
+ function removeSyntheticTodoParts(messages) {
28460
+ for (let index = messages.length - 1;index >= 0; index -= 1) {
28461
+ const message = messages[index];
28462
+ if (!message)
28463
+ continue;
28464
+ const retainedParts = message.parts.filter((part) => !isSyntheticTodoPart(part));
28465
+ if (retainedParts.length === message.parts.length)
28466
+ continue;
28467
+ message.parts = retainedParts;
28468
+ if (message.info.id === TODO_HEAD_ANCHOR_ID && retainedParts.length === 0) {
28469
+ messages.splice(index, 1);
28470
+ }
28471
+ }
28472
+ }
28473
+ async function applyTodoSynthesis(args) {
28474
+ if (!args.fullFeatureMode || args.compactionOff)
28475
+ return 0;
28476
+ const persistedAnchor = getPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28477
+ let permissionDenied = cachedToolPermissionDenied(args.sessionId, "todowrite") ?? getPersistedTodoPermissionDenied(args.db, args.sessionId) ?? false;
28478
+ const toolsMapUnavailable = args.todowriteAvailability.frozen && !args.todowriteAvailability.callable;
28479
+ if (args.isCacheBustingPass && args.client && !toolsMapUnavailable) {
28480
+ try {
28481
+ permissionDenied = await todowritePermissionDenied(args.client, args.sessionId, args.activeAgent);
28482
+ setPersistedTodoPermissionDenied(args.db, args.sessionId, permissionDenied);
28483
+ } catch (error) {
28484
+ sessionLog(args.sessionId, "todowrite permission read failed; retaining the last successful verdict:", error);
28485
+ }
28486
+ }
28487
+ const todowriteUnavailable = toolsMapUnavailable || permissionDenied;
28488
+ if (args.isCacheBustingPass && todowriteUnavailable) {
28489
+ removeSyntheticTodoParts(args.messages);
28490
+ clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28491
+ if (persistedAnchor) {
28492
+ sessionLog(args.sessionId, "todowrite synthetic pair cleared on a cache-busting pass because the tool is denied");
28493
+ }
28494
+ return 0;
28495
+ }
28496
+ if (args.isCacheBustingPass) {
28497
+ const part = buildSyntheticTodoPart(args.sessionMeta.lastTodoState);
28498
+ const persistedInjection = part !== null && persistedAnchor && persistedAnchor.callId === part.callID ? injectPersistedTodoAnchor(args.messages, args.sessionId, persistedAnchor.messageId, part) : null;
28499
+ if (part === null) {
28500
+ if (persistedAnchor)
28501
+ clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28502
+ return 0;
28503
+ }
28504
+ if (persistedAnchor && persistedInjection?.injected) {
28505
+ if (persistedAnchor.stateJson.length === 0) {
28506
+ setPersistedTodoSyntheticAnchor(args.db, args.sessionId, persistedAnchor.callId, persistedAnchor.messageId, args.sessionMeta.lastTodoState);
28507
+ }
28508
+ return persistedInjection.prependedMessageCount;
28509
+ }
28510
+ const existingAssistantId = injectToolPartIntoLatestAssistant(args.messages, part);
28511
+ const injection = existingAssistantId === null ? injectSyntheticTodoAtHead(args.messages, args.sessionId, part) : {
28512
+ injected: true,
28513
+ messageId: existingAssistantId,
28514
+ prependedMessageCount: 0
28515
+ };
28516
+ setPersistedTodoSyntheticAnchor(args.db, args.sessionId, part.callID, injection.messageId, args.sessionMeta.lastTodoState);
28517
+ return injection.prependedMessageCount;
28518
+ }
28519
+ if (persistedAnchor && persistedAnchor.stateJson.length > 0) {
28520
+ const part = buildSyntheticTodoPart(persistedAnchor.stateJson);
28521
+ if (part !== null && part.callID === persistedAnchor.callId) {
28522
+ return injectPersistedTodoAnchor(args.messages, args.sessionId, persistedAnchor.messageId, part).prependedMessageCount;
28523
+ }
28524
+ }
28525
+ return 0;
28526
+ }
27781
28527
  function runRustModePostprocess(args) {
27782
28528
  if (!args.fullFeatureMode)
27783
28529
  return;
@@ -27934,18 +28680,19 @@ function finalizeMessageRepresentation(messages, resolvedProviderID, options) {
27934
28680
  return { clearedParts, mergedReasoningParts };
27935
28681
  }
27936
28682
  async function runPostTransformPhase(args) {
28683
+ const compactionOff = args.compactionOff === true;
27937
28684
  const pendingMaterializationAtPassStart = args.pendingMaterializationSessions.has(args.sessionId);
27938
28685
  const deferredMaterializationAtPassStart = args.deferredMaterializationSessions.has(args.sessionId);
27939
28686
  const isExplicitFlush = pendingMaterializationAtPassStart;
27940
28687
  const deferredMaterializationWasPending = deferredMaterializationAtPassStart;
27941
28688
  const alreadyRanThisTurn = args.currentTurnId !== null && args.lastHeuristicsTurnId.get(args.sessionId) === args.currentTurnId;
27942
- const forceMaterialization = args.fullFeatureMode && args.contextUsage.percentage >= args.forceMaterializationPercentage;
27943
- const emergencyDropEligible = args.contextUsage.percentage >= args.forceMaterializationPercentage;
28689
+ const forceMaterialization = args.fullFeatureMode && !compactionOff && args.contextUsage.percentage >= args.forceMaterializationPercentage;
28690
+ const emergencyDropEligible = !compactionOff && args.contextUsage.percentage >= args.forceMaterializationPercentage;
27944
28691
  const activeCompartmentRun = args.canRunCompartments ? getActiveCompartmentRun(args.sessionId) : undefined;
27945
28692
  const compartmentRunning = args.canRunCompartments && !args.awaitedCompartmentRun && activeCompartmentRun !== undefined;
27946
28693
  const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
27947
28694
  const materializationRequested = isExplicitFlush || deferredMaterialize;
27948
- const m0M1EnabledForFold = args.fullFeatureMode && args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory);
28695
+ const m0M1EnabledForFold = args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory) && (args.fullFeatureMode || compactionOff);
27949
28696
  const m0HardFoldThisPass = m0M1EnabledForFold && args.m0M1 ? mustMaterialize({
27950
28697
  db: args.db,
27951
28698
  sessionId: args.sessionId,
@@ -27955,12 +28702,23 @@ async function runPostTransformPhase(args) {
27955
28702
  hardSignals: args.m0M1.hardSignals
27956
28703
  }).value : false;
27957
28704
  const bypassCompartmentGate = forceMaterialization || m0HardFoldThisPass;
27958
- const shouldReadPendingOps = materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning;
28705
+ const shouldReadPendingOps = !compactionOff && (materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning);
27959
28706
  const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
27960
28707
  const hasPendingUserOps = pendingOps.length > 0;
27961
- const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || bypassCompartmentGate);
27962
- const shouldRunHeuristics = (!compartmentRunning || bypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
28708
+ const shouldApplyPendingOps = !compactionOff && (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || bypassCompartmentGate);
28709
+ const shouldRunHeuristics = !compactionOff && (!compartmentRunning || bypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
27963
28710
  const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
28711
+ if (isCacheBustingPass && args.client && args.ctxReduceAvailability.callable && !hasLoggedCtxReducePermissionDeny(args.sessionId)) {
28712
+ try {
28713
+ const denied = await resolveToolPermissionDenied(args.client, args.sessionId, "ctx_reduce", args.activeAgent);
28714
+ if (denied) {
28715
+ markCtxReducePermissionDenyLogged(args.sessionId);
28716
+ sessionLog(args.sessionId, "ctx_reduce permission is denied by OpenCode; frozen guidance remains until session restart");
28717
+ }
28718
+ } catch (error) {
28719
+ sessionLog(args.sessionId, "ctx_reduce permission read failed (ignored):", error);
28720
+ }
28721
+ }
27964
28722
  const canUseEmptySentinels = modelAcceptsEmptyContent(args.resolvedProviderID);
27965
28723
  if (shouldRunHeuristics) {
27966
28724
  const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
@@ -27972,7 +28730,7 @@ async function runPostTransformPhase(args) {
27972
28730
  }
27973
28731
  if (compartmentRunning && hasPendingUserOps) {
27974
28732
  if (bypassCompartmentGate) {
27975
- const bypassReason = forceMaterialization ? "emergency >=85%" : "m0 hard fold";
28733
+ const bypassReason = forceMaterialization ? `emergency >=${args.forceMaterializationPercentage}%` : "m0 hard fold";
27976
28734
  sessionLog(args.sessionId, `transform: compartment-gate bypass (${bypassReason}) — applying ${pendingOps.length} pending ops while compartment agent runs (${args.contextUsage.percentage.toFixed(1)}%)`);
27977
28735
  } else {
27978
28736
  sessionLog(args.sessionId, "transform: deferring pending ops — compartment agent in progress");
@@ -28078,7 +28836,7 @@ async function runPostTransformPhase(args) {
28078
28836
  if (args.schedulerDecision === "execute" && !materializationRequested) {
28079
28837
  updateSessionMeta(args.db, args.sessionId, { lastResponseTime: Date.now() });
28080
28838
  }
28081
- const toolReclaimExecutePass = args.schedulerDecision === "execute";
28839
+ const toolReclaimExecutePass = !compactionOff && args.schedulerDecision === "execute";
28082
28840
  const alreadyMutatingThisPass = pendingOpsDidMutate || heuristicOrReasoningDidMutate;
28083
28841
  let autoReclaimTargetCount = 0;
28084
28842
  let autoReclaimDidMutate = false;
@@ -28162,7 +28920,7 @@ async function runPostTransformPhase(args) {
28162
28920
  sessionLog(args.sessionId, "transform failed applying pending operations:", error);
28163
28921
  updateSessionMeta(args.db, args.sessionId, { lastTransformError: getErrorMessage(error) });
28164
28922
  }
28165
- if (canUseEmptySentinels) {
28923
+ if (canUseEmptySentinels && !compactionOff) {
28166
28924
  try {
28167
28925
  const t8 = performance.now();
28168
28926
  const frozenStaleReduceIds = getStaleReduceStrippedIds(args.db, args.sessionId);
@@ -28179,7 +28937,7 @@ async function runPostTransformPhase(args) {
28179
28937
  sessionLog(args.sessionId, "transform failed dropping stale ctx_reduce calls:", error);
28180
28938
  }
28181
28939
  }
28182
- if (canUseEmptySentinels) {
28940
+ if (canUseEmptySentinels && !compactionOff) {
28183
28941
  try {
28184
28942
  const tImg = performance.now();
28185
28943
  const frozenImageIds = getProcessedImageStrippedIds(args.db, args.sessionId);
@@ -28214,7 +28972,8 @@ async function runPostTransformPhase(args) {
28214
28972
  temporalAwareness: args.m0M1.temporalAwareness,
28215
28973
  isCacheBustingPass,
28216
28974
  hardSignals: args.m0M1.hardSignals,
28217
- muralEnabled: args.m0M1.muralEnabled
28975
+ muralEnabled: args.m0M1.muralEnabled,
28976
+ compactionOff
28218
28977
  });
28219
28978
  if (result.injected) {
28220
28979
  m0M1InjectedThisPass = true;
@@ -28239,7 +28998,7 @@ async function runPostTransformPhase(args) {
28239
28998
  clearInjectionCache(args.sessionId);
28240
28999
  }
28241
29000
  logTransformTiming(args.sessionId, "pp.injectM0M1", tInjectM0M1);
28242
- } else if (args.fullFeatureMode && args.pendingCompartmentInjection) {
29001
+ } else if (args.fullFeatureMode && !compactionOff && args.pendingCompartmentInjection) {
28243
29002
  const compartmentResult = renderCompartmentInjection(args.sessionId, args.messages, args.pendingCompartmentInjection);
28244
29003
  if (compartmentResult.injected) {
28245
29004
  prependedMessageCount += compartmentResult.prependedMessageCount;
@@ -28250,7 +29009,7 @@ async function runPostTransformPhase(args) {
28250
29009
  }
28251
29010
  }
28252
29011
  }
28253
- {
29012
+ if (!compactionOff) {
28254
29013
  const tPlaceholder = performance.now();
28255
29014
  const persistedIds = getStrippedPlaceholderIds(args.db, args.sessionId);
28256
29015
  if (persistedIds.size > 0) {
@@ -28283,7 +29042,7 @@ async function runPostTransformPhase(args) {
28283
29042
  logTransformTiming(args.sessionId, "pp.placeholderNeutralize", tPlaceholder);
28284
29043
  }
28285
29044
  const tNudgeBlock = performance.now();
28286
- if (args.fullFeatureMode) {
29045
+ if (args.fullFeatureMode && !compactionOff) {
28287
29046
  for (const anchor of getNoteNudgeAnchors(args.db, args.sessionId)) {
28288
29047
  appendReminderToUserMessageById(args.messages, anchor.messageId, anchor.text);
28289
29048
  }
@@ -28328,12 +29087,14 @@ async function runPostTransformPhase(args) {
28328
29087
  }
28329
29088
  }
28330
29089
  }
28331
- reconcileMarkerRepresentation(args.messages, getPersistedCompactionMarkerState(args.db, args.sessionId), {
28332
- db: args.db,
28333
- sessionId: args.sessionId,
28334
- tagger: args.tagger,
28335
- ctxReduceAvailability: args.ctxReduceAvailability
28336
- });
29090
+ if (!compactionOff) {
29091
+ reconcileMarkerRepresentation(args.messages, getPersistedCompactionMarkerState(args.db, args.sessionId), {
29092
+ db: args.db,
29093
+ sessionId: args.sessionId,
29094
+ tagger: args.tagger,
29095
+ ctxReduceAvailability: args.ctxReduceAvailability
29096
+ });
29097
+ }
28337
29098
  const deferredHistoryDrainEligible = historyWasConsumedThisPass && args.deferredHistoryWasPendingAtPassStart && !suppressV12HistoryDrain;
28338
29099
  if (deferredHistoryDrainEligible) {
28339
29100
  args.deferredHistoryRefreshSessions.delete(args.sessionId);
@@ -28357,42 +29118,19 @@ async function runPostTransformPhase(args) {
28357
29118
  sessionLog(args.sessionId, `note-nudge delivery skipped wire append: ${outcome.kind}`);
28358
29119
  }
28359
29120
  }
28360
- if (args.fullFeatureMode) {
28361
- const persistedAnchor = getPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28362
- const todowriteUnavailable = args.todowriteAvailability.frozen && !args.todowriteAvailability.callable;
28363
- if (isCacheBustingPass && todowriteUnavailable) {
28364
- if (persistedAnchor) {
28365
- clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28366
- }
28367
- } else if (isCacheBustingPass) {
28368
- const part = buildSyntheticTodoPart(args.sessionMeta.lastTodoState);
28369
- const persistedInjection = part !== null && persistedAnchor && persistedAnchor.callId === part.callID ? injectPersistedTodoAnchor(args.messages, args.sessionId, persistedAnchor.messageId, part) : null;
28370
- if (part === null) {
28371
- if (persistedAnchor) {
28372
- clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28373
- }
28374
- } else if (persistedAnchor && persistedInjection?.injected) {
28375
- prependedMessageCount += persistedInjection.prependedMessageCount;
28376
- if (persistedAnchor.stateJson.length === 0) {
28377
- setPersistedTodoSyntheticAnchor(args.db, args.sessionId, persistedAnchor.callId, persistedAnchor.messageId, args.sessionMeta.lastTodoState);
28378
- }
28379
- } else {
28380
- const existingAssistantId = injectToolPartIntoLatestAssistant(args.messages, part);
28381
- const injection = existingAssistantId === null ? injectSyntheticTodoAtHead(args.messages, args.sessionId, part) : {
28382
- injected: true,
28383
- messageId: existingAssistantId,
28384
- prependedMessageCount: 0
28385
- };
28386
- prependedMessageCount += injection.prependedMessageCount;
28387
- setPersistedTodoSyntheticAnchor(args.db, args.sessionId, part.callID, injection.messageId, args.sessionMeta.lastTodoState);
28388
- }
28389
- } else if (persistedAnchor && persistedAnchor.stateJson.length > 0) {
28390
- const part = buildSyntheticTodoPart(persistedAnchor.stateJson);
28391
- if (part !== null && part.callID === persistedAnchor.callId) {
28392
- const injection = injectPersistedTodoAnchor(args.messages, args.sessionId, persistedAnchor.messageId, part);
28393
- prependedMessageCount += injection.prependedMessageCount;
28394
- }
28395
- }
29121
+ if (args.fullFeatureMode && !compactionOff) {
29122
+ prependedMessageCount += await applyTodoSynthesis({
29123
+ db: args.db,
29124
+ sessionId: args.sessionId,
29125
+ messages: args.messages,
29126
+ fullFeatureMode: args.fullFeatureMode,
29127
+ compactionOff,
29128
+ isCacheBustingPass,
29129
+ sessionMeta: args.sessionMeta,
29130
+ todowriteAvailability: args.todowriteAvailability,
29131
+ client: args.client,
29132
+ activeAgent: args.activeAgent
29133
+ });
28396
29134
  }
28397
29135
  logTransformTiming(args.sessionId, "pp.noteAndTodoSynthesis", tNoteAndTodo);
28398
29136
  if (args.compartmentInjectionRebuiltFromDb && args.pendingCompartmentInjection) {
@@ -28529,7 +29267,7 @@ class MemoryAuthorityUnavailableError extends Error {
28529
29267
  var RUST_FAILURE_PARK_THRESHOLD = 3;
28530
29268
  var RUST_PROBE_INTERVAL = 5;
28531
29269
  var RUST_SEND_TIMEOUT_MS = 15000;
28532
- function isRecord2(value) {
29270
+ function isRecord3(value) {
28533
29271
  return value !== null && typeof value === "object";
28534
29272
  }
28535
29273
  function replaceMessagesInPlace(output, next) {
@@ -28539,9 +29277,9 @@ function replaceMessagesInPlace(output, next) {
28539
29277
  return target;
28540
29278
  }
28541
29279
  function messageInfo2(value) {
28542
- if (!isRecord2(value))
29280
+ if (!isRecord3(value))
28543
29281
  return {};
28544
- return isRecord2(value.info) ? value.info : value;
29282
+ return isRecord3(value.info) ? value.info : value;
28545
29283
  }
28546
29284
  function messageIdOf(message) {
28547
29285
  const id = messageInfo2(message).id;
@@ -28735,7 +29473,7 @@ function isSyntheticUserMessage(message) {
28735
29473
  if (!message || messageInfo2(message).role !== "user" || !Array.isArray(message.parts)) {
28736
29474
  return false;
28737
29475
  }
28738
- return message.parts.length > 0 && message.parts.every((part) => isRecord2(part) && (part.synthetic === true || part.ignored === true));
29476
+ return message.parts.length > 0 && message.parts.every((part) => isRecord3(part) && (part.synthetic === true || part.ignored === true));
28739
29477
  }
28740
29478
  function observeSyntheticTurn(state, messages) {
28741
29479
  const newest = newestUserMessage(messages);
@@ -28755,16 +29493,16 @@ function observeSyntheticTurn(state, messages) {
28755
29493
  function assertNativeBoundary(output, sessionId, boundaryId) {
28756
29494
  const first = output.find((message) => messageInfo2(message).role !== "system");
28757
29495
  const info = messageInfo2(first);
28758
- const parts = isRecord2(first) && Array.isArray(first.parts) ? first.parts : [];
28759
- const synthetic = parts.length > 0 && parts.every((part) => isRecord2(part) && part.synthetic === true);
29496
+ const parts = isRecord3(first) && Array.isArray(first.parts) ? first.parts : [];
29497
+ const synthetic = parts.length > 0 && parts.every((part) => isRecord3(part) && part.synthetic === true);
28760
29498
  if (info.role === "user" && info.sessionID === sessionId && synthetic)
28761
29499
  return;
28762
29500
  throw new Error(`rust transform wire invariant failed: boundary=${boundaryId} expected a synthetic m0 user message scoped to session ${sessionId}`);
28763
29501
  }
28764
29502
  function responseValue(response) {
28765
- if (isRecord2(response) && isRecord2(response.result))
29503
+ if (isRecord3(response) && isRecord3(response.result))
28766
29504
  return response.result;
28767
- if (isRecord2(response))
29505
+ if (isRecord3(response))
28768
29506
  return response;
28769
29507
  throw new Error("module transform returned a non-object response");
28770
29508
  }
@@ -28773,7 +29511,7 @@ function noteDeliveryPassIds(response) {
28773
29511
  return [];
28774
29512
  return [
28775
29513
  ...new Set(response.note_deliveries.flatMap((delivery) => {
28776
- if (!isRecord2(delivery))
29514
+ if (!isRecord3(delivery))
28777
29515
  return [];
28778
29516
  const passId = delivery.transform_pass_id;
28779
29517
  return typeof passId === "string" && passId.length > 0 ? [passId] : [];
@@ -28783,7 +29521,7 @@ function noteDeliveryPassIds(response) {
28783
29521
  function modelFromMessages(messages) {
28784
29522
  for (let index = messages.length - 1;index >= 0; index -= 1) {
28785
29523
  const info = messages[index]?.info;
28786
- const model = isRecord2(info?.model) ? info.model : undefined;
29524
+ const model = isRecord3(info?.model) ? info.model : undefined;
28787
29525
  if (typeof model?.providerID === "string" && typeof model.modelID === "string") {
28788
29526
  return { providerID: model.providerID, modelID: model.modelID };
28789
29527
  }
@@ -28807,6 +29545,7 @@ function ensureState(states, sessionId) {
28807
29545
  ordinalMemoAnchor: null,
28808
29546
  ordinalMemoStoredCount: null,
28809
29547
  ordinalMemoCanonicalCount: 0,
29548
+ ordinalContinuationBase: null,
28810
29549
  seedPassPending: true,
28811
29550
  failureCount: 0,
28812
29551
  parkCount: 0,
@@ -28861,8 +29600,8 @@ function passUsage(usage, limit) {
28861
29600
  };
28862
29601
  }
28863
29602
  function directiveTextOf(response) {
28864
- const directives = isRecord2(response.host_directives) ? response.host_directives : undefined;
28865
- const channel2 = isRecord2(directives?.channel2_nudge) ? directives.channel2_nudge : undefined;
29603
+ const directives = isRecord3(response.host_directives) ? response.host_directives : undefined;
29604
+ const channel2 = isRecord3(directives?.channel2_nudge) ? directives.channel2_nudge : undefined;
28866
29605
  return typeof channel2?.text === "string" && channel2.text.length > 0 ? channel2.text : undefined;
28867
29606
  }
28868
29607
  function isNeedFullSync(response) {
@@ -28871,7 +29610,7 @@ function isNeedFullSync(response) {
28871
29610
  function canonicalizeForChecksum(value) {
28872
29611
  if (Array.isArray(value))
28873
29612
  return value.map(canonicalizeForChecksum);
28874
- if (!isRecord2(value))
29613
+ if (!isRecord3(value))
28875
29614
  return value;
28876
29615
  return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalizeForChecksum(value[key])]));
28877
29616
  }
@@ -28887,7 +29626,7 @@ function authoritySeedRows(db, projectPath, domain) {
28887
29626
  WHERE sp.session_id = n.session_id AND sp.project_path = ?
28888
29627
  ))
28889
29628
  ORDER BY n.id ASC`).all(projectPath, projectPath);
28890
- const memoryRows = snapshots.filter(isRecord2);
29629
+ const memoryRows = snapshots.filter(isRecord3);
28891
29630
  const mappings = domain === "memories" ? getMemoryVerifications(db, memoryRows.map((row) => Number(row.id))) : new Map;
28892
29631
  return memoryRows.map((snapshot) => {
28893
29632
  const id = Number(snapshot.id);
@@ -28912,11 +29651,36 @@ async function prepareRustMemoryAuthority(args) {
28912
29651
  throw new MemoryAuthorityUnavailableError("the module does not expose authority.status, authority.prepare, and authority.seed");
28913
29652
  }
28914
29653
  const authorityModule = {
28915
- authorityStatus: (request2) => module.authorityStatus({ ...request2, projectRoot }),
28916
- authorityPrepare: (request2) => module.authorityPrepare({ ...request2, projectRoot }),
28917
- authoritySeed: (request2) => module.authoritySeed({ ...request2, projectRoot }),
28918
- authorityDrain: module.authorityDrain ? (request2) => module.authorityDrain({ ...request2, projectRoot }) : undefined,
28919
- mirrorPull: module.mirrorPull ? (request2) => module.mirrorPull({ ...request2, projectRoot }) : undefined
29654
+ authorityStatus: (request2) => {
29655
+ const method = module.authorityStatus;
29656
+ if (!method)
29657
+ throw new MemoryAuthorityUnavailableError("authority.status unavailable");
29658
+ return method.call(module, { ...request2, projectRoot });
29659
+ },
29660
+ authorityPrepare: (request2) => {
29661
+ const method = module.authorityPrepare;
29662
+ if (!method)
29663
+ throw new MemoryAuthorityUnavailableError("authority.prepare unavailable");
29664
+ return method.call(module, { ...request2, projectRoot });
29665
+ },
29666
+ authoritySeed: (request2) => {
29667
+ const method = module.authoritySeed;
29668
+ if (!method)
29669
+ throw new MemoryAuthorityUnavailableError("authority.seed unavailable");
29670
+ return method.call(module, { ...request2, projectRoot });
29671
+ },
29672
+ authorityDrain: module.authorityDrain ? (request2) => {
29673
+ const method = module.authorityDrain;
29674
+ if (!method)
29675
+ throw new MemoryAuthorityUnavailableError("authority.drain unavailable");
29676
+ return method.call(module, { ...request2, projectRoot });
29677
+ } : undefined,
29678
+ mirrorPull: module.mirrorPull ? (request2) => {
29679
+ const method = module.mirrorPull;
29680
+ if (!method)
29681
+ throw new MemoryAuthorityUnavailableError("mirror.pull unavailable");
29682
+ return method.call(module, { ...request2, projectRoot });
29683
+ } : undefined
28920
29684
  };
28921
29685
  const contextStoreUuid = ensureContextStoreUuid(db);
28922
29686
  const domains = ["memories", "notes"];
@@ -28942,7 +29706,7 @@ async function prepareRustMemoryAuthority(args) {
28942
29706
  projectPath,
28943
29707
  domain,
28944
29708
  module: authorityModule,
28945
- checksum: () => checksumSeedRows(db.prepare(`SELECT * FROM ${domain === "memories" ? "memories" : "notes"} WHERE project_path = ? ORDER BY id ASC`).all(projectPath).filter(isRecord2))
29709
+ checksum: () => checksumSeedRows(db.prepare(`SELECT * FROM ${domain === "memories" ? "memories" : "notes"} WHERE project_path = ? ORDER BY id ASC`).all(projectPath).filter(isRecord3))
28946
29710
  });
28947
29711
  if (!("code" in drained))
28948
29712
  break;
@@ -29051,6 +29815,13 @@ function buildTransformBody(args) {
29051
29815
  caveman_enabled: args.passInputs.caveman_enabled === true,
29052
29816
  caveman_min_chars: args.passInputs.caveman_min_chars ?? 500,
29053
29817
  cache_ttl: args.passInputs.cache_ttl,
29818
+ lineage_switched: args.passInputs.lineage_switched === true,
29819
+ descent_edge_id: args.passInputs.descent_edge_id,
29820
+ prior_conversation_key: args.passInputs.prior_conversation_key,
29821
+ prior_epoch: args.passInputs.prior_epoch,
29822
+ new_epoch: args.passInputs.new_epoch,
29823
+ constituents: args.passInputs.constituents,
29824
+ compaction_observed: args.passInputs.compaction_observed === true,
29054
29825
  pass_inputs: args.passInputs,
29055
29826
  declared_trim: args.declaredTrim
29056
29827
  };
@@ -29282,7 +30053,7 @@ function createRustModeTransform(deps, options) {
29282
30053
  decision = typeof response.decision === "string" ? response.decision : typeof response.action === "string" ? response.action : typeof response.status === "string" ? response.status : "unknown";
29283
30054
  servedFrom = typeof response.served_from === "string" ? response.served_from : "unknown";
29284
30055
  materializeReason = typeof response.materialize_reason === "string" && response.materialize_reason.length > 0 ? response.materialize_reason : "none";
29285
- const timings2 = isRecord2(response.timings) ? response.timings : undefined;
30056
+ const timings2 = isRecord3(response.timings) ? response.timings : undefined;
29286
30057
  const total = timings2?.total;
29287
30058
  moduleElapsedMs = typeof total === "number" && Number.isFinite(total) ? total : 0;
29288
30059
  if (timings2 && moduleElapsedMs >= 1000) {
@@ -29383,10 +30154,10 @@ function createRustModeTransform(deps, options) {
29383
30154
  continue;
29384
30155
  const prior = state.idOrdinalMemo.get(priorId);
29385
30156
  if (prior !== undefined)
29386
- return prior;
30157
+ return Math.max(prior, state.ordinalContinuationBase ?? 0);
29387
30158
  }
29388
- return state.ordinalMemoCanonicalCount;
29389
- })() : undefined;
30159
+ return Math.max(state.ordinalMemoCanonicalCount, state.ordinalContinuationBase ?? 0);
30160
+ })() : state.ordinalContinuationBase ?? undefined;
29390
30161
  const ordinalStartedAt = performance.now();
29391
30162
  let resolved = await resolveOrdinalsForModule({
29392
30163
  sessionId,
@@ -29412,7 +30183,8 @@ function createRustModeTransform(deps, options) {
29412
30183
  memo: state.idOrdinalMemo,
29413
30184
  memoAnchor: state.ordinalMemoAnchor,
29414
30185
  memoStoredCount: state.ordinalMemoStoredCount,
29415
- memoCanonicalCount: state.ordinalMemoCanonicalCount
30186
+ memoCanonicalCount: state.ordinalMemoCanonicalCount,
30187
+ provisionalBase: state.ordinalContinuationBase ?? undefined
29416
30188
  });
29417
30189
  logStage(sessionId, "ordinalResolve", fullOrdinalStartedAt, timings, "fallback=clean_full");
29418
30190
  }
@@ -29454,10 +30226,11 @@ function createRustModeTransform(deps, options) {
29454
30226
  };
29455
30227
  }
29456
30228
  }
30229
+ const stateSyncCapabilities = options.moduleClient.stateSyncCapabilities;
29457
30230
  const stateSyncResult = await syncModuleState({
29458
30231
  client: {
29459
30232
  call: callModule,
29460
- stateSyncCapabilities: options.moduleClient.stateSyncCapabilities ? (capabilityArgs) => options.moduleClient.stateSyncCapabilities(capabilityArgs) : undefined
30233
+ stateSyncCapabilities: stateSyncCapabilities ? (capabilityArgs) => stateSyncCapabilities.call(options.moduleClient, capabilityArgs) : undefined
29461
30234
  },
29462
30235
  state,
29463
30236
  pass: syncPass,
@@ -29591,7 +30364,8 @@ function createRustModeTransform(deps, options) {
29591
30364
  memo: state.idOrdinalMemo,
29592
30365
  memoAnchor: state.ordinalMemoAnchor,
29593
30366
  memoStoredCount: state.ordinalMemoStoredCount,
29594
- memoCanonicalCount: state.ordinalMemoCanonicalCount
30367
+ memoCanonicalCount: state.ordinalMemoCanonicalCount,
30368
+ provisionalBase: state.ordinalContinuationBase ?? undefined
29595
30369
  });
29596
30370
  logStage(sessionId, "ordinalResolve", retryOrdinalStartedAt, timings, "retry=full");
29597
30371
  if (!retryResolved.ok) {
@@ -29741,6 +30515,16 @@ function createRustModeTransform(deps, options) {
29741
30515
  sessionLog(sessionId, "rust note delivery ack failed (will retry):", ackError);
29742
30516
  }
29743
30517
  }
30518
+ const ordinalContinuationBase = response.ordinal_continuation_base;
30519
+ if (typeof ordinalContinuationBase === "number" && Number.isSafeInteger(ordinalContinuationBase) && ordinalContinuationBase > 0) {
30520
+ if (state.ordinalContinuationBase === null) {
30521
+ for (const [messageId2, ordinal] of state.idOrdinalMemo) {
30522
+ state.idOrdinalMemo.set(messageId2, ordinal + ordinalContinuationBase);
30523
+ }
30524
+ state.ordinalMemoCanonicalCount += ordinalContinuationBase;
30525
+ }
30526
+ state.ordinalContinuationBase = ordinalContinuationBase;
30527
+ }
29744
30528
  if (!stateSyncRetryBusy) {
29745
30529
  state.initialized = true;
29746
30530
  state.seedPassPending = false;
@@ -29774,13 +30558,14 @@ function createRustModeTransform(deps, options) {
29774
30558
  sessionLog(sessionId, "rust memory mirror-back failed (ignored):", error);
29775
30559
  }
29776
30560
  }
29777
- if (options.moduleClient.getCompartmentsAfter) {
30561
+ const getCompartmentsAfter = options.moduleClient.getCompartmentsAfter;
30562
+ if (getCompartmentsAfter) {
29778
30563
  try {
29779
30564
  await mirrorModuleCompartments({
29780
30565
  db: deps.db,
29781
30566
  sessionId,
29782
30567
  reader: {
29783
- getCompartmentsAfter: (mirroredSessionId, afterSequence) => options.moduleClient.getCompartmentsAfter(mirroredSessionId, afterSequence)
30568
+ getCompartmentsAfter: (mirroredSessionId, afterSequence) => getCompartmentsAfter.call(options.moduleClient, mirroredSessionId, afterSequence)
29784
30569
  }
29785
30570
  });
29786
30571
  } catch (error) {
@@ -29838,7 +30623,7 @@ function createRustModeTransform(deps, options) {
29838
30623
  // src/hooks/magic-context/transform-compartment-phase.ts
29839
30624
  function runCompartmentPhase(args) {
29840
30625
  const historianRunnable = args.historianRunnable !== false;
29841
- const willReadRawHistory = historianRunnable && args.canRunCompartments && getActiveCompartmentRun(args.sessionId) === undefined && (args.sessionMeta.compartmentInProgress || !args.skipAwaitForThisPass && args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE);
30626
+ const willReadRawHistory = historianRunnable && !args.compactionOff && args.canRunCompartments && getActiveCompartmentRun(args.sessionId) === undefined && (args.sessionMeta.compartmentInProgress || !args.skipAwaitForThisPass && args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE);
29842
30627
  if (!willReadRawHistory) {
29843
30628
  return runCompartmentPhaseImpl(args);
29844
30629
  }
@@ -29862,6 +30647,21 @@ async function runCompartmentPhaseImpl(args) {
29862
30647
  let justAwaitedPublication = false;
29863
30648
  let rebuiltHistoryThisPass = false;
29864
30649
  const historianRunnable = args.historianRunnable !== false;
30650
+ if (args.compactionOff) {
30651
+ if (args.sessionMeta.compartmentInProgress) {
30652
+ sessionLog(args.sessionId, "transform: compaction off; clearing stale compartmentInProgress flag");
30653
+ updateSessionMeta(args.db, args.sessionId, { compartmentInProgress: false });
30654
+ compartmentInProgress = false;
30655
+ }
30656
+ return {
30657
+ pendingCompartmentInjection,
30658
+ awaitedCompartmentRun: false,
30659
+ compartmentInProgress,
30660
+ published,
30661
+ justAwaitedPublication,
30662
+ rebuiltHistoryThisPass
30663
+ };
30664
+ }
29865
30665
  let rawEligibility = null;
29866
30666
  let lastObservedCompartmentEnd = -1;
29867
30667
  let cachedBoundarySnapshot = null;
@@ -30047,12 +30847,31 @@ function clearMessageTokensCache(sessionId, messageId2) {
30047
30847
  cache.delete(messageId2);
30048
30848
  }
30049
30849
  var recordedSessionProjectIdentity = new BoundedSessionMap(MESSAGE_TOKENS_CACHE_MAX);
30850
+ function activeAgentFromMessages(messages) {
30851
+ for (let index = messages.length - 1;index >= 0; index -= 1) {
30852
+ const info = messages[index]?.info;
30853
+ if (info?.role !== "user")
30854
+ continue;
30855
+ return typeof info.agent === "string" && info.agent.length > 0 ? info.agent : undefined;
30856
+ }
30857
+ return;
30858
+ }
30050
30859
  function deriveTaggerLoadFloor(messages, sessionId, db) {
30051
30860
  return deriveTagLoadFloor(db, sessionId, function* () {
30052
30861
  for (const message of messages)
30053
30862
  yield message.info?.id;
30054
30863
  }());
30055
30864
  }
30865
+ function computeHardCacheExpired(cacheTtl, lastResponseTime, now, onInvalid) {
30866
+ let ttlMs;
30867
+ try {
30868
+ ttlMs = parseCacheTtl(cacheTtl);
30869
+ } catch (error) {
30870
+ onInvalid?.(error);
30871
+ ttlMs = 5 * 60 * 1000;
30872
+ }
30873
+ return lastResponseTime > 0 && now - lastResponseTime > ttlMs;
30874
+ }
30056
30875
  function findLastAssistantModel(messages) {
30057
30876
  for (let i = messages.length - 1;i >= 0; i--) {
30058
30877
  const info = messages[i].info;
@@ -30078,19 +30897,22 @@ var tsAuthorityRecoveryStateByProject = new Map;
30078
30897
  var tsAuthorityMismatchLoggedProjects = new Set;
30079
30898
  var tsAuthorityUnreachableLoggedProjects = new Set;
30080
30899
  function authorityModuleForProject(module, projectRoot) {
30081
- if (!module.authorityStatus || !module.authorityDrain || !module.mirrorPull) {
30900
+ const authorityStatus = module.authorityStatus;
30901
+ const authorityDrain = module.authorityDrain;
30902
+ const mirrorPull = module.mirrorPull;
30903
+ if (!authorityStatus || !authorityDrain || !mirrorPull) {
30082
30904
  throw new Error("the module does not expose authority.status, authority.drain, and mirror.pull");
30083
30905
  }
30084
30906
  return {
30085
- authorityStatus: (request2) => module.authorityStatus({ ...request2, projectRoot }),
30907
+ authorityStatus: (request2) => authorityStatus.call(module, { ...request2, projectRoot }),
30086
30908
  authorityPrepare: (request2) => {
30087
30909
  if (!module.authorityPrepare) {
30088
30910
  throw new Error("the module does not expose authority.prepare");
30089
30911
  }
30090
30912
  return module.authorityPrepare({ ...request2, projectRoot });
30091
30913
  },
30092
- authorityDrain: (request2) => module.authorityDrain({ ...request2, projectRoot }),
30093
- mirrorPull: (request2) => module.mirrorPull({ ...request2, projectRoot })
30914
+ authorityDrain: (request2) => authorityDrain.call(module, { ...request2, projectRoot }),
30915
+ mirrorPull: (request2) => mirrorPull.call(module, { ...request2, projectRoot })
30094
30916
  };
30095
30917
  }
30096
30918
  async function recoverTsAuthorityProject(args) {
@@ -30142,11 +30964,12 @@ function scheduleTsAuthorityRecovery(args) {
30142
30964
  return;
30143
30965
  if (tsAuthorityRecoveryStateByProject.has(args.projectPath))
30144
30966
  return;
30967
+ const module = args.module;
30145
30968
  if (!tsAuthorityMismatchLoggedProjects.has(args.projectPath)) {
30146
30969
  tsAuthorityMismatchLoggedProjects.add(args.projectPath);
30147
30970
  log(`[magic-context] project ${args.projectPath} is module-authority-managed but transform_mode is TS; draining authority back to TypeScript`);
30148
30971
  }
30149
- if (!args.module) {
30972
+ if (!module) {
30150
30973
  tsAuthorityRecoveryStateByProject.set(args.projectPath, "complete");
30151
30974
  if (!tsAuthorityUnreachableLoggedProjects.has(args.projectPath)) {
30152
30975
  tsAuthorityUnreachableLoggedProjects.add(args.projectPath);
@@ -30155,7 +30978,7 @@ function scheduleTsAuthorityRecovery(args) {
30155
30978
  return;
30156
30979
  }
30157
30980
  tsAuthorityRecoveryStateByProject.set(args.projectPath, "running");
30158
- Promise.resolve().then(() => recoverTsAuthorityProject({ ...args, module: args.module })).then((outcome) => {
30981
+ Promise.resolve().then(() => recoverTsAuthorityProject({ ...args, module })).then((outcome) => {
30159
30982
  if (outcome === "completed") {
30160
30983
  tsAuthorityRecoveryStateByProject.set(args.projectPath, "complete");
30161
30984
  log(`[magic-context] authority drain complete for project ${args.projectPath}`);
@@ -30201,6 +31024,7 @@ function createTransform(deps) {
30201
31024
  }
30202
31025
  const tUserMsg = performance.now();
30203
31026
  const currentTurnId = findLastUserMessageId(messages);
31027
+ const activeAgent = activeAgentFromMessages(messages);
30204
31028
  logTransformTiming(sessionId, "findLastUserMessageId", tUserMsg);
30205
31029
  const tMeta = performance.now();
30206
31030
  let sessionMeta;
@@ -30226,6 +31050,47 @@ function createTransform(deps) {
30226
31050
  }
30227
31051
  const reducedMode = sessionMeta.isSubagent;
30228
31052
  const fullFeatureMode = !reducedMode;
31053
+ const compactionOff = deps.compactionOff === true;
31054
+ try {
31055
+ const transition = reconcileCompactionMode({
31056
+ db,
31057
+ sessionId,
31058
+ compactionOff,
31059
+ historianRunnable: deps.historianRunnable !== false,
31060
+ compartmentInProgress: sessionMeta.compartmentInProgress
31061
+ });
31062
+ const hasTransitionEffects = transition.recordToWrite !== null || transition.notice !== null || transition.invalidatedM0Baseline || transition.clearedCompartmentInProgress || transition.historianCatchUpSignaled;
31063
+ if (hasTransitionEffects) {
31064
+ if (transition.invalidatedM0Baseline) {
31065
+ sessionMeta = {
31066
+ ...sessionMeta,
31067
+ cachedM0Bytes: null,
31068
+ cachedM1Bytes: null,
31069
+ cachedM0MuralDataUrl: null,
31070
+ cachedM0MuralHash: null
31071
+ };
31072
+ }
31073
+ if (transition.clearedCompartmentInProgress) {
31074
+ sessionMeta = { ...sessionMeta, compartmentInProgress: false };
31075
+ }
31076
+ if (transition.historianCatchUpSignaled) {
31077
+ sessionMeta = { ...sessionMeta, compartmentInProgress: true };
31078
+ }
31079
+ const notice = transition.notice;
31080
+ let noticeDelivered = notice === null || deps.client === undefined;
31081
+ if (notice && deps.client) {
31082
+ noticeDelivered = await sendIgnoredMessage(deps.client, sessionId, notice, deps.getNotificationParams?.(sessionId) ?? {}) === "sent";
31083
+ }
31084
+ if (noticeDelivered && transition.recordToWrite !== null) {
31085
+ commitCompactionModeRecord(db, sessionId, transition.recordToWrite);
31086
+ } else if (!noticeDelivered) {
31087
+ sessionLog(sessionId, "compaction mode notice was not delivered; durable pending record will retry on the next pass");
31088
+ }
31089
+ }
31090
+ } catch (error) {
31091
+ passOutcome.record("compaction-mode-transition-failure");
31092
+ sessionLog(sessionId, "compaction mode transition failed (retrying next pass):", error);
31093
+ }
30229
31094
  const ctxReduceAvailability = resolveCtxReduceAvailabilityFromMessages(sessionId, messages);
30230
31095
  const ctxReduceCallable = ctxReduceAvailability.callable;
30231
31096
  const todowriteAvailability = resolveTodowriteAvailabilityFromMessages(sessionId, messages);
@@ -30253,7 +31118,7 @@ function createTransform(deps) {
30253
31118
  }
30254
31119
  const compartmentDirectory = sessionDirectory;
30255
31120
  const historianRunnable = deps.historianRunnable !== false;
30256
- const canRunCompartments = fullFeatureMode && historianRunnable && deps.client !== undefined && compartmentDirectory.length > 0;
31121
+ const canRunCompartments = fullFeatureMode && !compactionOff && historianRunnable && deps.client !== undefined && compartmentDirectory.length > 0;
30257
31122
  const fallbackModelId = deps.getFallbackModelId?.(sessionId);
30258
31123
  const tModelDetect = performance.now();
30259
31124
  const persistedUsageBeforeResets = loadPersistedUsage(db, sessionId);
@@ -30313,7 +31178,7 @@ function createTransform(deps) {
30313
31178
  let emergencyRecoveryArmed = false;
30314
31179
  let emergencyRecoveryOrigin = null;
30315
31180
  let usagePercentageSynthetic = false;
30316
- if (fullFeatureMode) {
31181
+ if (fullFeatureMode && !compactionOff) {
30317
31182
  try {
30318
31183
  const armModel = deps.liveModelBySession?.get(sessionId);
30319
31184
  const armModelKey = deps.getModelKey?.(sessionId);
@@ -30366,25 +31231,27 @@ function createTransform(deps) {
30366
31231
  sessionID: sessionId
30367
31232
  }) : undefined;
30368
31233
  const currentModelKeyForBoundary = deps.getModelKey?.(sessionId);
31234
+ const thresholdContextLimit = resolvedContextLimit && resolvedContextLimit > 0 ? resolvedContextLimit : contextUsageEarly.percentage > 0 ? contextUsageEarly.inputTokens / (contextUsageEarly.percentage / 100) : undefined;
31235
+ const effectiveExecuteThresholdPercentage = resolveExecuteThreshold(deps.executeThresholdPercentage ?? 65, currentModelKeyForBoundary, 65, {
31236
+ tokensConfig: deps.executeThresholdTokens,
31237
+ contextLimit: thresholdContextLimit,
31238
+ sessionId
31239
+ });
31240
+ const { forceMaterializationPercentage } = escalationBands(effectiveExecuteThresholdPercentage);
30369
31241
  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;
30370
31242
  const boundaryUsageForProtectedTail = persistedUsageFreshForBoundary ?? contextUsageEarly;
30371
31243
  const boundaryUsageSource = persistedUsageFreshForBoundary ? "persisted" : "live";
30372
31244
  const historyBudgetTokens = resolveHistoryBudgetTokens(deps.historyBudgetPercentage, contextUsageEarly, deps.executeThresholdPercentage, deps.getModelKey?.(sessionId), deps.executeThresholdTokens, resolvedContextLimit);
30373
- let emergencyCeilingLimit = resolvedContextLimit && resolvedContextLimit > 0 ? resolvedContextLimit : 0;
30374
- if (emergencyCeilingLimit <= 0 && contextUsageEarly.percentage > 0) {
30375
- emergencyCeilingLimit = contextUsageEarly.inputTokens / (contextUsageEarly.percentage / 100);
30376
- }
30377
- const emergencyCeilingTokens = Number.isFinite(emergencyCeilingLimit) && emergencyCeilingLimit > 0 ? Math.floor(emergencyCeilingLimit * (resolveExecuteThreshold(deps.executeThresholdPercentage ?? 65, deps.getModelKey?.(sessionId), 65, {
30378
- tokensConfig: deps.executeThresholdTokens,
30379
- contextLimit: emergencyCeilingLimit
30380
- }) / 100)) : undefined;
30381
- const schedulerDecisionEarly = resolveSchedulerDecision(deps.scheduler, sessionMeta, contextUsageEarly, sessionId, deps.getModelKey?.(sessionId), resolvedContextLimit);
31245
+ const emergencyCeilingLimit = thresholdContextLimit ?? 0;
31246
+ const emergencyCeilingTokens = Number.isFinite(emergencyCeilingLimit) && emergencyCeilingLimit > 0 ? Math.floor(emergencyCeilingLimit * (effectiveExecuteThresholdPercentage / 100)) : undefined;
31247
+ const schedulerDecisionEarly = compactionOff ? "defer" : resolveSchedulerDecision(deps.scheduler, sessionMeta, contextUsageEarly, sessionId, deps.getModelKey?.(sessionId), resolvedContextLimit);
30382
31248
  const midTurn = isMidTurn(deps, resolvedSessionId);
30383
31249
  const bypassReason = detectMidTurnBypassReason({
30384
31250
  contextUsage: contextUsageEarly,
30385
31251
  sessionMeta,
30386
31252
  historyRefreshSessions: deps.historyRefreshSessions,
30387
- sessionId
31253
+ sessionId,
31254
+ effectiveExecuteThresholdPercentage
30388
31255
  });
30389
31256
  const { midTurnAdjustedSchedulerDecision, sideEffect } = applyMidTurnDeferral({
30390
31257
  base: schedulerDecisionEarly,
@@ -30402,12 +31269,13 @@ function createTransform(deps) {
30402
31269
  sessionLog(sessionId, `[boundary-exec] base=${schedulerDecisionEarly} bypass=${bypassReason} midTurn=${midTurn} effective=${midTurnAdjustedSchedulerDecision} sideEffect=${sideEffect}`);
30403
31270
  const historyRefreshExplicitBeforePrepare = deps.historyRefreshSessions.has(sessionId);
30404
31271
  const deferredHistoryWasPendingAtPassStart = deferredHistoryRefreshSessions.has(sessionId);
30405
- const earlyActiveRunBlocksMaterialization = (getActiveCompartmentRun(sessionId) !== undefined || sessionMeta.compartmentInProgress) && contextUsageEarly.percentage < FORCE_MATERIALIZE_PERCENTAGE;
31272
+ const earlyActiveRunBlocksMaterialization = (getActiveCompartmentRun(sessionId) !== undefined || sessionMeta.compartmentInProgress) && contextUsageEarly.percentage < forceMaterializationPercentage;
30406
31273
  const canConsumeDeferredEarly = canConsumeDeferredOnThisPass({
30407
31274
  schedulerDecision: midTurnAdjustedSchedulerDecision,
30408
31275
  contextPercentage: contextUsageEarly.percentage,
30409
31276
  justAwaitedPublication: false,
30410
- activeRunBlocksMaterialization: earlyActiveRunBlocksMaterialization
31277
+ activeRunBlocksMaterialization: earlyActiveRunBlocksMaterialization,
31278
+ forceMaterializationPercentage
30411
31279
  });
30412
31280
  const consumingDeferredEarly = canConsumeDeferredEarly && deferredHistoryWasPendingAtPassStart;
30413
31281
  const isCacheBusting = historyRefreshExplicitBeforePrepare || consumingDeferredEarly;
@@ -30488,7 +31356,7 @@ function createTransform(deps) {
30488
31356
  skipCompartmentAwaitForThisPass = true;
30489
31357
  return true;
30490
31358
  };
30491
- if (fullFeatureMode && historianFailureState.failureCount > 0 && contextUsageEarly.percentage >= 95 && !recoveryNoHeadEscapeActive) {
31359
+ if (fullFeatureMode && !compactionOff && historianFailureState.failureCount > 0 && contextUsageEarly.percentage >= 95 && !recoveryNoHeadEscapeActive) {
30492
31360
  skipCompartmentAwaitForThisPass = true;
30493
31361
  const emergencyPercentage = contextUsageEarly.percentage.toFixed(1);
30494
31362
  const recoveryStarted = startRecoveryRun();
@@ -30500,7 +31368,7 @@ function createTransform(deps) {
30500
31368
  sessionLog(sessionId, "transform: emergency recovery remains armed — no complete eligible head before protected tail");
30501
31369
  }
30502
31370
  sessionLog(sessionId, `EMERGENCY: historian recovery requested at ${emergencyPercentage}%, failures: ${historianFailureState.failureCount}`);
30503
- } else if (fullFeatureMode && isFirstTransformPassForSession && historianFailureState.failureCount > 0 && getEligibleHistoryForCompartment() && startRecoveryRun()) {
31371
+ } else if (fullFeatureMode && !compactionOff && isFirstTransformPassForSession && historianFailureState.failureCount > 0 && getEligibleHistoryForCompartment() && startRecoveryRun()) {
30504
31372
  sessionLog(sessionId, `transform: historian recovery triggered on session load after ${historianFailureState.failureCount} failure(s)`);
30505
31373
  if (deps.client) {
30506
31374
  sendIgnoredMessage(deps.client, sessionId, `## Historian recovery
@@ -30515,7 +31383,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30515
31383
  maybeSendProjectIdentityWarning(deps, sessionId, memoryProjectDirectory, notificationParams);
30516
31384
  }
30517
31385
  const sessionProjectIdentity = projectIdentity ?? (sessionDirectory ? resolveProjectIdentity(sessionDirectory) : deps.projectPath);
30518
- const sessionIdentityForBinding = sessionDirectory ? resolveProjectIdentityForSession(sessionDirectory) : undefined;
31386
+ const sessionIdentityForBinding = sessionDirectory ? resolveProjectIdentityForSession(sessionDirectory, deps.allowHomeProject) : undefined;
30519
31387
  if (sessionDirectory) {
30520
31388
  maybeSendProjectIdentityWarning(deps, sessionId, sessionDirectory, notificationParams);
30521
31389
  }
@@ -30532,16 +31400,16 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30532
31400
  recordSessionProjectIdentity(db, sessionId, sessionIdentityForBinding);
30533
31401
  recordedSessionProjectIdentity.set(sessionId, sessionIdentityForBinding);
30534
31402
  }
30535
- const taggerFloor = deriveTaggerLoadFloor(messages, sessionId, db);
30536
- if (taggerFloor === 0 && messages.length > 0) {
31403
+ const taggerFloor = compactionOff ? 0 : deriveTaggerLoadFloor(messages, sessionId, db);
31404
+ if (!compactionOff && taggerFloor === 0 && messages.length > 0) {
30537
31405
  sessionLog(sessionId, `tag floor: 0 (full-scan fallback) — no leading wire message resolved a tag across ${messages.length} msgs`);
30538
31406
  }
30539
31407
  let triggerBoundarySnapshot;
30540
- if (fullFeatureMode && historianRunnable && !sessionMeta.compartmentInProgress) {
31408
+ if (fullFeatureMode && !compactionOff && historianRunnable && !sessionMeta.compartmentInProgress) {
30541
31409
  const tTrigger = performance.now();
30542
31410
  try {
30543
31411
  const inMemoryTail = buildTriggerInMemoryTail(db, sessionId, extractInMemoryMessageViews(messages));
30544
- const triggerResult = checkCompartmentTrigger(db, sessionId, sessionMeta, boundaryUsageForProtectedTail, sessionMeta.lastContextPercentage, boundaryExecuteThreshold, deriveTriggerBudget(boundaryContextLimit, boundaryExecuteThreshold), deps.clearReasoningAge, deps.commitClusterTrigger, undefined, boundaryContextLimit, inMemoryTail, taggerFloor);
31412
+ const triggerResult = checkCompartmentTrigger(db, sessionId, sessionMeta, boundaryUsageForProtectedTail, sessionMeta.lastContextPercentage, boundaryExecuteThreshold, deriveTriggerBudget(boundaryContextLimit, boundaryExecuteThreshold), deps.clearReasoningAge, deps.commitClusterTrigger, undefined, boundaryContextLimit, inMemoryTail, taggerFloor, { providerID: resolvedProviderID });
30545
31413
  if (triggerResult.shouldFire) {
30546
31414
  sessionLog(sessionId, `compartment trigger: firing (reason=${triggerResult.reason})`);
30547
31415
  updateSessionMeta(db, sessionId, { compartmentInProgress: true });
@@ -30556,7 +31424,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30556
31424
  }
30557
31425
  let pendingCompartmentInjection = null;
30558
31426
  let rebuiltHistoryFromInitialPrepare = false;
30559
- if (fullFeatureMode) {
31427
+ if (fullFeatureMode && !compactionOff) {
30560
31428
  const tInj = performance.now();
30561
31429
  pendingCompartmentInjection = prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectIdentity, deps.memoryConfig?.injectionBudgetTokens, deps.experimentalTemporalAwareness);
30562
31430
  logTransformTiming(sessionId, "prepareCompartmentInjection", tInj);
@@ -30570,10 +31438,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30570
31438
  let targets = new Map;
30571
31439
  let reasoningByMessage = new Map;
30572
31440
  let messageTagNumbers = new Map;
30573
- let tagNormalizationTargets = [];
30574
31441
  let batch = null;
30575
31442
  let hasRecentReduceCall = false;
30576
- if (deps.experimentalTemporalAwareness) {
31443
+ if (deps.experimentalTemporalAwareness && !compactionOff) {
30577
31444
  const tTemporal = performance.now();
30578
31445
  const injected = injectTemporalMarkers(messages);
30579
31446
  if (injected > 0) {
@@ -30582,44 +31449,45 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30582
31449
  logTransformTiming(sessionId, "injectTemporalMarkers", tTemporal);
30583
31450
  }
30584
31451
  let taggingSucceeded = false;
30585
- try {
30586
- const t0 = performance.now();
30587
- const tInitFromDb = performance.now();
30588
- deps.tagger.initFromDb(sessionId, db, taggerFloor);
30589
- logTransformTiming(sessionId, "tag.initFromDb", tInitFromDb);
30590
- const skipPrefixInjection = !ctxReduceCallable;
30591
- const result = tagMessages(sessionId, messages, deps.tagger, db, {
30592
- skipPrefixInjection
30593
- });
30594
- targets = result.targets;
30595
- reasoningByMessage = result.reasoningByMessage;
30596
- messageTagNumbers = result.messageTagNumbers;
30597
- tagNormalizationTargets = result.normalizationTargets;
30598
- batch = result.batch;
30599
- hasRecentReduceCall = result.hasRecentReduceCall;
30600
- const hadPriorCommitState = deps.commitSeenLastPass?.has(sessionId) ?? false;
30601
- const sawCommitLastPass = deps.commitSeenLastPass?.get(sessionId) ?? false;
30602
- if (fullFeatureMode && hadPriorCommitState && result.hasRecentCommit && !sawCommitLastPass) {
30603
- onNoteTrigger(db, sessionId, "commit_detected");
30604
- }
30605
- deps.commitSeenLastPass?.set(sessionId, result.hasRecentCommit);
30606
- logTransformTiming(sessionId, "tagMessages", t0);
30607
- taggingSucceeded = true;
30608
- } catch (error) {
30609
- passOutcome.record("tagging-persistence-failure");
30610
- sessionLog(sessionId, "transform tag persistence failed; continuing without tagging:", error);
31452
+ if (!compactionOff) {
30611
31453
  try {
30612
- deps.tagger.cleanup(sessionId);
30613
- } catch (cleanupError) {
30614
- sessionLog(sessionId, "tagger cleanup after failure threw:", cleanupError);
31454
+ const t0 = performance.now();
31455
+ const tInitFromDb = performance.now();
31456
+ deps.tagger.initFromDb(sessionId, db, taggerFloor);
31457
+ logTransformTiming(sessionId, "tag.initFromDb", tInitFromDb);
31458
+ const skipPrefixInjection = !ctxReduceCallable;
31459
+ const result = tagMessages(sessionId, messages, deps.tagger, db, {
31460
+ skipPrefixInjection
31461
+ });
31462
+ targets = result.targets;
31463
+ reasoningByMessage = result.reasoningByMessage;
31464
+ messageTagNumbers = result.messageTagNumbers;
31465
+ batch = result.batch;
31466
+ hasRecentReduceCall = result.hasRecentReduceCall;
31467
+ const hadPriorCommitState = deps.commitSeenLastPass?.has(sessionId) ?? false;
31468
+ const sawCommitLastPass = deps.commitSeenLastPass?.get(sessionId) ?? false;
31469
+ if (fullFeatureMode && hadPriorCommitState && result.hasRecentCommit && !sawCommitLastPass) {
31470
+ onNoteTrigger(db, sessionId, "commit_detected");
31471
+ }
31472
+ deps.commitSeenLastPass?.set(sessionId, result.hasRecentCommit);
31473
+ logTransformTiming(sessionId, "tagMessages", t0);
31474
+ taggingSucceeded = true;
31475
+ } catch (error) {
31476
+ passOutcome.record("tagging-persistence-failure");
31477
+ sessionLog(sessionId, "transform tag persistence failed; continuing without tagging:", error);
31478
+ try {
31479
+ deps.tagger.cleanup(sessionId);
31480
+ } catch (cleanupError) {
31481
+ sessionLog(sessionId, "tagger cleanup after failure threw:", cleanupError);
31482
+ }
30615
31483
  }
30616
31484
  }
30617
31485
  const t1 = performance.now();
30618
- const activeTags = getActiveTagsBySession(db, sessionId);
31486
+ const activeTags = compactionOff ? [] : getActiveTagsBySession(db, sessionId);
30619
31487
  logTransformTiming(sessionId, "getActiveTagsBySession", t1, `count=${activeTags.length}`);
30620
31488
  const t1b = performance.now();
30621
31489
  const targetTagNumbers = [...targets.keys()];
30622
- const targetsSliceTags = getTagsByNumbers(db, sessionId, targetTagNumbers);
31490
+ const targetsSliceTags = compactionOff ? [] : getTagsByNumbers(db, sessionId, targetTagNumbers);
30623
31491
  logTransformTiming(sessionId, "getTagsByNumbers", t1b, `targets=${targetTagNumbers.length} fetched=${targetsSliceTags.length}`);
30624
31492
  let didMutateFromFlushedStatuses = false;
30625
31493
  if (taggingSucceeded) {
@@ -30635,10 +31503,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30635
31503
  }
30636
31504
  }
30637
31505
  const t3 = performance.now();
30638
- const strippedStructuralNoise = canUseEmptySentinels ? stripStructuralNoise(messages) : 0;
31506
+ const strippedStructuralNoise = canUseEmptySentinels && !compactionOff ? stripStructuralNoise(messages) : 0;
30639
31507
  logTransformTiming(sessionId, "stripStructuralNoise", t3, `strippedParts=${strippedStructuralNoise}`);
30640
31508
  const persistedReasoningWatermark = sessionMeta?.clearedReasoningThroughTag ?? 0;
30641
- if (persistedReasoningWatermark > 0) {
31509
+ if (persistedReasoningWatermark > 0 && !compactionOff) {
30642
31510
  const tReplay = performance.now();
30643
31511
  const replayed = canUseEmptySentinels ? replayClearedReasoning(messages, reasoningByMessage, messageTagNumbers, persistedReasoningWatermark) : 0;
30644
31512
  const replayedInline = replayStrippedInlineThinking(messages, messageTagNumbers, persistedReasoningWatermark);
@@ -30647,7 +31515,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30647
31515
  }
30648
31516
  logTransformTiming(sessionId, "replayReasoningClearing", tReplay);
30649
31517
  }
30650
- if (!reducedMode && deps.cavemanTextCompression?.enabled) {
31518
+ if (!reducedMode && !compactionOff && deps.cavemanTextCompression?.enabled) {
30651
31519
  const tCavemanReplay = performance.now();
30652
31520
  const replayedCaveman = replayCavemanCompression(sessionId, db, targets, targetsSliceTags);
30653
31521
  if (replayedCaveman > 0) {
@@ -30656,7 +31524,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30656
31524
  logTransformTiming(sessionId, "replayCavemanCompression", tCavemanReplay);
30657
31525
  }
30658
31526
  const t4 = performance.now();
30659
- const strippedClearedReasoning = canUseEmptySentinels ? stripClearedReasoning(messages) : 0;
31527
+ const strippedClearedReasoning = canUseEmptySentinels && !compactionOff ? stripClearedReasoning(messages) : 0;
30660
31528
  logTransformTiming(sessionId, "stripClearedReasoning", t4, `strippedParts=${strippedClearedReasoning}`);
30661
31529
  const watermark = getMaxDroppedTagNumber(db, sessionId);
30662
31530
  const contextUsage = contextUsageEarly;
@@ -30666,6 +31534,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30666
31534
  const compartmentPhase = await runCompartmentPhase({
30667
31535
  canRunCompartments,
30668
31536
  fullFeatureMode,
31537
+ compactionOff,
30669
31538
  historianRunnable,
30670
31539
  sessionMeta,
30671
31540
  contextUsage,
@@ -30715,28 +31584,25 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30715
31584
  const hardModel = deps.liveModelBySession?.get(sessionId);
30716
31585
  const hardModelKey = hardModel ? `${hardModel.providerID}/${hardModel.modelID}` : "";
30717
31586
  const hardSystemHash = typeof sessionMeta.systemPromptHash === "string" ? sessionMeta.systemPromptHash : "";
30718
- let hardTtlMs = 5 * 60 * 1000;
30719
- try {
30720
- hardTtlMs = parseCacheTtl(sessionMeta.cacheTtl);
30721
- } catch (error) {
31587
+ const hardCacheExpired = computeHardCacheExpired(sessionMeta.cacheTtl, sessionMeta.lastResponseTime, Date.now(), (error) => {
30722
31588
  passOutcome.record("invalid-cache-ttl-fallback");
30723
31589
  sessionLog(sessionId, "invalid cache_ttl; using the 5m default:", error);
30724
- }
30725
- const hardCacheExpired = sessionMeta.lastResponseTime > 0 && Date.now() - sessionMeta.lastResponseTime >= hardTtlMs;
31590
+ });
30726
31591
  const m0HardSignals = {
30727
31592
  systemHash: hardSystemHash,
30728
31593
  modelKey: hardModelKey,
30729
31594
  cacheExpired: hardCacheExpired,
30730
31595
  lastResponseTime: sessionMeta.lastResponseTime
30731
31596
  };
30732
- const lateActiveRunBlocksMaterialization = getActiveCompartmentRun(sessionId) !== undefined && contextUsageEarly.percentage < FORCE_MATERIALIZE_PERCENTAGE;
31597
+ const lateActiveRunBlocksMaterialization = getActiveCompartmentRun(sessionId) !== undefined && contextUsageEarly.percentage < forceMaterializationPercentage;
30733
31598
  const canConsumeDeferredLate = canConsumeDeferredOnThisPass({
30734
31599
  schedulerDecision: midTurnAdjustedSchedulerDecision,
30735
31600
  contextPercentage: contextUsageEarly.percentage,
30736
31601
  justAwaitedPublication: compartmentPhase.justAwaitedPublication,
30737
- activeRunBlocksMaterialization: lateActiveRunBlocksMaterialization
31602
+ activeRunBlocksMaterialization: lateActiveRunBlocksMaterialization,
31603
+ forceMaterializationPercentage
30738
31604
  });
30739
- const wasEmergencyBlock = contextUsageEarly.percentage >= FORCE_MATERIALIZE_PERCENTAGE && compartmentPhase.justAwaitedPublication;
31605
+ const wasEmergencyBlock = contextUsageEarly.percentage >= forceMaterializationPercentage && compartmentPhase.justAwaitedPublication;
30740
31606
  const historyRebuiltThisPass = wasEmergencyBlock ? compartmentPhase.rebuiltHistoryThisPass : rebuiltHistoryFromInitialPrepare || compartmentPhase.rebuiltHistoryThisPass;
30741
31607
  const tPostProcess = performance.now();
30742
31608
  const postTransformResult = await runPostTransformPhase({
@@ -30750,10 +31616,13 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30750
31616
  tagger: deps.tagger,
30751
31617
  ctxReduceAvailability,
30752
31618
  todowriteAvailability,
31619
+ client: deps.client,
31620
+ activeAgent,
30753
31621
  batch,
30754
31622
  contextUsage,
30755
31623
  schedulerDecision,
30756
31624
  fullFeatureMode,
31625
+ compactionOff,
30757
31626
  canRunCompartments,
30758
31627
  awaitedCompartmentRun,
30759
31628
  phaseJustAwaitedPublication: compartmentPhase.justAwaitedPublication,
@@ -30776,7 +31645,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30776
31645
  pendingCompartmentInjection,
30777
31646
  didMutateFromFlushedStatuses,
30778
31647
  watermark,
30779
- forceMaterializationPercentage: FORCE_MATERIALIZE_PERCENTAGE,
31648
+ forceMaterializationPercentage,
30780
31649
  hasRecentReduceCall,
30781
31650
  projectPath: sessionProjectIdentity,
30782
31651
  sessionDirectory,
@@ -30794,67 +31663,74 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30794
31663
  historyBudgetTokens,
30795
31664
  temporalAwareness: deps.experimentalTemporalAwareness,
30796
31665
  hardSignals: m0HardSignals,
30797
- muralEnabled: deps.experimentalMuralEnabled
31666
+ muralEnabled: deps.muralEnabled
30798
31667
  }
30799
31668
  });
30800
31669
  passOutcome.markFinalized();
30801
- const finalWireEstimate = contextUsage.percentage >= 95 ? estimateFinalWireInputTokens({
30802
- messages,
30803
- systemPromptTokens: sessionMeta.systemPromptTokens,
30804
- providerID: modelForBudget?.providerID,
30805
- modelID: modelForBudget?.modelID,
30806
- agentName: notificationParams.agent
30807
- }) : undefined;
30808
- if (finalWireEstimate) {
30809
- 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"}`);
30810
- }
30811
- const currentModelKeyForRecovery = deps.getModelKey?.(sessionId);
30812
- const overflowStateForFinalWire = getOverflowState(db, sessionId, currentModelKeyForRecovery);
30813
- const providerProvenLimitTokens = typeof currentModelKeyForRecovery === "string" && currentModelKeyForRecovery.length > 0 && overflowStateForFinalWire.detectedContextLimit > 0 && overflowStateForFinalWire.detectedContextLimitModelKey === currentModelKeyForRecovery ? overflowStateForFinalWire.detectedContextLimit : undefined;
30814
- const emergencyFailClosed = evaluateEmergencyFailClosed({
30815
- usagePercentage: contextUsage.percentage,
30816
- emergencyRecoveryArmed,
30817
- emergencyRecoveryOrigin,
30818
- foldMaterializedThisPass: postTransformResult.historianFoldMaterializedThisPass,
30819
- finalWireEstimate,
30820
- providerProvenLimitTokens
30821
- });
30822
- if (emergencyFailClosed.disarm) {
30823
- clearEmergencyRecovery(db, sessionId);
30824
- sessionLog(sessionId, `emergency disarm: trusted final-wire ${emergencyFailClosed.disarm.finalWireTokens} under limit ${emergencyFailClosed.disarm.provenLimitTokens}`);
30825
- }
30826
- if (emergencyFailClosed.shouldAbort) {
30827
- if (!deps.client) {
30828
- throw new EmergencyFailClosedError("Cannot fail closed: OpenCode client is unavailable");
30829
- }
30830
- let notification;
30831
- try {
30832
- notification = await sendIgnoredMessage(deps.client, sessionId, "Context full — /ctx-flush or /clear to continue.", notificationParams);
30833
- } catch (error) {
30834
- throw new EmergencyFailClosedError("Emergency recovery notification failed", {
30835
- cause: error
30836
- });
30837
- }
30838
- if (notification !== "sent") {
30839
- throw new EmergencyFailClosedError(`Emergency recovery notification was ${notification}`);
30840
- }
30841
- try {
30842
- await abortSessionFailClosed(deps.client, sessionId);
30843
- } catch (error) {
30844
- sessionLog(sessionId, "transform: emergency fail-closed abort failed; refusing to return a sendable prompt:", getErrorMessage(error));
30845
- throw new EmergencyFailClosedError("Emergency recovery abort failed", {
30846
- cause: error
30847
- });
31670
+ const finalWireTail = describeFinalWireTail(messages);
31671
+ let finalWireEstimate;
31672
+ if (!compactionOff) {
31673
+ finalWireEstimate = contextUsage.percentage >= 95 ? estimateFinalWireInputTokens({
31674
+ messages,
31675
+ systemPromptTokens: sessionMeta.systemPromptTokens,
31676
+ providerID: modelForBudget?.providerID,
31677
+ modelID: modelForBudget?.modelID,
31678
+ agentName: notificationParams.agent
31679
+ }) : undefined;
31680
+ if (finalWireEstimate) {
31681
+ 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}`);
31682
+ }
31683
+ const currentModelKeyForRecovery = deps.getModelKey?.(sessionId);
31684
+ const overflowStateForFinalWire = getOverflowState(db, sessionId, currentModelKeyForRecovery);
31685
+ const providerProvenLimitTokens = typeof currentModelKeyForRecovery === "string" && currentModelKeyForRecovery.length > 0 && overflowStateForFinalWire.detectedContextLimit > 0 && overflowStateForFinalWire.detectedContextLimitModelKey === currentModelKeyForRecovery ? overflowStateForFinalWire.detectedContextLimit : undefined;
31686
+ const emergencyFailClosed = evaluateEmergencyFailClosed({
31687
+ usagePercentage: contextUsage.percentage,
31688
+ emergencyRecoveryArmed,
31689
+ emergencyRecoveryOrigin,
31690
+ foldMaterializedThisPass: postTransformResult.historianFoldMaterializedThisPass,
31691
+ finalWireEstimate,
31692
+ providerProvenLimitTokens
31693
+ });
31694
+ if (emergencyFailClosed.disarm) {
31695
+ clearEmergencyRecovery(db, sessionId);
31696
+ sessionLog(sessionId, `emergency disarm: trusted final-wire ${emergencyFailClosed.disarm.finalWireTokens} under limit ${emergencyFailClosed.disarm.provenLimitTokens}`);
30848
31697
  }
30849
- try {
30850
- clearEmergencyDropSample(db, sessionId);
30851
- } catch (error) {
30852
- throw new EmergencyFailClosedError("Emergency recovery cleanup failed", {
30853
- cause: error
30854
- });
31698
+ if (emergencyFailClosed.shouldAbort) {
31699
+ if (!deps.client) {
31700
+ throw new EmergencyFailClosedError("Cannot fail closed: OpenCode client is unavailable");
31701
+ }
31702
+ let notification;
31703
+ try {
31704
+ notification = await sendIgnoredMessage(deps.client, sessionId, "Context full — /ctx-flush or /clear to continue.", notificationParams);
31705
+ } catch (error) {
31706
+ throw new EmergencyFailClosedError("Emergency recovery notification failed", {
31707
+ cause: error
31708
+ });
31709
+ }
31710
+ if (notification !== "sent" && notification !== "queued") {
31711
+ throw new EmergencyFailClosedError(`Emergency recovery notification was ${notification}`);
31712
+ }
31713
+ try {
31714
+ await abortSessionFailClosed(deps.client, sessionId);
31715
+ } catch (error) {
31716
+ sessionLog(sessionId, "transform: emergency fail-closed abort failed; refusing to return a sendable prompt:", getErrorMessage(error));
31717
+ throw new EmergencyFailClosedError("Emergency recovery abort failed", {
31718
+ cause: error
31719
+ });
31720
+ }
31721
+ try {
31722
+ clearEmergencyDropSample(db, sessionId);
31723
+ } catch (error) {
31724
+ throw new EmergencyFailClosedError("Emergency recovery cleanup failed", {
31725
+ cause: error
31726
+ });
31727
+ }
31728
+ sessionLog(sessionId, `EMERGENCY: fail-closed (reason=${emergencyFailClosed.reason}, recoveryOrigin=${emergencyRecoveryOrigin ?? "unknown"}, finalEstimate=${finalWireEstimate?.tokens ?? "unavailable"}, estimateTrusted=${finalWireEstimate?.trusted ?? false}, syntheticUsage=${usagePercentageSynthetic})`);
31729
+ return;
30855
31730
  }
30856
- sessionLog(sessionId, `EMERGENCY: fail-closed (reason=${emergencyFailClosed.reason}, recoveryOrigin=${emergencyRecoveryOrigin ?? "unknown"}, finalEstimate=${finalWireEstimate?.tokens ?? "unavailable"}, estimateTrusted=${finalWireEstimate?.trusted ?? false}, syntheticUsage=${usagePercentageSynthetic})`);
30857
- return;
31731
+ }
31732
+ if (!finalWireEstimate) {
31733
+ sessionLog(sessionId, `transform: final-wire telemetry estimate=unavailable trusted=false conversation=unknown tools=unknown system=unknown toolDefinitions=unknown tail=${finalWireTail}`);
30858
31734
  }
30859
31735
  if (passOutcome.captureEligible) {
30860
31736
  const keys = resolveLkgModelKeys(messages);
@@ -30930,7 +31806,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30930
31806
  sessionLog(sessionId, "conversation_tokens UPDATE failed:", error);
30931
31807
  }
30932
31808
  }
30933
- if (ctxReduceCallable && deps.channel1StateBySession) {
31809
+ if (ctxReduceCallable && !compactionOff && deps.channel1StateBySession) {
30934
31810
  try {
30935
31811
  const resolvedExecuteThresholdPct = resolveExecuteThreshold(deps.executeThresholdPercentage ?? 65, deps.getModelKey?.(sessionId), 65, {
30936
31812
  tokensConfig: deps.executeThresholdTokens,
@@ -31119,15 +31995,22 @@ function createEventHandler2(deps) {
31119
31995
  const sessionMeta = getOrCreateSessionMeta(deps.db, errInfo.sessionID);
31120
31996
  if (sessionMeta.isSubagent) {
31121
31997
  if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
31122
- recordDetectedContextLimit(deps.db, errInfo.sessionID, detection.reportedLimit);
31998
+ recordDetectedContextLimit(deps.db, errInfo.sessionID, detection.reportedLimit, undefined, detection.reportedLimitProvenance);
31123
31999
  }
31124
- sessionLog(errInfo.sessionID, `overflow detected on subagent: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only (subagents cannot run historian)`);
32000
+ 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)`);
31125
32001
  return;
31126
32002
  }
31127
32003
  const existing = getOverflowState(deps.db, errInfo.sessionID);
32004
+ if (deps.compactionOff) {
32005
+ if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
32006
+ recordDetectedContextLimit(deps.db, errInfo.sessionID, detection.reportedLimit, undefined, detection.reportedLimitProvenance);
32007
+ }
32008
+ 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)`);
32009
+ return;
32010
+ }
31128
32011
  dropSlot(errInfo.sessionID, "overflow-recovery-arm");
31129
- recordOverflowDetected(deps.db, errInfo.sessionID, detection.reportedLimit);
31130
- sessionLog(errInfo.sessionID, `overflow detected via session.error: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"} (previousRecovery=${existing.needsEmergencyRecovery})`);
32012
+ recordOverflowDetected(deps.db, errInfo.sessionID, detection.reportedLimit, undefined, "provider_overflow", detection.reportedLimitProvenance);
32013
+ 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})`);
31131
32014
  deps.onSessionCacheInvalidated?.(errInfo.sessionID);
31132
32015
  } catch (error) {
31133
32016
  sessionLog(errInfo.sessionID, "event session.error handling failed:", error);
@@ -31169,13 +32052,18 @@ function createEventHandler2(deps) {
31169
32052
  const metaForOverflow = getOrCreateSessionMeta(deps.db, info.sessionID);
31170
32053
  if (metaForOverflow.isSubagent) {
31171
32054
  if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
31172
- recordDetectedContextLimit(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey);
32055
+ recordDetectedContextLimit(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey, detection.reportedLimitProvenance);
32056
+ }
32057
+ 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`);
32058
+ } else if (deps.compactionOff) {
32059
+ if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
32060
+ recordDetectedContextLimit(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey, detection.reportedLimitProvenance);
31173
32061
  }
31174
- sessionLog(info.sessionID, `overflow detected on subagent via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only`);
32062
+ 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`);
31175
32063
  } else {
31176
32064
  dropSlot(info.sessionID, "overflow-recovery-arm");
31177
- recordOverflowDetected(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey);
31178
- sessionLog(info.sessionID, `overflow detected via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"}`);
32065
+ recordOverflowDetected(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey, "provider_overflow", detection.reportedLimitProvenance);
32066
+ sessionLog(info.sessionID, `overflow detected via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"}`);
31179
32067
  deps.onSessionCacheInvalidated?.(info.sessionID);
31180
32068
  }
31181
32069
  } catch (error) {
@@ -31274,7 +32162,7 @@ function createEventHandler2(deps) {
31274
32162
  } catch (error) {
31275
32163
  sessionLog(info.sessionID, "event message.updated persistence failed:", error);
31276
32164
  }
31277
- if ((info.finish === "stop" || info.finish === "tool-calls") && deps.client && deps.channel1StateBySession) {
32165
+ if ((info.finish === "stop" || info.finish === "tool-calls") && deps.client && deps.channel1StateBySession && !deps.compactionOff) {
31278
32166
  deliverChannel2IfPending(deps, info.sessionID);
31279
32167
  }
31280
32168
  return;
@@ -31916,11 +32804,15 @@ function createEventHook(args) {
31916
32804
  args.deferredMaterializationSessions.delete(sessionId);
31917
32805
  args.lastHeuristicsTurnId.delete(sessionId);
31918
32806
  args.commitSeenLastPass?.delete(sessionId);
32807
+ clearIgnoredMessages(sessionId);
31919
32808
  resetNoteNudgeCooldownOnly(sessionId);
31920
32809
  clearAutoSearchForSession(sessionId);
31921
32810
  clearSidebarSnapshotCache(sessionId);
31922
32811
  clearSessionTracking(sessionId);
31923
32812
  }
32813
+ if (input.event.type !== "session.deleted") {
32814
+ await flushIgnoredMessages(sessionId);
32815
+ }
31924
32816
  };
31925
32817
  }
31926
32818
  function createCommandExecuteBeforeHook(commandHandler) {
@@ -31980,6 +32872,7 @@ function createToolExecuteAfterHook(args) {
31980
32872
  if (!typedInput.sessionID || !typedInput.tool) {
31981
32873
  return;
31982
32874
  }
32875
+ await flushIgnoredMessages(typedInput.sessionID);
31983
32876
  if (typedInput.tool === "ctx_reduce") {
31984
32877
  const state = args.channel1StateBySession.get(typedInput.sessionID);
31985
32878
  if (state)
@@ -32000,6 +32893,19 @@ function createToolExecuteAfterHook(args) {
32000
32893
  const todowriteVerdict = resolveTodowriteAvailability(typedInput.sessionID);
32001
32894
  if (todowriteVerdict.frozen && !todowriteVerdict.callable)
32002
32895
  return;
32896
+ const activeAgent = typedInput.agent;
32897
+ if (args.client) {
32898
+ try {
32899
+ if (await todowritePermissionDenied(args.client, typedInput.sessionID, activeAgent)) {
32900
+ return;
32901
+ }
32902
+ } catch (error) {
32903
+ if (cachedToolPermissionDenied(typedInput.sessionID, "todowrite")) {
32904
+ return;
32905
+ }
32906
+ sessionLog(typedInput.sessionID, "todowrite permission read failed during capture (ignored):", error);
32907
+ }
32908
+ }
32003
32909
  const todoArgs = typedInput.args;
32004
32910
  const todos = todoArgs?.todos;
32005
32911
  const sessionMeta = Array.isArray(todos) ? getOrCreateSessionMeta(args.db, typedInput.sessionID) : null;
@@ -32424,14 +33330,24 @@ function createMagicContextHook(deps) {
32424
33330
  const reason = (opened ? getDatabasePersistenceError(opened) : null) ?? "Failed to initialize the persistent SQLite database.";
32425
33331
  log("[magic-context] disabling feature because persistent storage is unavailable:", reason);
32426
33332
  notifyMagicContextDisabled(deps.client, reason);
33333
+ const migration = getMigrationOnOpenRefusal();
33334
+ const blockingProcesses = migration?.serverPids.map((pid) => ({ harness: "OpenCode server", pid })) ?? [];
32427
33335
  const fence = getSchemaFenceRejection();
32428
33336
  recordHookInitFailure({
32429
33337
  type: "storage",
32430
- reason: fence ? {
33338
+ reason: migration && blockingProcesses.length > 0 ? {
33339
+ kind: "migration_guard",
33340
+ persistedVersion: migration.persistedVersion,
33341
+ supportedVersion: migration.supportedVersion,
33342
+ blockingProcesses
33343
+ } : fence ? {
32431
33344
  kind: "schema_fence",
32432
33345
  persistedVersion: fence.persistedVersion,
32433
33346
  supportedVersion: fence.supportedVersion
32434
- } : { kind: "storage_failure", cause: reason }
33347
+ } : {
33348
+ kind: "storage_failure",
33349
+ cause: migration?.unreadableFile ? `migration guard could not read RPC discovery file ${migration.unreadableFile}` : reason
33350
+ }
32435
33351
  });
32436
33352
  return null;
32437
33353
  }
@@ -32447,9 +33363,9 @@ function createMagicContextHook(deps) {
32447
33363
  });
32448
33364
  return null;
32449
33365
  }
32450
- const projectPath = resolveProjectIdentityForSession(deps.directory);
33366
+ const projectPath = resolveProjectIdentityForSession(deps.directory, deps.config.allow_home_project);
32451
33367
  if (!projectPath) {
32452
- log("[magic-context] not binding a project identity for the user's home directory");
33368
+ log("[magic-context] not binding a project identity for this directory");
32453
33369
  clearHookInitFailure();
32454
33370
  recordHookInitFailure({ type: "no_project" });
32455
33371
  return null;
@@ -32488,6 +33404,7 @@ function createMagicContextHook(deps) {
32488
33404
  const sessionDirectoryBySession = deps.liveSessionState?.sessionDirectoryBySession ?? new Map;
32489
33405
  const internalChildSessions = deps.liveSessionState?.internalChildSessions ?? new Set;
32490
33406
  const recompProgressBySession = deps.liveSessionState?.recompProgressBySession ?? new Map;
33407
+ const dreamerProgressByProject = deps.liveSessionState?.dreamerProgressByProject ?? new Map;
32491
33408
  const channel1StateBySession = new Map;
32492
33409
  const channel2DirectiveTextBySession = new Map;
32493
33410
  const resolveLiveModel = (sessionId) => {
@@ -32513,6 +33430,7 @@ function createMagicContextHook(deps) {
32513
33430
  const dreamerRunnable = isDreamerRunnable(deps.config);
32514
33431
  const dreamerConfig = dreamerRunnable ? deps.config.dreamer : undefined;
32515
33432
  const historianRunnable = isHistorianRunnable(deps.config);
33433
+ const compactionOff = !isCompactionEnabled(deps.config);
32516
33434
  const buildManagedRecompCtx = (sessionId) => ({
32517
33435
  client: deps.client,
32518
33436
  db,
@@ -32527,6 +33445,7 @@ function createMagicContextHook(deps) {
32527
33445
  deferredMaterializationSessions,
32528
33446
  sessionDirectoryBySession,
32529
33447
  recompProgressBySession,
33448
+ dreamerProgressByProject,
32530
33449
  internalChildSessions
32531
33450
  },
32532
33451
  directory: deps.directory,
@@ -32573,7 +33492,7 @@ function createMagicContextHook(deps) {
32573
33492
  return "Embedding is already running for this session.";
32574
33493
  }
32575
33494
  await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
32576
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33495
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32577
33496
  if (!sessionProjectIdentity)
32578
33497
  return "No project identity is bound for the home directory.";
32579
33498
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32641,7 +33560,7 @@ function createMagicContextHook(deps) {
32641
33560
  if (ctrl)
32642
33561
  ctrl.abort();
32643
33562
  const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
32644
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33563
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32645
33564
  if (!sessionProjectIdentity)
32646
33565
  return "No project identity is bound for the home directory.";
32647
33566
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32650,7 +33569,7 @@ function createMagicContextHook(deps) {
32650
33569
  };
32651
33570
  const getEmbedStatusText = (sessionId) => {
32652
33571
  const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
32653
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33572
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32654
33573
  if (!sessionProjectIdentity)
32655
33574
  return "No project identity is bound for the home directory.";
32656
33575
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32676,7 +33595,7 @@ function createMagicContextHook(deps) {
32676
33595
  try {
32677
33596
  await new Promise((resolve3) => setTimeout(resolve3, 0));
32678
33597
  await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
32679
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33598
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32680
33599
  if (!sessionProjectIdentity)
32681
33600
  return;
32682
33601
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32909,6 +33828,7 @@ function createMagicContextHook(deps) {
32909
33828
  internalChildSessions,
32910
33829
  client: deps.client,
32911
33830
  directory: deps.directory,
33831
+ allowHomeProject: deps.config.allow_home_project,
32912
33832
  injectDocs: deps.config.dreamer?.inject_docs !== false,
32913
33833
  memoryConfig: deps.config.memory ? {
32914
33834
  enabled: deps.config.memory.enabled,
@@ -32933,9 +33853,10 @@ function createMagicContextHook(deps) {
32933
33853
  },
32934
33854
  projectPath,
32935
33855
  historianRunnable,
33856
+ compactionOff,
32936
33857
  experimentalUserMemories: userMemoryCollectionEnabled(dreamerConfig),
32937
33858
  experimentalTemporalAwareness: deps.config.temporal_awareness === true,
32938
- experimentalMuralEnabled: deps.config.experimental?.mural?.enabled === true,
33859
+ muralEnabled: deps.config.mural?.enabled === true,
32939
33860
  historianTwoPass: deps.config.historian?.two_pass === true,
32940
33861
  liveModelBySession,
32941
33862
  sessionDirectoryBySession,
@@ -32946,7 +33867,7 @@ function createMagicContextHook(deps) {
32946
33867
  directory: deps.directory,
32947
33868
  ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory
32948
33869
  } : undefined,
32949
- cavemanTextCompression: deps.config.caveman_text_compression?.enabled === true ? {
33870
+ cavemanTextCompression: compactionOff ? undefined : deps.config.caveman_text_compression?.enabled === true ? {
32950
33871
  enabled: true,
32951
33872
  minChars: deps.config.caveman_text_compression.min_chars ?? 500
32952
33873
  } : undefined,
@@ -32962,6 +33883,7 @@ function createMagicContextHook(deps) {
32962
33883
  contextUsageMap,
32963
33884
  compactionHandler: deps.compactionHandler,
32964
33885
  config: deps.config,
33886
+ compactionOff,
32965
33887
  tagger: deps.tagger,
32966
33888
  db,
32967
33889
  client: deps.client,
@@ -32982,6 +33904,7 @@ function createMagicContextHook(deps) {
32982
33904
  transform.clearRustSession(sessionId);
32983
33905
  systemPromptHash.clearSession(sessionId);
32984
33906
  lastHeuristicsTurnId.delete(sessionId);
33907
+ clearToolPermissionDenied(sessionId);
32985
33908
  commitSeenLastPass.delete(sessionId);
32986
33909
  variantBySession.delete(sessionId);
32987
33910
  liveModelBySession.delete(sessionId);
@@ -33027,7 +33950,14 @@ function createMagicContextHook(deps) {
33027
33950
  userMemoryCollectionEnabled: userMemoryCollectionEnabled(dreaming),
33028
33951
  language: deps.config.language,
33029
33952
  transformMode: deps.config.transform_mode,
33030
- moduleClient: rustModeModuleClient
33953
+ moduleClient: rustModeModuleClient,
33954
+ onProgress: (progress, completedTask) => {
33955
+ if (progress) {
33956
+ dreamerProgressByProject.set(projectPath, progress);
33957
+ } else if (dreamerProgressByProject.get(projectPath)?.task === completedTask) {
33958
+ dreamerProgressByProject.delete(projectPath);
33959
+ }
33960
+ }
33031
33961
  });
33032
33962
  runDueTasksForProject({
33033
33963
  db,
@@ -33041,6 +33971,7 @@ function createMagicContextHook(deps) {
33041
33971
  const commandHandler = createMagicContextCommandHandler({
33042
33972
  db,
33043
33973
  protectedTags: deps.config.protected_tags,
33974
+ compactionOff,
33044
33975
  toastDurationMs: deps.config.toast_duration_ms,
33045
33976
  executeThresholdPercentage: deps.config.execute_threshold_percentage ?? 65,
33046
33977
  executeThresholdTokens: deps.config.execute_threshold_tokens,
@@ -33053,6 +33984,7 @@ function createMagicContextHook(deps) {
33053
33984
  const model = resolveLiveModel(sessionId);
33054
33985
  return model ? `${model.providerID}/${model.modelID}` : undefined;
33055
33986
  },
33987
+ getDreamerProgress: () => dreamerProgressByProject.get(projectPath) ?? null,
33056
33988
  getContextLimit: (sessionId) => {
33057
33989
  const model = resolveLiveModel(sessionId);
33058
33990
  if (!model)
@@ -33100,10 +34032,17 @@ function createMagicContextHook(deps) {
33100
34032
  }),
33101
34033
  userMemoryCollectionEnabled: userMemoryCollectionEnabled(dreamerConfig),
33102
34034
  language: deps.config.language,
33103
- experimentalMural: deps.config.experimental?.mural,
34035
+ mural: deps.config.mural,
33104
34036
  memoryInjectionBudgetTokens: deps.config.memory?.injection_budget_tokens,
33105
34037
  transformMode: deps.config.transform_mode,
33106
- moduleClient: rustModeModuleClient
34038
+ moduleClient: rustModeModuleClient,
34039
+ onProgress: (progress, completedTask) => {
34040
+ if (progress) {
34041
+ dreamerProgressByProject.set(projectPath, progress);
34042
+ } else if (dreamerProgressByProject.get(projectPath)?.task === completedTask) {
34043
+ dreamerProgressByProject.delete(projectPath);
34044
+ }
34045
+ }
33107
34046
  }),
33108
34047
  task
33109
34048
  })
@@ -33184,6 +34123,7 @@ function createMagicContextHook(deps) {
33184
34123
  "tool.execute.after": createToolExecuteAfterHook({
33185
34124
  db,
33186
34125
  channel1StateBySession,
34126
+ client: deps.client,
33187
34127
  transformMode: deps.config.transform_mode,
33188
34128
  todoStateSet: deps.config.transform_mode === "rust" && rustModeModuleClient ? ({ sessionId, stateJson, ownerMessageId }) => rustModeModuleClient.call({
33189
34129
  sessionId,
@@ -33279,15 +34219,30 @@ function createMessagesTransformHandler(args) {
33279
34219
  const sessionId = resolveSessionId2(output);
33280
34220
  const agent = resolveAgentNameFromMessages(output.messages);
33281
34221
  const isInternalChild = typeof sessionId === "string" && sessionId.length > 0 && args.internalChildSessions?.has(sessionId) === true;
34222
+ const compactionOffInputSnapshot = args.compactionOff ? [...output.messages] : null;
34223
+ const restoreCompactionOffInput = () => {
34224
+ if (compactionOffInputSnapshot && output.messages !== compactionOffInputSnapshot) {
34225
+ output.messages.splice(0, output.messages.length, ...compactionOffInputSnapshot);
34226
+ }
34227
+ };
33282
34228
  if (args.failClosed) {
33283
- await args.failClosed.enforce({
33284
- blockingEnabled: args.failClosedBlockingEnabled !== false,
33285
- exempt: shouldBypassFailClosedBlock({
33286
- agent,
33287
- isInternalChildSession: isInternalChild
33288
- }),
33289
- tryReopen: args.tryReopenStorage
33290
- });
34229
+ try {
34230
+ await args.failClosed.enforce({
34231
+ blockingEnabled: args.failClosedBlockingEnabled !== false,
34232
+ exempt: shouldBypassFailClosedBlock({
34233
+ agent,
34234
+ isInternalChildSession: isInternalChild
34235
+ }),
34236
+ tryReopen: args.tryReopenStorage
34237
+ });
34238
+ } catch (error) {
34239
+ if (args.compactionOff && isFailClosedBlockingError(error)) {
34240
+ log(`[magic-context] compaction-off: fail-closed inert, passing through: ${error.message}`);
34241
+ restoreCompactionOffInput();
34242
+ return output.messages;
34243
+ }
34244
+ throw error;
34245
+ }
33291
34246
  }
33292
34247
  const magicContext = args.getMagicContext ? args.getMagicContext() : args.magicContext;
33293
34248
  const slotAtEntry = sessionId ? getSlot(sessionId) : undefined;
@@ -33304,9 +34259,15 @@ function createMessagesTransformHandler(args) {
33304
34259
  return output.messages;
33305
34260
  } catch (error) {
33306
34261
  if (error instanceof EmergencyFailClosedError || isFailClosedBlockingError(error)) {
33307
- throw error;
34262
+ if (!args.compactionOff)
34263
+ throw error;
34264
+ log(`[magic-context] compaction-off: fail-closed inert, passing through: ${error instanceof Error ? error.message : String(error)}`);
34265
+ restoreCompactionOffInput();
34266
+ return output.messages;
33308
34267
  }
33309
- if (sessionId && slotAtEntry && !entry) {
34268
+ if (args.compactionOff) {
34269
+ restoreCompactionOffInput();
34270
+ } else if (sessionId && slotAtEntry && !entry) {
33310
34271
  dropSlot(sessionId, "lkg_invalidated_reshape");
33311
34272
  sessionLog(sessionId, "lkg_invalidated_reshape");
33312
34273
  } else if (sessionId && entry) {
@@ -33348,6 +34309,7 @@ function createMessagesTransformHandler(args) {
33348
34309
  const isTransient = typeof code === "string" && TRANSIENT_SQLITE_CODES.has(code);
33349
34310
  if (isTransient) {
33350
34311
  log(`[magic-context] transform skipped this pass — ${code} (transient; retrying next pass): ${message}`);
34312
+ restoreCompactionOffInput();
33351
34313
  return output.messages;
33352
34314
  }
33353
34315
  log(`[magic-context] transform FAILED code=${code ?? "none"} name=${name ?? "none"}: ${message}. Continuing with unmodified messages for this pass.`, error);
@@ -33369,6 +34331,7 @@ function createMessagesTransformHandler(args) {
33369
34331
  }
33370
34332
  }
33371
34333
  }
34334
+ restoreCompactionOffInput();
33372
34335
  return output.messages;
33373
34336
  };
33374
34337
  }
@@ -33601,21 +34564,11 @@ async function loadRustSessionStatus(client, sessionId, directory) {
33601
34564
  return;
33602
34565
  }
33603
34566
  }
33604
- function parseTtlString(ttl) {
33605
- const match = ttl.match(/^(\d+)(s|m|h)$/);
33606
- if (!match)
34567
+ function safeParseTtl(ttl) {
34568
+ try {
34569
+ return parseCacheTtl(ttl);
34570
+ } catch {
33607
34571
  return 5 * 60 * 1000;
33608
- const val = Number.parseInt(match[1], 10);
33609
- const unit = match[2];
33610
- switch (unit) {
33611
- case "s":
33612
- return val * 1000;
33613
- case "m":
33614
- return val * 60 * 1000;
33615
- case "h":
33616
- return val * 3600 * 1000;
33617
- default:
33618
- return 5 * 60 * 1000;
33619
34572
  }
33620
34573
  }
33621
34574
  function resolveConfigValue(cfg, key, modelKey, defaultValue) {
@@ -33638,7 +34591,7 @@ function resolveConfigValue(cfg, key, modelKey, defaultValue) {
33638
34591
  }
33639
34592
  return defaultValue;
33640
34593
  }
33641
- function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus) {
34594
+ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled = true) {
33642
34595
  try {
33643
34596
  const projectIdentity = resolveProjectIdentity(directory);
33644
34597
  const meta = db.prepare("SELECT * FROM session_meta WHERE session_id = ?").get(sessionId);
@@ -33659,7 +34612,8 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33659
34612
  const cacheTtl = meta ? String(meta.cache_ttl ?? "5m") : "5m";
33660
34613
  const memoryBlockCount = meta ? Number(meta.memory_block_count ?? 0) : 0;
33661
34614
  const compartmentRow = db.prepare("SELECT COUNT(*) as count FROM compartments WHERE session_id = ?").get(sessionId);
33662
- const compartmentCount = typeof moduleStatus?.compartment_count === "number" ? moduleStatus.compartment_count : compartmentRow?.count ?? 0;
34615
+ const archivedCompartmentCount = compartmentRow?.count ?? 0;
34616
+ const compartmentCount = typeof moduleStatus?.compartment_count === "number" ? moduleStatus.compartment_count : archivedCompartmentCount;
33663
34617
  let memoryCount = 0;
33664
34618
  if (projectIdentity) {
33665
34619
  const memRow = db.prepare("SELECT COUNT(*) as count FROM memories WHERE project_path = ? AND status = 'active'").get(projectIdentity);
@@ -33700,6 +34654,13 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33700
34654
  const docsTokens = m0Blocks.docsTokens;
33701
34655
  const profileTokens = m0Blocks.profileTokens;
33702
34656
  let lastDreamerRunAt = null;
34657
+ let dreamerBacklog;
34658
+ const dreamerProgress = projectIdentity ? liveSessionState?.dreamerProgressByProject?.get(projectIdentity) ?? null : null;
34659
+ if (projectIdentity) {
34660
+ try {
34661
+ dreamerBacklog = getDreamTaskBacklogs(db, projectIdentity, CANONICAL_DREAM_TASKS);
34662
+ } catch {}
34663
+ }
33703
34664
  if (projectIdentity) {
33704
34665
  try {
33705
34666
  lastDreamerRunAt = getMostRecentTaskRunAt(db, projectIdentity);
@@ -33754,6 +34715,12 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33754
34715
  executeThreshold = thresholdDetail.percentage;
33755
34716
  executeThresholdClamped = thresholdDetail.clamped === true;
33756
34717
  }
34718
+ const nativeContextLimit = activeProviderID && activeModelID ? resolveContextLimit(activeProviderID, activeModelID, {
34719
+ db,
34720
+ sessionID: sessionId,
34721
+ reservation: "none"
34722
+ }) : contextLimit;
34723
+ const nativeContextUsagePercentage = nativeContextLimit > 0 ? effectiveInputTokens / nativeContextLimit * 100 : undefined;
33757
34724
  const calibration = resolveModelCalibration(activeProviderID, activeModelID);
33758
34725
  const calibrated = calibrateBuckets({
33759
34726
  inputTokens: effectiveInputTokens,
@@ -33773,8 +34740,11 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33773
34740
  usagePercentage: effectiveUsagePercentage,
33774
34741
  inputTokens: effectiveInputTokens,
33775
34742
  contextLimit,
34743
+ native_context_usage_percentage: nativeContextUsagePercentage,
34744
+ compaction_enabled: compactionEnabled,
33776
34745
  systemPromptTokens: calibrated.systemTokens,
33777
34746
  compartmentCount,
34747
+ archivedCompartmentCount,
33778
34748
  memoryCount,
33779
34749
  memoryBlockCount,
33780
34750
  pendingOpsCount,
@@ -33783,8 +34753,11 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33783
34753
  sessionNoteCount,
33784
34754
  readySmartNoteCount,
33785
34755
  cacheTtl,
34756
+ lastTransformError: meta?.last_transform_error ? String(meta.last_transform_error) : null,
33786
34757
  lastDreamerRunAt,
33787
34758
  projectIdentity,
34759
+ dreamerBacklog,
34760
+ dreamerProgress,
33788
34761
  compartmentTokens: calibrated.compartmentTokens,
33789
34762
  factTokens: calibrated.factTokens,
33790
34763
  memoryTokens: calibrated.memoryTokens,
@@ -33821,15 +34794,15 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33821
34794
  throw err;
33822
34795
  }
33823
34796
  }
33824
- function buildSidebarSnapshotRpcResponse(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus) {
34797
+ function buildSidebarSnapshotRpcResponse(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled = true) {
33825
34798
  try {
33826
- return buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus);
34799
+ return buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled);
33827
34800
  } catch {
33828
34801
  return { error: "sidebar snapshot unavailable" };
33829
34802
  }
33830
34803
  }
33831
- function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessionState, injectionBudgetTokens, moduleStatus) {
33832
- const base = buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus);
34804
+ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessionState, injectionBudgetTokens, moduleStatus, compactionEnabled = true) {
34805
+ const base = buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled);
33833
34806
  const detail = {
33834
34807
  ...base,
33835
34808
  tagCounter: 0,
@@ -33846,6 +34819,7 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessi
33846
34819
  cacheTtlMs: 0,
33847
34820
  cacheRemainingMs: 0,
33848
34821
  cacheExpired: false,
34822
+ cacheNeverExpires: false,
33849
34823
  executeThreshold: 65,
33850
34824
  executeThresholdMode: "percentage",
33851
34825
  protectedTagCount: 20,
@@ -33854,9 +34828,17 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessi
33854
34828
  compressionBudget: null,
33855
34829
  compressionUsage: null,
33856
34830
  toastDurationMs: 5000,
33857
- mural: undefined
34831
+ mural: undefined,
34832
+ storage_versions: {
34833
+ context_db_schema_version: null,
34834
+ plugin_supported_version: LATEST_SUPPORTED_VERSION
34835
+ }
33858
34836
  };
33859
34837
  try {
34838
+ detail.storage_versions = {
34839
+ context_db_schema_version: getPersistedSchemaVersion(db),
34840
+ plugin_supported_version: LATEST_SUPPORTED_VERSION
34841
+ };
33860
34842
  const muralConfig = config?.experimental?.mural;
33861
34843
  if (muralConfig?.enabled && base.projectIdentity) {
33862
34844
  const row = getMural(db, base.projectIdentity);
@@ -33915,11 +34897,20 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessi
33915
34897
  } else if (base.usagePercentage > 0) {
33916
34898
  detail.contextLimit = Math.round(base.inputTokens / (base.usagePercentage / 100));
33917
34899
  }
33918
- detail.cacheTtlMs = parseTtlString(detail.cacheTtl);
34900
+ detail.cacheTtlMs = safeParseTtl(detail.cacheTtl);
34901
+ if (detail.cacheTtlMs === Number.POSITIVE_INFINITY) {
34902
+ detail.cacheNeverExpires = true;
34903
+ detail.cacheTtlMs = -1;
34904
+ }
33919
34905
  if (detail.lastResponseTime > 0) {
33920
34906
  const elapsed = Date.now() - detail.lastResponseTime;
33921
- detail.cacheRemainingMs = Math.max(0, detail.cacheTtlMs - elapsed);
33922
- detail.cacheExpired = detail.cacheRemainingMs === 0;
34907
+ if (detail.cacheNeverExpires) {
34908
+ detail.cacheRemainingMs = -1;
34909
+ detail.cacheExpired = false;
34910
+ } else {
34911
+ detail.cacheRemainingMs = Math.max(0, detail.cacheTtlMs - elapsed);
34912
+ detail.cacheExpired = detail.cacheRemainingMs === 0;
34913
+ }
33923
34914
  }
33924
34915
  try {
33925
34916
  const histTokens = base.compartmentTokens + base.factTokens;
@@ -33957,6 +34948,7 @@ function buildEmbedDetail(db, sessionId, dir, liveSessionState) {
33957
34948
  }
33958
34949
  function registerRpcHandlers(rpcServer, args) {
33959
34950
  const { directory, config, liveSessionState, rustModeModuleClient } = args;
34951
+ const compactionEnabled = isCompactionEnabled(config);
33960
34952
  const rawConfig = config;
33961
34953
  const getNotificationParams = (sessionId) => getLiveNotificationParams(sessionId, liveSessionState.liveModelBySession, liveSessionState.variantBySession, liveSessionState.agentBySession, config.toast_duration_ms);
33962
34954
  const injectionBudgetTokens = config.memory?.injection_budget_tokens;
@@ -33967,7 +34959,7 @@ function registerRpcHandlers(rpcServer, args) {
33967
34959
  if (!db || !sessionId)
33968
34960
  return { error: "unavailable" };
33969
34961
  const moduleStatus = config.transform_mode === "rust" ? await loadRustSessionStatus(rustModeModuleClient, sessionId, dir) : undefined;
33970
- return buildSidebarSnapshotRpcResponse(db, sessionId, dir, liveSessionState, injectionBudgetTokens, rawConfig, moduleStatus);
34962
+ return buildSidebarSnapshotRpcResponse(db, sessionId, dir, liveSessionState, injectionBudgetTokens, rawConfig, moduleStatus, compactionEnabled);
33971
34963
  });
33972
34964
  rpcServer.handle("status-detail", async (params) => {
33973
34965
  const sessionId = String(params.sessionId ?? "");
@@ -33977,7 +34969,7 @@ function registerRpcHandlers(rpcServer, args) {
33977
34969
  if (!db || !sessionId)
33978
34970
  return { error: "unavailable" };
33979
34971
  const moduleStatus = config.transform_mode === "rust" ? await loadRustSessionStatus(rustModeModuleClient, sessionId, dir) : undefined;
33980
- return buildStatusDetail(db, sessionId, dir, modelKey, rawConfig, liveSessionState, injectionBudgetTokens, moduleStatus);
34972
+ return buildStatusDetail(db, sessionId, dir, modelKey, rawConfig, liveSessionState, injectionBudgetTokens, moduleStatus, compactionEnabled);
33981
34973
  });
33982
34974
  rpcServer.handle("embed-detail", async (params) => {
33983
34975
  const sessionId = String(params.sessionId ?? "");
@@ -34005,9 +34997,9 @@ function registerRpcHandlers(rpcServer, args) {
34005
34997
  }
34006
34998
  });
34007
34999
  const buildManagedCtx = async (db) => {
34008
- const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await import("./derive-budgets-e9j09sjr.js");
35000
+ const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await import("./derive-budgets-9crp0cvd.js");
34009
35001
  const { resolveFallbackChain: resolveFallbackChain2 } = await import("./resolve-fallbacks-5n5tvge1.js");
34010
- const { userMemoryCollectionEnabled: userMemoryCollectionEnabled2 } = await import("./task-config-5nx3qfz8.js");
35002
+ const { userMemoryCollectionEnabled: userMemoryCollectionEnabled2 } = await import("./task-config-gbp7r23g.js");
34011
35003
  const DEFAULT_HISTORIAN_TIMEOUT_MS2 = 600000;
34012
35004
  return {
34013
35005
  client: args.client,
@@ -34032,8 +35024,8 @@ function registerRpcHandlers(rpcServer, args) {
34032
35024
  const db = getDb();
34033
35025
  if (!db)
34034
35026
  return { ok: false, error: "db unavailable" };
34035
- const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-2yb2hfh2.js");
34036
- const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-tghq9gnh.js");
35027
+ const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-k72ejkkh.js");
35028
+ const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-6njqewzk.js");
34037
35029
  log(`[rpc] recomp requested for session ${sessionId}`);
34038
35030
  const ctx = await buildManagedCtx(db);
34039
35031
  runManagedRecomp2(ctx, sessionId).then((message) => {
@@ -34048,8 +35040,8 @@ function registerRpcHandlers(rpcServer, args) {
34048
35040
  const db = getDb();
34049
35041
  if (!db)
34050
35042
  return { ok: false, error: "db unavailable" };
34051
- const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-2yb2hfh2.js");
34052
- const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-tghq9gnh.js");
35043
+ const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-k72ejkkh.js");
35044
+ const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-6njqewzk.js");
34053
35045
  log(`[rpc] session-upgrade requested for session ${sessionId}`);
34054
35046
  const ctx = await buildManagedCtx(db);
34055
35047
  runManagedUpgrade2(ctx, sessionId).then((message) => {
@@ -34065,7 +35057,7 @@ function registerRpcHandlers(rpcServer, args) {
34065
35057
  if (!db)
34066
35058
  return { ok: false, error: "db unavailable" };
34067
35059
  try {
34068
- const { updateSessionMeta: updateSessionMeta2 } = await import("./storage-meta-session-td6bwtky.js");
35060
+ const { updateSessionMeta: updateSessionMeta2 } = await import("./storage-meta-session-xt41zbw4.js");
34069
35061
  updateSessionMeta2(db, sessionId, { upgradeRemindedAt: Date.now() });
34070
35062
  return { ok: true };
34071
35063
  } catch (error) {
@@ -34169,7 +35161,7 @@ Two recovery modes for finer detail:
34169
35161
  var CTX_EXPAND_TOKEN_BUDGET = 15000;
34170
35162
 
34171
35163
  // src/tools/ctx-expand/render.ts
34172
- function isRecord3(value) {
35164
+ function isRecord4(value) {
34173
35165
  return value !== null && typeof value === "object" && !Array.isArray(value);
34174
35166
  }
34175
35167
  function roleLabel(role) {
@@ -34198,15 +35190,15 @@ function keyArg(input) {
34198
35190
  function asToolPart(part) {
34199
35191
  const type = typeof part.type === "string" ? part.type : "";
34200
35192
  if (type === "tool") {
34201
- const state = isRecord3(part.state) ? part.state : null;
35193
+ const state = isRecord4(part.state) ? part.state : null;
34202
35194
  const output = state && typeof state.output === "string" ? state.output : state && state.output != null ? JSON.stringify(state.output) : null;
34203
- const metadata = state && isRecord3(state.metadata) ? state.metadata : null;
35195
+ const metadata = state && isRecord4(state.metadata) ? state.metadata : null;
34204
35196
  const title = state && typeof state.title === "string" && state.title || metadata && typeof metadata.title === "string" && metadata.title || null;
34205
35197
  return {
34206
35198
  name: typeof part.tool === "string" ? part.tool : "tool",
34207
35199
  callId: typeof part.callID === "string" ? part.callID : "",
34208
35200
  title,
34209
- input: state && isRecord3(state.input) ? state.input : null,
35201
+ input: state && isRecord4(state.input) ? state.input : null,
34210
35202
  output
34211
35203
  };
34212
35204
  }
@@ -34215,7 +35207,7 @@ function asToolPart(part) {
34215
35207
  name: typeof part.name === "string" ? part.name : "tool",
34216
35208
  callId: typeof part.id === "string" ? part.id : "",
34217
35209
  title: null,
34218
- input: isRecord3(part.input) ? part.input : null,
35210
+ input: isRecord4(part.input) ? part.input : null,
34219
35211
  output: null
34220
35212
  };
34221
35213
  }
@@ -34244,7 +35236,7 @@ function reasoningOf(part) {
34244
35236
  return null;
34245
35237
  }
34246
35238
  function renderPartPreview(part) {
34247
- if (!isRecord3(part))
35239
+ if (!isRecord4(part))
34248
35240
  return null;
34249
35241
  const text = textOf(part);
34250
35242
  if (text !== null) {
@@ -34268,7 +35260,7 @@ function renderPartPreview(part) {
34268
35260
  return ` • [${type}]`;
34269
35261
  }
34270
35262
  function renderPartFull(part) {
34271
- if (!isRecord3(part))
35263
+ if (!isRecord4(part))
34272
35264
  return null;
34273
35265
  const text = textOf(part);
34274
35266
  if (text !== null) {
@@ -35774,6 +36766,8 @@ function createToolRegistry(args) {
35774
36766
  if (pluginConfig.enabled !== true) {
35775
36767
  return {};
35776
36768
  }
36769
+ const compactionOff = !isCompactionEnabled(pluginConfig);
36770
+ setCtxReduceRegisteredGlobally(!compactionOff);
35777
36771
  let db;
35778
36772
  try {
35779
36773
  const opened = openDatabase();
@@ -35791,10 +36785,10 @@ function createToolRegistry(args) {
35791
36785
  ensureProjectRegisteredFromOpenCodeDirectory(ctx.directory, db).catch((error) => {
35792
36786
  log(`[magic-context] embedding registration skipped: ${getErrorMessage(error)}`);
35793
36787
  });
35794
- const resolveProjectPath = (directory) => resolveProjectIdentityForSession(directory);
36788
+ const resolveProjectPath = (directory) => resolveProjectIdentityForSession(directory, pluginConfig.allow_home_project);
35795
36789
  const memoryEnabled = pluginConfig.memory?.enabled !== false;
35796
36790
  const allTools = {
35797
- ...createCtxReduceTools({
36791
+ ...compactionOff ? {} : createCtxReduceTools({
35798
36792
  db,
35799
36793
  protectedTags: pluginConfig.protected_tags ?? DEFAULT_PROTECTED_TAGS,
35800
36794
  rustToolBackends
@@ -35859,64 +36853,6 @@ import {
35859
36853
  writeFileSync as writeFileSync5
35860
36854
  } from "node:fs";
35861
36855
  import { dirname as dirname5 } from "node:path";
35862
-
35863
- // src/shared/rpc-utils.ts
35864
- import { createHash as createHash14 } from "node:crypto";
35865
- import { join as join7 } from "node:path";
35866
- function projectHash(directory) {
35867
- const normalized = directory.replace(/\/+$/, "");
35868
- return createHash14("sha256").update(normalized).digest("hex").slice(0, 16);
35869
- }
35870
- function rpcPortDir(storageDir, directory) {
35871
- return join7(storageDir, "rpc", projectHash(directory));
35872
- }
35873
- function rpcPortFilePath(storageDir, directory, pid = process.pid, instanceId) {
35874
- const suffix = instanceId ? `-${instanceId}` : "";
35875
- return join7(rpcPortDir(storageDir, directory), `port-${pid}${suffix}.json`);
35876
- }
35877
- function isPidAlive(pid) {
35878
- if (!Number.isInteger(pid) || pid <= 0)
35879
- return false;
35880
- try {
35881
- process.kill(pid, 0);
35882
- return true;
35883
- } catch (err) {
35884
- return err.code === "EPERM";
35885
- }
35886
- }
35887
- function parseRpcPortFile(content, fallbackPid = 0) {
35888
- const trimmed = content.trim();
35889
- if (!trimmed)
35890
- return null;
35891
- if (trimmed.startsWith("{")) {
35892
- try {
35893
- const parsed = JSON.parse(trimmed);
35894
- const port2 = Number(parsed.port);
35895
- const pid = Number(parsed.pid);
35896
- const startedAt = Number(parsed.started_at);
35897
- if (!isValidPort(port2) || !Number.isInteger(pid) || pid <= 0)
35898
- return null;
35899
- return {
35900
- port: port2,
35901
- pid,
35902
- started_at: Number.isFinite(startedAt) ? startedAt : 0,
35903
- token: typeof parsed.token === "string" ? parsed.token : undefined,
35904
- instance_id: typeof parsed.instance_id === "string" ? parsed.instance_id : undefined
35905
- };
35906
- } catch {
35907
- return null;
35908
- }
35909
- }
35910
- const port = Number.parseInt(trimmed, 10);
35911
- if (!isValidPort(port))
35912
- return null;
35913
- return { port, pid: fallbackPid, started_at: 0 };
35914
- }
35915
- function isValidPort(port) {
35916
- return Number.isInteger(port) && port > 0 && port <= 65535;
35917
- }
35918
-
35919
- // src/shared/rpc-server.ts
35920
36856
  var MAX_BODY_BYTES = 1048576;
35921
36857
  var WS_AUTH_TIMEOUT_MS = 5000;
35922
36858
  var WS_CLOSE_UNAUTHORIZED = 4401;
@@ -35991,10 +36927,15 @@ class MagicContextRpcServer {
35991
36927
  try {
35992
36928
  this.warnIfOtherLiveInstance();
35993
36929
  const dir = dirname5(this.portFilePath);
35994
- mkdirSync3(dir, { recursive: true, mode: 448 });
35995
- try {
35996
- chmodSync(dir, 448);
35997
- } catch {}
36930
+ const enforcePrivatePermissions = shouldEnforcePrivateStoragePermissions();
36931
+ if (enforcePrivatePermissions) {
36932
+ mkdirSync3(dir, { recursive: true, mode: 448 });
36933
+ try {
36934
+ chmodSync(dir, 448);
36935
+ } catch {}
36936
+ } else {
36937
+ mkdirSync3(dir, { recursive: true });
36938
+ }
35998
36939
  const tmpPath = `${this.portFilePath}.tmp`;
35999
36940
  try {
36000
36941
  rmSync3(tmpPath, { force: true });
@@ -36005,11 +36946,13 @@ class MagicContextRpcServer {
36005
36946
  started_at: this.startedAt,
36006
36947
  token: this.token,
36007
36948
  instance_id: this.instanceId
36008
- }), { encoding: "utf-8", mode: 384 });
36949
+ }), enforcePrivatePermissions ? { encoding: "utf-8", mode: 384 } : { encoding: "utf-8" });
36009
36950
  renameSync4(tmpPath, this.portFilePath);
36010
- try {
36011
- chmodSync(this.portFilePath, 384);
36012
- } catch {}
36951
+ if (enforcePrivatePermissions) {
36952
+ try {
36953
+ chmodSync(this.portFilePath, 384);
36954
+ } catch {}
36955
+ }
36013
36956
  log(`[rpc] server listening on 127.0.0.1:${this.port}`);
36014
36957
  } catch (err) {
36015
36958
  log(`[rpc] failed to write port file: ${err}`);
@@ -36186,6 +37129,7 @@ var server = async (ctx) => {
36186
37129
  ...pluginConfig.configWarnings ?? []
36187
37130
  ];
36188
37131
  }
37132
+ setStoragePrivatePermissionEnforcement(pluginConfig.storage.enforce_private_permissions);
36189
37133
  setSqlitePragmaConfig({
36190
37134
  cacheSizeMb: pluginConfig.sqlite.cache_size_mb,
36191
37135
  mmapSizeMb: pluginConfig.sqlite.mmap_size_mb
@@ -36209,7 +37153,7 @@ var server = async (ctx) => {
36209
37153
  `);
36210
37154
  setTimeout(async () => {
36211
37155
  try {
36212
- const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-tghq9gnh.js");
37156
+ const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-6njqewzk.js");
36213
37157
  const clientWithSessions = ctx.client;
36214
37158
  const sessions = await Promise.resolve(clientWithSessions.session?.list?.()).catch(() => null);
36215
37159
  const sessionList = Array.isArray(sessions) ? sessions : sessions?.data;
@@ -36222,7 +37166,9 @@ var server = async (ctx) => {
36222
37166
  }
36223
37167
  let conflictResult = null;
36224
37168
  if (pluginConfig.enabled) {
36225
- conflictResult = detectConflicts(ctx.directory);
37169
+ conflictResult = detectConflicts(ctx.directory, {
37170
+ compactionEnabled: isCompactionEnabled(pluginConfig)
37171
+ });
36226
37172
  if (conflictResult.hasConflict) {
36227
37173
  pluginConfig.enabled = false;
36228
37174
  log(`[magic-context] disabled due to conflicts: ${conflictResult.reasons.join("; ")}`);
@@ -36332,9 +37278,9 @@ var server = async (ctx) => {
36332
37278
  if (pluginConfig.enabled) {
36333
37279
  const dreamerRunnable = isDreamerRunnable(pluginConfig);
36334
37280
  const classifyModuleClient = createDreamTimerModuleClient(rustModeModuleClient);
36335
- const timerProjectIdentity = resolveProjectIdentityForSession(ctx.directory);
37281
+ const timerProjectIdentity = resolveProjectIdentityForSession(ctx.directory, pluginConfig.allow_home_project);
36336
37282
  if (!timerProjectIdentity) {
36337
- log("[magic-context] dream timer skipped: cwd is the user's home directory");
37283
+ log("[magic-context] dream timer skipped: no project identity is bound for this directory");
36338
37284
  } else {
36339
37285
  const timerRegistration = {
36340
37286
  directory: ctx.directory,
@@ -36346,13 +37292,20 @@ var server = async (ctx) => {
36346
37292
  embeddingConfig: pluginConfig.embedding,
36347
37293
  memoryEnabled: pluginConfig.memory?.enabled === true,
36348
37294
  memoryInjectionBudgetTokens: pluginConfig.memory?.injection_budget_tokens,
36349
- experimentalMural: pluginConfig.experimental?.mural,
37295
+ mural: pluginConfig.mural,
36350
37296
  gitCommitIndexing: pluginConfig.memory.git_commit_indexing?.enabled ? {
36351
37297
  enabled: true,
36352
37298
  since_days: pluginConfig.memory.git_commit_indexing.since_days,
36353
37299
  max_commits: pluginConfig.memory.git_commit_indexing.max_commits
36354
37300
  } : undefined,
36355
37301
  ensureRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
37302
+ onDreamerProgress: (progress, completedTask) => {
37303
+ if (progress) {
37304
+ liveSessionState.dreamerProgressByProject.set(timerProjectIdentity, progress);
37305
+ } else if (liveSessionState.dreamerProgressByProject.get(timerProjectIdentity)?.task === completedTask) {
37306
+ liveSessionState.dreamerProgressByProject.delete(timerProjectIdentity);
37307
+ }
37308
+ },
36356
37309
  moduleClient: classifyModuleClient
36357
37310
  };
36358
37311
  try {
@@ -36377,7 +37330,7 @@ var server = async (ctx) => {
36377
37330
  {
36378
37331
  const fence = getSchemaFenceRejection();
36379
37332
  if (fence) {
36380
- import("./conflict-warning-hook-n48c783v.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
37333
+ import("./conflict-warning-hook-fvpfvt0w.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
36381
37334
  }
36382
37335
  }
36383
37336
  if (conflictResult?.hasConflict) {
@@ -36398,7 +37351,7 @@ var server = async (ctx) => {
36398
37351
  } = await import("./announcement-gms2nhya.js");
36399
37352
  if (shouldShowAnnouncement2()) {
36400
37353
  setTimeout(() => {
36401
- import("./conflict-warning-hook-n48c783v.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION2, ANNOUNCEMENT_FEATURES2, ANNOUNCEMENT_FOOTER2, markAnnouncementSeen2)).catch(() => {});
37354
+ import("./conflict-warning-hook-fvpfvt0w.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION2, ANNOUNCEMENT_FEATURES2, ANNOUNCEMENT_FOOTER2, markAnnouncementSeen2)).catch(() => {});
36402
37355
  }, 8000);
36403
37356
  }
36404
37357
  } catch {}
@@ -36439,6 +37392,7 @@ var server = async (ctx) => {
36439
37392
  getMagicContext: () => magicContextRuntime.magicContext,
36440
37393
  failClosed,
36441
37394
  failClosedBlockingEnabled,
37395
+ compactionOff: !isCompactionEnabled(pluginConfig),
36442
37396
  internalChildSessions: liveSessionState.internalChildSessions,
36443
37397
  tryReopenStorage
36444
37398
  }),
@@ -36480,7 +37434,7 @@ var server = async (ctx) => {
36480
37434
  }
36481
37435
  const commandConfig = {
36482
37436
  ...config.command ?? {},
36483
- ...getMagicContextBuiltinCommands(),
37437
+ ...getMagicContextBuiltinCommands(isCompactionEnabled(pluginConfig)),
36484
37438
  ...pluginConfig.command ?? {}
36485
37439
  };
36486
37440
  config.command = commandConfig;