@cortexkit/opencode-magic-context 0.33.1 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/dist/config/agent-disable.d.ts +22 -0
  2. package/dist/config/agent-disable.d.ts.map +1 -1
  3. package/dist/config/index.d.ts.map +1 -1
  4. package/dist/config/project-security.d.ts +7 -0
  5. package/dist/config/project-security.d.ts.map +1 -1
  6. package/dist/config/schema/magic-context.d.ts +82 -2
  7. package/dist/config/schema/magic-context.d.ts.map +1 -1
  8. package/dist/config/transform-mode.d.ts +2 -0
  9. package/dist/config/transform-mode.d.ts.map +1 -1
  10. package/dist/{conflict-warning-hook-n48c783v.js → conflict-warning-hook-fvpfvt0w.js} +1 -1
  11. package/dist/{derive-budgets-e9j09sjr.js → derive-budgets-9crp0cvd.js} +1 -1
  12. package/dist/features/builtin-commands/commands.d.ts +1 -1
  13. package/dist/features/builtin-commands/commands.d.ts.map +1 -1
  14. package/dist/features/magic-context/compaction-marker.d.ts +57 -0
  15. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  16. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  17. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  18. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  19. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  21. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  23. package/dist/features/magic-context/fail-closed-block.d.ts +10 -0
  24. package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
  25. package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -1
  26. package/dist/features/magic-context/git-commits/storage-git-commits.d.ts.map +1 -1
  27. package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -1
  28. package/dist/features/magic-context/memory/embedding-local.d.ts +7 -1
  29. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  30. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
  31. package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
  32. package/dist/features/magic-context/memory/project-identity.d.ts +2 -6
  33. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  34. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
  35. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  36. package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
  37. package/dist/features/magic-context/mural/render-mural.d.ts.map +1 -1
  38. package/dist/features/magic-context/overflow-detection.d.ts +8 -1
  39. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  40. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  41. package/dist/features/magic-context/scheduler.d.ts.map +1 -1
  42. package/dist/features/magic-context/schema-fence-probe.d.ts +28 -0
  43. package/dist/features/magic-context/schema-fence-probe.d.ts.map +1 -0
  44. package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
  45. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
  46. package/dist/features/magic-context/storage-db.d.ts +35 -1
  47. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  48. package/dist/features/magic-context/storage-meta-persisted.d.ts +38 -4
  49. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  50. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  51. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  52. package/dist/features/magic-context/storage.d.ts +1 -1
  53. package/dist/features/magic-context/storage.d.ts.map +1 -1
  54. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
  55. package/dist/hooks/magic-context/boundary-execution.d.ts +1 -1
  56. package/dist/hooks/magic-context/boundary-execution.d.ts.map +1 -1
  57. package/dist/hooks/magic-context/cache-busting-signals.d.ts +1 -0
  58. package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
  59. package/dist/hooks/magic-context/child-session-spawn.d.ts +26 -0
  60. package/dist/hooks/magic-context/child-session-spawn.d.ts.map +1 -0
  61. package/dist/hooks/magic-context/command-handler.d.ts +2 -0
  62. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  63. package/dist/hooks/magic-context/compaction-off-transition.d.ts +96 -0
  64. package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -0
  65. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +2 -0
  66. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  67. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  68. package/dist/hooks/magic-context/compartment-runner-mapping.d.ts.map +1 -1
  69. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  70. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  71. package/dist/hooks/magic-context/compartment-trigger.d.ts +12 -5
  72. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  73. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +47 -1
  74. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
  75. package/dist/hooks/magic-context/emergency-drop.d.ts +2 -2
  76. package/dist/hooks/magic-context/event-handler.d.ts +7 -0
  77. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  78. package/dist/hooks/magic-context/event-resolvers.d.ts +13 -21
  79. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  80. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
  81. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  82. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +1 -1
  83. package/dist/hooks/magic-context/hook-handlers.d.ts +1 -0
  84. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  85. package/dist/hooks/magic-context/hook.d.ts +11 -1
  86. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  87. package/dist/hooks/magic-context/inject-compartments.d.ts +9 -0
  88. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  89. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  90. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  91. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  92. package/dist/hooks/magic-context/rust-mode-transform.d.ts +3 -0
  93. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  94. package/dist/hooks/magic-context/send-session-notification.d.ts +20 -1
  95. package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
  96. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +3 -0
  97. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  98. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +30 -0
  99. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  100. package/dist/hooks/magic-context/transform.d.ts +27 -0
  101. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  102. package/dist/{index-ey1bc14z.js → index-b563sga5.js} +7 -264
  103. package/dist/{index-y1c9tcm3.js → index-cn960ffd.js} +101 -20
  104. package/dist/{index-xyaekybw.js → index-dtas91s5.js} +6 -4
  105. package/dist/index-fcyvznch.js +279 -0
  106. package/dist/{index-63dq2g4d.js → index-ry8rh8cv.js} +138 -24
  107. package/dist/{index-c2gahrks.js → index-s0mdn690.js} +1599 -892
  108. package/dist/index.d.ts.map +1 -1
  109. package/dist/index.js +1292 -623
  110. package/dist/plugin/embedding-bootstrap.d.ts.map +1 -1
  111. package/dist/plugin/hooks/create-session-hooks.d.ts +11 -0
  112. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  113. package/dist/plugin/messages-transform.d.ts +10 -0
  114. package/dist/plugin/messages-transform.d.ts.map +1 -1
  115. package/dist/plugin/rpc-handlers.d.ts +3 -7
  116. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  117. package/dist/plugin/tool-registry.d.ts +8 -0
  118. package/dist/plugin/tool-registry.d.ts.map +1 -1
  119. package/dist/{recomp-orchestrator-2yb2hfh2.js → recomp-orchestrator-8e82vmvb.js} +6 -4
  120. package/dist/send-session-notification-6njqewzk.js +20 -0
  121. package/dist/shared/conflict-detector.d.ts +38 -1
  122. package/dist/shared/conflict-detector.d.ts.map +1 -1
  123. package/dist/shared/conflict-fixer.d.ts +18 -1
  124. package/dist/shared/conflict-fixer.d.ts.map +1 -1
  125. package/dist/shared/context-limit-provenance.d.ts +3 -0
  126. package/dist/shared/context-limit-provenance.d.ts.map +1 -0
  127. package/dist/shared/escalation-bands.d.ts +9 -0
  128. package/dist/shared/escalation-bands.d.ts.map +1 -0
  129. package/dist/shared/format-threshold.d.ts +1 -1
  130. package/dist/shared/models-dev-cache.d.ts +29 -3
  131. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  132. package/dist/shared/rpc-server.d.ts.map +1 -1
  133. package/dist/shared/rpc-types.d.ts +46 -1
  134. package/dist/shared/rpc-types.d.ts.map +1 -1
  135. package/dist/shared/storage-permissions.d.ts +5 -0
  136. package/dist/shared/storage-permissions.d.ts.map +1 -0
  137. package/dist/{storage-meta-session-td6bwtky.js → storage-meta-session-xt41zbw4.js} +2 -1
  138. package/dist/tui/compaction-off.d.ts +13 -0
  139. package/dist/tui/compaction-off.d.ts.map +1 -0
  140. package/dist/tui/data/context-db.d.ts.map +1 -1
  141. package/dist/tui-compiled/compaction-off.d.ts +13 -0
  142. package/dist/tui-compiled/compaction-off.d.ts.map +1 -0
  143. package/dist/tui-compiled/data/context-db.d.ts.map +1 -1
  144. package/package.json +7 -2
  145. package/src/agents/dreamer.ts +68 -0
  146. package/src/agents/hidden-agent-registrations.ts +331 -0
  147. package/src/agents/historian.ts +3 -0
  148. package/src/agents/language-directive.test.ts +138 -0
  149. package/src/agents/language-directive.ts +121 -0
  150. package/src/agents/magic-context-prompt.language.test.ts +35 -0
  151. package/src/agents/magic-context-prompt.test.ts +292 -0
  152. package/src/agents/magic-context-prompt.ts +182 -0
  153. package/src/agents/permissions.test.ts +252 -0
  154. package/src/agents/permissions.ts +186 -0
  155. package/src/agents/sidekick.ts +1 -0
  156. package/src/agents/smart-note-compiler.ts +1 -0
  157. package/src/config/agent-disable.ts +106 -0
  158. package/src/config/compaction-accessor-guard.test.ts +82 -0
  159. package/src/config/compaction-backcompat.test.ts +52 -0
  160. package/src/config/index.test.ts +904 -0
  161. package/src/config/index.ts +601 -0
  162. package/src/config/migrate-config-location.test.ts +332 -0
  163. package/src/config/migrate-config-location.ts +635 -0
  164. package/src/config/migrate-dreamer-v2.test.ts +287 -0
  165. package/src/config/migrate-dreamer-v2.ts +336 -0
  166. package/src/config/migrate-experimental.ts +159 -0
  167. package/src/config/project-security.test.ts +366 -0
  168. package/src/config/project-security.ts +588 -0
  169. package/src/config/prune-config-leaf.test.ts +78 -0
  170. package/src/config/prune-config-leaf.ts +68 -0
  171. package/src/config/removed-config-keys.test.ts +116 -0
  172. package/src/config/schema/agent-overrides.ts +45 -0
  173. package/src/config/schema/magic-context.test.ts +358 -0
  174. package/src/config/schema/magic-context.ts +1002 -0
  175. package/src/config/transform-mode.test.ts +62 -0
  176. package/src/config/transform-mode.ts +34 -0
  177. package/src/config/variable.test.ts +323 -0
  178. package/src/config/variable.ts +192 -0
  179. package/src/features/magic-context/defaults.ts +1 -0
  180. package/src/features/magic-context/dreamer/cron.ts +243 -0
  181. package/src/features/magic-context/dreamer/task-registry.ts +104 -0
  182. package/src/shared/conflict-detector.test.ts +121 -0
  183. package/src/shared/conflict-detector.ts +50 -3
  184. package/src/shared/conflict-fixer.test.ts +309 -0
  185. package/src/shared/conflict-fixer.ts +82 -5
  186. package/src/shared/context-limit-provenance.ts +6 -0
  187. package/src/shared/escalation-bands.test.ts +23 -0
  188. package/src/shared/escalation-bands.ts +18 -0
  189. package/src/shared/format-threshold.ts +1 -1
  190. package/src/shared/models-dev-cache.test.ts +171 -0
  191. package/src/shared/models-dev-cache.ts +195 -38
  192. package/src/shared/rpc-server.ts +27 -18
  193. package/src/shared/rpc-types.ts +46 -1
  194. package/src/shared/storage-permissions.ts +20 -0
  195. package/src/tui/compaction-off.test.ts +56 -0
  196. package/src/tui/compaction-off.ts +29 -0
  197. package/src/tui/data/context-db.ts +6 -0
  198. package/src/tui/index.tsx +113 -65
  199. package/src/tui/slots/sidebar-content.tsx +139 -83
  200. package/src/tui-compiled/compaction-off.ts +29 -0
  201. package/src/tui-compiled/data/context-db.ts +6 -0
  202. package/src/tui-compiled/index.tsx +558 -455
  203. package/src/tui-compiled/slots/sidebar-content.tsx +237 -161
  204. package/dist/send-session-notification-tghq9gnh.js +0 -11
  205. /package/dist/{index-v7fmc1s2.js → index-ygcng9t8.js} +0 -0
package/dist/index.js CHANGED
@@ -22,7 +22,9 @@ import {
22
22
  GIT_SWEEP_LEASE_RENEWAL_MS,
23
23
  GLOBAL_USER_PROFILE_PROJECT_PATH,
24
24
  HISTORIAN_EDITOR_SYSTEM_PROMPT,
25
+ LATEST_SUPPORTED_VERSION,
25
26
  MARKER_SUMMARY_TEXT,
27
+ MAX_EXECUTE_THRESHOLD,
26
28
  MagicContextConfigSchema,
27
29
  ModuleMemoryAuthorityError,
28
30
  PRIMER_CANDIDATE_MAX_AGE_MS,
@@ -73,6 +75,7 @@ import {
73
75
  clearNoteNudgeTriggerAndCooldown,
74
76
  clearNoteNudgeTriggerOnly,
75
77
  clearPendingCompactionMarkerStateIf,
78
+ clearPendingOps,
76
79
  clearPersistedReasoningWatermark,
77
80
  clearPersistedTodoSyntheticAnchor,
78
81
  clearRecompStaging,
@@ -83,6 +86,7 @@ import {
83
86
  cosineSimilarity,
84
87
  countEmbeddedCommits,
85
88
  countPrimerCandidatesForProject,
89
+ createChildSessionWithFence,
86
90
  createPrimer,
87
91
  deleteTagsByMessageId,
88
92
  deleteUserMemoryCandidates,
@@ -104,6 +108,7 @@ import {
104
108
  enqueueShadowEmbeddingItems,
105
109
  ensureContextStoreUuid,
106
110
  ensureMemoryEmbeddings,
111
+ escalationBands,
107
112
  estimateTrueRawMessageTokens,
108
113
  expandWorkspaceIdentitySetWithAliases,
109
114
  exports_external,
@@ -122,6 +127,7 @@ import {
122
127
  getCandidateToolOwners,
123
128
  getChannel2NudgeClaim,
124
129
  getChannel2NudgeState,
130
+ getCompactionModeRecord,
125
131
  getCompartmentEvents,
126
132
  getCompartments,
127
133
  getContextStoreUuid,
@@ -150,6 +156,7 @@ import {
150
156
  getMemoryCountsByStatus,
151
157
  getMemoryMutationsForRenderByProjects,
152
158
  getMemoryVerifications,
159
+ getMigrationOnOpenRefusal,
153
160
  getMirrorCursor,
154
161
  getModuleNoteEvaluationBridge,
155
162
  getMural,
@@ -166,6 +173,8 @@ import {
166
173
  getPersistedCompactionMarkerState,
167
174
  getPersistedNoteNudge,
168
175
  getPersistedReasoningWatermark,
176
+ getPersistedSchemaVersion,
177
+ getPersistedTodoPermissionDenied,
169
178
  getPersistedTodoSyntheticAnchor,
170
179
  getPrimaryEmbeddingMeasurementCohort,
171
180
  getPrimerCandidatesByIds,
@@ -212,6 +221,7 @@ import {
212
221
  isDatabasePersisted,
213
222
  isEmbeddingEnabled,
214
223
  isEmergencyRecoveryArmed,
224
+ isPidAlive,
215
225
  isProviderOverflowReconfirmed,
216
226
  lkgContentDigest,
217
227
  loadCompartmentChunkEmbeddingsForSearch,
@@ -239,6 +249,7 @@ import {
239
249
  openDatabaseAsync,
240
250
  parkGitSweepNonIndexable,
241
251
  parseCron,
252
+ parseRpcPortFile,
242
253
  peekDeferredExecutePending,
243
254
  peekNoteNudgeText,
244
255
  peekProjectEmbeddings,
@@ -278,6 +289,7 @@ import {
278
289
  releaseWrapupInProgress,
279
290
  removeAutoSearchHintDecisionByMessageId,
280
291
  removeCompactionMarkerForSession,
292
+ removeMcOwnedCompactionMarkers,
281
293
  removeNoteNudgeAnchorByMessageId,
282
294
  removePendingOp,
283
295
  removeStrippedPlaceholderId,
@@ -290,6 +302,7 @@ import {
290
302
  resetLastNudgeCycleIfTailShrank,
291
303
  resetNoteNudgeCooldownOnly,
292
304
  resetProtectedTailNoEligibleHead,
305
+ resolveCompactionModeRecord,
293
306
  resolveGitTopLevel,
294
307
  resolveOpenCodeProtectedTailBoundary,
295
308
  resolveProjectIdentity,
@@ -299,6 +312,8 @@ import {
299
312
  resolveWorkspaceIdentitySet,
300
313
  resolveWorkspaceShareCategories,
301
314
  resolveWrapupProtectedTailBoundary,
315
+ rpcPortDir,
316
+ rpcPortFilePath,
302
317
  runCompartmentAgent,
303
318
  runManagedRecomp,
304
319
  runManagedUpgrade,
@@ -310,6 +325,8 @@ import {
310
325
  scheduleAfterBootQuiet,
311
326
  searchMemoriesFTS,
312
327
  searchMemoriesFTSUnion,
328
+ setChannel2NudgeState,
329
+ setCompactionModeRecord,
313
330
  setDeferredExecutePendingIfAbsent,
314
331
  setEmergencyDropSample,
315
332
  setKeepSubagents,
@@ -318,7 +335,9 @@ import {
318
335
  setMemoryClassification,
319
336
  setMuralCue,
320
337
  setNoteLastReadAt,
338
+ setPersistedCompactionMarkerState,
321
339
  setPersistedReasoningWatermark,
340
+ setPersistedTodoPermissionDenied,
322
341
  setPersistedTodoSyntheticAnchor,
323
342
  setRecompStarting,
324
343
  setRecompTerminal,
@@ -350,7 +369,7 @@ import {
350
369
  upsertCommits,
351
370
  verificationFileExists,
352
371
  withContentLanguageDirective
353
- } from "./index-c2gahrks.js";
372
+ } from "./index-s0mdn690.js";
354
373
  import {
355
374
  deriveHistorianChunkTokens,
356
375
  deriveTriggerBudget,
@@ -358,20 +377,24 @@ import {
358
377
  isSaneLimit,
359
378
  refreshModelLimitsAfterAuthOnce,
360
379
  refreshModelLimitsFromApi,
361
- resolveHistorianContextLimit
362
- } from "./index-63dq2g4d.js";
380
+ resolveHistorianContextLimit,
381
+ setOutputReserveConfig,
382
+ setStoragePrivatePermissionEnforcement,
383
+ shouldEnforcePrivateStoragePermissions
384
+ } from "./index-ry8rh8cv.js";
363
385
  import {
364
386
  modelBodyField,
365
387
  resolveFallbackChain
366
388
  } from "./index-td9depx5.js";
367
389
  import {
390
+ clearIgnoredMessages,
368
391
  describeError,
392
+ flushIgnoredMessages,
369
393
  getErrorMessage,
370
394
  sendIgnoredMessage,
371
395
  sendUserPrompt
372
- } from "./index-y1c9tcm3.js";
396
+ } from "./index-cn960ffd.js";
373
397
  import {
374
- Database,
375
398
  ToolMutationBatch,
376
399
  advanceToolReclaimWatermark,
377
400
  buildFileSourceContent,
@@ -380,7 +403,6 @@ import {
380
403
  cleanUserText,
381
404
  clearIndexedMessages,
382
405
  clearSession,
383
- closeQuietly,
384
406
  createToolDropTarget,
385
407
  deleteIndexedMessage,
386
408
  estimateTokens,
@@ -388,12 +410,10 @@ import {
388
410
  extractTexts,
389
411
  extractToolCallObservation,
390
412
  extractToolCallSummaries,
391
- findLastAssistantModelFromOpenCodeDb,
392
413
  getIndexedMessageCorpusSize,
393
414
  getLastIndexedOrdinal,
394
415
  getMessageIndexReconciliationStartOrdinal,
395
416
  getMessageIndexSourceIdentity,
396
- getMessageTimesFromOpenCodeDb,
397
417
  getOrCreateSessionMeta,
398
418
  getRawSessionStoredMessageCount,
399
419
  hasMeaningfulUserText,
@@ -403,7 +423,6 @@ import {
403
423
  isFilePart,
404
424
  isMessageIndexReconciledThrough,
405
425
  isMessageIndexSourceCurrent,
406
- isMidTurn,
407
426
  isRawCompactionSummaryInfo,
408
427
  isRecord,
409
428
  isTextPart,
@@ -411,7 +430,6 @@ import {
411
430
  isToolPartWithOutput,
412
431
  markSessionCleanupPending,
413
432
  normalizeText,
414
- openCodeDbExists,
415
433
  partHasCompletedResult,
416
434
  prependTag,
417
435
  primeInMemoryTailRawMessageCache,
@@ -429,9 +447,17 @@ import {
429
447
  sweepOrphanedOpenCodeMessageIndexes,
430
448
  textMentionsRecentCommit,
431
449
  updateSessionMeta,
432
- withRawSessionMessageCache,
450
+ withRawSessionMessageCache
451
+ } from "./index-b563sga5.js";
452
+ import {
453
+ Database,
454
+ closeQuietly,
455
+ findLastAssistantModelFromOpenCodeDb,
456
+ getMessageTimesFromOpenCodeDb,
457
+ isMidTurn,
458
+ openCodeDbExists,
433
459
  withReadOnlySessionDb
434
- } from "./index-ey1bc14z.js";
460
+ } from "./index-fcyvznch.js";
435
461
  import {
436
462
  cleanupConflictWarnings,
437
463
  detectConfigFile,
@@ -439,7 +465,7 @@ import {
439
465
  parseJsonc,
440
466
  sendConflictWarning,
441
467
  stripJsonComments
442
- } from "./index-xyaekybw.js";
468
+ } from "./index-dtas91s5.js";
443
469
  import {
444
470
  ANNOUNCEMENT_FEATURES,
445
471
  ANNOUNCEMENT_FOOTER,
@@ -449,6 +475,13 @@ import {
449
475
  markAnnouncementSeen,
450
476
  shouldShowAnnouncement
451
477
  } from "./index-dmr999a2.js";
478
+ import {
479
+ acknowledgeNotifications,
480
+ drainNotifications,
481
+ isTuiConnected,
482
+ pushNotification,
483
+ registerNotificationSink
484
+ } from "./index-d62ypazr.js";
452
485
  import"./index-73xz0247.js";
453
486
  import {
454
487
  log,
@@ -463,13 +496,6 @@ import {
463
496
  import {
464
497
  resolvePromptContext
465
498
  } from "./index-szf8w1p5.js";
466
- import {
467
- acknowledgeNotifications,
468
- drainNotifications,
469
- isTuiConnected,
470
- pushNotification,
471
- registerNotificationSink
472
- } from "./index-d62ypazr.js";
473
499
  import {
474
500
  __commonJS,
475
501
  __require,
@@ -8488,6 +8514,7 @@ function buildHiddenAgentConfig(prompt, allowedTools, maxSteps, overrides, agent
8488
8514
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
8489
8515
 
8490
8516
  // src/config/agent-disable.ts
8517
+ var COMPACTION_ENABLED_PATH = `compaction${"."}enabled`;
8491
8518
  function isDreamerRunnable(config) {
8492
8519
  return !!config.dreamer && config.dreamer.disable !== true;
8493
8520
  }
@@ -8497,6 +8524,9 @@ function isSidekickRunnable(config) {
8497
8524
  function isHistorianRunnable(config) {
8498
8525
  return config.historian?.disable !== true;
8499
8526
  }
8527
+ function isCompactionEnabled(config) {
8528
+ return config.compaction?.enabled !== false;
8529
+ }
8500
8530
  function clonePlainObject(value) {
8501
8531
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
8502
8532
  return;
@@ -9326,6 +9356,19 @@ function stripUnsafeProjectConfigFields(projectRaw) {
9326
9356
  delete projectRaw.fail_closed_blocking;
9327
9357
  warnings.push("Ignoring fail_closed_blocking from project config (security: only user-level config may disable or force the loud inoperability gate).");
9328
9358
  }
9359
+ if ("allow_home_project" in projectRaw) {
9360
+ delete projectRaw.allow_home_project;
9361
+ warnings.push("Ignoring allow_home_project from project config (security: only user-level config may opt the user's home directory into Magic Context).");
9362
+ }
9363
+ const compaction = projectRaw.compaction;
9364
+ if (isPlainObject(compaction) && "enabled" in compaction) {
9365
+ delete compaction.enabled;
9366
+ warnings.push("Ignoring compaction.enabled from project config (security: only user-level config may disable Magic Context's context-window management; a cloned repo cannot change how the user's window is owned).");
9367
+ }
9368
+ if ("output_reserve" in projectRaw) {
9369
+ delete projectRaw.output_reserve;
9370
+ warnings.push("Ignoring output_reserve from project config (security: output-token reservation only honors user-level config).");
9371
+ }
9329
9372
  if ("language" in projectRaw) {
9330
9373
  delete projectRaw.language;
9331
9374
  warnings.push("Ignoring language from project config (security: output language is a user-level setting).");
@@ -9334,6 +9377,11 @@ function stripUnsafeProjectConfigFields(projectRaw) {
9334
9377
  delete projectRaw.sqlite;
9335
9378
  warnings.push("Ignoring sqlite.* from project config (security: SQLite cache/mmap PRAGMAs apply to the " + "process-global shared database handle; only user-level config may set them).");
9336
9379
  }
9380
+ const storage = projectRaw.storage;
9381
+ if (isPlainObject(storage) && "enforce_private_permissions" in storage) {
9382
+ delete storage.enforce_private_permissions;
9383
+ warnings.push("Ignoring storage.enforce_private_permissions from project config (security: only user-level config may opt into externally managed shared storage permissions).");
9384
+ }
9337
9385
  const pi = projectRaw.pi;
9338
9386
  if (isPlainObject(pi) && "subagent_extensions" in pi) {
9339
9387
  delete pi.subagent_extensions;
@@ -9551,8 +9599,15 @@ function pruneNestedConfigLeaf(block, relativePath) {
9551
9599
  }
9552
9600
 
9553
9601
  // src/config/transform-mode.ts
9602
+ var RUST_COMPACTION_OFF_WARNING = "compaction-off mode does not support rust transform mode; using the TypeScript transform.";
9554
9603
  var RUST_REQUIRES_USER_SUBC_WARNING = "rust mode requires user-level subc configuration; running ts.";
9555
9604
  function resolveTransformMode(args) {
9605
+ if (args.configured === "rust" && !args.compactionEnabled) {
9606
+ return {
9607
+ mode: "ts",
9608
+ warnings: [RUST_COMPACTION_OFF_WARNING]
9609
+ };
9610
+ }
9556
9611
  if (args.configured === "rust" && !args.userTierHasSubc) {
9557
9612
  return {
9558
9613
  mode: "ts",
@@ -9932,6 +9987,7 @@ function loadPluginConfigDetailed(directory) {
9932
9987
  }
9933
9988
  const recoveredTopLevelKeys = [];
9934
9989
  const config = parsePluginConfig(mergedRaw, recoveredTopLevelKeys);
9990
+ setOutputReserveConfig(config.output_reserve);
9935
9991
  if (config.configWarnings?.length) {
9936
9992
  allWarnings.push(...config.configWarnings.map((w) => {
9937
9993
  if (userLoaded && projectLoaded)
@@ -9943,7 +9999,8 @@ function loadPluginConfigDetailed(directory) {
9943
9999
  }
9944
10000
  const resolvedTransformMode = resolveTransformMode({
9945
10001
  configured: config.transform_mode,
9946
- userTierHasSubc: hasUserTierSubcConfig(userLoaded?.config)
10002
+ userTierHasSubc: hasUserTierSubcConfig(userLoaded?.config),
10003
+ compactionEnabled: isCompactionEnabled(config)
9947
10004
  });
9948
10005
  config.transform_mode = resolvedTransformMode.mode;
9949
10006
  allWarnings.push(...resolvedTransformMode.warnings.map((warning) => `[config] ${warning}`));
@@ -9970,7 +10027,9 @@ function loadPluginConfigDetailed(directory) {
9970
10027
  }
9971
10028
 
9972
10029
  // src/features/builtin-commands/commands.ts
9973
- function getMagicContextBuiltinCommands() {
10030
+ var COMPACTION_ENABLED_PATH2 = `compaction${".enabled"}`;
10031
+ function getMagicContextBuiltinCommands(compactionEnabled = true) {
10032
+ const unavailableInCompactionOff = (command) => `Unavailable when ${COMPACTION_ENABLED_PATH2} is false: /${command} manages compacted history.`;
9974
10033
  return {
9975
10034
  "ctx-status": {
9976
10035
  template: "ctx-status",
@@ -9978,11 +10037,11 @@ function getMagicContextBuiltinCommands() {
9978
10037
  },
9979
10038
  "ctx-recomp": {
9980
10039
  template: "ctx-recomp",
9981
- description: "Rebuild compartments and facts from raw history (full or <start>-<end> range)"
10040
+ description: compactionEnabled ? "Rebuild compartments and facts from raw history (full or <start>-<end> range)" : unavailableInCompactionOff("ctx-recomp")
9982
10041
  },
9983
10042
  "ctx-wrapup": {
9984
10043
  template: "ctx-wrapup",
9985
- description: "Compact older live history while keeping the newest messages raw"
10044
+ description: compactionEnabled ? "Compact older live history while keeping the newest messages raw" : unavailableInCompactionOff("ctx-wrapup")
9986
10045
  },
9987
10046
  "ctx-session-upgrade": {
9988
10047
  template: "ctx-session-upgrade",
@@ -9990,7 +10049,7 @@ function getMagicContextBuiltinCommands() {
9990
10049
  },
9991
10050
  "ctx-flush": {
9992
10051
  template: "ctx-flush",
9993
- description: "Force-process all pending magic context operations immediately"
10052
+ description: compactionEnabled ? "Force-process all pending magic context operations immediately" : unavailableInCompactionOff("ctx-flush")
9994
10053
  },
9995
10054
  "ctx-aug": {
9996
10055
  template: "ctx-aug",
@@ -10355,14 +10414,41 @@ function isMagicContextHiddenAgentName(agent) {
10355
10414
  return true;
10356
10415
  return false;
10357
10416
  }
10417
+ var MAX_FORMATTED_BLOCKING_PROCESSES = 8;
10418
+ function formatFailClosedBlockingProcesses(processes) {
10419
+ const uniqueProcesses = new Map;
10420
+ for (const process2 of processes) {
10421
+ if (!process2.harness.trim() || !Number.isInteger(process2.pid) || process2.pid <= 0)
10422
+ continue;
10423
+ uniqueProcesses.set(`${process2.harness}\x00${process2.pid}`, {
10424
+ harness: process2.harness.trim(),
10425
+ pid: process2.pid
10426
+ });
10427
+ }
10428
+ const entries = [...uniqueProcesses.values()];
10429
+ const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
10430
+ const rendered = visible.map(({ harness, pid }) => `${harness} (PID ${pid})`);
10431
+ const omitted = entries.length - visible.length;
10432
+ if (omitted > 0)
10433
+ rendered.push(`${omitted} more blocking process(es)`);
10434
+ if (rendered.length === 0)
10435
+ return "a live harness process";
10436
+ if (rendered.length === 1)
10437
+ return rendered[0];
10438
+ const last = rendered.pop();
10439
+ return `${rendered.join(", ")}, and ${last}`;
10440
+ }
10358
10441
  function formatFailClosedBlockingMessage(reason) {
10442
+ if (reason.kind === "migration_guard") {
10443
+ return [
10444
+ `Magic Context cannot migrate the shared database because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
10445
+ "Restart the blocking process (it will pick up the new build and migrate on start), or shut it down and retry.",
10446
+ `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
10447
+ ].join(" ");
10448
+ }
10359
10449
  if (reason.kind === "schema_fence") {
10360
10450
  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.`,
10451
+ `Magic Context cannot operate: this Magic Context build is older than the database; upgrade/restart this harness (database schema v${reason.persistedVersion}, build supports through v${reason.supportedVersion}).`,
10366
10452
  `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
10367
10453
  ].join(" ");
10368
10454
  }
@@ -10434,7 +10520,7 @@ function createFailClosedController(options) {
10434
10520
  const shouldReprobe = typeof input.tryReopen === "function" && (blockedPassCount === 1 || blockedPassCount % reprobeEveryN === 0);
10435
10521
  if (shouldReprobe) {
10436
10522
  try {
10437
- const healed = await input.tryReopen();
10523
+ const healed = await input.tryReopen?.();
10438
10524
  if (healed) {
10439
10525
  reason = null;
10440
10526
  blockedPassCount = 0;
@@ -10752,12 +10838,12 @@ async function runSidekick(deps) {
10752
10838
  }
10753
10839
  };
10754
10840
  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 }
10841
+ const createResponse = await createChildSessionWithFence({
10842
+ client: deps.client,
10843
+ db: openDatabase(),
10844
+ parentSessionId: deps.sessionId,
10845
+ title: "magic-context-sidekick",
10846
+ directory: deps.sessionDirectory ?? deps.projectPath
10761
10847
  });
10762
10848
  const createdSession = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
10763
10849
  agentSessionId = typeof createdSession?.id === "string" ? createdSession.id : null;
@@ -12849,7 +12935,7 @@ function parseCuesManifest(text) {
12849
12935
  const body = extractCompleteManifestBody(text, "cues");
12850
12936
  const out = [];
12851
12937
  for (const match of body.matchAll(/<cue\s+id="(\d+)"\s*>([\s\S]*?)<\/cue>/g)) {
12852
- const id = Number.parseInt(match[1], 10);
12938
+ const id = Number.parseInt(match[1] ?? "", 10);
12853
12939
  if (!Number.isInteger(id))
12854
12940
  continue;
12855
12941
  out.push({ id, cue: unescapeXml(match[2] ?? "").trim() });
@@ -12950,7 +13036,10 @@ async function runCompressCues(args) {
12950
13036
  break;
12951
13037
  }
12952
13038
  const sliceMs = computeChunkSliceMs(remainingMs, chunks.length - i);
12953
- const outcome = await compressOneChunk(args, chunks[i], sliceMs, abortController.signal);
13039
+ const chunk = chunks[i];
13040
+ if (!chunk)
13041
+ break;
13042
+ const outcome = await compressOneChunk(args, chunk, sliceMs, abortController.signal);
12954
13043
  result.compressed += outcome.compressed;
12955
13044
  result.skipped += outcome.skipped;
12956
13045
  result.remaining -= outcome.compressed;
@@ -12985,12 +13074,12 @@ async function compressOneChunk(args, chunk, sliceMs, signal) {
12985
13074
  projectPath: args.projectIdentity,
12986
13075
  memories: chunk.map(toPromptMemory)
12987
13076
  });
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 }
13077
+ const createResponse = await createChildSessionWithFence({
13078
+ client: args.client,
13079
+ db: args.db,
13080
+ parentSessionId: args.parentSessionId,
13081
+ title: "magic-context-dream-compress-cues",
13082
+ directory: args.sessionDirectory
12994
13083
  });
12995
13084
  const created = normalizeSDKResponse(createResponse, null, {
12996
13085
  preferResponseOnMissingData: true
@@ -13169,12 +13258,12 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
13169
13258
  abortController.abort();
13170
13259
  });
13171
13260
  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 }
13261
+ const createResponse = await createChildSessionWithFence({
13262
+ client: args.client,
13263
+ db: args.db,
13264
+ parentSessionId: args.parentSessionId,
13265
+ title: "magic-context-dream-user-memories",
13266
+ directory: args.sessionDirectory
13178
13267
  });
13179
13268
  const created = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
13180
13269
  agentSessionId = typeof created?.id === "string" ? created.id : null;
@@ -13786,12 +13875,12 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
13786
13875
  recordInvocation(args, startedAt, { status: "completed" });
13787
13876
  return run2;
13788
13877
  }
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 }
13878
+ const createResponse = await createChildSessionWithFence({
13879
+ client: args.client,
13880
+ db: args.db,
13881
+ parentSessionId: args.parentSessionId,
13882
+ title: "magic-context-dream-classify",
13883
+ directory: args.sessionDirectory
13795
13884
  });
13796
13885
  const created = normalizeSDKResponse(createResponse, null, {
13797
13886
  preferResponseOnMissingData: true
@@ -14573,7 +14662,7 @@ function getAsyncModule() {
14573
14662
  asyncModulePromise ??= (async () => {
14574
14663
  const [{ default: singlefileAsyncifyVariant }, { newQuickJSAsyncWASMModuleFromVariant }] = await Promise.all([
14575
14664
  import("./index-ayd60xnw.js").then((m)=>__toESM(m.default,1)),
14576
- import("./index-v7fmc1s2.js")
14665
+ import("./index-ygcng9t8.js")
14577
14666
  ]);
14578
14667
  return newQuickJSAsyncWASMModuleFromVariant(singlefileAsyncifyVariant);
14579
14668
  })();
@@ -14792,12 +14881,12 @@ Remember: output only the JSON object described by the system prompt.`;
14792
14881
  });
14793
14882
  };
14794
14883
  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 }
14884
+ const createResponse = await createChildSessionWithFence({
14885
+ client: args.client,
14886
+ db: args.db ?? null,
14887
+ parentSessionId: args.parentSessionId,
14888
+ title: `magic-context-smart-note-compile-${args.note.id}`,
14889
+ directory: args.sessionDirectory ?? args.projectIdentity
14801
14890
  });
14802
14891
  const created = normalizeSDKResponse(createResponse, null, {
14803
14892
  preferResponseOnMissingData: true
@@ -15578,12 +15667,12 @@ async function confirmReadOnly(args, noteId, content, surfaceCondition, leaseSig
15578
15667
  });
15579
15668
  };
15580
15669
  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 }
15670
+ const createResponse = await createChildSessionWithFence({
15671
+ client: args.client,
15672
+ db: args.db,
15673
+ parentSessionId: args.parentSessionId,
15674
+ title: `magic-context-smart-note-confirm-${noteId}`,
15675
+ directory: args.sessionDirectory ?? args.projectIdentity
15587
15676
  });
15588
15677
  const created = normalizeSDKResponse(createResponse, null, {
15589
15678
  preferResponseOnMissingData: true
@@ -15928,12 +16017,12 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
15928
16017
  let agentSessionId = null;
15929
16018
  const startedAt = Date.now();
15930
16019
  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 }
16020
+ const createResponse = await createChildSessionWithFence({
16021
+ client: args.client,
16022
+ db: args.db,
16023
+ parentSessionId: args.parentSessionId,
16024
+ title: "magic-context-dream-map-memories",
16025
+ directory: args.sessionDirectory
15937
16026
  });
15938
16027
  const created = normalizeSDKResponse(createResponse, null, {
15939
16028
  preferResponseOnMissingData: true
@@ -16545,12 +16634,12 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
16545
16634
  let agentSessionId = null;
16546
16635
  const startedAt = Date.now();
16547
16636
  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 }
16637
+ const createResponse = await createChildSessionWithFence({
16638
+ client: args.client,
16639
+ db: args.db,
16640
+ parentSessionId: args.parentSessionId,
16641
+ title: "magic-context-dream-refresh-primers",
16642
+ directory: args.sessionDirectory
16554
16643
  });
16555
16644
  const created = normalizeSDKResponse(createResponse, null, {
16556
16645
  preferResponseOnMissingData: true
@@ -16997,12 +17086,12 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
16997
17086
  let agentSessionId = null;
16998
17087
  const startedAt = Date.now();
16999
17088
  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 }
17089
+ const createResponse = await createChildSessionWithFence({
17090
+ client: args.client,
17091
+ db: args.db,
17092
+ parentSessionId: args.parentSessionId,
17093
+ title: "magic-context-dream-verify",
17094
+ directory: args.sessionDirectory
17006
17095
  });
17007
17096
  const created = normalizeSDKResponse(createResponse, null, {
17008
17097
  preferResponseOnMissingData: true
@@ -17689,12 +17778,12 @@ async function runRetrospectiveTask(config, ctx, helpers) {
17689
17778
  });
17690
17779
  let childSessionId = null;
17691
17780
  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 }
17781
+ const createResponse = await createChildSessionWithFence({
17782
+ client: deps.client,
17783
+ db,
17784
+ parentSessionId: parent ?? undefined,
17785
+ title: "magic-context-dream-retrospective",
17786
+ directory: deps.sessionDirectory
17698
17787
  });
17699
17788
  const created = normalizeSDKResponse(createResponse, null, { preferResponseOnMissingData: true });
17700
17789
  childSessionId = typeof created?.id === "string" ? created.id : null;
@@ -17879,12 +17968,12 @@ async function runAgenticTask(config, ctx, helpers) {
17879
17968
  });
17880
17969
  let childSessionId = null;
17881
17970
  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 }
17971
+ const createResponse = await createChildSessionWithFence({
17972
+ client: deps.client,
17973
+ db,
17974
+ parentSessionId: parent ?? undefined,
17975
+ title: `magic-context-dream-${task}`,
17976
+ directory: docsDir
17888
17977
  });
17889
17978
  const created = normalizeSDKResponse(createResponse, null, {
17890
17979
  preferResponseOnMissingData: true
@@ -19172,11 +19261,11 @@ async function resolveEmbeddingRouting(args) {
19172
19261
 
19173
19262
  // src/plugin/embedding-bootstrap.ts
19174
19263
  async function ensureProjectRegisteredFromOpenCodeDirectory(directory, db) {
19175
- const projectIdentity = resolveProjectIdentityForSession(directory);
19264
+ const detailed = loadPluginConfigDetailed(directory);
19265
+ const projectIdentity = resolveProjectIdentityForSession(directory, detailed.config.allow_home_project);
19176
19266
  if (!projectIdentity)
19177
19267
  return;
19178
19268
  invalidateProject(projectIdentity);
19179
- const detailed = loadPluginConfigDetailed(directory);
19180
19269
  if (isConfigLoadUntrusted(detailed)) {
19181
19270
  handleUntrustedLoad(db, projectIdentity, directory, detailed);
19182
19271
  return;
@@ -19230,41 +19319,45 @@ function createCompactionHandler() {
19230
19319
 
19231
19320
  // src/hooks/magic-context/event-resolvers.ts
19232
19321
  var DEFAULT_CONTEXT_LIMIT = 128000;
19233
- var MAX_EXECUTE_THRESHOLD = 80;
19234
19322
  function resolveContextLimit(providerID, modelID, ctx) {
19235
- const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID) : undefined;
19236
- const baseline = fromModelsDev ?? DEFAULT_CONTEXT_LIMIT;
19237
19323
  const modelKey = resolveModelKey(providerID, modelID);
19324
+ let detected;
19325
+ let detectedLimitProvenance = "unknown";
19238
19326
  if (ctx?.db && ctx.sessionID) {
19239
19327
  try {
19240
19328
  const overflow = getOverflowState(ctx.db, ctx.sessionID, modelKey);
19241
- if (overflow.detectedContextLimit > 0 && overflow.detectedContextLimit < baseline) {
19242
- return overflow.detectedContextLimit;
19329
+ if (overflow.detectedContextLimit > 0) {
19330
+ detected = overflow.detectedContextLimit;
19331
+ detectedLimitProvenance = overflow.detectedContextLimitProvenance;
19243
19332
  }
19244
19333
  } catch {}
19245
19334
  }
19246
- return baseline;
19335
+ const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID, detected, {
19336
+ reservation: ctx?.reservation,
19337
+ detectedLimitProvenance
19338
+ }) : undefined;
19339
+ return fromModelsDev ?? detected ?? DEFAULT_CONTEXT_LIMIT;
19247
19340
  }
19248
19341
  function resolveTrustedContextLimit(providerID, modelID, ctx) {
19249
- const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID) : undefined;
19250
19342
  const modelKey = resolveModelKey(providerID, modelID);
19251
19343
  let detected;
19344
+ let detectedLimitProvenance = "unknown";
19252
19345
  if (ctx?.db && ctx.sessionID) {
19253
19346
  try {
19254
19347
  const overflow = getOverflowState(ctx.db, ctx.sessionID, modelKey);
19255
19348
  if (overflow.detectedContextLimit > 0) {
19256
19349
  detected = overflow.detectedContextLimit;
19350
+ detectedLimitProvenance = overflow.detectedContextLimitProvenance;
19257
19351
  }
19258
19352
  } catch {}
19259
19353
  }
19260
- if (typeof fromModelsDev === "number" && fromModelsDev > 0) {
19261
- if (detected !== undefined && detected < fromModelsDev)
19262
- return detected;
19354
+ const fromModelsDev = providerID && modelID ? getSdkContextLimit(providerID, modelID, detected, {
19355
+ detectedLimitProvenance
19356
+ }) : undefined;
19357
+ if (typeof fromModelsDev === "number" && fromModelsDev > 0)
19263
19358
  return fromModelsDev;
19264
- }
19265
- if (detected !== undefined) {
19359
+ if (detected !== undefined)
19266
19360
  return detected;
19267
- }
19268
19361
  if (modelKey && ctx?.db && ctx.sessionID) {
19269
19362
  try {
19270
19363
  const persisted = loadPersistedUsage(ctx.db, ctx.sessionID);
@@ -19319,7 +19412,7 @@ function resolveExecuteThresholdDetail(config, modelKey, fallback, options) {
19319
19412
  const dedupeKey = `${options.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${tokenMatch.value}|${cap}`;
19320
19413
  if (!clampWarnSeen.has(dedupeKey)) {
19321
19414
  clampWarnSeen.add(dedupeKey);
19322
- const msg = `execute_threshold_tokens clamped: ${tokenMatch.value} → ${effectiveTokens} (80% of ${contextLimit}) for ${modelKey ?? "default"}`;
19415
+ const msg = `execute_threshold_tokens clamped: ${tokenMatch.value} → ${effectiveTokens} (${MAX_EXECUTE_THRESHOLD}% of ${contextLimit}) for ${modelKey ?? "default"}`;
19323
19416
  if (options.sessionId) {
19324
19417
  sessionLog(options.sessionId, `WARN: ${msg}`);
19325
19418
  } else {
@@ -19375,7 +19468,7 @@ function resolveExecuteThresholdDetail(config, modelKey, fallback, options) {
19375
19468
  const dedupeKey = `pct|${options?.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${resolved}`;
19376
19469
  if (!clampWarnSeen.has(dedupeKey)) {
19377
19470
  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)`;
19471
+ const msg = `execute_threshold clamped ${resolved}% → ${MAX_EXECUTE_THRESHOLD}% for ${modelKey ?? "default"} (capped against the output-reserved safe window; 10% remains for mid-turn growth before the absolute 95% wall)`;
19379
19472
  if (options?.sessionId) {
19380
19473
  sessionLog(options.sessionId, `WARN: ${msg}`);
19381
19474
  } else {
@@ -19448,6 +19541,9 @@ var UNIT_TO_MS = {
19448
19541
  };
19449
19542
  function parseCacheTtl(ttl) {
19450
19543
  const normalizedTtl = ttl.trim();
19544
+ if (normalizedTtl.toLowerCase() === "never") {
19545
+ return Number.POSITIVE_INFINITY;
19546
+ }
19451
19547
  if (NUMERIC_PATTERN.test(normalizedTtl)) {
19452
19548
  return Number(normalizedTtl);
19453
19549
  }
@@ -19846,6 +19942,75 @@ function formatThresholdClampNote(opts) {
19846
19942
  return ` [clamped: ${opts.configuredValue}% > ${opts.maxPercentage}%]`;
19847
19943
  }
19848
19944
 
19945
+ // src/hooks/magic-context/sentinel.ts
19946
+ var WHOLE_MESSAGE_PLACEHOLDER_TEXT = "[dropped]";
19947
+ function modelAcceptsEmptyContent(providerID) {
19948
+ return providerID === "anthropic";
19949
+ }
19950
+ function variantChangeBustsProviderCache(providerID) {
19951
+ if (providerID === undefined)
19952
+ return true;
19953
+ if (providerID === "anthropic")
19954
+ return true;
19955
+ if (providerID === "google-vertex-anthropic")
19956
+ return true;
19957
+ if (providerID.includes("bedrock"))
19958
+ return true;
19959
+ return false;
19960
+ }
19961
+ function makeSentinel(originalPart) {
19962
+ const sentinel = {
19963
+ type: "text",
19964
+ text: ""
19965
+ };
19966
+ if (isRecord(originalPart)) {
19967
+ if (originalPart.cache_control !== undefined) {
19968
+ sentinel.cache_control = originalPart.cache_control;
19969
+ }
19970
+ if (originalPart.cacheControl !== undefined) {
19971
+ sentinel.cacheControl = originalPart.cacheControl;
19972
+ }
19973
+ }
19974
+ return sentinel;
19975
+ }
19976
+ function makeWholeMessageSentinel(providerID) {
19977
+ return {
19978
+ type: "text",
19979
+ text: modelAcceptsEmptyContent(providerID) ? "" : WHOLE_MESSAGE_PLACEHOLDER_TEXT
19980
+ };
19981
+ }
19982
+ function isSentinel(part) {
19983
+ if (!isRecord(part))
19984
+ return false;
19985
+ if (part.type !== "text")
19986
+ return false;
19987
+ if (typeof part.text !== "string")
19988
+ return false;
19989
+ return part.text === "" || part.text === WHOLE_MESSAGE_PLACEHOLDER_TEXT;
19990
+ }
19991
+ function replaySentinelByMessageIds(messages, ids, providerID) {
19992
+ if (ids.size === 0)
19993
+ return { replayed: 0, missingIds: [] };
19994
+ const seen = new Set;
19995
+ let replayed = 0;
19996
+ for (const msg of messages) {
19997
+ const id = msg.info.id;
19998
+ if (!id || !ids.has(id))
19999
+ continue;
20000
+ seen.add(id);
20001
+ if (msg.parts.length === 1 && isSentinel(msg.parts[0]))
20002
+ continue;
20003
+ msg.parts.length = 0;
20004
+ msg.parts.push(makeWholeMessageSentinel(providerID));
20005
+ replayed++;
20006
+ }
20007
+ const missingIds = [];
20008
+ for (const id of ids)
20009
+ if (!seen.has(id))
20010
+ missingIds.push(id);
20011
+ return { replayed, missingIds };
20012
+ }
20013
+
19849
20014
  // src/hooks/magic-context/compartment-trigger.ts
19850
20015
  var PROACTIVE_TRIGGER_OFFSET_PERCENTAGE = 2;
19851
20016
  var POST_DROP_TARGET_RATIO = 0.75;
@@ -19853,9 +20018,7 @@ var MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE = 6000;
19853
20018
  var MIN_PROACTIVE_TAIL_MESSAGE_COUNT = 12;
19854
20019
  var DEFAULT_MIN_COMMIT_CLUSTERS_FOR_TRIGGER = 3;
19855
20020
  var TAIL_SIZE_TRIGGER_MULTIPLIER = 3;
19856
- var FORCE_COMPARTMENT_PERCENTAGE = 80;
19857
20021
  var BLOCK_UNTIL_DONE_PERCENTAGE = 95;
19858
- var FORCE_MATERIALIZE_PERCENTAGE = 85;
19859
20022
  var CONTENT_TAG_OWNER_SUFFIX = /:(?:p|file)\d+$/;
19860
20023
  function tagOwnerMessageId(row) {
19861
20024
  if (row.type === "tool")
@@ -19909,7 +20072,7 @@ function buildTriggerInMemoryTail(db, sessionId, messages) {
19909
20072
  function getProactiveCompartmentTriggerPercentage(executeThresholdPercentage) {
19910
20073
  return Math.max(0, executeThresholdPercentage - PROACTIVE_TRIGGER_OFFSET_PERCENTAGE);
19911
20074
  }
19912
- function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, clearReasoningAge, clearedReasoningThroughTag) {
20075
+ function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, clearReasoningAge, clearedReasoningThroughTag, canClearReasoning) {
19913
20076
  const totalActiveBytes = activeTags.reduce((sum, tag) => sum + tag.byteSize + tag.reasoningByteSize, 0);
19914
20077
  if (totalActiveBytes === 0)
19915
20078
  return null;
@@ -19920,7 +20083,7 @@ function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, c
19920
20083
  droppableBytes += activeTags.filter((tag) => pendingDropTagIds.has(tag.tagNumber)).reduce((sum, tag) => sum + tag.byteSize + tag.reasoningByteSize, 0);
19921
20084
  }
19922
20085
  const maxTag = activeTags.reduce((max, t) => Math.max(max, t.tagNumber), 0);
19923
- if (clearReasoningAge !== undefined && clearedReasoningThroughTag !== undefined) {
20086
+ if (canClearReasoning && clearReasoningAge !== undefined && clearedReasoningThroughTag !== undefined) {
19924
20087
  const reasoningAgeCutoff = maxTag - clearReasoningAge;
19925
20088
  for (const tag of activeTags) {
19926
20089
  if (tag.type !== "message")
@@ -20020,7 +20183,7 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
20020
20183
  }
20021
20184
  });
20022
20185
  }
20023
- function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride) {
20186
+ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, clearReasoningAge, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride, reasoningProjection) {
20024
20187
  if (sessionMeta.compartmentInProgress) {
20025
20188
  sessionLog(sessionId, `compartment trigger: skipped — historian already in progress (usage=${usage.percentage.toFixed(1)}%)`);
20026
20189
  return { shouldFire: false };
@@ -20074,18 +20237,20 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
20074
20237
  }
20075
20238
  return { shouldFire: false };
20076
20239
  }
20077
- const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), clearReasoningAge, sessionMeta.clearedReasoningThroughTag);
20240
+ const canClearReasoning = reasoningProjection?.canClearReasoning ?? modelAcceptsEmptyContent(reasoningProjection?.providerID);
20241
+ const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), clearReasoningAge, sessionMeta.clearedReasoningThroughTag, canClearReasoning);
20078
20242
  const relativePostDropTarget = executeThresholdPercentage * POST_DROP_TARGET_RATIO;
20079
- if (usage.percentage >= FORCE_COMPARTMENT_PERCENTAGE) {
20243
+ const forceMaterializationPercentage = escalationBands(executeThresholdPercentage).forceMaterializationPercentage;
20244
+ if (usage.percentage >= forceMaterializationPercentage) {
20080
20245
  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)}%)`);
20246
+ sessionLog(sessionId, `compartment trigger: skipping force band ${forceMaterializationPercentage}% because projected post-drop usage is ${projectedPostDropPercentage.toFixed(1)}% (target ${relativePostDropTarget.toFixed(1)}%)`);
20082
20247
  return { shouldFire: false };
20083
20248
  }
20084
20249
  sessionLog(sessionId, `compartment trigger: force-firing at ${usage.percentage.toFixed(1)}% (projected post-drop ${projectedPostDropPercentage?.toFixed(1) ?? "none"}%)`);
20085
20250
  if (tailInfo.boundarySnapshot && hasRunnableCompartmentWindow(tailInfo.boundarySnapshot)) {
20086
20251
  return {
20087
20252
  shouldFire: true,
20088
- reason: "force_80",
20253
+ reason: "force_band",
20089
20254
  boundarySnapshot: tailInfo.boundarySnapshot
20090
20255
  };
20091
20256
  }
@@ -20110,9 +20275,9 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
20110
20275
  });
20111
20276
  });
20112
20277
  if (hasRunnableCompartmentWindow(scaledBoundary)) {
20113
- return { shouldFire: true, reason: "force_80", boundarySnapshot: scaledBoundary };
20278
+ return { shouldFire: true, reason: "force_band", boundarySnapshot: scaledBoundary };
20114
20279
  }
20115
- sessionLog(sessionId, "compartment trigger: force_80 skipped — raw exists but protected head genuinely empty after emergency tail scale");
20280
+ sessionLog(sessionId, "compartment trigger: force_band skipped — raw exists but protected head genuinely empty after emergency tail scale");
20116
20281
  return { shouldFire: false };
20117
20282
  }
20118
20283
  const clusterEnabled = commitClusterTrigger?.enabled ?? true;
@@ -20227,8 +20392,8 @@ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageC
20227
20392
  "### Cache TTL",
20228
20393
  `- Configured: ${meta.cacheTtl}`,
20229
20394
  `- 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}%`}`,
20395
+ `- Remaining: ${cacheExpired ? "expired" : ttlMs === Number.POSITIVE_INFINITY ? "never expires (always-warm lane)" : `${Math.round(remainingMs / 1000)}s`}`,
20396
+ `- Queue will auto-execute: ${cacheExpired ? "yes (cache expired)" : ttlMs === Number.POSITIVE_INFINITY ? `when context >= ${executeThresholdPercentage}%` : `when TTL expires or context >= ${executeThresholdPercentage}%`}`,
20232
20397
  "",
20233
20398
  "### Execute Threshold",
20234
20399
  `- Execute threshold: ${formatExecuteThreshold(thresholdDetail, displayContextLimit)}`,
@@ -20579,6 +20744,11 @@ function createMagicContextCommandHandler(deps) {
20579
20744
  }
20580
20745
  const sessionId = input.sessionID;
20581
20746
  let result = "";
20747
+ if (deps.compactionOff && (isFlush || isRecomp || isWrapup)) {
20748
+ const command = `/${input.command}`;
20749
+ await deps.sendNotification(sessionId, `Magic Context compaction is disabled (${COMPACTION_ENABLED_PATH}: false) — ${command} manages compacted history and has no effect in this mode.`, {});
20750
+ throwSentinel(input.command);
20751
+ }
20582
20752
  if (isAug) {
20583
20753
  await executeAugmentation(deps, sessionId, input.arguments);
20584
20754
  return;
@@ -20668,7 +20838,10 @@ Embedding status is unavailable.`;
20668
20838
  const moduleStatus = rustStatus ? `
20669
20839
 
20670
20840
  ${formatRustStatusText(rustStatus)}` : "";
20671
- const combinedStatus = `${statusOutput}${moduleStatus}`;
20841
+ const modeStatus = deps.compactionOff ? `**Compaction:** disabled (${COMPACTION_ENABLED_PATH}: false) — native compaction owns the context window.
20842
+
20843
+ ` : "";
20844
+ const combinedStatus = `${modeStatus}${statusOutput}${moduleStatus}`;
20672
20845
  result += result ? `
20673
20846
 
20674
20847
  ${combinedStatus}` : combinedStatus;
@@ -20835,6 +21008,212 @@ ${snap.error}`;
20835
21008
  };
20836
21009
  }
20837
21010
 
21011
+ // src/hooks/magic-context/ctx-reduce-availability.ts
21012
+ var ctxReduceRegisteredGlobally = true;
21013
+ function setCtxReduceRegisteredGlobally(registered) {
21014
+ ctxReduceRegisteredGlobally = registered;
21015
+ }
21016
+ var CTX_REDUCE_TOOL = "ctx_reduce";
21017
+ var TODOWRITE_TOOL = "todowrite";
21018
+ var availabilityBySession = new BoundedSessionMap(1000);
21019
+ var permissionDeniedBySession = new BoundedSessionMap(2000);
21020
+ var ctxReducePermissionDenyLogged = new BoundedSessionMap(1000);
21021
+ function permissionCacheKey(toolName, sessionId) {
21022
+ return `${toolName}\x00${sessionId}`;
21023
+ }
21024
+ function cacheKey(toolName, sessionId) {
21025
+ return `${toolName}\x00${sessionId}`;
21026
+ }
21027
+ function verdictFromToolsMap(tools, toolName) {
21028
+ if (tools === null || typeof tools !== "object" || Array.isArray(tools))
21029
+ return null;
21030
+ const map = tools;
21031
+ if (map[toolName] === true)
21032
+ return true;
21033
+ if (map[toolName] === false)
21034
+ return false;
21035
+ if (map["*"] === false)
21036
+ return false;
21037
+ return null;
21038
+ }
21039
+ function resolveToolAvailabilityFromMessages(sessionId, toolName, messages) {
21040
+ if (toolName === CTX_REDUCE_TOOL && !ctxReduceRegisteredGlobally) {
21041
+ return { callable: false, frozen: true };
21042
+ }
21043
+ const key = cacheKey(toolName, sessionId);
21044
+ const cached = availabilityBySession.get(key);
21045
+ if (cached !== undefined)
21046
+ return { callable: cached, frozen: true };
21047
+ for (const message of messages) {
21048
+ if (message.info?.role !== "user")
21049
+ continue;
21050
+ const verdict = verdictFromToolsMap(message.info.tools, toolName) ?? true;
21051
+ availabilityBySession.set(key, verdict);
21052
+ return { callable: verdict, frozen: true };
21053
+ }
21054
+ return { callable: true, frozen: false };
21055
+ }
21056
+ function resolveToolAvailability(sessionId, toolName) {
21057
+ if (toolName === CTX_REDUCE_TOOL && !ctxReduceRegisteredGlobally) {
21058
+ return { callable: false, frozen: true };
21059
+ }
21060
+ const key = cacheKey(toolName, sessionId);
21061
+ const cached = availabilityBySession.get(key);
21062
+ if (cached !== undefined)
21063
+ return { callable: cached, frozen: true };
21064
+ if (!openCodeDbExists())
21065
+ return { callable: true, frozen: true };
21066
+ try {
21067
+ const row = withReadOnlySessionDb((db) => db.prepare(`SELECT json_extract(data, '$.tools') AS tools FROM message
21068
+ WHERE session_id = ? AND json_extract(data, '$.role') = 'user'
21069
+ ORDER BY time_created ASC LIMIT 1`).get(sessionId));
21070
+ if (!row)
21071
+ return { callable: true, frozen: false };
21072
+ const verdict = row.tools === null ? null : verdictFromToolsMap(JSON.parse(row.tools), toolName);
21073
+ const resolved = verdict ?? true;
21074
+ availabilityBySession.set(key, resolved);
21075
+ return { callable: resolved, frozen: true };
21076
+ } catch (error) {
21077
+ sessionLog(sessionId, `${toolName} availability read failed (fail-open):`, error);
21078
+ return { callable: true, frozen: false };
21079
+ }
21080
+ }
21081
+ function resolveCtxReduceAvailabilityFromMessages(sessionId, messages) {
21082
+ return resolveToolAvailabilityFromMessages(sessionId, CTX_REDUCE_TOOL, messages);
21083
+ }
21084
+ function resolveCtxReduceAvailability(sessionId) {
21085
+ return resolveToolAvailability(sessionId, CTX_REDUCE_TOOL);
21086
+ }
21087
+ function isRecord2(value) {
21088
+ return value !== null && typeof value === "object" && !Array.isArray(value);
21089
+ }
21090
+ function responseData(value) {
21091
+ if (isRecord2(value) && Object.hasOwn(value, "data"))
21092
+ return value.data;
21093
+ return value;
21094
+ }
21095
+ function escapeRegExpLiteral(value) {
21096
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
21097
+ }
21098
+ function permissionNameMatches(rulePermission, toolName) {
21099
+ if (rulePermission === "*" || rulePermission === toolName)
21100
+ return true;
21101
+ if (!rulePermission.includes("*"))
21102
+ return false;
21103
+ const pattern = rulePermission.split("*").map(escapeRegExpLiteral).join(".*");
21104
+ return new RegExp(`^${pattern}$`).test(toolName);
21105
+ }
21106
+ function permissionDisabled(toolName, rules) {
21107
+ let finalRule;
21108
+ for (let index = rules.length - 1;index >= 0; index -= 1) {
21109
+ const rule = rules[index];
21110
+ if (rule && permissionNameMatches(rule.permission, toolName)) {
21111
+ finalRule = rule;
21112
+ break;
21113
+ }
21114
+ }
21115
+ return finalRule?.action === "deny" && finalRule.pattern === "*";
21116
+ }
21117
+ function actionOf(value) {
21118
+ return value === "ask" || value === "allow" || value === "deny" ? value : null;
21119
+ }
21120
+ function appendPermissionRule(target, permission, pattern, action) {
21121
+ if (typeof permission !== "string" || permission.length === 0)
21122
+ return;
21123
+ const normalizedAction = actionOf(action);
21124
+ if (!normalizedAction)
21125
+ return;
21126
+ const patterns = Array.isArray(pattern) ? pattern : [pattern ?? "*"];
21127
+ for (const candidate of patterns) {
21128
+ if (typeof candidate === "string") {
21129
+ target.push({ permission, pattern: candidate, action: normalizedAction });
21130
+ }
21131
+ }
21132
+ }
21133
+ function permissionRules(value) {
21134
+ if (Array.isArray(value)) {
21135
+ const result2 = [];
21136
+ for (const item of value) {
21137
+ if (!isRecord2(item))
21138
+ continue;
21139
+ appendPermissionRule(result2, item.permission ?? item.tool ?? item.name, item.pattern, item.action ?? item.value);
21140
+ }
21141
+ return result2;
21142
+ }
21143
+ if (!isRecord2(value))
21144
+ return [];
21145
+ const result = [];
21146
+ if (Array.isArray(value.rules))
21147
+ result.push(...permissionRules(value.rules));
21148
+ for (const [permission, configured] of Object.entries(value)) {
21149
+ if (permission === "rules")
21150
+ continue;
21151
+ const simpleAction = actionOf(configured);
21152
+ if (simpleAction) {
21153
+ appendPermissionRule(result, permission, "*", simpleAction);
21154
+ continue;
21155
+ }
21156
+ if (!isRecord2(configured))
21157
+ continue;
21158
+ for (const [pattern, action] of Object.entries(configured)) {
21159
+ appendPermissionRule(result, permission, pattern, action);
21160
+ }
21161
+ }
21162
+ return result;
21163
+ }
21164
+ function activeAgentNameFromSession(value) {
21165
+ if (!isRecord2(value))
21166
+ return;
21167
+ const agent = value.agent;
21168
+ return typeof agent === "string" && agent.length > 0 ? agent : undefined;
21169
+ }
21170
+ async function resolveToolPermissionDenied(client, sessionId, toolName, activeAgent) {
21171
+ const sdk = client;
21172
+ if (!sdk.app?.agents || !sdk.session?.get) {
21173
+ throw new Error("OpenCode permission APIs are unavailable");
21174
+ }
21175
+ const [agentsResponse, sessionResponse] = await Promise.all([
21176
+ sdk.app.agents(),
21177
+ sdk.session.get({ path: { id: sessionId } })
21178
+ ]);
21179
+ const agents = responseData(agentsResponse);
21180
+ const session = responseData(sessionResponse);
21181
+ const agentName = activeAgent ?? activeAgentNameFromSession(session);
21182
+ const agent = Array.isArray(agents) ? agents.find((candidate) => isRecord2(candidate) && candidate.name === agentName) : undefined;
21183
+ const agentRules = permissionRules(isRecord2(agent) ? agent.permission : undefined);
21184
+ const sessionRules = permissionRules(isRecord2(session) ? session.permission ?? session.permissions : undefined);
21185
+ const denied = permissionDisabled(toolName, [...agentRules, ...sessionRules]);
21186
+ permissionDeniedBySession.set(permissionCacheKey(toolName, sessionId), denied);
21187
+ return denied;
21188
+ }
21189
+ function todowritePermissionDenied(client, sessionId, activeAgent) {
21190
+ return resolveToolPermissionDenied(client, sessionId, TODOWRITE_TOOL, activeAgent);
21191
+ }
21192
+ function cachedToolPermissionDenied(sessionId, toolName) {
21193
+ return permissionDeniedBySession.get(permissionCacheKey(toolName, sessionId));
21194
+ }
21195
+ function clearToolPermissionDenied(sessionId, toolName) {
21196
+ if (toolName) {
21197
+ permissionDeniedBySession.delete(permissionCacheKey(toolName, sessionId));
21198
+ } else {
21199
+ permissionDeniedBySession.delete(permissionCacheKey(TODOWRITE_TOOL, sessionId));
21200
+ permissionDeniedBySession.delete(permissionCacheKey(CTX_REDUCE_TOOL, sessionId));
21201
+ }
21202
+ ctxReducePermissionDenyLogged.delete(sessionId);
21203
+ }
21204
+ function hasLoggedCtxReducePermissionDeny(sessionId) {
21205
+ return ctxReducePermissionDenyLogged.get(sessionId) === true;
21206
+ }
21207
+ function markCtxReducePermissionDenyLogged(sessionId) {
21208
+ ctxReducePermissionDenyLogged.set(sessionId, true);
21209
+ }
21210
+ function resolveTodowriteAvailabilityFromMessages(sessionId, messages) {
21211
+ return resolveToolAvailabilityFromMessages(sessionId, TODOWRITE_TOOL, messages);
21212
+ }
21213
+ function resolveTodowriteAvailability(sessionId) {
21214
+ return resolveToolAvailability(sessionId, TODOWRITE_TOOL);
21215
+ }
21216
+
20838
21217
  // src/hooks/magic-context/embed-session-state.ts
20839
21218
  var embedPauseBySession = new Set;
20840
21219
  var embedRunStateBySession = new Map;
@@ -21615,9 +21994,9 @@ function getMessageRemovedInfo(properties) {
21615
21994
  import * as crypto3 from "node:crypto";
21616
21995
 
21617
21996
  // src/hooks/magic-context/boundary-execution.ts
21618
- var FORCE_MATERIALIZE_PERCENTAGE2 = 85;
21619
21997
  function detectMidTurnBypassReason(input) {
21620
- if (input.contextUsage.percentage >= FORCE_MATERIALIZE_PERCENTAGE2)
21998
+ const { forceMaterializationPercentage } = escalationBands(input.effectiveExecuteThresholdPercentage);
21999
+ if (input.contextUsage.percentage >= forceMaterializationPercentage)
21621
22000
  return "force-materialize";
21622
22001
  if (input.historyRefreshSessions.has(input.sessionId))
21623
22002
  return "explicit-bust";
@@ -21644,7 +22023,7 @@ function canConsumeDeferredOnThisPass(args) {
21644
22023
  return true;
21645
22024
  if (args.activeRunBlocksMaterialization)
21646
22025
  return false;
21647
- return args.schedulerDecision === "execute" || args.contextPercentage >= FORCE_MATERIALIZE_PERCENTAGE;
22026
+ return args.schedulerDecision === "execute" || args.contextPercentage >= (args.forceMaterializationPercentage ?? escalationBands(65).forceMaterializationPercentage);
21648
22027
  }
21649
22028
 
21650
22029
  // src/hooks/magic-context/caveman.ts
@@ -21988,72 +22367,157 @@ function replayCavemanCompression(sessionId, db, targets, tags) {
21988
22367
  return replayed;
21989
22368
  }
21990
22369
 
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 };
22370
+ // src/hooks/magic-context/compaction-off-transition.ts
22371
+ import { existsSync as existsSync11 } from "node:fs";
22372
+ var loggedUnverifiedMarkerCleanupRetry = false;
22373
+ var COMPACTION_OFF_FLIP_NOTICE = [
22374
+ "## Magic Context — compaction-off mode is now active",
22375
+ "",
22376
+ "Magic Context no longer manages this session's context window; native compaction (or nothing) owns it. Memory, dreamer, notes and ctx_search stay live.",
22377
+ "",
22378
+ "Magic Context's compaction markers for this session were removed, so history previously hidden by them becomes visible again — the first turn after disabling may trigger one native compaction cycle on long sessions."
22379
+ ].join(`
22380
+ `);
22381
+ var COMPACTION_ON_WRAPUP_SUGGESTION = [
22382
+ "## Magic Context — compaction re-enabled",
22383
+ "",
22384
+ "Context-window management resumed for this session. History that grew while compaction was off will be picked up by the historian automatically; run `/ctx-wrapup` to digest the backlog now in bounded chunks."
22385
+ ].join(`
22386
+ `);
22387
+ var NO_TRANSITION = {
22388
+ recordToWrite: null,
22389
+ notice: null,
22390
+ invalidatedM0Baseline: false,
22391
+ historianCatchUpSignaled: false,
22392
+ clearedCompartmentInProgress: false,
22393
+ clearedSomething: false,
22394
+ markerCleanup: {
22395
+ verified: true,
22396
+ removedLineages: 0,
22397
+ removedRows: 0,
22398
+ retainedLineages: 0
22021
22399
  }
22022
- return { callable: true, frozen: false };
22400
+ };
22401
+ function clearCachedM0Baseline(db, sessionId) {
22402
+ const result = db.prepare("UPDATE session_meta SET cached_m0_bytes = NULL, cached_m1_bytes = NULL, cached_m0_mural_data_url = NULL WHERE session_id = ?").run(sessionId);
22403
+ return (result.changes ?? 0) > 0;
22023
22404
  }
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 };
22405
+ function cleanupOffMarkers(sessionId) {
22406
+ if (!existsSync11(getOpenCodeDbPath())) {
22407
+ return { verified: true, removedLineages: 0, removedRows: 0, retainedLineages: 0 };
22044
22408
  }
22409
+ return removeMcOwnedCompactionMarkers(sessionId, MARKER_SUMMARY_TEXT);
22045
22410
  }
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);
22411
+ function reconcileCompactionMode(args) {
22412
+ const { db, sessionId } = args;
22413
+ const stored = getCompactionModeRecord(db, sessionId);
22414
+ if (stored === "on_notice_pending") {
22415
+ return {
22416
+ ...NO_TRANSITION,
22417
+ recordToWrite: "on",
22418
+ notice: COMPACTION_ON_WRAPUP_SUGGESTION
22419
+ };
22420
+ }
22421
+ if (stored === "off_notice_pending") {
22422
+ const markerCleanup2 = cleanupOffMarkers(sessionId);
22423
+ return {
22424
+ ...NO_TRANSITION,
22425
+ recordToWrite: markerCleanup2.verified ? "off" : "off_cleanup_pending",
22426
+ notice: COMPACTION_OFF_FLIP_NOTICE,
22427
+ markerCleanup: markerCleanup2
22428
+ };
22429
+ }
22430
+ if (!args.compactionOff) {
22431
+ if (stored === null || resolveCompactionModeRecord(stored) === "on") {
22432
+ return stored === null ? { ...NO_TRANSITION, recordToWrite: "on" } : NO_TRANSITION;
22433
+ }
22434
+ const invalidatedM0Baseline2 = clearCachedM0Baseline(db, sessionId);
22435
+ let historianCatchUpSignaled = false;
22436
+ if (args.historianRunnable) {
22437
+ updateSessionMeta(db, sessionId, { compartmentInProgress: true });
22438
+ historianCatchUpSignaled = true;
22439
+ }
22440
+ if (!historianCatchUpSignaled) {
22441
+ return {
22442
+ ...NO_TRANSITION,
22443
+ recordToWrite: "on",
22444
+ invalidatedM0Baseline: invalidatedM0Baseline2
22445
+ };
22446
+ }
22447
+ setCompactionModeRecord(db, sessionId, "on_notice_pending");
22448
+ return {
22449
+ ...NO_TRANSITION,
22450
+ recordToWrite: "on",
22451
+ notice: COMPACTION_ON_WRAPUP_SUGGESTION,
22452
+ invalidatedM0Baseline: invalidatedM0Baseline2,
22453
+ historianCatchUpSignaled
22454
+ };
22455
+ }
22456
+ if (stored === "off")
22457
+ return NO_TRANSITION;
22458
+ if (stored === "off_cleanup_pending") {
22459
+ const markerCleanup2 = cleanupOffMarkers(sessionId);
22460
+ return {
22461
+ ...NO_TRANSITION,
22462
+ recordToWrite: markerCleanup2.verified ? "off" : null,
22463
+ markerCleanup: markerCleanup2
22464
+ };
22465
+ }
22466
+ let clearedSomething = false;
22467
+ const markerCleanup = cleanupOffMarkers(sessionId);
22468
+ if (markerCleanup.removedRows > 0)
22469
+ clearedSomething = true;
22470
+ if (getPersistedCompactionMarkerState(db, sessionId) !== null) {
22471
+ setPersistedCompactionMarkerState(db, sessionId, null);
22472
+ clearedSomething = true;
22473
+ }
22474
+ const pendingMarker = getPendingCompactionMarkerState(db, sessionId);
22475
+ if (pendingMarker !== null) {
22476
+ clearPendingCompactionMarkerStateIf(db, sessionId, pendingMarker);
22477
+ clearedSomething = true;
22478
+ }
22479
+ if (getOverflowState(db, sessionId).needsEmergencyRecovery) {
22480
+ clearEmergencyRecovery(db, sessionId);
22481
+ clearedSomething = true;
22482
+ }
22483
+ const channel2State = getChannel2NudgeState(db, sessionId);
22484
+ if (channel2State === "pending" || channel2State === "claimed") {
22485
+ setChannel2NudgeState(db, sessionId, "");
22486
+ clearedSomething = true;
22487
+ }
22488
+ if (getPendingOps(db, sessionId).length > 0) {
22489
+ clearPendingOps(db, sessionId);
22490
+ clearedSomething = true;
22491
+ }
22492
+ const invalidatedM0Baseline = clearCachedM0Baseline(db, sessionId);
22493
+ let clearedCompartmentInProgress = false;
22494
+ if (args.compartmentInProgress) {
22495
+ updateSessionMeta(db, sessionId, { compartmentInProgress: false });
22496
+ clearedCompartmentInProgress = true;
22497
+ }
22498
+ sessionLog(sessionId, `compaction-off transition: marker cleanup verified=${markerCleanup.verified}, removed=${markerCleanup.removedLineages} lineage(s)/${markerCleanup.removedRows} row(s), retained=${markerCleanup.retainedLineages}, clearedSomething=${clearedSomething}`);
22499
+ if (!markerCleanup.verified && !loggedUnverifiedMarkerCleanupRetry) {
22500
+ loggedUnverifiedMarkerCleanupRetry = true;
22501
+ sessionLog(sessionId, "compaction-off transition could not verify complete marker cleanup; durable cleanup retry will run on the next pass");
22502
+ }
22503
+ const notice = clearedSomething ? COMPACTION_OFF_FLIP_NOTICE : null;
22504
+ if (notice) {
22505
+ setCompactionModeRecord(db, sessionId, "off_notice_pending");
22506
+ } else if (!markerCleanup.verified) {
22507
+ setCompactionModeRecord(db, sessionId, "off_cleanup_pending");
22508
+ }
22509
+ return {
22510
+ recordToWrite: notice ? markerCleanup.verified ? "off" : "off_cleanup_pending" : markerCleanup.verified ? "off" : null,
22511
+ notice,
22512
+ invalidatedM0Baseline,
22513
+ historianCatchUpSignaled: false,
22514
+ clearedCompartmentInProgress,
22515
+ clearedSomething,
22516
+ markerCleanup
22517
+ };
22054
22518
  }
22055
- function resolveTodowriteAvailability(sessionId) {
22056
- return resolveToolAvailability(sessionId, TODOWRITE_TOOL);
22519
+ function commitCompactionModeRecord(db, sessionId, record) {
22520
+ setCompactionModeRecord(db, sessionId, record);
22057
22521
  }
22058
22522
 
22059
22523
  // src/hooks/magic-context/emergency-fail-closed.ts
@@ -22404,6 +22868,29 @@ function calibrateBuckets(input) {
22404
22868
  }
22405
22869
 
22406
22870
  // src/hooks/magic-context/final-wire-token-estimate.ts
22871
+ function compactWireLabel(value, fallback) {
22872
+ if (typeof value !== "string" || value.length === 0)
22873
+ return fallback;
22874
+ return value.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 32) || fallback;
22875
+ }
22876
+ function wirePartKind(part, role) {
22877
+ const rawType = part !== null && typeof part === "object" && typeof part.type === "string" ? part.type : "unknown";
22878
+ if (rawType === "tool_result" || rawType === "tool-result")
22879
+ return "toolresult";
22880
+ if (rawType === "tool_use" || rawType === "tool-use" || rawType === "tool-invocation") {
22881
+ return "tool";
22882
+ }
22883
+ if (role === "user" && rawType === "tool")
22884
+ return "toolresult";
22885
+ return compactWireLabel(rawType, "unknown");
22886
+ }
22887
+ function describeFinalWireTail(messages) {
22888
+ return `[${messages.slice(-3).map((message) => {
22889
+ const role = compactWireLabel(message.info.role, "unknown");
22890
+ const kinds = message.parts.map((part) => wirePartKind(part, role)).join("+") || "none";
22891
+ return `${role}:${kinds}`;
22892
+ }).join(", ")}]`;
22893
+ }
22407
22894
  function serializedTokens(value) {
22408
22895
  if (value === undefined)
22409
22896
  return 0;
@@ -25926,75 +26413,6 @@ ${hintText}`;
25926
26413
  }
25927
26414
  function clearAutoSearchForSession(_sessionId) {}
25928
26415
 
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
26416
  // src/hooks/magic-context/drop-stale-reduce-calls.ts
25999
26417
  var STALE_TOOL_NAMES = new Set(["ctx_reduce"]);
26000
26418
  function isReduceToolPart(part) {
@@ -27039,6 +27457,14 @@ function computeSyntheticCallId(stateJson) {
27039
27457
  const hash = createHash10("sha256").update(stateJson).digest("hex").slice(0, 16);
27040
27458
  return `${SYNTHETIC_CALL_ID_PREFIX}${hash}`;
27041
27459
  }
27460
+ function isSyntheticTodoPart(part) {
27461
+ if (part === null || typeof part !== "object")
27462
+ return false;
27463
+ const p = part;
27464
+ if (p.syntheticTodoMarker === true)
27465
+ return true;
27466
+ return p.type === "tool" && p.tool === "todowrite" && typeof p.callID === "string" && p.callID.startsWith(SYNTHETIC_CALL_ID_PREFIX);
27467
+ }
27042
27468
  function parseTodoState(stateJson) {
27043
27469
  if (stateJson.length === 0)
27044
27470
  return null;
@@ -27778,6 +28204,74 @@ function injectPersistedTodoAnchor(messages, sessionId, messageId2, part) {
27778
28204
  }
27779
28205
  return injectSyntheticTodoAtHead(messages, sessionId, part);
27780
28206
  }
28207
+ function removeSyntheticTodoParts(messages) {
28208
+ for (let index = messages.length - 1;index >= 0; index -= 1) {
28209
+ const message = messages[index];
28210
+ if (!message)
28211
+ continue;
28212
+ const retainedParts = message.parts.filter((part) => !isSyntheticTodoPart(part));
28213
+ if (retainedParts.length === message.parts.length)
28214
+ continue;
28215
+ message.parts = retainedParts;
28216
+ if (message.info.id === TODO_HEAD_ANCHOR_ID && retainedParts.length === 0) {
28217
+ messages.splice(index, 1);
28218
+ }
28219
+ }
28220
+ }
28221
+ async function applyTodoSynthesis(args) {
28222
+ if (!args.fullFeatureMode || args.compactionOff)
28223
+ return 0;
28224
+ const persistedAnchor = getPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28225
+ let permissionDenied = cachedToolPermissionDenied(args.sessionId, "todowrite") ?? getPersistedTodoPermissionDenied(args.db, args.sessionId) ?? false;
28226
+ const toolsMapUnavailable = args.todowriteAvailability.frozen && !args.todowriteAvailability.callable;
28227
+ if (args.isCacheBustingPass && args.client && !toolsMapUnavailable) {
28228
+ try {
28229
+ permissionDenied = await todowritePermissionDenied(args.client, args.sessionId, args.activeAgent);
28230
+ setPersistedTodoPermissionDenied(args.db, args.sessionId, permissionDenied);
28231
+ } catch (error) {
28232
+ sessionLog(args.sessionId, "todowrite permission read failed; retaining the last successful verdict:", error);
28233
+ }
28234
+ }
28235
+ const todowriteUnavailable = toolsMapUnavailable || permissionDenied;
28236
+ if (args.isCacheBustingPass && todowriteUnavailable) {
28237
+ removeSyntheticTodoParts(args.messages);
28238
+ clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28239
+ if (persistedAnchor) {
28240
+ sessionLog(args.sessionId, "todowrite synthetic pair cleared on a cache-busting pass because the tool is denied");
28241
+ }
28242
+ return 0;
28243
+ }
28244
+ if (args.isCacheBustingPass) {
28245
+ const part = buildSyntheticTodoPart(args.sessionMeta.lastTodoState);
28246
+ const persistedInjection = part !== null && persistedAnchor && persistedAnchor.callId === part.callID ? injectPersistedTodoAnchor(args.messages, args.sessionId, persistedAnchor.messageId, part) : null;
28247
+ if (part === null) {
28248
+ if (persistedAnchor)
28249
+ clearPersistedTodoSyntheticAnchor(args.db, args.sessionId);
28250
+ return 0;
28251
+ }
28252
+ if (persistedAnchor && persistedInjection?.injected) {
28253
+ if (persistedAnchor.stateJson.length === 0) {
28254
+ setPersistedTodoSyntheticAnchor(args.db, args.sessionId, persistedAnchor.callId, persistedAnchor.messageId, args.sessionMeta.lastTodoState);
28255
+ }
28256
+ return persistedInjection.prependedMessageCount;
28257
+ }
28258
+ const existingAssistantId = injectToolPartIntoLatestAssistant(args.messages, part);
28259
+ const injection = existingAssistantId === null ? injectSyntheticTodoAtHead(args.messages, args.sessionId, part) : {
28260
+ injected: true,
28261
+ messageId: existingAssistantId,
28262
+ prependedMessageCount: 0
28263
+ };
28264
+ setPersistedTodoSyntheticAnchor(args.db, args.sessionId, part.callID, injection.messageId, args.sessionMeta.lastTodoState);
28265
+ return injection.prependedMessageCount;
28266
+ }
28267
+ if (persistedAnchor && persistedAnchor.stateJson.length > 0) {
28268
+ const part = buildSyntheticTodoPart(persistedAnchor.stateJson);
28269
+ if (part !== null && part.callID === persistedAnchor.callId) {
28270
+ return injectPersistedTodoAnchor(args.messages, args.sessionId, persistedAnchor.messageId, part).prependedMessageCount;
28271
+ }
28272
+ }
28273
+ return 0;
28274
+ }
27781
28275
  function runRustModePostprocess(args) {
27782
28276
  if (!args.fullFeatureMode)
27783
28277
  return;
@@ -27934,18 +28428,19 @@ function finalizeMessageRepresentation(messages, resolvedProviderID, options) {
27934
28428
  return { clearedParts, mergedReasoningParts };
27935
28429
  }
27936
28430
  async function runPostTransformPhase(args) {
28431
+ const compactionOff = args.compactionOff === true;
27937
28432
  const pendingMaterializationAtPassStart = args.pendingMaterializationSessions.has(args.sessionId);
27938
28433
  const deferredMaterializationAtPassStart = args.deferredMaterializationSessions.has(args.sessionId);
27939
28434
  const isExplicitFlush = pendingMaterializationAtPassStart;
27940
28435
  const deferredMaterializationWasPending = deferredMaterializationAtPassStart;
27941
28436
  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;
28437
+ const forceMaterialization = args.fullFeatureMode && !compactionOff && args.contextUsage.percentage >= args.forceMaterializationPercentage;
28438
+ const emergencyDropEligible = !compactionOff && args.contextUsage.percentage >= args.forceMaterializationPercentage;
27944
28439
  const activeCompartmentRun = args.canRunCompartments ? getActiveCompartmentRun(args.sessionId) : undefined;
27945
28440
  const compartmentRunning = args.canRunCompartments && !args.awaitedCompartmentRun && activeCompartmentRun !== undefined;
27946
28441
  const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
27947
28442
  const materializationRequested = isExplicitFlush || deferredMaterialize;
27948
- const m0M1EnabledForFold = args.fullFeatureMode && args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory);
28443
+ const m0M1EnabledForFold = args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory) && (args.fullFeatureMode || compactionOff);
27949
28444
  const m0HardFoldThisPass = m0M1EnabledForFold && args.m0M1 ? mustMaterialize({
27950
28445
  db: args.db,
27951
28446
  sessionId: args.sessionId,
@@ -27955,12 +28450,23 @@ async function runPostTransformPhase(args) {
27955
28450
  hardSignals: args.m0M1.hardSignals
27956
28451
  }).value : false;
27957
28452
  const bypassCompartmentGate = forceMaterialization || m0HardFoldThisPass;
27958
- const shouldReadPendingOps = materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning;
28453
+ const shouldReadPendingOps = !compactionOff && (materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning);
27959
28454
  const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
27960
28455
  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));
28456
+ const shouldApplyPendingOps = !compactionOff && (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || bypassCompartmentGate);
28457
+ const shouldRunHeuristics = !compactionOff && (!compartmentRunning || bypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
27963
28458
  const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
28459
+ if (isCacheBustingPass && args.client && args.ctxReduceAvailability.callable && !hasLoggedCtxReducePermissionDeny(args.sessionId)) {
28460
+ try {
28461
+ const denied = await resolveToolPermissionDenied(args.client, args.sessionId, "ctx_reduce", args.activeAgent);
28462
+ if (denied) {
28463
+ markCtxReducePermissionDenyLogged(args.sessionId);
28464
+ sessionLog(args.sessionId, "ctx_reduce permission is denied by OpenCode; frozen guidance remains until session restart");
28465
+ }
28466
+ } catch (error) {
28467
+ sessionLog(args.sessionId, "ctx_reduce permission read failed (ignored):", error);
28468
+ }
28469
+ }
27964
28470
  const canUseEmptySentinels = modelAcceptsEmptyContent(args.resolvedProviderID);
27965
28471
  if (shouldRunHeuristics) {
27966
28472
  const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
@@ -27972,7 +28478,7 @@ async function runPostTransformPhase(args) {
27972
28478
  }
27973
28479
  if (compartmentRunning && hasPendingUserOps) {
27974
28480
  if (bypassCompartmentGate) {
27975
- const bypassReason = forceMaterialization ? "emergency >=85%" : "m0 hard fold";
28481
+ const bypassReason = forceMaterialization ? `emergency >=${args.forceMaterializationPercentage}%` : "m0 hard fold";
27976
28482
  sessionLog(args.sessionId, `transform: compartment-gate bypass (${bypassReason}) — applying ${pendingOps.length} pending ops while compartment agent runs (${args.contextUsage.percentage.toFixed(1)}%)`);
27977
28483
  } else {
27978
28484
  sessionLog(args.sessionId, "transform: deferring pending ops — compartment agent in progress");
@@ -28078,7 +28584,7 @@ async function runPostTransformPhase(args) {
28078
28584
  if (args.schedulerDecision === "execute" && !materializationRequested) {
28079
28585
  updateSessionMeta(args.db, args.sessionId, { lastResponseTime: Date.now() });
28080
28586
  }
28081
- const toolReclaimExecutePass = args.schedulerDecision === "execute";
28587
+ const toolReclaimExecutePass = !compactionOff && args.schedulerDecision === "execute";
28082
28588
  const alreadyMutatingThisPass = pendingOpsDidMutate || heuristicOrReasoningDidMutate;
28083
28589
  let autoReclaimTargetCount = 0;
28084
28590
  let autoReclaimDidMutate = false;
@@ -28162,7 +28668,7 @@ async function runPostTransformPhase(args) {
28162
28668
  sessionLog(args.sessionId, "transform failed applying pending operations:", error);
28163
28669
  updateSessionMeta(args.db, args.sessionId, { lastTransformError: getErrorMessage(error) });
28164
28670
  }
28165
- if (canUseEmptySentinels) {
28671
+ if (canUseEmptySentinels && !compactionOff) {
28166
28672
  try {
28167
28673
  const t8 = performance.now();
28168
28674
  const frozenStaleReduceIds = getStaleReduceStrippedIds(args.db, args.sessionId);
@@ -28179,7 +28685,7 @@ async function runPostTransformPhase(args) {
28179
28685
  sessionLog(args.sessionId, "transform failed dropping stale ctx_reduce calls:", error);
28180
28686
  }
28181
28687
  }
28182
- if (canUseEmptySentinels) {
28688
+ if (canUseEmptySentinels && !compactionOff) {
28183
28689
  try {
28184
28690
  const tImg = performance.now();
28185
28691
  const frozenImageIds = getProcessedImageStrippedIds(args.db, args.sessionId);
@@ -28214,7 +28720,8 @@ async function runPostTransformPhase(args) {
28214
28720
  temporalAwareness: args.m0M1.temporalAwareness,
28215
28721
  isCacheBustingPass,
28216
28722
  hardSignals: args.m0M1.hardSignals,
28217
- muralEnabled: args.m0M1.muralEnabled
28723
+ muralEnabled: args.m0M1.muralEnabled,
28724
+ compactionOff
28218
28725
  });
28219
28726
  if (result.injected) {
28220
28727
  m0M1InjectedThisPass = true;
@@ -28239,7 +28746,7 @@ async function runPostTransformPhase(args) {
28239
28746
  clearInjectionCache(args.sessionId);
28240
28747
  }
28241
28748
  logTransformTiming(args.sessionId, "pp.injectM0M1", tInjectM0M1);
28242
- } else if (args.fullFeatureMode && args.pendingCompartmentInjection) {
28749
+ } else if (args.fullFeatureMode && !compactionOff && args.pendingCompartmentInjection) {
28243
28750
  const compartmentResult = renderCompartmentInjection(args.sessionId, args.messages, args.pendingCompartmentInjection);
28244
28751
  if (compartmentResult.injected) {
28245
28752
  prependedMessageCount += compartmentResult.prependedMessageCount;
@@ -28250,7 +28757,7 @@ async function runPostTransformPhase(args) {
28250
28757
  }
28251
28758
  }
28252
28759
  }
28253
- {
28760
+ if (!compactionOff) {
28254
28761
  const tPlaceholder = performance.now();
28255
28762
  const persistedIds = getStrippedPlaceholderIds(args.db, args.sessionId);
28256
28763
  if (persistedIds.size > 0) {
@@ -28283,7 +28790,7 @@ async function runPostTransformPhase(args) {
28283
28790
  logTransformTiming(args.sessionId, "pp.placeholderNeutralize", tPlaceholder);
28284
28791
  }
28285
28792
  const tNudgeBlock = performance.now();
28286
- if (args.fullFeatureMode) {
28793
+ if (args.fullFeatureMode && !compactionOff) {
28287
28794
  for (const anchor of getNoteNudgeAnchors(args.db, args.sessionId)) {
28288
28795
  appendReminderToUserMessageById(args.messages, anchor.messageId, anchor.text);
28289
28796
  }
@@ -28328,12 +28835,14 @@ async function runPostTransformPhase(args) {
28328
28835
  }
28329
28836
  }
28330
28837
  }
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
- });
28838
+ if (!compactionOff) {
28839
+ reconcileMarkerRepresentation(args.messages, getPersistedCompactionMarkerState(args.db, args.sessionId), {
28840
+ db: args.db,
28841
+ sessionId: args.sessionId,
28842
+ tagger: args.tagger,
28843
+ ctxReduceAvailability: args.ctxReduceAvailability
28844
+ });
28845
+ }
28337
28846
  const deferredHistoryDrainEligible = historyWasConsumedThisPass && args.deferredHistoryWasPendingAtPassStart && !suppressV12HistoryDrain;
28338
28847
  if (deferredHistoryDrainEligible) {
28339
28848
  args.deferredHistoryRefreshSessions.delete(args.sessionId);
@@ -28357,42 +28866,19 @@ async function runPostTransformPhase(args) {
28357
28866
  sessionLog(args.sessionId, `note-nudge delivery skipped wire append: ${outcome.kind}`);
28358
28867
  }
28359
28868
  }
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
- }
28869
+ if (args.fullFeatureMode && !compactionOff) {
28870
+ prependedMessageCount += await applyTodoSynthesis({
28871
+ db: args.db,
28872
+ sessionId: args.sessionId,
28873
+ messages: args.messages,
28874
+ fullFeatureMode: args.fullFeatureMode,
28875
+ compactionOff,
28876
+ isCacheBustingPass,
28877
+ sessionMeta: args.sessionMeta,
28878
+ todowriteAvailability: args.todowriteAvailability,
28879
+ client: args.client,
28880
+ activeAgent: args.activeAgent
28881
+ });
28396
28882
  }
28397
28883
  logTransformTiming(args.sessionId, "pp.noteAndTodoSynthesis", tNoteAndTodo);
28398
28884
  if (args.compartmentInjectionRebuiltFromDb && args.pendingCompartmentInjection) {
@@ -28529,7 +29015,7 @@ class MemoryAuthorityUnavailableError extends Error {
28529
29015
  var RUST_FAILURE_PARK_THRESHOLD = 3;
28530
29016
  var RUST_PROBE_INTERVAL = 5;
28531
29017
  var RUST_SEND_TIMEOUT_MS = 15000;
28532
- function isRecord2(value) {
29018
+ function isRecord3(value) {
28533
29019
  return value !== null && typeof value === "object";
28534
29020
  }
28535
29021
  function replaceMessagesInPlace(output, next) {
@@ -28539,9 +29025,9 @@ function replaceMessagesInPlace(output, next) {
28539
29025
  return target;
28540
29026
  }
28541
29027
  function messageInfo2(value) {
28542
- if (!isRecord2(value))
29028
+ if (!isRecord3(value))
28543
29029
  return {};
28544
- return isRecord2(value.info) ? value.info : value;
29030
+ return isRecord3(value.info) ? value.info : value;
28545
29031
  }
28546
29032
  function messageIdOf(message) {
28547
29033
  const id = messageInfo2(message).id;
@@ -28735,7 +29221,7 @@ function isSyntheticUserMessage(message) {
28735
29221
  if (!message || messageInfo2(message).role !== "user" || !Array.isArray(message.parts)) {
28736
29222
  return false;
28737
29223
  }
28738
- return message.parts.length > 0 && message.parts.every((part) => isRecord2(part) && (part.synthetic === true || part.ignored === true));
29224
+ return message.parts.length > 0 && message.parts.every((part) => isRecord3(part) && (part.synthetic === true || part.ignored === true));
28739
29225
  }
28740
29226
  function observeSyntheticTurn(state, messages) {
28741
29227
  const newest = newestUserMessage(messages);
@@ -28755,16 +29241,16 @@ function observeSyntheticTurn(state, messages) {
28755
29241
  function assertNativeBoundary(output, sessionId, boundaryId) {
28756
29242
  const first = output.find((message) => messageInfo2(message).role !== "system");
28757
29243
  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);
29244
+ const parts = isRecord3(first) && Array.isArray(first.parts) ? first.parts : [];
29245
+ const synthetic = parts.length > 0 && parts.every((part) => isRecord3(part) && part.synthetic === true);
28760
29246
  if (info.role === "user" && info.sessionID === sessionId && synthetic)
28761
29247
  return;
28762
29248
  throw new Error(`rust transform wire invariant failed: boundary=${boundaryId} expected a synthetic m0 user message scoped to session ${sessionId}`);
28763
29249
  }
28764
29250
  function responseValue(response) {
28765
- if (isRecord2(response) && isRecord2(response.result))
29251
+ if (isRecord3(response) && isRecord3(response.result))
28766
29252
  return response.result;
28767
- if (isRecord2(response))
29253
+ if (isRecord3(response))
28768
29254
  return response;
28769
29255
  throw new Error("module transform returned a non-object response");
28770
29256
  }
@@ -28773,7 +29259,7 @@ function noteDeliveryPassIds(response) {
28773
29259
  return [];
28774
29260
  return [
28775
29261
  ...new Set(response.note_deliveries.flatMap((delivery) => {
28776
- if (!isRecord2(delivery))
29262
+ if (!isRecord3(delivery))
28777
29263
  return [];
28778
29264
  const passId = delivery.transform_pass_id;
28779
29265
  return typeof passId === "string" && passId.length > 0 ? [passId] : [];
@@ -28783,7 +29269,7 @@ function noteDeliveryPassIds(response) {
28783
29269
  function modelFromMessages(messages) {
28784
29270
  for (let index = messages.length - 1;index >= 0; index -= 1) {
28785
29271
  const info = messages[index]?.info;
28786
- const model = isRecord2(info?.model) ? info.model : undefined;
29272
+ const model = isRecord3(info?.model) ? info.model : undefined;
28787
29273
  if (typeof model?.providerID === "string" && typeof model.modelID === "string") {
28788
29274
  return { providerID: model.providerID, modelID: model.modelID };
28789
29275
  }
@@ -28807,6 +29293,7 @@ function ensureState(states, sessionId) {
28807
29293
  ordinalMemoAnchor: null,
28808
29294
  ordinalMemoStoredCount: null,
28809
29295
  ordinalMemoCanonicalCount: 0,
29296
+ ordinalContinuationBase: null,
28810
29297
  seedPassPending: true,
28811
29298
  failureCount: 0,
28812
29299
  parkCount: 0,
@@ -28861,8 +29348,8 @@ function passUsage(usage, limit) {
28861
29348
  };
28862
29349
  }
28863
29350
  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;
29351
+ const directives = isRecord3(response.host_directives) ? response.host_directives : undefined;
29352
+ const channel2 = isRecord3(directives?.channel2_nudge) ? directives.channel2_nudge : undefined;
28866
29353
  return typeof channel2?.text === "string" && channel2.text.length > 0 ? channel2.text : undefined;
28867
29354
  }
28868
29355
  function isNeedFullSync(response) {
@@ -28871,7 +29358,7 @@ function isNeedFullSync(response) {
28871
29358
  function canonicalizeForChecksum(value) {
28872
29359
  if (Array.isArray(value))
28873
29360
  return value.map(canonicalizeForChecksum);
28874
- if (!isRecord2(value))
29361
+ if (!isRecord3(value))
28875
29362
  return value;
28876
29363
  return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalizeForChecksum(value[key])]));
28877
29364
  }
@@ -28887,7 +29374,7 @@ function authoritySeedRows(db, projectPath, domain) {
28887
29374
  WHERE sp.session_id = n.session_id AND sp.project_path = ?
28888
29375
  ))
28889
29376
  ORDER BY n.id ASC`).all(projectPath, projectPath);
28890
- const memoryRows = snapshots.filter(isRecord2);
29377
+ const memoryRows = snapshots.filter(isRecord3);
28891
29378
  const mappings = domain === "memories" ? getMemoryVerifications(db, memoryRows.map((row) => Number(row.id))) : new Map;
28892
29379
  return memoryRows.map((snapshot) => {
28893
29380
  const id = Number(snapshot.id);
@@ -28912,11 +29399,36 @@ async function prepareRustMemoryAuthority(args) {
28912
29399
  throw new MemoryAuthorityUnavailableError("the module does not expose authority.status, authority.prepare, and authority.seed");
28913
29400
  }
28914
29401
  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
29402
+ authorityStatus: (request2) => {
29403
+ const method = module.authorityStatus;
29404
+ if (!method)
29405
+ throw new MemoryAuthorityUnavailableError("authority.status unavailable");
29406
+ return method.call(module, { ...request2, projectRoot });
29407
+ },
29408
+ authorityPrepare: (request2) => {
29409
+ const method = module.authorityPrepare;
29410
+ if (!method)
29411
+ throw new MemoryAuthorityUnavailableError("authority.prepare unavailable");
29412
+ return method.call(module, { ...request2, projectRoot });
29413
+ },
29414
+ authoritySeed: (request2) => {
29415
+ const method = module.authoritySeed;
29416
+ if (!method)
29417
+ throw new MemoryAuthorityUnavailableError("authority.seed unavailable");
29418
+ return method.call(module, { ...request2, projectRoot });
29419
+ },
29420
+ authorityDrain: module.authorityDrain ? (request2) => {
29421
+ const method = module.authorityDrain;
29422
+ if (!method)
29423
+ throw new MemoryAuthorityUnavailableError("authority.drain unavailable");
29424
+ return method.call(module, { ...request2, projectRoot });
29425
+ } : undefined,
29426
+ mirrorPull: module.mirrorPull ? (request2) => {
29427
+ const method = module.mirrorPull;
29428
+ if (!method)
29429
+ throw new MemoryAuthorityUnavailableError("mirror.pull unavailable");
29430
+ return method.call(module, { ...request2, projectRoot });
29431
+ } : undefined
28920
29432
  };
28921
29433
  const contextStoreUuid = ensureContextStoreUuid(db);
28922
29434
  const domains = ["memories", "notes"];
@@ -28942,7 +29454,7 @@ async function prepareRustMemoryAuthority(args) {
28942
29454
  projectPath,
28943
29455
  domain,
28944
29456
  module: authorityModule,
28945
- checksum: () => checksumSeedRows(db.prepare(`SELECT * FROM ${domain === "memories" ? "memories" : "notes"} WHERE project_path = ? ORDER BY id ASC`).all(projectPath).filter(isRecord2))
29457
+ checksum: () => checksumSeedRows(db.prepare(`SELECT * FROM ${domain === "memories" ? "memories" : "notes"} WHERE project_path = ? ORDER BY id ASC`).all(projectPath).filter(isRecord3))
28946
29458
  });
28947
29459
  if (!("code" in drained))
28948
29460
  break;
@@ -29051,6 +29563,13 @@ function buildTransformBody(args) {
29051
29563
  caveman_enabled: args.passInputs.caveman_enabled === true,
29052
29564
  caveman_min_chars: args.passInputs.caveman_min_chars ?? 500,
29053
29565
  cache_ttl: args.passInputs.cache_ttl,
29566
+ lineage_switched: args.passInputs.lineage_switched === true,
29567
+ descent_edge_id: args.passInputs.descent_edge_id,
29568
+ prior_conversation_key: args.passInputs.prior_conversation_key,
29569
+ prior_epoch: args.passInputs.prior_epoch,
29570
+ new_epoch: args.passInputs.new_epoch,
29571
+ constituents: args.passInputs.constituents,
29572
+ compaction_observed: args.passInputs.compaction_observed === true,
29054
29573
  pass_inputs: args.passInputs,
29055
29574
  declared_trim: args.declaredTrim
29056
29575
  };
@@ -29282,7 +29801,7 @@ function createRustModeTransform(deps, options) {
29282
29801
  decision = typeof response.decision === "string" ? response.decision : typeof response.action === "string" ? response.action : typeof response.status === "string" ? response.status : "unknown";
29283
29802
  servedFrom = typeof response.served_from === "string" ? response.served_from : "unknown";
29284
29803
  materializeReason = typeof response.materialize_reason === "string" && response.materialize_reason.length > 0 ? response.materialize_reason : "none";
29285
- const timings2 = isRecord2(response.timings) ? response.timings : undefined;
29804
+ const timings2 = isRecord3(response.timings) ? response.timings : undefined;
29286
29805
  const total = timings2?.total;
29287
29806
  moduleElapsedMs = typeof total === "number" && Number.isFinite(total) ? total : 0;
29288
29807
  if (timings2 && moduleElapsedMs >= 1000) {
@@ -29383,10 +29902,10 @@ function createRustModeTransform(deps, options) {
29383
29902
  continue;
29384
29903
  const prior = state.idOrdinalMemo.get(priorId);
29385
29904
  if (prior !== undefined)
29386
- return prior;
29905
+ return Math.max(prior, state.ordinalContinuationBase ?? 0);
29387
29906
  }
29388
- return state.ordinalMemoCanonicalCount;
29389
- })() : undefined;
29907
+ return Math.max(state.ordinalMemoCanonicalCount, state.ordinalContinuationBase ?? 0);
29908
+ })() : state.ordinalContinuationBase ?? undefined;
29390
29909
  const ordinalStartedAt = performance.now();
29391
29910
  let resolved = await resolveOrdinalsForModule({
29392
29911
  sessionId,
@@ -29412,7 +29931,8 @@ function createRustModeTransform(deps, options) {
29412
29931
  memo: state.idOrdinalMemo,
29413
29932
  memoAnchor: state.ordinalMemoAnchor,
29414
29933
  memoStoredCount: state.ordinalMemoStoredCount,
29415
- memoCanonicalCount: state.ordinalMemoCanonicalCount
29934
+ memoCanonicalCount: state.ordinalMemoCanonicalCount,
29935
+ provisionalBase: state.ordinalContinuationBase ?? undefined
29416
29936
  });
29417
29937
  logStage(sessionId, "ordinalResolve", fullOrdinalStartedAt, timings, "fallback=clean_full");
29418
29938
  }
@@ -29454,10 +29974,11 @@ function createRustModeTransform(deps, options) {
29454
29974
  };
29455
29975
  }
29456
29976
  }
29977
+ const stateSyncCapabilities = options.moduleClient.stateSyncCapabilities;
29457
29978
  const stateSyncResult = await syncModuleState({
29458
29979
  client: {
29459
29980
  call: callModule,
29460
- stateSyncCapabilities: options.moduleClient.stateSyncCapabilities ? (capabilityArgs) => options.moduleClient.stateSyncCapabilities(capabilityArgs) : undefined
29981
+ stateSyncCapabilities: stateSyncCapabilities ? (capabilityArgs) => stateSyncCapabilities.call(options.moduleClient, capabilityArgs) : undefined
29461
29982
  },
29462
29983
  state,
29463
29984
  pass: syncPass,
@@ -29591,7 +30112,8 @@ function createRustModeTransform(deps, options) {
29591
30112
  memo: state.idOrdinalMemo,
29592
30113
  memoAnchor: state.ordinalMemoAnchor,
29593
30114
  memoStoredCount: state.ordinalMemoStoredCount,
29594
- memoCanonicalCount: state.ordinalMemoCanonicalCount
30115
+ memoCanonicalCount: state.ordinalMemoCanonicalCount,
30116
+ provisionalBase: state.ordinalContinuationBase ?? undefined
29595
30117
  });
29596
30118
  logStage(sessionId, "ordinalResolve", retryOrdinalStartedAt, timings, "retry=full");
29597
30119
  if (!retryResolved.ok) {
@@ -29741,6 +30263,16 @@ function createRustModeTransform(deps, options) {
29741
30263
  sessionLog(sessionId, "rust note delivery ack failed (will retry):", ackError);
29742
30264
  }
29743
30265
  }
30266
+ const ordinalContinuationBase = response.ordinal_continuation_base;
30267
+ if (typeof ordinalContinuationBase === "number" && Number.isSafeInteger(ordinalContinuationBase) && ordinalContinuationBase > 0) {
30268
+ if (state.ordinalContinuationBase === null) {
30269
+ for (const [messageId2, ordinal] of state.idOrdinalMemo) {
30270
+ state.idOrdinalMemo.set(messageId2, ordinal + ordinalContinuationBase);
30271
+ }
30272
+ state.ordinalMemoCanonicalCount += ordinalContinuationBase;
30273
+ }
30274
+ state.ordinalContinuationBase = ordinalContinuationBase;
30275
+ }
29744
30276
  if (!stateSyncRetryBusy) {
29745
30277
  state.initialized = true;
29746
30278
  state.seedPassPending = false;
@@ -29774,13 +30306,14 @@ function createRustModeTransform(deps, options) {
29774
30306
  sessionLog(sessionId, "rust memory mirror-back failed (ignored):", error);
29775
30307
  }
29776
30308
  }
29777
- if (options.moduleClient.getCompartmentsAfter) {
30309
+ const getCompartmentsAfter = options.moduleClient.getCompartmentsAfter;
30310
+ if (getCompartmentsAfter) {
29778
30311
  try {
29779
30312
  await mirrorModuleCompartments({
29780
30313
  db: deps.db,
29781
30314
  sessionId,
29782
30315
  reader: {
29783
- getCompartmentsAfter: (mirroredSessionId, afterSequence) => options.moduleClient.getCompartmentsAfter(mirroredSessionId, afterSequence)
30316
+ getCompartmentsAfter: (mirroredSessionId, afterSequence) => getCompartmentsAfter.call(options.moduleClient, mirroredSessionId, afterSequence)
29784
30317
  }
29785
30318
  });
29786
30319
  } catch (error) {
@@ -29838,7 +30371,7 @@ function createRustModeTransform(deps, options) {
29838
30371
  // src/hooks/magic-context/transform-compartment-phase.ts
29839
30372
  function runCompartmentPhase(args) {
29840
30373
  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);
30374
+ const willReadRawHistory = historianRunnable && !args.compactionOff && args.canRunCompartments && getActiveCompartmentRun(args.sessionId) === undefined && (args.sessionMeta.compartmentInProgress || !args.skipAwaitForThisPass && args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE);
29842
30375
  if (!willReadRawHistory) {
29843
30376
  return runCompartmentPhaseImpl(args);
29844
30377
  }
@@ -29862,6 +30395,21 @@ async function runCompartmentPhaseImpl(args) {
29862
30395
  let justAwaitedPublication = false;
29863
30396
  let rebuiltHistoryThisPass = false;
29864
30397
  const historianRunnable = args.historianRunnable !== false;
30398
+ if (args.compactionOff) {
30399
+ if (args.sessionMeta.compartmentInProgress) {
30400
+ sessionLog(args.sessionId, "transform: compaction off; clearing stale compartmentInProgress flag");
30401
+ updateSessionMeta(args.db, args.sessionId, { compartmentInProgress: false });
30402
+ compartmentInProgress = false;
30403
+ }
30404
+ return {
30405
+ pendingCompartmentInjection,
30406
+ awaitedCompartmentRun: false,
30407
+ compartmentInProgress,
30408
+ published,
30409
+ justAwaitedPublication,
30410
+ rebuiltHistoryThisPass
30411
+ };
30412
+ }
29865
30413
  let rawEligibility = null;
29866
30414
  let lastObservedCompartmentEnd = -1;
29867
30415
  let cachedBoundarySnapshot = null;
@@ -30047,12 +30595,31 @@ function clearMessageTokensCache(sessionId, messageId2) {
30047
30595
  cache.delete(messageId2);
30048
30596
  }
30049
30597
  var recordedSessionProjectIdentity = new BoundedSessionMap(MESSAGE_TOKENS_CACHE_MAX);
30598
+ function activeAgentFromMessages(messages) {
30599
+ for (let index = messages.length - 1;index >= 0; index -= 1) {
30600
+ const info = messages[index]?.info;
30601
+ if (info?.role !== "user")
30602
+ continue;
30603
+ return typeof info.agent === "string" && info.agent.length > 0 ? info.agent : undefined;
30604
+ }
30605
+ return;
30606
+ }
30050
30607
  function deriveTaggerLoadFloor(messages, sessionId, db) {
30051
30608
  return deriveTagLoadFloor(db, sessionId, function* () {
30052
30609
  for (const message of messages)
30053
30610
  yield message.info?.id;
30054
30611
  }());
30055
30612
  }
30613
+ function computeHardCacheExpired(cacheTtl, lastResponseTime, now, onInvalid) {
30614
+ let ttlMs;
30615
+ try {
30616
+ ttlMs = parseCacheTtl(cacheTtl);
30617
+ } catch (error) {
30618
+ onInvalid?.(error);
30619
+ ttlMs = 5 * 60 * 1000;
30620
+ }
30621
+ return lastResponseTime > 0 && now - lastResponseTime > ttlMs;
30622
+ }
30056
30623
  function findLastAssistantModel(messages) {
30057
30624
  for (let i = messages.length - 1;i >= 0; i--) {
30058
30625
  const info = messages[i].info;
@@ -30078,19 +30645,22 @@ var tsAuthorityRecoveryStateByProject = new Map;
30078
30645
  var tsAuthorityMismatchLoggedProjects = new Set;
30079
30646
  var tsAuthorityUnreachableLoggedProjects = new Set;
30080
30647
  function authorityModuleForProject(module, projectRoot) {
30081
- if (!module.authorityStatus || !module.authorityDrain || !module.mirrorPull) {
30648
+ const authorityStatus = module.authorityStatus;
30649
+ const authorityDrain = module.authorityDrain;
30650
+ const mirrorPull = module.mirrorPull;
30651
+ if (!authorityStatus || !authorityDrain || !mirrorPull) {
30082
30652
  throw new Error("the module does not expose authority.status, authority.drain, and mirror.pull");
30083
30653
  }
30084
30654
  return {
30085
- authorityStatus: (request2) => module.authorityStatus({ ...request2, projectRoot }),
30655
+ authorityStatus: (request2) => authorityStatus.call(module, { ...request2, projectRoot }),
30086
30656
  authorityPrepare: (request2) => {
30087
30657
  if (!module.authorityPrepare) {
30088
30658
  throw new Error("the module does not expose authority.prepare");
30089
30659
  }
30090
30660
  return module.authorityPrepare({ ...request2, projectRoot });
30091
30661
  },
30092
- authorityDrain: (request2) => module.authorityDrain({ ...request2, projectRoot }),
30093
- mirrorPull: (request2) => module.mirrorPull({ ...request2, projectRoot })
30662
+ authorityDrain: (request2) => authorityDrain.call(module, { ...request2, projectRoot }),
30663
+ mirrorPull: (request2) => mirrorPull.call(module, { ...request2, projectRoot })
30094
30664
  };
30095
30665
  }
30096
30666
  async function recoverTsAuthorityProject(args) {
@@ -30142,11 +30712,12 @@ function scheduleTsAuthorityRecovery(args) {
30142
30712
  return;
30143
30713
  if (tsAuthorityRecoveryStateByProject.has(args.projectPath))
30144
30714
  return;
30715
+ const module = args.module;
30145
30716
  if (!tsAuthorityMismatchLoggedProjects.has(args.projectPath)) {
30146
30717
  tsAuthorityMismatchLoggedProjects.add(args.projectPath);
30147
30718
  log(`[magic-context] project ${args.projectPath} is module-authority-managed but transform_mode is TS; draining authority back to TypeScript`);
30148
30719
  }
30149
- if (!args.module) {
30720
+ if (!module) {
30150
30721
  tsAuthorityRecoveryStateByProject.set(args.projectPath, "complete");
30151
30722
  if (!tsAuthorityUnreachableLoggedProjects.has(args.projectPath)) {
30152
30723
  tsAuthorityUnreachableLoggedProjects.add(args.projectPath);
@@ -30155,7 +30726,7 @@ function scheduleTsAuthorityRecovery(args) {
30155
30726
  return;
30156
30727
  }
30157
30728
  tsAuthorityRecoveryStateByProject.set(args.projectPath, "running");
30158
- Promise.resolve().then(() => recoverTsAuthorityProject({ ...args, module: args.module })).then((outcome) => {
30729
+ Promise.resolve().then(() => recoverTsAuthorityProject({ ...args, module })).then((outcome) => {
30159
30730
  if (outcome === "completed") {
30160
30731
  tsAuthorityRecoveryStateByProject.set(args.projectPath, "complete");
30161
30732
  log(`[magic-context] authority drain complete for project ${args.projectPath}`);
@@ -30201,6 +30772,7 @@ function createTransform(deps) {
30201
30772
  }
30202
30773
  const tUserMsg = performance.now();
30203
30774
  const currentTurnId = findLastUserMessageId(messages);
30775
+ const activeAgent = activeAgentFromMessages(messages);
30204
30776
  logTransformTiming(sessionId, "findLastUserMessageId", tUserMsg);
30205
30777
  const tMeta = performance.now();
30206
30778
  let sessionMeta;
@@ -30226,6 +30798,47 @@ function createTransform(deps) {
30226
30798
  }
30227
30799
  const reducedMode = sessionMeta.isSubagent;
30228
30800
  const fullFeatureMode = !reducedMode;
30801
+ const compactionOff = deps.compactionOff === true;
30802
+ try {
30803
+ const transition = reconcileCompactionMode({
30804
+ db,
30805
+ sessionId,
30806
+ compactionOff,
30807
+ historianRunnable: deps.historianRunnable !== false,
30808
+ compartmentInProgress: sessionMeta.compartmentInProgress
30809
+ });
30810
+ const hasTransitionEffects = transition.recordToWrite !== null || transition.notice !== null || transition.invalidatedM0Baseline || transition.clearedCompartmentInProgress || transition.historianCatchUpSignaled;
30811
+ if (hasTransitionEffects) {
30812
+ if (transition.invalidatedM0Baseline) {
30813
+ sessionMeta = {
30814
+ ...sessionMeta,
30815
+ cachedM0Bytes: null,
30816
+ cachedM1Bytes: null,
30817
+ cachedM0MuralDataUrl: null,
30818
+ cachedM0MuralHash: null
30819
+ };
30820
+ }
30821
+ if (transition.clearedCompartmentInProgress) {
30822
+ sessionMeta = { ...sessionMeta, compartmentInProgress: false };
30823
+ }
30824
+ if (transition.historianCatchUpSignaled) {
30825
+ sessionMeta = { ...sessionMeta, compartmentInProgress: true };
30826
+ }
30827
+ const notice = transition.notice;
30828
+ let noticeDelivered = notice === null || deps.client === undefined;
30829
+ if (notice && deps.client) {
30830
+ noticeDelivered = await sendIgnoredMessage(deps.client, sessionId, notice, deps.getNotificationParams?.(sessionId) ?? {}) === "sent";
30831
+ }
30832
+ if (noticeDelivered && transition.recordToWrite !== null) {
30833
+ commitCompactionModeRecord(db, sessionId, transition.recordToWrite);
30834
+ } else if (!noticeDelivered) {
30835
+ sessionLog(sessionId, "compaction mode notice was not delivered; durable pending record will retry on the next pass");
30836
+ }
30837
+ }
30838
+ } catch (error) {
30839
+ passOutcome.record("compaction-mode-transition-failure");
30840
+ sessionLog(sessionId, "compaction mode transition failed (retrying next pass):", error);
30841
+ }
30229
30842
  const ctxReduceAvailability = resolveCtxReduceAvailabilityFromMessages(sessionId, messages);
30230
30843
  const ctxReduceCallable = ctxReduceAvailability.callable;
30231
30844
  const todowriteAvailability = resolveTodowriteAvailabilityFromMessages(sessionId, messages);
@@ -30253,7 +30866,7 @@ function createTransform(deps) {
30253
30866
  }
30254
30867
  const compartmentDirectory = sessionDirectory;
30255
30868
  const historianRunnable = deps.historianRunnable !== false;
30256
- const canRunCompartments = fullFeatureMode && historianRunnable && deps.client !== undefined && compartmentDirectory.length > 0;
30869
+ const canRunCompartments = fullFeatureMode && !compactionOff && historianRunnable && deps.client !== undefined && compartmentDirectory.length > 0;
30257
30870
  const fallbackModelId = deps.getFallbackModelId?.(sessionId);
30258
30871
  const tModelDetect = performance.now();
30259
30872
  const persistedUsageBeforeResets = loadPersistedUsage(db, sessionId);
@@ -30313,7 +30926,7 @@ function createTransform(deps) {
30313
30926
  let emergencyRecoveryArmed = false;
30314
30927
  let emergencyRecoveryOrigin = null;
30315
30928
  let usagePercentageSynthetic = false;
30316
- if (fullFeatureMode) {
30929
+ if (fullFeatureMode && !compactionOff) {
30317
30930
  try {
30318
30931
  const armModel = deps.liveModelBySession?.get(sessionId);
30319
30932
  const armModelKey = deps.getModelKey?.(sessionId);
@@ -30366,25 +30979,27 @@ function createTransform(deps) {
30366
30979
  sessionID: sessionId
30367
30980
  }) : undefined;
30368
30981
  const currentModelKeyForBoundary = deps.getModelKey?.(sessionId);
30982
+ const thresholdContextLimit = resolvedContextLimit && resolvedContextLimit > 0 ? resolvedContextLimit : contextUsageEarly.percentage > 0 ? contextUsageEarly.inputTokens / (contextUsageEarly.percentage / 100) : undefined;
30983
+ const effectiveExecuteThresholdPercentage = resolveExecuteThreshold(deps.executeThresholdPercentage ?? 65, currentModelKeyForBoundary, 65, {
30984
+ tokensConfig: deps.executeThresholdTokens,
30985
+ contextLimit: thresholdContextLimit,
30986
+ sessionId
30987
+ });
30988
+ const { forceMaterializationPercentage } = escalationBands(effectiveExecuteThresholdPercentage);
30369
30989
  const persistedUsageFreshForBoundary = persistedUsageBeforeResets && Date.now() - persistedUsageBeforeResets.updatedAt <= 10 * 60 * 1000 && (persistedUsageBeforeResets.lastObservedModelKey === null || currentModelKeyForBoundary === undefined || persistedUsageBeforeResets.lastObservedModelKey === currentModelKeyForBoundary) && (resolvedContextLimit === undefined || persistedUsageBeforeResets.lastUsageContextLimit === 0 || persistedUsageBeforeResets.lastUsageContextLimit === resolvedContextLimit) ? persistedUsageBeforeResets.usage : null;
30370
30990
  const boundaryUsageForProtectedTail = persistedUsageFreshForBoundary ?? contextUsageEarly;
30371
30991
  const boundaryUsageSource = persistedUsageFreshForBoundary ? "persisted" : "live";
30372
30992
  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);
30993
+ const emergencyCeilingLimit = thresholdContextLimit ?? 0;
30994
+ const emergencyCeilingTokens = Number.isFinite(emergencyCeilingLimit) && emergencyCeilingLimit > 0 ? Math.floor(emergencyCeilingLimit * (effectiveExecuteThresholdPercentage / 100)) : undefined;
30995
+ const schedulerDecisionEarly = compactionOff ? "defer" : resolveSchedulerDecision(deps.scheduler, sessionMeta, contextUsageEarly, sessionId, deps.getModelKey?.(sessionId), resolvedContextLimit);
30382
30996
  const midTurn = isMidTurn(deps, resolvedSessionId);
30383
30997
  const bypassReason = detectMidTurnBypassReason({
30384
30998
  contextUsage: contextUsageEarly,
30385
30999
  sessionMeta,
30386
31000
  historyRefreshSessions: deps.historyRefreshSessions,
30387
- sessionId
31001
+ sessionId,
31002
+ effectiveExecuteThresholdPercentage
30388
31003
  });
30389
31004
  const { midTurnAdjustedSchedulerDecision, sideEffect } = applyMidTurnDeferral({
30390
31005
  base: schedulerDecisionEarly,
@@ -30402,12 +31017,13 @@ function createTransform(deps) {
30402
31017
  sessionLog(sessionId, `[boundary-exec] base=${schedulerDecisionEarly} bypass=${bypassReason} midTurn=${midTurn} effective=${midTurnAdjustedSchedulerDecision} sideEffect=${sideEffect}`);
30403
31018
  const historyRefreshExplicitBeforePrepare = deps.historyRefreshSessions.has(sessionId);
30404
31019
  const deferredHistoryWasPendingAtPassStart = deferredHistoryRefreshSessions.has(sessionId);
30405
- const earlyActiveRunBlocksMaterialization = (getActiveCompartmentRun(sessionId) !== undefined || sessionMeta.compartmentInProgress) && contextUsageEarly.percentage < FORCE_MATERIALIZE_PERCENTAGE;
31020
+ const earlyActiveRunBlocksMaterialization = (getActiveCompartmentRun(sessionId) !== undefined || sessionMeta.compartmentInProgress) && contextUsageEarly.percentage < forceMaterializationPercentage;
30406
31021
  const canConsumeDeferredEarly = canConsumeDeferredOnThisPass({
30407
31022
  schedulerDecision: midTurnAdjustedSchedulerDecision,
30408
31023
  contextPercentage: contextUsageEarly.percentage,
30409
31024
  justAwaitedPublication: false,
30410
- activeRunBlocksMaterialization: earlyActiveRunBlocksMaterialization
31025
+ activeRunBlocksMaterialization: earlyActiveRunBlocksMaterialization,
31026
+ forceMaterializationPercentage
30411
31027
  });
30412
31028
  const consumingDeferredEarly = canConsumeDeferredEarly && deferredHistoryWasPendingAtPassStart;
30413
31029
  const isCacheBusting = historyRefreshExplicitBeforePrepare || consumingDeferredEarly;
@@ -30488,7 +31104,7 @@ function createTransform(deps) {
30488
31104
  skipCompartmentAwaitForThisPass = true;
30489
31105
  return true;
30490
31106
  };
30491
- if (fullFeatureMode && historianFailureState.failureCount > 0 && contextUsageEarly.percentage >= 95 && !recoveryNoHeadEscapeActive) {
31107
+ if (fullFeatureMode && !compactionOff && historianFailureState.failureCount > 0 && contextUsageEarly.percentage >= 95 && !recoveryNoHeadEscapeActive) {
30492
31108
  skipCompartmentAwaitForThisPass = true;
30493
31109
  const emergencyPercentage = contextUsageEarly.percentage.toFixed(1);
30494
31110
  const recoveryStarted = startRecoveryRun();
@@ -30500,7 +31116,7 @@ function createTransform(deps) {
30500
31116
  sessionLog(sessionId, "transform: emergency recovery remains armed — no complete eligible head before protected tail");
30501
31117
  }
30502
31118
  sessionLog(sessionId, `EMERGENCY: historian recovery requested at ${emergencyPercentage}%, failures: ${historianFailureState.failureCount}`);
30503
- } else if (fullFeatureMode && isFirstTransformPassForSession && historianFailureState.failureCount > 0 && getEligibleHistoryForCompartment() && startRecoveryRun()) {
31119
+ } else if (fullFeatureMode && !compactionOff && isFirstTransformPassForSession && historianFailureState.failureCount > 0 && getEligibleHistoryForCompartment() && startRecoveryRun()) {
30504
31120
  sessionLog(sessionId, `transform: historian recovery triggered on session load after ${historianFailureState.failureCount} failure(s)`);
30505
31121
  if (deps.client) {
30506
31122
  sendIgnoredMessage(deps.client, sessionId, `## Historian recovery
@@ -30515,7 +31131,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30515
31131
  maybeSendProjectIdentityWarning(deps, sessionId, memoryProjectDirectory, notificationParams);
30516
31132
  }
30517
31133
  const sessionProjectIdentity = projectIdentity ?? (sessionDirectory ? resolveProjectIdentity(sessionDirectory) : deps.projectPath);
30518
- const sessionIdentityForBinding = sessionDirectory ? resolveProjectIdentityForSession(sessionDirectory) : undefined;
31134
+ const sessionIdentityForBinding = sessionDirectory ? resolveProjectIdentityForSession(sessionDirectory, deps.allowHomeProject) : undefined;
30519
31135
  if (sessionDirectory) {
30520
31136
  maybeSendProjectIdentityWarning(deps, sessionId, sessionDirectory, notificationParams);
30521
31137
  }
@@ -30532,16 +31148,16 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30532
31148
  recordSessionProjectIdentity(db, sessionId, sessionIdentityForBinding);
30533
31149
  recordedSessionProjectIdentity.set(sessionId, sessionIdentityForBinding);
30534
31150
  }
30535
- const taggerFloor = deriveTaggerLoadFloor(messages, sessionId, db);
30536
- if (taggerFloor === 0 && messages.length > 0) {
31151
+ const taggerFloor = compactionOff ? 0 : deriveTaggerLoadFloor(messages, sessionId, db);
31152
+ if (!compactionOff && taggerFloor === 0 && messages.length > 0) {
30537
31153
  sessionLog(sessionId, `tag floor: 0 (full-scan fallback) — no leading wire message resolved a tag across ${messages.length} msgs`);
30538
31154
  }
30539
31155
  let triggerBoundarySnapshot;
30540
- if (fullFeatureMode && historianRunnable && !sessionMeta.compartmentInProgress) {
31156
+ if (fullFeatureMode && !compactionOff && historianRunnable && !sessionMeta.compartmentInProgress) {
30541
31157
  const tTrigger = performance.now();
30542
31158
  try {
30543
31159
  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);
31160
+ const triggerResult = checkCompartmentTrigger(db, sessionId, sessionMeta, boundaryUsageForProtectedTail, sessionMeta.lastContextPercentage, boundaryExecuteThreshold, deriveTriggerBudget(boundaryContextLimit, boundaryExecuteThreshold), deps.clearReasoningAge, deps.commitClusterTrigger, undefined, boundaryContextLimit, inMemoryTail, taggerFloor, { providerID: resolvedProviderID });
30545
31161
  if (triggerResult.shouldFire) {
30546
31162
  sessionLog(sessionId, `compartment trigger: firing (reason=${triggerResult.reason})`);
30547
31163
  updateSessionMeta(db, sessionId, { compartmentInProgress: true });
@@ -30556,7 +31172,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30556
31172
  }
30557
31173
  let pendingCompartmentInjection = null;
30558
31174
  let rebuiltHistoryFromInitialPrepare = false;
30559
- if (fullFeatureMode) {
31175
+ if (fullFeatureMode && !compactionOff) {
30560
31176
  const tInj = performance.now();
30561
31177
  pendingCompartmentInjection = prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectIdentity, deps.memoryConfig?.injectionBudgetTokens, deps.experimentalTemporalAwareness);
30562
31178
  logTransformTiming(sessionId, "prepareCompartmentInjection", tInj);
@@ -30570,10 +31186,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30570
31186
  let targets = new Map;
30571
31187
  let reasoningByMessage = new Map;
30572
31188
  let messageTagNumbers = new Map;
30573
- let tagNormalizationTargets = [];
30574
31189
  let batch = null;
30575
31190
  let hasRecentReduceCall = false;
30576
- if (deps.experimentalTemporalAwareness) {
31191
+ if (deps.experimentalTemporalAwareness && !compactionOff) {
30577
31192
  const tTemporal = performance.now();
30578
31193
  const injected = injectTemporalMarkers(messages);
30579
31194
  if (injected > 0) {
@@ -30582,44 +31197,45 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30582
31197
  logTransformTiming(sessionId, "injectTemporalMarkers", tTemporal);
30583
31198
  }
30584
31199
  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);
31200
+ if (!compactionOff) {
30611
31201
  try {
30612
- deps.tagger.cleanup(sessionId);
30613
- } catch (cleanupError) {
30614
- sessionLog(sessionId, "tagger cleanup after failure threw:", cleanupError);
31202
+ const t0 = performance.now();
31203
+ const tInitFromDb = performance.now();
31204
+ deps.tagger.initFromDb(sessionId, db, taggerFloor);
31205
+ logTransformTiming(sessionId, "tag.initFromDb", tInitFromDb);
31206
+ const skipPrefixInjection = !ctxReduceCallable;
31207
+ const result = tagMessages(sessionId, messages, deps.tagger, db, {
31208
+ skipPrefixInjection
31209
+ });
31210
+ targets = result.targets;
31211
+ reasoningByMessage = result.reasoningByMessage;
31212
+ messageTagNumbers = result.messageTagNumbers;
31213
+ batch = result.batch;
31214
+ hasRecentReduceCall = result.hasRecentReduceCall;
31215
+ const hadPriorCommitState = deps.commitSeenLastPass?.has(sessionId) ?? false;
31216
+ const sawCommitLastPass = deps.commitSeenLastPass?.get(sessionId) ?? false;
31217
+ if (fullFeatureMode && hadPriorCommitState && result.hasRecentCommit && !sawCommitLastPass) {
31218
+ onNoteTrigger(db, sessionId, "commit_detected");
31219
+ }
31220
+ deps.commitSeenLastPass?.set(sessionId, result.hasRecentCommit);
31221
+ logTransformTiming(sessionId, "tagMessages", t0);
31222
+ taggingSucceeded = true;
31223
+ } catch (error) {
31224
+ passOutcome.record("tagging-persistence-failure");
31225
+ sessionLog(sessionId, "transform tag persistence failed; continuing without tagging:", error);
31226
+ try {
31227
+ deps.tagger.cleanup(sessionId);
31228
+ } catch (cleanupError) {
31229
+ sessionLog(sessionId, "tagger cleanup after failure threw:", cleanupError);
31230
+ }
30615
31231
  }
30616
31232
  }
30617
31233
  const t1 = performance.now();
30618
- const activeTags = getActiveTagsBySession(db, sessionId);
31234
+ const activeTags = compactionOff ? [] : getActiveTagsBySession(db, sessionId);
30619
31235
  logTransformTiming(sessionId, "getActiveTagsBySession", t1, `count=${activeTags.length}`);
30620
31236
  const t1b = performance.now();
30621
31237
  const targetTagNumbers = [...targets.keys()];
30622
- const targetsSliceTags = getTagsByNumbers(db, sessionId, targetTagNumbers);
31238
+ const targetsSliceTags = compactionOff ? [] : getTagsByNumbers(db, sessionId, targetTagNumbers);
30623
31239
  logTransformTiming(sessionId, "getTagsByNumbers", t1b, `targets=${targetTagNumbers.length} fetched=${targetsSliceTags.length}`);
30624
31240
  let didMutateFromFlushedStatuses = false;
30625
31241
  if (taggingSucceeded) {
@@ -30635,10 +31251,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30635
31251
  }
30636
31252
  }
30637
31253
  const t3 = performance.now();
30638
- const strippedStructuralNoise = canUseEmptySentinels ? stripStructuralNoise(messages) : 0;
31254
+ const strippedStructuralNoise = canUseEmptySentinels && !compactionOff ? stripStructuralNoise(messages) : 0;
30639
31255
  logTransformTiming(sessionId, "stripStructuralNoise", t3, `strippedParts=${strippedStructuralNoise}`);
30640
31256
  const persistedReasoningWatermark = sessionMeta?.clearedReasoningThroughTag ?? 0;
30641
- if (persistedReasoningWatermark > 0) {
31257
+ if (persistedReasoningWatermark > 0 && !compactionOff) {
30642
31258
  const tReplay = performance.now();
30643
31259
  const replayed = canUseEmptySentinels ? replayClearedReasoning(messages, reasoningByMessage, messageTagNumbers, persistedReasoningWatermark) : 0;
30644
31260
  const replayedInline = replayStrippedInlineThinking(messages, messageTagNumbers, persistedReasoningWatermark);
@@ -30647,7 +31263,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30647
31263
  }
30648
31264
  logTransformTiming(sessionId, "replayReasoningClearing", tReplay);
30649
31265
  }
30650
- if (!reducedMode && deps.cavemanTextCompression?.enabled) {
31266
+ if (!reducedMode && !compactionOff && deps.cavemanTextCompression?.enabled) {
30651
31267
  const tCavemanReplay = performance.now();
30652
31268
  const replayedCaveman = replayCavemanCompression(sessionId, db, targets, targetsSliceTags);
30653
31269
  if (replayedCaveman > 0) {
@@ -30656,7 +31272,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30656
31272
  logTransformTiming(sessionId, "replayCavemanCompression", tCavemanReplay);
30657
31273
  }
30658
31274
  const t4 = performance.now();
30659
- const strippedClearedReasoning = canUseEmptySentinels ? stripClearedReasoning(messages) : 0;
31275
+ const strippedClearedReasoning = canUseEmptySentinels && !compactionOff ? stripClearedReasoning(messages) : 0;
30660
31276
  logTransformTiming(sessionId, "stripClearedReasoning", t4, `strippedParts=${strippedClearedReasoning}`);
30661
31277
  const watermark = getMaxDroppedTagNumber(db, sessionId);
30662
31278
  const contextUsage = contextUsageEarly;
@@ -30666,6 +31282,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30666
31282
  const compartmentPhase = await runCompartmentPhase({
30667
31283
  canRunCompartments,
30668
31284
  fullFeatureMode,
31285
+ compactionOff,
30669
31286
  historianRunnable,
30670
31287
  sessionMeta,
30671
31288
  contextUsage,
@@ -30715,28 +31332,25 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30715
31332
  const hardModel = deps.liveModelBySession?.get(sessionId);
30716
31333
  const hardModelKey = hardModel ? `${hardModel.providerID}/${hardModel.modelID}` : "";
30717
31334
  const hardSystemHash = typeof sessionMeta.systemPromptHash === "string" ? sessionMeta.systemPromptHash : "";
30718
- let hardTtlMs = 5 * 60 * 1000;
30719
- try {
30720
- hardTtlMs = parseCacheTtl(sessionMeta.cacheTtl);
30721
- } catch (error) {
31335
+ const hardCacheExpired = computeHardCacheExpired(sessionMeta.cacheTtl, sessionMeta.lastResponseTime, Date.now(), (error) => {
30722
31336
  passOutcome.record("invalid-cache-ttl-fallback");
30723
31337
  sessionLog(sessionId, "invalid cache_ttl; using the 5m default:", error);
30724
- }
30725
- const hardCacheExpired = sessionMeta.lastResponseTime > 0 && Date.now() - sessionMeta.lastResponseTime >= hardTtlMs;
31338
+ });
30726
31339
  const m0HardSignals = {
30727
31340
  systemHash: hardSystemHash,
30728
31341
  modelKey: hardModelKey,
30729
31342
  cacheExpired: hardCacheExpired,
30730
31343
  lastResponseTime: sessionMeta.lastResponseTime
30731
31344
  };
30732
- const lateActiveRunBlocksMaterialization = getActiveCompartmentRun(sessionId) !== undefined && contextUsageEarly.percentage < FORCE_MATERIALIZE_PERCENTAGE;
31345
+ const lateActiveRunBlocksMaterialization = getActiveCompartmentRun(sessionId) !== undefined && contextUsageEarly.percentage < forceMaterializationPercentage;
30733
31346
  const canConsumeDeferredLate = canConsumeDeferredOnThisPass({
30734
31347
  schedulerDecision: midTurnAdjustedSchedulerDecision,
30735
31348
  contextPercentage: contextUsageEarly.percentage,
30736
31349
  justAwaitedPublication: compartmentPhase.justAwaitedPublication,
30737
- activeRunBlocksMaterialization: lateActiveRunBlocksMaterialization
31350
+ activeRunBlocksMaterialization: lateActiveRunBlocksMaterialization,
31351
+ forceMaterializationPercentage
30738
31352
  });
30739
- const wasEmergencyBlock = contextUsageEarly.percentage >= FORCE_MATERIALIZE_PERCENTAGE && compartmentPhase.justAwaitedPublication;
31353
+ const wasEmergencyBlock = contextUsageEarly.percentage >= forceMaterializationPercentage && compartmentPhase.justAwaitedPublication;
30740
31354
  const historyRebuiltThisPass = wasEmergencyBlock ? compartmentPhase.rebuiltHistoryThisPass : rebuiltHistoryFromInitialPrepare || compartmentPhase.rebuiltHistoryThisPass;
30741
31355
  const tPostProcess = performance.now();
30742
31356
  const postTransformResult = await runPostTransformPhase({
@@ -30750,10 +31364,13 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30750
31364
  tagger: deps.tagger,
30751
31365
  ctxReduceAvailability,
30752
31366
  todowriteAvailability,
31367
+ client: deps.client,
31368
+ activeAgent,
30753
31369
  batch,
30754
31370
  contextUsage,
30755
31371
  schedulerDecision,
30756
31372
  fullFeatureMode,
31373
+ compactionOff,
30757
31374
  canRunCompartments,
30758
31375
  awaitedCompartmentRun,
30759
31376
  phaseJustAwaitedPublication: compartmentPhase.justAwaitedPublication,
@@ -30776,7 +31393,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30776
31393
  pendingCompartmentInjection,
30777
31394
  didMutateFromFlushedStatuses,
30778
31395
  watermark,
30779
- forceMaterializationPercentage: FORCE_MATERIALIZE_PERCENTAGE,
31396
+ forceMaterializationPercentage,
30780
31397
  hasRecentReduceCall,
30781
31398
  projectPath: sessionProjectIdentity,
30782
31399
  sessionDirectory,
@@ -30798,63 +31415,70 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30798
31415
  }
30799
31416
  });
30800
31417
  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
- });
31418
+ const finalWireTail = describeFinalWireTail(messages);
31419
+ let finalWireEstimate;
31420
+ if (!compactionOff) {
31421
+ finalWireEstimate = contextUsage.percentage >= 95 ? estimateFinalWireInputTokens({
31422
+ messages,
31423
+ systemPromptTokens: sessionMeta.systemPromptTokens,
31424
+ providerID: modelForBudget?.providerID,
31425
+ modelID: modelForBudget?.modelID,
31426
+ agentName: notificationParams.agent
31427
+ }) : undefined;
31428
+ if (finalWireEstimate) {
31429
+ sessionLog(sessionId, `transform: final-wire telemetry estimate=${finalWireEstimate.tokens} trusted=${finalWireEstimate.trusted} conversation=${finalWireEstimate.messageTokens.conversation} tools=${finalWireEstimate.messageTokens.toolCall} system=${finalWireEstimate.systemTokens} toolDefinitions=${finalWireEstimate.toolDefinitionTokens ?? "unknown"} tail=${finalWireTail}`);
31430
+ }
31431
+ const currentModelKeyForRecovery = deps.getModelKey?.(sessionId);
31432
+ const overflowStateForFinalWire = getOverflowState(db, sessionId, currentModelKeyForRecovery);
31433
+ const providerProvenLimitTokens = typeof currentModelKeyForRecovery === "string" && currentModelKeyForRecovery.length > 0 && overflowStateForFinalWire.detectedContextLimit > 0 && overflowStateForFinalWire.detectedContextLimitModelKey === currentModelKeyForRecovery ? overflowStateForFinalWire.detectedContextLimit : undefined;
31434
+ const emergencyFailClosed = evaluateEmergencyFailClosed({
31435
+ usagePercentage: contextUsage.percentage,
31436
+ emergencyRecoveryArmed,
31437
+ emergencyRecoveryOrigin,
31438
+ foldMaterializedThisPass: postTransformResult.historianFoldMaterializedThisPass,
31439
+ finalWireEstimate,
31440
+ providerProvenLimitTokens
31441
+ });
31442
+ if (emergencyFailClosed.disarm) {
31443
+ clearEmergencyRecovery(db, sessionId);
31444
+ sessionLog(sessionId, `emergency disarm: trusted final-wire ${emergencyFailClosed.disarm.finalWireTokens} under limit ${emergencyFailClosed.disarm.provenLimitTokens}`);
30848
31445
  }
30849
- try {
30850
- clearEmergencyDropSample(db, sessionId);
30851
- } catch (error) {
30852
- throw new EmergencyFailClosedError("Emergency recovery cleanup failed", {
30853
- cause: error
30854
- });
31446
+ if (emergencyFailClosed.shouldAbort) {
31447
+ if (!deps.client) {
31448
+ throw new EmergencyFailClosedError("Cannot fail closed: OpenCode client is unavailable");
31449
+ }
31450
+ let notification;
31451
+ try {
31452
+ notification = await sendIgnoredMessage(deps.client, sessionId, "Context full — /ctx-flush or /clear to continue.", notificationParams);
31453
+ } catch (error) {
31454
+ throw new EmergencyFailClosedError("Emergency recovery notification failed", {
31455
+ cause: error
31456
+ });
31457
+ }
31458
+ if (notification !== "sent" && notification !== "queued") {
31459
+ throw new EmergencyFailClosedError(`Emergency recovery notification was ${notification}`);
31460
+ }
31461
+ try {
31462
+ await abortSessionFailClosed(deps.client, sessionId);
31463
+ } catch (error) {
31464
+ sessionLog(sessionId, "transform: emergency fail-closed abort failed; refusing to return a sendable prompt:", getErrorMessage(error));
31465
+ throw new EmergencyFailClosedError("Emergency recovery abort failed", {
31466
+ cause: error
31467
+ });
31468
+ }
31469
+ try {
31470
+ clearEmergencyDropSample(db, sessionId);
31471
+ } catch (error) {
31472
+ throw new EmergencyFailClosedError("Emergency recovery cleanup failed", {
31473
+ cause: error
31474
+ });
31475
+ }
31476
+ sessionLog(sessionId, `EMERGENCY: fail-closed (reason=${emergencyFailClosed.reason}, recoveryOrigin=${emergencyRecoveryOrigin ?? "unknown"}, finalEstimate=${finalWireEstimate?.tokens ?? "unavailable"}, estimateTrusted=${finalWireEstimate?.trusted ?? false}, syntheticUsage=${usagePercentageSynthetic})`);
31477
+ return;
30855
31478
  }
30856
- sessionLog(sessionId, `EMERGENCY: fail-closed (reason=${emergencyFailClosed.reason}, recoveryOrigin=${emergencyRecoveryOrigin ?? "unknown"}, finalEstimate=${finalWireEstimate?.tokens ?? "unavailable"}, estimateTrusted=${finalWireEstimate?.trusted ?? false}, syntheticUsage=${usagePercentageSynthetic})`);
30857
- return;
31479
+ }
31480
+ if (!finalWireEstimate) {
31481
+ sessionLog(sessionId, `transform: final-wire telemetry estimate=unavailable trusted=false conversation=unknown tools=unknown system=unknown toolDefinitions=unknown tail=${finalWireTail}`);
30858
31482
  }
30859
31483
  if (passOutcome.captureEligible) {
30860
31484
  const keys = resolveLkgModelKeys(messages);
@@ -30930,7 +31554,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
30930
31554
  sessionLog(sessionId, "conversation_tokens UPDATE failed:", error);
30931
31555
  }
30932
31556
  }
30933
- if (ctxReduceCallable && deps.channel1StateBySession) {
31557
+ if (ctxReduceCallable && !compactionOff && deps.channel1StateBySession) {
30934
31558
  try {
30935
31559
  const resolvedExecuteThresholdPct = resolveExecuteThreshold(deps.executeThresholdPercentage ?? 65, deps.getModelKey?.(sessionId), 65, {
30936
31560
  tokensConfig: deps.executeThresholdTokens,
@@ -31119,15 +31743,22 @@ function createEventHandler2(deps) {
31119
31743
  const sessionMeta = getOrCreateSessionMeta(deps.db, errInfo.sessionID);
31120
31744
  if (sessionMeta.isSubagent) {
31121
31745
  if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
31122
- recordDetectedContextLimit(deps.db, errInfo.sessionID, detection.reportedLimit);
31746
+ recordDetectedContextLimit(deps.db, errInfo.sessionID, detection.reportedLimit, undefined, detection.reportedLimitProvenance);
31123
31747
  }
31124
- sessionLog(errInfo.sessionID, `overflow detected on subagent: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only (subagents cannot run historian)`);
31748
+ sessionLog(errInfo.sessionID, `overflow detected on subagent: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only (subagents cannot run historian)`);
31125
31749
  return;
31126
31750
  }
31127
31751
  const existing = getOverflowState(deps.db, errInfo.sessionID);
31752
+ if (deps.compactionOff) {
31753
+ if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
31754
+ recordDetectedContextLimit(deps.db, errInfo.sessionID, detection.reportedLimit, undefined, detection.reportedLimitProvenance);
31755
+ }
31756
+ sessionLog(errInfo.sessionID, `overflow detected in compaction-off mode: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only (recovery disarmed; native compaction owns the window)`);
31757
+ return;
31758
+ }
31128
31759
  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})`);
31760
+ recordOverflowDetected(deps.db, errInfo.sessionID, detection.reportedLimit, undefined, "provider_overflow", detection.reportedLimitProvenance);
31761
+ sessionLog(errInfo.sessionID, `overflow detected via session.error: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"} (previousRecovery=${existing.needsEmergencyRecovery})`);
31131
31762
  deps.onSessionCacheInvalidated?.(errInfo.sessionID);
31132
31763
  } catch (error) {
31133
31764
  sessionLog(errInfo.sessionID, "event session.error handling failed:", error);
@@ -31169,13 +31800,18 @@ function createEventHandler2(deps) {
31169
31800
  const metaForOverflow = getOrCreateSessionMeta(deps.db, info.sessionID);
31170
31801
  if (metaForOverflow.isSubagent) {
31171
31802
  if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
31172
- recordDetectedContextLimit(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey);
31803
+ recordDetectedContextLimit(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey, detection.reportedLimitProvenance);
31804
+ }
31805
+ sessionLog(info.sessionID, `overflow detected on subagent via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only`);
31806
+ } else if (deps.compactionOff) {
31807
+ if (typeof detection.reportedLimit === "number" && detection.reportedLimit > 0) {
31808
+ recordDetectedContextLimit(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey, detection.reportedLimitProvenance);
31173
31809
  }
31174
- sessionLog(info.sessionID, `overflow detected on subagent via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only`);
31810
+ sessionLog(info.sessionID, `overflow detected in compaction-off mode via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"} — recorded limit only`);
31175
31811
  } else {
31176
31812
  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"}`);
31813
+ recordOverflowDetected(deps.db, info.sessionID, detection.reportedLimit, overflowModelKey, "provider_overflow", detection.reportedLimitProvenance);
31814
+ sessionLog(info.sessionID, `overflow detected via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} provenance=${detection.reportedLimitProvenance ?? "n/a"} pattern=${detection.matchedPattern ?? "n/a"}`);
31179
31815
  deps.onSessionCacheInvalidated?.(info.sessionID);
31180
31816
  }
31181
31817
  } catch (error) {
@@ -31274,7 +31910,7 @@ function createEventHandler2(deps) {
31274
31910
  } catch (error) {
31275
31911
  sessionLog(info.sessionID, "event message.updated persistence failed:", error);
31276
31912
  }
31277
- if ((info.finish === "stop" || info.finish === "tool-calls") && deps.client && deps.channel1StateBySession) {
31913
+ if ((info.finish === "stop" || info.finish === "tool-calls") && deps.client && deps.channel1StateBySession && !deps.compactionOff) {
31278
31914
  deliverChannel2IfPending(deps, info.sessionID);
31279
31915
  }
31280
31916
  return;
@@ -31916,11 +32552,15 @@ function createEventHook(args) {
31916
32552
  args.deferredMaterializationSessions.delete(sessionId);
31917
32553
  args.lastHeuristicsTurnId.delete(sessionId);
31918
32554
  args.commitSeenLastPass?.delete(sessionId);
32555
+ clearIgnoredMessages(sessionId);
31919
32556
  resetNoteNudgeCooldownOnly(sessionId);
31920
32557
  clearAutoSearchForSession(sessionId);
31921
32558
  clearSidebarSnapshotCache(sessionId);
31922
32559
  clearSessionTracking(sessionId);
31923
32560
  }
32561
+ if (input.event.type !== "session.deleted") {
32562
+ await flushIgnoredMessages(sessionId);
32563
+ }
31924
32564
  };
31925
32565
  }
31926
32566
  function createCommandExecuteBeforeHook(commandHandler) {
@@ -31980,6 +32620,7 @@ function createToolExecuteAfterHook(args) {
31980
32620
  if (!typedInput.sessionID || !typedInput.tool) {
31981
32621
  return;
31982
32622
  }
32623
+ await flushIgnoredMessages(typedInput.sessionID);
31983
32624
  if (typedInput.tool === "ctx_reduce") {
31984
32625
  const state = args.channel1StateBySession.get(typedInput.sessionID);
31985
32626
  if (state)
@@ -32000,6 +32641,19 @@ function createToolExecuteAfterHook(args) {
32000
32641
  const todowriteVerdict = resolveTodowriteAvailability(typedInput.sessionID);
32001
32642
  if (todowriteVerdict.frozen && !todowriteVerdict.callable)
32002
32643
  return;
32644
+ const activeAgent = typedInput.agent;
32645
+ if (args.client) {
32646
+ try {
32647
+ if (await todowritePermissionDenied(args.client, typedInput.sessionID, activeAgent)) {
32648
+ return;
32649
+ }
32650
+ } catch (error) {
32651
+ if (cachedToolPermissionDenied(typedInput.sessionID, "todowrite")) {
32652
+ return;
32653
+ }
32654
+ sessionLog(typedInput.sessionID, "todowrite permission read failed during capture (ignored):", error);
32655
+ }
32656
+ }
32003
32657
  const todoArgs = typedInput.args;
32004
32658
  const todos = todoArgs?.todos;
32005
32659
  const sessionMeta = Array.isArray(todos) ? getOrCreateSessionMeta(args.db, typedInput.sessionID) : null;
@@ -32424,14 +33078,24 @@ function createMagicContextHook(deps) {
32424
33078
  const reason = (opened ? getDatabasePersistenceError(opened) : null) ?? "Failed to initialize the persistent SQLite database.";
32425
33079
  log("[magic-context] disabling feature because persistent storage is unavailable:", reason);
32426
33080
  notifyMagicContextDisabled(deps.client, reason);
33081
+ const migration = getMigrationOnOpenRefusal();
33082
+ const blockingProcesses = migration?.serverPids.map((pid) => ({ harness: "OpenCode server", pid })) ?? [];
32427
33083
  const fence = getSchemaFenceRejection();
32428
33084
  recordHookInitFailure({
32429
33085
  type: "storage",
32430
- reason: fence ? {
33086
+ reason: migration && blockingProcesses.length > 0 ? {
33087
+ kind: "migration_guard",
33088
+ persistedVersion: migration.persistedVersion,
33089
+ supportedVersion: migration.supportedVersion,
33090
+ blockingProcesses
33091
+ } : fence ? {
32431
33092
  kind: "schema_fence",
32432
33093
  persistedVersion: fence.persistedVersion,
32433
33094
  supportedVersion: fence.supportedVersion
32434
- } : { kind: "storage_failure", cause: reason }
33095
+ } : {
33096
+ kind: "storage_failure",
33097
+ cause: migration?.unreadableFile ? `migration guard could not read RPC discovery file ${migration.unreadableFile}` : reason
33098
+ }
32435
33099
  });
32436
33100
  return null;
32437
33101
  }
@@ -32447,9 +33111,9 @@ function createMagicContextHook(deps) {
32447
33111
  });
32448
33112
  return null;
32449
33113
  }
32450
- const projectPath = resolveProjectIdentityForSession(deps.directory);
33114
+ const projectPath = resolveProjectIdentityForSession(deps.directory, deps.config.allow_home_project);
32451
33115
  if (!projectPath) {
32452
- log("[magic-context] not binding a project identity for the user's home directory");
33116
+ log("[magic-context] not binding a project identity for this directory");
32453
33117
  clearHookInitFailure();
32454
33118
  recordHookInitFailure({ type: "no_project" });
32455
33119
  return null;
@@ -32513,6 +33177,7 @@ function createMagicContextHook(deps) {
32513
33177
  const dreamerRunnable = isDreamerRunnable(deps.config);
32514
33178
  const dreamerConfig = dreamerRunnable ? deps.config.dreamer : undefined;
32515
33179
  const historianRunnable = isHistorianRunnable(deps.config);
33180
+ const compactionOff = !isCompactionEnabled(deps.config);
32516
33181
  const buildManagedRecompCtx = (sessionId) => ({
32517
33182
  client: deps.client,
32518
33183
  db,
@@ -32573,7 +33238,7 @@ function createMagicContextHook(deps) {
32573
33238
  return "Embedding is already running for this session.";
32574
33239
  }
32575
33240
  await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
32576
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33241
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32577
33242
  if (!sessionProjectIdentity)
32578
33243
  return "No project identity is bound for the home directory.";
32579
33244
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32641,7 +33306,7 @@ function createMagicContextHook(deps) {
32641
33306
  if (ctrl)
32642
33307
  ctrl.abort();
32643
33308
  const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
32644
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33309
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32645
33310
  if (!sessionProjectIdentity)
32646
33311
  return "No project identity is bound for the home directory.";
32647
33312
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32650,7 +33315,7 @@ function createMagicContextHook(deps) {
32650
33315
  };
32651
33316
  const getEmbedStatusText = (sessionId) => {
32652
33317
  const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
32653
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33318
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32654
33319
  if (!sessionProjectIdentity)
32655
33320
  return "No project identity is bound for the home directory.";
32656
33321
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32676,7 +33341,7 @@ function createMagicContextHook(deps) {
32676
33341
  try {
32677
33342
  await new Promise((resolve3) => setTimeout(resolve3, 0));
32678
33343
  await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
32679
- const sessionProjectIdentity = resolveProjectIdentityForSession(directory);
33344
+ const sessionProjectIdentity = resolveProjectIdentityForSession(directory, deps.config.allow_home_project);
32680
33345
  if (!sessionProjectIdentity)
32681
33346
  return;
32682
33347
  maybeSendProjectIdentitySessionWarning(sessionId, directory);
@@ -32909,6 +33574,7 @@ function createMagicContextHook(deps) {
32909
33574
  internalChildSessions,
32910
33575
  client: deps.client,
32911
33576
  directory: deps.directory,
33577
+ allowHomeProject: deps.config.allow_home_project,
32912
33578
  injectDocs: deps.config.dreamer?.inject_docs !== false,
32913
33579
  memoryConfig: deps.config.memory ? {
32914
33580
  enabled: deps.config.memory.enabled,
@@ -32933,6 +33599,7 @@ function createMagicContextHook(deps) {
32933
33599
  },
32934
33600
  projectPath,
32935
33601
  historianRunnable,
33602
+ compactionOff,
32936
33603
  experimentalUserMemories: userMemoryCollectionEnabled(dreamerConfig),
32937
33604
  experimentalTemporalAwareness: deps.config.temporal_awareness === true,
32938
33605
  experimentalMuralEnabled: deps.config.experimental?.mural?.enabled === true,
@@ -32946,7 +33613,7 @@ function createMagicContextHook(deps) {
32946
33613
  directory: deps.directory,
32947
33614
  ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory
32948
33615
  } : undefined,
32949
- cavemanTextCompression: deps.config.caveman_text_compression?.enabled === true ? {
33616
+ cavemanTextCompression: compactionOff ? undefined : deps.config.caveman_text_compression?.enabled === true ? {
32950
33617
  enabled: true,
32951
33618
  minChars: deps.config.caveman_text_compression.min_chars ?? 500
32952
33619
  } : undefined,
@@ -32962,6 +33629,7 @@ function createMagicContextHook(deps) {
32962
33629
  contextUsageMap,
32963
33630
  compactionHandler: deps.compactionHandler,
32964
33631
  config: deps.config,
33632
+ compactionOff,
32965
33633
  tagger: deps.tagger,
32966
33634
  db,
32967
33635
  client: deps.client,
@@ -32982,6 +33650,7 @@ function createMagicContextHook(deps) {
32982
33650
  transform.clearRustSession(sessionId);
32983
33651
  systemPromptHash.clearSession(sessionId);
32984
33652
  lastHeuristicsTurnId.delete(sessionId);
33653
+ clearToolPermissionDenied(sessionId);
32985
33654
  commitSeenLastPass.delete(sessionId);
32986
33655
  variantBySession.delete(sessionId);
32987
33656
  liveModelBySession.delete(sessionId);
@@ -33041,6 +33710,7 @@ function createMagicContextHook(deps) {
33041
33710
  const commandHandler = createMagicContextCommandHandler({
33042
33711
  db,
33043
33712
  protectedTags: deps.config.protected_tags,
33713
+ compactionOff,
33044
33714
  toastDurationMs: deps.config.toast_duration_ms,
33045
33715
  executeThresholdPercentage: deps.config.execute_threshold_percentage ?? 65,
33046
33716
  executeThresholdTokens: deps.config.execute_threshold_tokens,
@@ -33184,6 +33854,7 @@ function createMagicContextHook(deps) {
33184
33854
  "tool.execute.after": createToolExecuteAfterHook({
33185
33855
  db,
33186
33856
  channel1StateBySession,
33857
+ client: deps.client,
33187
33858
  transformMode: deps.config.transform_mode,
33188
33859
  todoStateSet: deps.config.transform_mode === "rust" && rustModeModuleClient ? ({ sessionId, stateJson, ownerMessageId }) => rustModeModuleClient.call({
33189
33860
  sessionId,
@@ -33279,15 +33950,30 @@ function createMessagesTransformHandler(args) {
33279
33950
  const sessionId = resolveSessionId2(output);
33280
33951
  const agent = resolveAgentNameFromMessages(output.messages);
33281
33952
  const isInternalChild = typeof sessionId === "string" && sessionId.length > 0 && args.internalChildSessions?.has(sessionId) === true;
33953
+ const compactionOffInputSnapshot = args.compactionOff ? [...output.messages] : null;
33954
+ const restoreCompactionOffInput = () => {
33955
+ if (compactionOffInputSnapshot && output.messages !== compactionOffInputSnapshot) {
33956
+ output.messages.splice(0, output.messages.length, ...compactionOffInputSnapshot);
33957
+ }
33958
+ };
33282
33959
  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
- });
33960
+ try {
33961
+ await args.failClosed.enforce({
33962
+ blockingEnabled: args.failClosedBlockingEnabled !== false,
33963
+ exempt: shouldBypassFailClosedBlock({
33964
+ agent,
33965
+ isInternalChildSession: isInternalChild
33966
+ }),
33967
+ tryReopen: args.tryReopenStorage
33968
+ });
33969
+ } catch (error) {
33970
+ if (args.compactionOff && isFailClosedBlockingError(error)) {
33971
+ log(`[magic-context] compaction-off: fail-closed inert, passing through: ${error.message}`);
33972
+ restoreCompactionOffInput();
33973
+ return output.messages;
33974
+ }
33975
+ throw error;
33976
+ }
33291
33977
  }
33292
33978
  const magicContext = args.getMagicContext ? args.getMagicContext() : args.magicContext;
33293
33979
  const slotAtEntry = sessionId ? getSlot(sessionId) : undefined;
@@ -33304,9 +33990,15 @@ function createMessagesTransformHandler(args) {
33304
33990
  return output.messages;
33305
33991
  } catch (error) {
33306
33992
  if (error instanceof EmergencyFailClosedError || isFailClosedBlockingError(error)) {
33307
- throw error;
33993
+ if (!args.compactionOff)
33994
+ throw error;
33995
+ log(`[magic-context] compaction-off: fail-closed inert, passing through: ${error instanceof Error ? error.message : String(error)}`);
33996
+ restoreCompactionOffInput();
33997
+ return output.messages;
33308
33998
  }
33309
- if (sessionId && slotAtEntry && !entry) {
33999
+ if (args.compactionOff) {
34000
+ restoreCompactionOffInput();
34001
+ } else if (sessionId && slotAtEntry && !entry) {
33310
34002
  dropSlot(sessionId, "lkg_invalidated_reshape");
33311
34003
  sessionLog(sessionId, "lkg_invalidated_reshape");
33312
34004
  } else if (sessionId && entry) {
@@ -33348,6 +34040,7 @@ function createMessagesTransformHandler(args) {
33348
34040
  const isTransient = typeof code === "string" && TRANSIENT_SQLITE_CODES.has(code);
33349
34041
  if (isTransient) {
33350
34042
  log(`[magic-context] transform skipped this pass — ${code} (transient; retrying next pass): ${message}`);
34043
+ restoreCompactionOffInput();
33351
34044
  return output.messages;
33352
34045
  }
33353
34046
  log(`[magic-context] transform FAILED code=${code ?? "none"} name=${name ?? "none"}: ${message}. Continuing with unmodified messages for this pass.`, error);
@@ -33369,6 +34062,7 @@ function createMessagesTransformHandler(args) {
33369
34062
  }
33370
34063
  }
33371
34064
  }
34065
+ restoreCompactionOffInput();
33372
34066
  return output.messages;
33373
34067
  };
33374
34068
  }
@@ -33601,21 +34295,11 @@ async function loadRustSessionStatus(client, sessionId, directory) {
33601
34295
  return;
33602
34296
  }
33603
34297
  }
33604
- function parseTtlString(ttl) {
33605
- const match = ttl.match(/^(\d+)(s|m|h)$/);
33606
- if (!match)
34298
+ function safeParseTtl(ttl) {
34299
+ try {
34300
+ return parseCacheTtl(ttl);
34301
+ } catch {
33607
34302
  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
34303
  }
33620
34304
  }
33621
34305
  function resolveConfigValue(cfg, key, modelKey, defaultValue) {
@@ -33638,7 +34322,7 @@ function resolveConfigValue(cfg, key, modelKey, defaultValue) {
33638
34322
  }
33639
34323
  return defaultValue;
33640
34324
  }
33641
- function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus) {
34325
+ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled = true) {
33642
34326
  try {
33643
34327
  const projectIdentity = resolveProjectIdentity(directory);
33644
34328
  const meta = db.prepare("SELECT * FROM session_meta WHERE session_id = ?").get(sessionId);
@@ -33659,7 +34343,8 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33659
34343
  const cacheTtl = meta ? String(meta.cache_ttl ?? "5m") : "5m";
33660
34344
  const memoryBlockCount = meta ? Number(meta.memory_block_count ?? 0) : 0;
33661
34345
  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;
34346
+ const archivedCompartmentCount = compartmentRow?.count ?? 0;
34347
+ const compartmentCount = typeof moduleStatus?.compartment_count === "number" ? moduleStatus.compartment_count : archivedCompartmentCount;
33663
34348
  let memoryCount = 0;
33664
34349
  if (projectIdentity) {
33665
34350
  const memRow = db.prepare("SELECT COUNT(*) as count FROM memories WHERE project_path = ? AND status = 'active'").get(projectIdentity);
@@ -33754,6 +34439,12 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33754
34439
  executeThreshold = thresholdDetail.percentage;
33755
34440
  executeThresholdClamped = thresholdDetail.clamped === true;
33756
34441
  }
34442
+ const nativeContextLimit = activeProviderID && activeModelID ? resolveContextLimit(activeProviderID, activeModelID, {
34443
+ db,
34444
+ sessionID: sessionId,
34445
+ reservation: "none"
34446
+ }) : contextLimit;
34447
+ const nativeContextUsagePercentage = nativeContextLimit > 0 ? effectiveInputTokens / nativeContextLimit * 100 : undefined;
33757
34448
  const calibration = resolveModelCalibration(activeProviderID, activeModelID);
33758
34449
  const calibrated = calibrateBuckets({
33759
34450
  inputTokens: effectiveInputTokens,
@@ -33773,8 +34464,11 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33773
34464
  usagePercentage: effectiveUsagePercentage,
33774
34465
  inputTokens: effectiveInputTokens,
33775
34466
  contextLimit,
34467
+ native_context_usage_percentage: nativeContextUsagePercentage,
34468
+ compaction_enabled: compactionEnabled,
33776
34469
  systemPromptTokens: calibrated.systemTokens,
33777
34470
  compartmentCount,
34471
+ archivedCompartmentCount,
33778
34472
  memoryCount,
33779
34473
  memoryBlockCount,
33780
34474
  pendingOpsCount,
@@ -33783,6 +34477,7 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33783
34477
  sessionNoteCount,
33784
34478
  readySmartNoteCount,
33785
34479
  cacheTtl,
34480
+ lastTransformError: meta?.last_transform_error ? String(meta.last_transform_error) : null,
33786
34481
  lastDreamerRunAt,
33787
34482
  projectIdentity,
33788
34483
  compartmentTokens: calibrated.compartmentTokens,
@@ -33821,15 +34516,15 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
33821
34516
  throw err;
33822
34517
  }
33823
34518
  }
33824
- function buildSidebarSnapshotRpcResponse(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus) {
34519
+ function buildSidebarSnapshotRpcResponse(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled = true) {
33825
34520
  try {
33826
- return buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus);
34521
+ return buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled);
33827
34522
  } catch {
33828
34523
  return { error: "sidebar snapshot unavailable" };
33829
34524
  }
33830
34525
  }
33831
- function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessionState, injectionBudgetTokens, moduleStatus) {
33832
- const base = buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus);
34526
+ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessionState, injectionBudgetTokens, moduleStatus, compactionEnabled = true) {
34527
+ const base = buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled);
33833
34528
  const detail = {
33834
34529
  ...base,
33835
34530
  tagCounter: 0,
@@ -33846,6 +34541,7 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessi
33846
34541
  cacheTtlMs: 0,
33847
34542
  cacheRemainingMs: 0,
33848
34543
  cacheExpired: false,
34544
+ cacheNeverExpires: false,
33849
34545
  executeThreshold: 65,
33850
34546
  executeThresholdMode: "percentage",
33851
34547
  protectedTagCount: 20,
@@ -33854,9 +34550,17 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessi
33854
34550
  compressionBudget: null,
33855
34551
  compressionUsage: null,
33856
34552
  toastDurationMs: 5000,
33857
- mural: undefined
34553
+ mural: undefined,
34554
+ storage_versions: {
34555
+ context_db_schema_version: null,
34556
+ plugin_supported_version: LATEST_SUPPORTED_VERSION
34557
+ }
33858
34558
  };
33859
34559
  try {
34560
+ detail.storage_versions = {
34561
+ context_db_schema_version: getPersistedSchemaVersion(db),
34562
+ plugin_supported_version: LATEST_SUPPORTED_VERSION
34563
+ };
33860
34564
  const muralConfig = config?.experimental?.mural;
33861
34565
  if (muralConfig?.enabled && base.projectIdentity) {
33862
34566
  const row = getMural(db, base.projectIdentity);
@@ -33915,11 +34619,20 @@ function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessi
33915
34619
  } else if (base.usagePercentage > 0) {
33916
34620
  detail.contextLimit = Math.round(base.inputTokens / (base.usagePercentage / 100));
33917
34621
  }
33918
- detail.cacheTtlMs = parseTtlString(detail.cacheTtl);
34622
+ detail.cacheTtlMs = safeParseTtl(detail.cacheTtl);
34623
+ if (detail.cacheTtlMs === Number.POSITIVE_INFINITY) {
34624
+ detail.cacheNeverExpires = true;
34625
+ detail.cacheTtlMs = -1;
34626
+ }
33919
34627
  if (detail.lastResponseTime > 0) {
33920
34628
  const elapsed = Date.now() - detail.lastResponseTime;
33921
- detail.cacheRemainingMs = Math.max(0, detail.cacheTtlMs - elapsed);
33922
- detail.cacheExpired = detail.cacheRemainingMs === 0;
34629
+ if (detail.cacheNeverExpires) {
34630
+ detail.cacheRemainingMs = -1;
34631
+ detail.cacheExpired = false;
34632
+ } else {
34633
+ detail.cacheRemainingMs = Math.max(0, detail.cacheTtlMs - elapsed);
34634
+ detail.cacheExpired = detail.cacheRemainingMs === 0;
34635
+ }
33923
34636
  }
33924
34637
  try {
33925
34638
  const histTokens = base.compartmentTokens + base.factTokens;
@@ -33957,6 +34670,7 @@ function buildEmbedDetail(db, sessionId, dir, liveSessionState) {
33957
34670
  }
33958
34671
  function registerRpcHandlers(rpcServer, args) {
33959
34672
  const { directory, config, liveSessionState, rustModeModuleClient } = args;
34673
+ const compactionEnabled = isCompactionEnabled(config);
33960
34674
  const rawConfig = config;
33961
34675
  const getNotificationParams = (sessionId) => getLiveNotificationParams(sessionId, liveSessionState.liveModelBySession, liveSessionState.variantBySession, liveSessionState.agentBySession, config.toast_duration_ms);
33962
34676
  const injectionBudgetTokens = config.memory?.injection_budget_tokens;
@@ -33967,7 +34681,7 @@ function registerRpcHandlers(rpcServer, args) {
33967
34681
  if (!db || !sessionId)
33968
34682
  return { error: "unavailable" };
33969
34683
  const moduleStatus = config.transform_mode === "rust" ? await loadRustSessionStatus(rustModeModuleClient, sessionId, dir) : undefined;
33970
- return buildSidebarSnapshotRpcResponse(db, sessionId, dir, liveSessionState, injectionBudgetTokens, rawConfig, moduleStatus);
34684
+ return buildSidebarSnapshotRpcResponse(db, sessionId, dir, liveSessionState, injectionBudgetTokens, rawConfig, moduleStatus, compactionEnabled);
33971
34685
  });
33972
34686
  rpcServer.handle("status-detail", async (params) => {
33973
34687
  const sessionId = String(params.sessionId ?? "");
@@ -33977,7 +34691,7 @@ function registerRpcHandlers(rpcServer, args) {
33977
34691
  if (!db || !sessionId)
33978
34692
  return { error: "unavailable" };
33979
34693
  const moduleStatus = config.transform_mode === "rust" ? await loadRustSessionStatus(rustModeModuleClient, sessionId, dir) : undefined;
33980
- return buildStatusDetail(db, sessionId, dir, modelKey, rawConfig, liveSessionState, injectionBudgetTokens, moduleStatus);
34694
+ return buildStatusDetail(db, sessionId, dir, modelKey, rawConfig, liveSessionState, injectionBudgetTokens, moduleStatus, compactionEnabled);
33981
34695
  });
33982
34696
  rpcServer.handle("embed-detail", async (params) => {
33983
34697
  const sessionId = String(params.sessionId ?? "");
@@ -34005,7 +34719,7 @@ function registerRpcHandlers(rpcServer, args) {
34005
34719
  }
34006
34720
  });
34007
34721
  const buildManagedCtx = async (db) => {
34008
- const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await import("./derive-budgets-e9j09sjr.js");
34722
+ const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await import("./derive-budgets-9crp0cvd.js");
34009
34723
  const { resolveFallbackChain: resolveFallbackChain2 } = await import("./resolve-fallbacks-5n5tvge1.js");
34010
34724
  const { userMemoryCollectionEnabled: userMemoryCollectionEnabled2 } = await import("./task-config-5nx3qfz8.js");
34011
34725
  const DEFAULT_HISTORIAN_TIMEOUT_MS2 = 600000;
@@ -34032,8 +34746,8 @@ function registerRpcHandlers(rpcServer, args) {
34032
34746
  const db = getDb();
34033
34747
  if (!db)
34034
34748
  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");
34749
+ const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-8e82vmvb.js");
34750
+ const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-6njqewzk.js");
34037
34751
  log(`[rpc] recomp requested for session ${sessionId}`);
34038
34752
  const ctx = await buildManagedCtx(db);
34039
34753
  runManagedRecomp2(ctx, sessionId).then((message) => {
@@ -34048,8 +34762,8 @@ function registerRpcHandlers(rpcServer, args) {
34048
34762
  const db = getDb();
34049
34763
  if (!db)
34050
34764
  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");
34765
+ const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-8e82vmvb.js");
34766
+ const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-6njqewzk.js");
34053
34767
  log(`[rpc] session-upgrade requested for session ${sessionId}`);
34054
34768
  const ctx = await buildManagedCtx(db);
34055
34769
  runManagedUpgrade2(ctx, sessionId).then((message) => {
@@ -34065,7 +34779,7 @@ function registerRpcHandlers(rpcServer, args) {
34065
34779
  if (!db)
34066
34780
  return { ok: false, error: "db unavailable" };
34067
34781
  try {
34068
- const { updateSessionMeta: updateSessionMeta2 } = await import("./storage-meta-session-td6bwtky.js");
34782
+ const { updateSessionMeta: updateSessionMeta2 } = await import("./storage-meta-session-xt41zbw4.js");
34069
34783
  updateSessionMeta2(db, sessionId, { upgradeRemindedAt: Date.now() });
34070
34784
  return { ok: true };
34071
34785
  } catch (error) {
@@ -34169,7 +34883,7 @@ Two recovery modes for finer detail:
34169
34883
  var CTX_EXPAND_TOKEN_BUDGET = 15000;
34170
34884
 
34171
34885
  // src/tools/ctx-expand/render.ts
34172
- function isRecord3(value) {
34886
+ function isRecord4(value) {
34173
34887
  return value !== null && typeof value === "object" && !Array.isArray(value);
34174
34888
  }
34175
34889
  function roleLabel(role) {
@@ -34198,15 +34912,15 @@ function keyArg(input) {
34198
34912
  function asToolPart(part) {
34199
34913
  const type = typeof part.type === "string" ? part.type : "";
34200
34914
  if (type === "tool") {
34201
- const state = isRecord3(part.state) ? part.state : null;
34915
+ const state = isRecord4(part.state) ? part.state : null;
34202
34916
  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;
34917
+ const metadata = state && isRecord4(state.metadata) ? state.metadata : null;
34204
34918
  const title = state && typeof state.title === "string" && state.title || metadata && typeof metadata.title === "string" && metadata.title || null;
34205
34919
  return {
34206
34920
  name: typeof part.tool === "string" ? part.tool : "tool",
34207
34921
  callId: typeof part.callID === "string" ? part.callID : "",
34208
34922
  title,
34209
- input: state && isRecord3(state.input) ? state.input : null,
34923
+ input: state && isRecord4(state.input) ? state.input : null,
34210
34924
  output
34211
34925
  };
34212
34926
  }
@@ -34215,7 +34929,7 @@ function asToolPart(part) {
34215
34929
  name: typeof part.name === "string" ? part.name : "tool",
34216
34930
  callId: typeof part.id === "string" ? part.id : "",
34217
34931
  title: null,
34218
- input: isRecord3(part.input) ? part.input : null,
34932
+ input: isRecord4(part.input) ? part.input : null,
34219
34933
  output: null
34220
34934
  };
34221
34935
  }
@@ -34244,7 +34958,7 @@ function reasoningOf(part) {
34244
34958
  return null;
34245
34959
  }
34246
34960
  function renderPartPreview(part) {
34247
- if (!isRecord3(part))
34961
+ if (!isRecord4(part))
34248
34962
  return null;
34249
34963
  const text = textOf(part);
34250
34964
  if (text !== null) {
@@ -34268,7 +34982,7 @@ function renderPartPreview(part) {
34268
34982
  return ` • [${type}]`;
34269
34983
  }
34270
34984
  function renderPartFull(part) {
34271
- if (!isRecord3(part))
34985
+ if (!isRecord4(part))
34272
34986
  return null;
34273
34987
  const text = textOf(part);
34274
34988
  if (text !== null) {
@@ -35774,6 +36488,8 @@ function createToolRegistry(args) {
35774
36488
  if (pluginConfig.enabled !== true) {
35775
36489
  return {};
35776
36490
  }
36491
+ const compactionOff = !isCompactionEnabled(pluginConfig);
36492
+ setCtxReduceRegisteredGlobally(!compactionOff);
35777
36493
  let db;
35778
36494
  try {
35779
36495
  const opened = openDatabase();
@@ -35791,10 +36507,10 @@ function createToolRegistry(args) {
35791
36507
  ensureProjectRegisteredFromOpenCodeDirectory(ctx.directory, db).catch((error) => {
35792
36508
  log(`[magic-context] embedding registration skipped: ${getErrorMessage(error)}`);
35793
36509
  });
35794
- const resolveProjectPath = (directory) => resolveProjectIdentityForSession(directory);
36510
+ const resolveProjectPath = (directory) => resolveProjectIdentityForSession(directory, pluginConfig.allow_home_project);
35795
36511
  const memoryEnabled = pluginConfig.memory?.enabled !== false;
35796
36512
  const allTools = {
35797
- ...createCtxReduceTools({
36513
+ ...compactionOff ? {} : createCtxReduceTools({
35798
36514
  db,
35799
36515
  protectedTags: pluginConfig.protected_tags ?? DEFAULT_PROTECTED_TAGS,
35800
36516
  rustToolBackends
@@ -35859,64 +36575,6 @@ import {
35859
36575
  writeFileSync as writeFileSync5
35860
36576
  } from "node:fs";
35861
36577
  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
36578
  var MAX_BODY_BYTES = 1048576;
35921
36579
  var WS_AUTH_TIMEOUT_MS = 5000;
35922
36580
  var WS_CLOSE_UNAUTHORIZED = 4401;
@@ -35991,10 +36649,15 @@ class MagicContextRpcServer {
35991
36649
  try {
35992
36650
  this.warnIfOtherLiveInstance();
35993
36651
  const dir = dirname5(this.portFilePath);
35994
- mkdirSync3(dir, { recursive: true, mode: 448 });
35995
- try {
35996
- chmodSync(dir, 448);
35997
- } catch {}
36652
+ const enforcePrivatePermissions = shouldEnforcePrivateStoragePermissions();
36653
+ if (enforcePrivatePermissions) {
36654
+ mkdirSync3(dir, { recursive: true, mode: 448 });
36655
+ try {
36656
+ chmodSync(dir, 448);
36657
+ } catch {}
36658
+ } else {
36659
+ mkdirSync3(dir, { recursive: true });
36660
+ }
35998
36661
  const tmpPath = `${this.portFilePath}.tmp`;
35999
36662
  try {
36000
36663
  rmSync3(tmpPath, { force: true });
@@ -36005,11 +36668,13 @@ class MagicContextRpcServer {
36005
36668
  started_at: this.startedAt,
36006
36669
  token: this.token,
36007
36670
  instance_id: this.instanceId
36008
- }), { encoding: "utf-8", mode: 384 });
36671
+ }), enforcePrivatePermissions ? { encoding: "utf-8", mode: 384 } : { encoding: "utf-8" });
36009
36672
  renameSync4(tmpPath, this.portFilePath);
36010
- try {
36011
- chmodSync(this.portFilePath, 384);
36012
- } catch {}
36673
+ if (enforcePrivatePermissions) {
36674
+ try {
36675
+ chmodSync(this.portFilePath, 384);
36676
+ } catch {}
36677
+ }
36013
36678
  log(`[rpc] server listening on 127.0.0.1:${this.port}`);
36014
36679
  } catch (err) {
36015
36680
  log(`[rpc] failed to write port file: ${err}`);
@@ -36186,6 +36851,7 @@ var server = async (ctx) => {
36186
36851
  ...pluginConfig.configWarnings ?? []
36187
36852
  ];
36188
36853
  }
36854
+ setStoragePrivatePermissionEnforcement(pluginConfig.storage.enforce_private_permissions);
36189
36855
  setSqlitePragmaConfig({
36190
36856
  cacheSizeMb: pluginConfig.sqlite.cache_size_mb,
36191
36857
  mmapSizeMb: pluginConfig.sqlite.mmap_size_mb
@@ -36209,7 +36875,7 @@ var server = async (ctx) => {
36209
36875
  `);
36210
36876
  setTimeout(async () => {
36211
36877
  try {
36212
- const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-tghq9gnh.js");
36878
+ const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-6njqewzk.js");
36213
36879
  const clientWithSessions = ctx.client;
36214
36880
  const sessions = await Promise.resolve(clientWithSessions.session?.list?.()).catch(() => null);
36215
36881
  const sessionList = Array.isArray(sessions) ? sessions : sessions?.data;
@@ -36222,7 +36888,9 @@ var server = async (ctx) => {
36222
36888
  }
36223
36889
  let conflictResult = null;
36224
36890
  if (pluginConfig.enabled) {
36225
- conflictResult = detectConflicts(ctx.directory);
36891
+ conflictResult = detectConflicts(ctx.directory, {
36892
+ compactionEnabled: isCompactionEnabled(pluginConfig)
36893
+ });
36226
36894
  if (conflictResult.hasConflict) {
36227
36895
  pluginConfig.enabled = false;
36228
36896
  log(`[magic-context] disabled due to conflicts: ${conflictResult.reasons.join("; ")}`);
@@ -36332,9 +37000,9 @@ var server = async (ctx) => {
36332
37000
  if (pluginConfig.enabled) {
36333
37001
  const dreamerRunnable = isDreamerRunnable(pluginConfig);
36334
37002
  const classifyModuleClient = createDreamTimerModuleClient(rustModeModuleClient);
36335
- const timerProjectIdentity = resolveProjectIdentityForSession(ctx.directory);
37003
+ const timerProjectIdentity = resolveProjectIdentityForSession(ctx.directory, pluginConfig.allow_home_project);
36336
37004
  if (!timerProjectIdentity) {
36337
- log("[magic-context] dream timer skipped: cwd is the user's home directory");
37005
+ log("[magic-context] dream timer skipped: no project identity is bound for this directory");
36338
37006
  } else {
36339
37007
  const timerRegistration = {
36340
37008
  directory: ctx.directory,
@@ -36377,7 +37045,7 @@ var server = async (ctx) => {
36377
37045
  {
36378
37046
  const fence = getSchemaFenceRejection();
36379
37047
  if (fence) {
36380
- import("./conflict-warning-hook-n48c783v.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
37048
+ import("./conflict-warning-hook-fvpfvt0w.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
36381
37049
  }
36382
37050
  }
36383
37051
  if (conflictResult?.hasConflict) {
@@ -36398,7 +37066,7 @@ var server = async (ctx) => {
36398
37066
  } = await import("./announcement-gms2nhya.js");
36399
37067
  if (shouldShowAnnouncement2()) {
36400
37068
  setTimeout(() => {
36401
- import("./conflict-warning-hook-n48c783v.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION2, ANNOUNCEMENT_FEATURES2, ANNOUNCEMENT_FOOTER2, markAnnouncementSeen2)).catch(() => {});
37069
+ import("./conflict-warning-hook-fvpfvt0w.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION2, ANNOUNCEMENT_FEATURES2, ANNOUNCEMENT_FOOTER2, markAnnouncementSeen2)).catch(() => {});
36402
37070
  }, 8000);
36403
37071
  }
36404
37072
  } catch {}
@@ -36439,6 +37107,7 @@ var server = async (ctx) => {
36439
37107
  getMagicContext: () => magicContextRuntime.magicContext,
36440
37108
  failClosed,
36441
37109
  failClosedBlockingEnabled,
37110
+ compactionOff: !isCompactionEnabled(pluginConfig),
36442
37111
  internalChildSessions: liveSessionState.internalChildSessions,
36443
37112
  tryReopenStorage
36444
37113
  }),
@@ -36480,7 +37149,7 @@ var server = async (ctx) => {
36480
37149
  }
36481
37150
  const commandConfig = {
36482
37151
  ...config.command ?? {},
36483
- ...getMagicContextBuiltinCommands(),
37152
+ ...getMagicContextBuiltinCommands(isCompactionEnabled(pluginConfig)),
36484
37153
  ...pluginConfig.command ?? {}
36485
37154
  };
36486
37155
  config.command = commandConfig;