@retaw106/mmc-oc 2.3.0 → 2.5.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 (216) hide show
  1. package/dist/cli.js +12 -1
  2. package/dist/config/schema/magic-context.d.ts +33 -0
  3. package/dist/config/schema/magic-context.d.ts.map +1 -1
  4. package/dist/config-init.js +12 -1
  5. package/dist/{context-wt7g4f8k.js → context-xx09sh1g.js} +1985 -603
  6. package/dist/features/magic-context/memory-maintainer/launcher.d.ts +13 -4
  7. package/dist/features/magic-context/memory-maintainer/launcher.d.ts.map +1 -1
  8. package/dist/features/magic-context/memory-maintainer/manual-commands.d.ts.map +1 -1
  9. package/dist/features/magic-context/memory-maintainer/model-chain.d.ts +47 -0
  10. package/dist/features/magic-context/memory-maintainer/model-chain.d.ts.map +1 -0
  11. package/dist/features/magic-context/memory-maintainer/oc2-adapter.d.ts +17 -4
  12. package/dist/features/magic-context/memory-maintainer/oc2-adapter.d.ts.map +1 -1
  13. package/dist/features/magic-context/memory-maintainer/pipeline.d.ts +6 -0
  14. package/dist/features/magic-context/memory-maintainer/pipeline.d.ts.map +1 -1
  15. package/dist/features/magic-context/message-index-async.d.ts +6 -2
  16. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  17. package/dist/features/magic-context/message-index.d.ts +5 -8
  18. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  19. package/dist/features/magic-context/search.d.ts +5 -1
  20. package/dist/features/magic-context/search.d.ts.map +1 -1
  21. package/dist/features/magic-context/storage-db.d.ts +2 -0
  22. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  23. package/dist/features/magic-context/storage-host-instruction-retention.d.ts +4 -0
  24. package/dist/features/magic-context/storage-host-instruction-retention.d.ts.map +1 -0
  25. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  26. package/dist/features/magic-context/storage-meta-shared.d.ts +2 -2
  27. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  28. package/dist/features/magic-context/storage-session-tables.d.ts +9 -1
  29. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  30. package/dist/features/magic-context/storage-tags.d.ts +4 -0
  31. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  32. package/dist/features/magic-context/transform-decision-log.d.ts +57 -2
  33. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  34. package/dist/hooks/magic-context/__fixtures__/tail-hygiene-refresh.d.ts +34 -0
  35. package/dist/hooks/magic-context/__fixtures__/tail-hygiene-refresh.d.ts.map +1 -0
  36. package/dist/hooks/magic-context/apply-operations.d.ts +3 -1
  37. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  38. package/dist/hooks/magic-context/auto-search-hint.d.ts +3 -0
  39. package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
  40. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  41. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  42. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +2 -2
  43. package/dist/hooks/magic-context/compartment-runner-types.d.ts +2 -2
  44. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  46. package/dist/hooks/magic-context/compartment-runner.d.ts +4 -0
  47. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
  48. package/dist/hooks/magic-context/compartment-trigger-error.d.ts +11 -0
  49. package/dist/hooks/magic-context/compartment-trigger-error.d.ts.map +1 -0
  50. package/dist/hooks/magic-context/compartment-trigger.d.ts +1 -1
  51. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  52. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +1 -0
  53. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  54. package/dist/hooks/magic-context/degraded-pass-refusal.d.ts +2 -0
  55. package/dist/hooks/magic-context/degraded-pass-refusal.d.ts.map +1 -1
  56. package/dist/hooks/magic-context/diagnostic-log-state.d.ts +4 -0
  57. package/dist/hooks/magic-context/diagnostic-log-state.d.ts.map +1 -0
  58. package/dist/hooks/magic-context/edit-marker.d.ts +2 -0
  59. package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
  60. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  61. package/dist/hooks/magic-context/file-token-coverage.d.ts +11 -0
  62. package/dist/hooks/magic-context/file-token-coverage.d.ts.map +1 -0
  63. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +2 -0
  64. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  65. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  66. package/dist/hooks/magic-context/host-served-rows.d.ts +10 -0
  67. package/dist/hooks/magic-context/host-served-rows.d.ts.map +1 -1
  68. package/dist/hooks/magic-context/inject-compartments.d.ts +1 -1
  69. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  70. package/dist/hooks/magic-context/lkg-recovery-fence.d.ts.map +1 -1
  71. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  72. package/dist/hooks/magic-context/lkg-slot.d.ts +1 -1
  73. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  74. package/dist/hooks/magic-context/nudge-evaluation-log.d.ts +3 -0
  75. package/dist/hooks/magic-context/nudge-evaluation-log.d.ts.map +1 -0
  76. package/dist/hooks/magic-context/pass-outcome.d.ts +2 -0
  77. package/dist/hooks/magic-context/pass-outcome.d.ts.map +1 -1
  78. package/dist/hooks/magic-context/pending-drop-eligibility.d.ts +14 -0
  79. package/dist/hooks/magic-context/pending-drop-eligibility.d.ts.map +1 -0
  80. package/dist/hooks/magic-context/pending-materialization.d.ts +2 -0
  81. package/dist/hooks/magic-context/pending-materialization.d.ts.map +1 -1
  82. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +2 -0
  83. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  84. package/dist/hooks/magic-context/provider-visible-parts.d.ts +10 -4
  85. package/dist/hooks/magic-context/provider-visible-parts.d.ts.map +1 -1
  86. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  87. package/dist/hooks/magic-context/recomp-orchestrator.d.ts +3 -3
  88. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  89. package/dist/hooks/magic-context/render-options.d.ts +19 -0
  90. package/dist/hooks/magic-context/render-options.d.ts.map +1 -0
  91. package/dist/hooks/magic-context/supersession-reclaim.d.ts +5 -3
  92. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
  93. package/dist/hooks/magic-context/system-date-refresh.d.ts +3 -2
  94. package/dist/hooks/magic-context/system-date-refresh.d.ts.map +1 -1
  95. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  96. package/dist/hooks/magic-context/system-prompt-sticky-date.d.ts +4 -0
  97. package/dist/hooks/magic-context/system-prompt-sticky-date.d.ts.map +1 -0
  98. package/dist/hooks/magic-context/tag-content-primitives.d.ts +1 -1
  99. package/dist/hooks/magic-context/tag-content-primitives.d.ts.map +1 -1
  100. package/dist/hooks/magic-context/tag-messages.d.ts +15 -2
  101. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  102. package/dist/hooks/magic-context/tail-hygiene-output-count.d.ts +18 -0
  103. package/dist/hooks/magic-context/tail-hygiene-output-count.d.ts.map +1 -0
  104. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +8 -4
  105. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  106. package/dist/hooks/magic-context/text-complete.d.ts +1 -1
  107. package/dist/hooks/magic-context/text-complete.d.ts.map +1 -1
  108. package/dist/hooks/magic-context/todo-view.d.ts +2 -2
  109. package/dist/hooks/magic-context/tool-drop-target.d.ts +3 -2
  110. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  111. package/dist/hooks/magic-context/tool-reclaim.d.ts +5 -2
  112. package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
  113. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +1 -0
  114. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  115. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +8 -0
  116. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  117. package/dist/hooks/magic-context/transform-stage-logger.d.ts +3 -0
  118. package/dist/hooks/magic-context/transform-stage-logger.d.ts.map +1 -1
  119. package/dist/hooks/magic-context/transform.d.ts +4 -9
  120. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  121. package/dist/hooks/magic-context/unresolved-history-boundary.d.ts +5 -1
  122. package/dist/hooks/magic-context/unresolved-history-boundary.d.ts.map +1 -1
  123. package/dist/{index-kw21z5pe.js → index-0d40b4q8.js} +17119 -16569
  124. package/dist/{index-z2w1eq3y.js → index-1vxffj5j.js} +558 -211
  125. package/dist/{index-z2g20msd.js → index-azbmnekv.js} +4 -4
  126. package/dist/{index-18yrysyj.js → index-bpjjcdy9.js} +1 -1
  127. package/dist/{index-a5mw0xp3.js → index-k25thxq7.js} +1 -1
  128. package/dist/{index-3gj1ak4c.js → index-mjf0p7yq.js} +1 -1
  129. package/dist/{index-czba8tw3.js → index-pte3cfs9.js} +226 -14
  130. package/dist/index.js +2 -2
  131. package/dist/{message-time-backfill-sykevdax.js → message-time-backfill-g9py24yt.js} +1 -1
  132. package/dist/model-resolution-cvyrrcjw.js +8 -0
  133. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  134. package/dist/plugin/subagent-tool-policy.d.ts +4 -0
  135. package/dist/plugin/subagent-tool-policy.d.ts.map +1 -1
  136. package/dist/{read-session-chunk-863d6c06.js → read-session-chunk-eb3fy45y.js} +3 -3
  137. package/dist/{recomp-orchestrator-wrjy3qym.js → recomp-orchestrator-mmpy5cb7.js} +6 -6
  138. package/dist/{send-session-notification-cz6ev088.js → send-session-notification-zpqs213d.js} +3 -3
  139. package/dist/shared/model-suggestion-retry.d.ts +23 -0
  140. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  141. package/dist/shared/prompt-surface-runtime.d.ts +5 -0
  142. package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
  143. package/dist/shared/reclaim-distance.d.ts +33 -0
  144. package/dist/shared/reclaim-distance.d.ts.map +1 -0
  145. package/dist/shared/rpc-discovery-cleanup.d.ts +3 -0
  146. package/dist/shared/rpc-discovery-cleanup.d.ts.map +1 -0
  147. package/dist/shared/rpc-server.d.ts +2 -0
  148. package/dist/shared/rpc-server.d.ts.map +1 -1
  149. package/dist/shared/search-text.d.ts +8 -0
  150. package/dist/shared/search-text.d.ts.map +1 -0
  151. package/dist/shared/sqlite.d.ts +8 -1
  152. package/dist/shared/sqlite.d.ts.map +1 -1
  153. package/dist/shared/stable-json.d.ts +7 -0
  154. package/dist/shared/stable-json.d.ts.map +1 -1
  155. package/dist/shared/storage-file-mutex.d.ts.map +1 -1
  156. package/dist/shared/system-directive.d.ts +2 -0
  157. package/dist/shared/system-directive.d.ts.map +1 -1
  158. package/dist/shared/tail-hygiene-json.d.ts +22 -0
  159. package/dist/shared/tail-hygiene-json.d.ts.map +1 -0
  160. package/dist/shared/user-facing-codes.d.ts +2 -2
  161. package/dist/v2/fold/native-replay.d.ts +11 -2
  162. package/dist/v2/fold/native-replay.d.ts.map +1 -1
  163. package/dist/v2/fold/policy.d.ts.map +1 -1
  164. package/dist/v2/fold/restore.d.ts.map +1 -1
  165. package/dist/v2/hidden-completion.d.ts +20 -1
  166. package/dist/v2/hidden-completion.d.ts.map +1 -1
  167. package/dist/v2/hooks/context.d.ts +1 -1
  168. package/dist/v2/hooks/context.d.ts.map +1 -1
  169. package/dist/v2/hooks/generate.d.ts +36 -1
  170. package/dist/v2/hooks/generate.d.ts.map +1 -1
  171. package/dist/v2/hooks/hidden-child.d.ts +22 -1
  172. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  173. package/dist/v2/hooks/lkg-system.d.ts +35 -4
  174. package/dist/v2/hooks/lkg-system.d.ts.map +1 -1
  175. package/dist/v2/hooks/payload.d.ts +10 -1
  176. package/dist/v2/hooks/payload.d.ts.map +1 -1
  177. package/dist/v2/hooks/store.d.ts +2 -0
  178. package/dist/v2/hooks/store.d.ts.map +1 -1
  179. package/dist/v2/hooks/types.d.ts +12 -0
  180. package/dist/v2/hooks/types.d.ts.map +1 -1
  181. package/dist/v2/server.js +16272 -13742
  182. package/dist/v2/store-reader.d.ts +38 -1
  183. package/dist/v2/store-reader.d.ts.map +1 -1
  184. package/dist/web/main.js +262 -17
  185. package/dist/{wrapup-orchestrator-bmybc5p5.js → wrapup-orchestrator-jq589pgr.js} +6 -6
  186. package/package.json +1 -1
  187. package/src/config/latch-permanence-guard.test.ts +8 -0
  188. package/src/config/project-security.test.ts +17 -0
  189. package/src/config/schema/magic-context.test.ts +50 -0
  190. package/src/config/schema/magic-context.ts +34 -1
  191. package/src/shared/model-suggestion-retry.test.ts +52 -0
  192. package/src/shared/model-suggestion-retry.ts +13 -4
  193. package/src/shared/prompt-surface-runtime.ts +12 -0
  194. package/src/shared/reclaim-distance.test.ts +111 -0
  195. package/src/shared/reclaim-distance.ts +91 -0
  196. package/src/shared/root-async-context.probe.mjs +36 -0
  197. package/src/shared/root-async-context.test.ts +49 -0
  198. package/src/shared/rpc-discovery-cleanup.test.ts +125 -0
  199. package/src/shared/rpc-discovery-cleanup.ts +57 -0
  200. package/src/shared/rpc-server.ts +36 -13
  201. package/src/shared/search-text.test.ts +30 -0
  202. package/src/shared/search-text.ts +62 -0
  203. package/src/shared/sqlite-busy-budget-review.test.ts +291 -0
  204. package/src/shared/sqlite-foreground-wait.test.ts +237 -1
  205. package/src/shared/sqlite-turn-deadline.test.ts +286 -0
  206. package/src/shared/sqlite.ts +292 -23
  207. package/src/shared/stable-json.ts +56 -14
  208. package/src/shared/storage-file-mutex.test.ts +51 -2
  209. package/src/shared/storage-file-mutex.ts +11 -1
  210. package/src/shared/system-directive.test.ts +37 -0
  211. package/src/shared/system-directive.ts +19 -1
  212. package/src/shared/tag-transcript.ts +16 -4
  213. package/src/shared/tail-hygiene-json.test.ts +117 -0
  214. package/src/shared/tail-hygiene-json.ts +217 -0
  215. package/src/shared/user-facing-codes.ts +2 -2
  216. package/dist/model-resolution-wazv26n0.js +0 -6
@@ -34,6 +34,19 @@ import {
34
34
  resolveProjectIdentityForSession,
35
35
  normalizeStoredProjectPath,
36
36
  storedPathBelongsToIdentity,
37
+ parseProviderModel,
38
+ modelBodyField,
39
+ toModelEntry,
40
+ HiddenCompletionRefusal,
41
+ HIDDEN_HISTORIAN_AGENT,
42
+ resolveHistorianStepCap,
43
+ HIDDEN_RUN_DISPOSED_REASON,
44
+ noteChildOfDisposedInstance,
45
+ hiddenChildPermissions,
46
+ registerHiddenChildAgents,
47
+ HiddenAgentStepLimit,
48
+ HiddenChildHook,
49
+ isNonRetryable,
37
50
  V2_MEMORY_CATEGORIES,
38
51
  CATEGORY_PRIORITY,
39
52
  computeNormalizedHash,
@@ -58,7 +71,6 @@ import {
58
71
  searchMemoriesFTSUnion,
59
72
  clearMemoryVerifications,
60
73
  queueMemoryMutation,
61
- scheduleAfterBootQuiet,
62
74
  BoundedSessionMap,
63
75
  registerOwnRpcServerInstance,
64
76
  rpcPortDir,
@@ -68,6 +80,12 @@ import {
68
80
  dirtyLkgRecoveryRevision,
69
81
  ownsLkgDirtyFence,
70
82
  invalidateCleanLkgRecoveryFence,
83
+ cleanSearchText,
84
+ keywordRelevance,
85
+ matchedSearchSnippet,
86
+ gaDatabasePath,
87
+ RAW_MESSAGE_TYPES,
88
+ V2StoreReaderPool,
71
89
  getLastIndexedOrdinal,
72
90
  getIndexedMessageIdAtOrdinal,
73
91
  getIndexedMessageCorpusSize,
@@ -75,6 +93,8 @@ import {
75
93
  isMessageIndexReconciledThrough,
76
94
  clearIndexedMessages,
77
95
  indexMessagesAfterOrdinal,
96
+ sweepOrphanedOpenCodeMessageIndexesCooperatively,
97
+ scheduleAfterBootQuiet,
78
98
  acquireCompartmentLease,
79
99
  releaseCompartmentLeaseBestEffort,
80
100
  isCompartmentLeaseHeld,
@@ -82,6 +102,7 @@ import {
82
102
  getMaxM0MutationId,
83
103
  ensureSessionMetaRow,
84
104
  clearCachedM0M1,
105
+ clearCachedM0,
85
106
  getCompartments,
86
107
  getLastCompartmentEndMessage,
87
108
  getLastCompartmentEndMessageId,
@@ -97,6 +118,7 @@ import {
97
118
  HYGIENE_PROVIDER_UNITS_VERSION,
98
119
  sessionDecisionCalibration,
99
120
  transitionSessionHygieneUnits,
121
+ readEpochFloorSnapshot,
100
122
  getProtectionWindowForSession,
101
123
  ReplayDocumentError,
102
124
  readReplayEnvelope,
@@ -173,9 +195,6 @@ import {
173
195
  getUnpublishedAutoSearchNoHint,
174
196
  forgetUnpublishedAutoSearchNoHint,
175
197
  registerAutoSearchWork,
176
- gaDatabasePath,
177
- RAW_MESSAGE_TYPES,
178
- V2StoreReaderPool,
179
198
  getOrCreateSessionMeta,
180
199
  updateSessionMeta,
181
200
  advanceToolReclaimWatermark,
@@ -183,6 +202,7 @@ import {
183
202
  clearSession,
184
203
  requestPendingMaterialization,
185
204
  pendingMaterializationOrigin,
205
+ hasPendingMaterializationOrigin,
186
206
  clearPendingMaterialization,
187
207
  recordSystemPromptForRequest,
188
208
  recordHeldHeadForRequest,
@@ -242,18 +262,10 @@ import {
242
262
  sourceNameForMemory,
243
263
  rebaseSessionCoordinatesAsync,
244
264
  renderUserFacingFailure,
265
+ userFacingFailureCode,
245
266
  renderCapabilityRefusal,
246
- HiddenCompletionRefusal,
247
- HIDDEN_HISTORIAN_AGENT,
248
- resolveHistorianStepCap,
249
- hiddenChildPermissions,
250
- registerHiddenChildAgents,
251
- HiddenAgentStepLimit,
252
- HiddenChildHook,
253
- parseProviderModel,
254
- toModelEntry,
255
267
  ACTIVE_TOOL_IDS,
256
- promptSurfaceHashMaterial,
268
+ systemPromptFingerprint,
257
269
  createPromptSurfaceRuntime,
258
270
  createPromptSurfaceGuidanceEpochCache,
259
271
  getOpenCodeDbPath,
@@ -285,6 +297,7 @@ import {
285
297
  prepareCachedM0M1Replay,
286
298
  hasCompleteCachedM0M1,
287
299
  injectM0M1,
300
+ omitIncompleteFileTokenTotals,
288
301
  RECOVERY_NO_HEAD_LIMIT,
289
302
  deriveProtectedTailTokenTarget,
290
303
  selectPerRunCap,
@@ -294,7 +307,7 @@ import {
294
307
  recordHighPressureNoEligibleHead,
295
308
  getActiveCompartmentRun,
296
309
  startCompartmentAgent
297
- } from "./index-kw21z5pe.js";
310
+ } from "./index-0d40b4q8.js";
298
311
  import {
299
312
  getHarness,
300
313
  getDataDir,
@@ -326,6 +339,16 @@ import {
326
339
  import {
327
340
  normalizeProtectedToolName,
328
341
  mergeProtectedTools,
342
+ detectLatestTurnThinkingMismatch,
343
+ isPrefixBoundThinkingModel,
344
+ detectOverflow,
345
+ stripWellFormedLeadingTagPrefix,
346
+ stripPersistedAssistantText,
347
+ byteSize,
348
+ stripTagPrefix,
349
+ peelLeadingMcTagNotation,
350
+ prependTag,
351
+ isThinkingPart,
329
352
  isRecord,
330
353
  protectedToolTagNumbers,
331
354
  protectedToolTokenCount,
@@ -335,13 +358,7 @@ import {
335
358
  preloadTokenizer,
336
359
  estimateTokens,
337
360
  estimateFixedPromptTokens,
338
- stripWellFormedLeadingTagPrefix,
339
- stripPersistedAssistantText,
340
- byteSize,
341
- stripTagPrefix,
342
- peelLeadingMcTagNotation,
343
- prependTag,
344
- isThinkingPart,
361
+ currentReclaimableToolOutputCount,
345
362
  contentTagOwnerMessageId,
346
363
  estimateImageTokensFromDataUrl,
347
364
  estimateToolAttachmentImageTokens,
@@ -374,6 +391,7 @@ import {
374
391
  getPendingOpsCount,
375
392
  clearPendingOps,
376
393
  removePendingOp,
394
+ tagRevisionKey,
377
395
  tagIdentityRevisionKey,
378
396
  getRecentTagOwnerMessageIds,
379
397
  AGE_RECLAIM_MIN_TOKENS,
@@ -390,6 +408,7 @@ import {
390
408
  backfillTagTokenCounts,
391
409
  insertTag,
392
410
  updateTagStatus,
411
+ markTagDropped,
393
412
  markWhitespaceAssistantTagInert,
394
413
  getInertWhitespaceAssistantTags,
395
414
  getInertWhitespaceAssistantTagsByNumbers,
@@ -416,12 +435,16 @@ import {
416
435
  pickNearestPriorOwner,
417
436
  expandToolPart,
418
437
  markHostUnservedRow,
438
+ isHostRenderedSystemMessage,
439
+ markCoveredInstructionRow,
440
+ isCoveredInstructionRow,
441
+ takeCoveredInstructionRows,
442
+ cloneKeepingCoveredInstructionMarks,
419
443
  estimateTrueRawMessageTokens,
420
444
  stripSystemInjection,
421
445
  isTextPart,
422
446
  isToolPartWithOutput,
423
447
  isFilePart,
424
- buildFileSourceContent,
425
448
  toolPartHasUserAnswer,
426
449
  recordToolParameters,
427
450
  createDroppedInputGuard,
@@ -431,13 +454,11 @@ import {
431
454
  recordToolDefinition,
432
455
  getMeasuredToolDefinitionTokens,
433
456
  describeFinalWireTail,
457
+ estimatePartImageTokens,
434
458
  estimateMessageTokens,
435
459
  wireContentBytes,
436
460
  createFinalWireUsageTracker,
437
461
  estimateFinalWireInputTokens,
438
- detectLatestTurnThinkingMismatch,
439
- isPrefixBoundThinkingModel,
440
- detectOverflow,
441
462
  modelAcceptsEmptyContent,
442
463
  isAnthropicFamilyRoute,
443
464
  neutralizeDroppedReasoningPart,
@@ -463,10 +484,16 @@ import {
463
484
  primeTailRawMessageCache2,
464
485
  primeInMemoryTailRawMessageCache2,
465
486
  readRawSessionMessageIdOrdinalsForRange2,
487
+ hasRawSessionMessageById2,
466
488
  readRawSessionMessageById2,
467
489
  readSessionChunk2
468
- } from "./index-z2w1eq3y.js";
490
+ } from "./index-1vxffj5j.js";
491
+ import {
492
+ normalizeModelEntry2,
493
+ resolveHistorianModel2
494
+ } from "./index-azbmnekv.js";
469
495
  import {
496
+ Database,
470
497
  getSqliteMemoryStats,
471
498
  withSqliteBackgroundWriter,
472
499
  withSqliteTransformPass,
@@ -476,7 +503,7 @@ import {
476
503
  withAsyncPrivilegedWriter,
477
504
  indexCoordinationInput,
478
505
  withIndexChunk
479
- } from "./index-czba8tw3.js";
506
+ } from "./index-pte3cfs9.js";
480
507
  import {
481
508
  canonicalModelIdentity,
482
509
  piModelRefToCanonical,
@@ -493,7 +520,7 @@ import {
493
520
  latestRealUserTurnIdFromOpenCodeDb,
494
521
  getMessageTimesFromOpenCodeDb,
495
522
  findLastAssistantModelFromOpenCodeDb
496
- } from "./index-18yrysyj.js";
523
+ } from "./index-bpjjcdy9.js";
497
524
  import {
498
525
  registerNotificationSink2,
499
526
  pushNotification2,
@@ -506,14 +533,14 @@ import {
506
533
  getErrorMessage,
507
534
  flushIgnoredMessages2,
508
535
  sendStatusNotification2
509
- } from "./index-a5mw0xp3.js";
510
- import {
511
- resolveHistorianModel2
512
- } from "./index-z2g20msd.js";
536
+ } from "./index-k25thxq7.js";
513
537
  import {
514
538
  logSlowWriteTransaction
515
539
  } from "./index-yjv8dpht.js";
516
540
 
541
+ // src/v2/hooks/context.ts
542
+ import { setTimeout as delay } from "node:timers/promises";
543
+
517
544
  // src/config/index.ts
518
545
  import { existsSync as existsSync4 } from "node:fs";
519
546
 
@@ -3159,6 +3186,40 @@ function currentPluginConfigReader(directory) {
3159
3186
  return pluginReaders.get(directory);
3160
3187
  }
3161
3188
 
3189
+ // src/features/magic-context/memory-maintainer/model-chain.ts
3190
+ var MAINTENANCE_MODEL_UNCONFIGURED_MESSAGE = "memory maintenance has no primary model configured — set maintenance.model or historian.model in the user-level mmc config (fallback_models alone does not enable maintenance; the session model is never inherited)";
3191
+ function inheritMaintenanceModelConfig(config) {
3192
+ const { maintenance, historian } = config;
3193
+ if (maintenance.model !== undefined || historian?.model === undefined)
3194
+ return maintenance;
3195
+ const entry = typeof historian.model === "string" ? { model: historian.model } : historian.model;
3196
+ return {
3197
+ ...maintenance,
3198
+ model: {
3199
+ ...entry,
3200
+ variant: entry.variant ?? historian.variant,
3201
+ thinking_level: entry.thinking_level ?? historian.thinking_level
3202
+ },
3203
+ fallback_models: maintenance.fallback_models ?? historian.fallback_models
3204
+ };
3205
+ }
3206
+ function resolveMaintenanceModelChain(config, harness) {
3207
+ const primary = normalizeModelEntry2(config.model, harness);
3208
+ if (!primary)
3209
+ return;
3210
+ const fallbacks = [];
3211
+ for (const entry of config.fallback_models ?? []) {
3212
+ const resolved = normalizeModelEntry2(entry, harness);
3213
+ if (resolved)
3214
+ fallbacks.push(resolved);
3215
+ }
3216
+ return { primary, fallbacks };
3217
+ }
3218
+ function hasMaintenancePrimary(config) {
3219
+ const primary = toModelEntry(config.model);
3220
+ return primary !== undefined && primary.model.trim().length > 0;
3221
+ }
3222
+
3162
3223
  // src/features/magic-context/memory-maintainer/dream-state.ts
3163
3224
  var getDreamStateStatements = new WeakMap;
3164
3225
  var setDreamStateStatements = new WeakMap;
@@ -4500,6 +4561,7 @@ async function executeGuardedRun(opts, holderId, leaseKey, acquisition) {
4500
4561
  pending,
4501
4562
  fullPool: roundState.snapshot,
4502
4563
  shouldContinue: () => meter.shouldContinue(),
4564
+ remainingWallMs: () => Math.max(0, config.budgets.wallMs - meter.getState().spent.wallMs),
4503
4565
  recordUsage: (delta) => meter.recordUsage(delta),
4504
4566
  recordToolStep: () => meter.recordToolStep(),
4505
4567
  refuseToolStep: () => meter.refuseToolStep()
@@ -4798,49 +4860,86 @@ function transcriptFromCompletion(completion, createdAt) {
4798
4860
  }
4799
4861
  ];
4800
4862
  }
4801
- async function runOc2MaintenancePhase(ctx, phase, deps, stageAManifest = "") {
4802
- if (!deps.executor)
4803
- return emptyPhaseResult();
4804
- const agentId = phase === "A" ? MEMORY_MAINTAINER_A_AGENT : MEMORY_MAINTAINER_B_AGENT;
4805
- const system = phase === "A" ? MEMORY_MAINTAINER_A_SYSTEM_PROMPT : MEMORY_MAINTAINER_B_SYSTEM_PROMPT;
4806
- const basePrompt = buildPhasePrompt(ctx, phase, deps, stageAManifest);
4807
- let manifestText = "";
4808
- let messages;
4809
- for (let round = 0;round < 2; round += 1) {
4810
- const decision = ctx.shouldContinue();
4811
- if (decision === "stop")
4812
- break;
4813
- const prompt = decision === "finalize" ? `${MEMORY_MAINTAINER_FINALIZE_INSTRUCTION}
4814
-
4815
- ${basePrompt}` : basePrompt;
4863
+ async function attemptPhaseModelChain(ctx, phase, executor, deps, agentId, system, prompt) {
4864
+ const chain = [deps.modelChain.primary, ...deps.modelChain.fallbacks];
4865
+ let lastError;
4866
+ for (let index = 0;index < chain.length; index += 1) {
4867
+ const entry = toModelEntry(chain[index]);
4868
+ if (!entry || entry.model.trim().length === 0)
4869
+ continue;
4870
+ if (!parseProviderModel(entry.model)) {
4871
+ if (index === 0) {
4872
+ throw new Error(`memory maintenance: primary model "${entry.model}" is not in provider/model form — the hidden executor cannot use it and no model substitution is allowed`);
4873
+ }
4874
+ log(`[magic-context][maintenance] phase ${phase}: dropping invalid fallback spec: ${entry.model}`);
4875
+ continue;
4876
+ }
4877
+ if (index > 0) {
4878
+ if (ctx.shouldContinue() !== "continue")
4879
+ throw lastError;
4880
+ log(`[magic-context][maintenance] phase ${phase}: switching to fallback model ${entry.model} (attempt ${index + 1}/${chain.length})`);
4881
+ }
4816
4882
  const identity = {
4817
4883
  parentSessionId: deps.parentSessionId(),
4818
4884
  kind: "memory-maintenance",
4819
4885
  agent: agentId,
4820
4886
  system,
4821
- timeoutMs: deps.budget.wallMs,
4887
+ model: entry,
4888
+ timeoutMs: Math.max(1000, Math.min(deps.budget.wallMs, ctx.remainingWallMs())),
4822
4889
  title: `magic-context-maintainer-${phase.toLowerCase()}`,
4823
4890
  directory: deps.directory() ?? ""
4824
4891
  };
4825
- const handle = await deps.executor.open(identity);
4826
- let completion;
4892
+ const handle = await executor.open(identity);
4827
4893
  let promptSettled = false;
4828
4894
  try {
4829
4895
  const request = {
4830
4896
  path: { id: handle.id },
4831
- body: { parts: [{ type: "text", text: prompt }] }
4897
+ body: {
4898
+ parts: [{ type: "text", text: prompt }],
4899
+ ...modelBodyField(entry)
4900
+ }
4832
4901
  };
4833
- await deps.executor.attempt(handle, request);
4834
- completion = await deps.executor.collect(handle, 50);
4902
+ try {
4903
+ await executor.attempt(handle, request);
4904
+ } catch (error) {
4905
+ lastError = error;
4906
+ if (index >= chain.length - 1 || isNonRetryable(error))
4907
+ throw error;
4908
+ log(`[magic-context][maintenance] phase ${phase}: model ${entry.model} failed: ${error instanceof Error ? error.message : String(error)}; trying next fallback`);
4909
+ continue;
4910
+ }
4911
+ const completion = await executor.collect(handle, 50);
4835
4912
  promptSettled = true;
4913
+ return completion;
4836
4914
  } finally {
4837
- await deps.executor.close(handle, {
4915
+ await executor.close(handle, {
4838
4916
  promptSettled,
4839
4917
  privacySensitive: false,
4840
4918
  context: "memory-maintenance",
4841
4919
  log: (message) => log(`[magic-context][maintenance] ${message}`)
4842
4920
  });
4843
4921
  }
4922
+ }
4923
+ if (lastError !== undefined)
4924
+ throw lastError;
4925
+ return;
4926
+ }
4927
+ async function runOc2MaintenancePhase(ctx, phase, deps, stageAManifest = "") {
4928
+ if (!deps.executor)
4929
+ return emptyPhaseResult();
4930
+ const agentId = phase === "A" ? MEMORY_MAINTAINER_A_AGENT : MEMORY_MAINTAINER_B_AGENT;
4931
+ const system = phase === "A" ? MEMORY_MAINTAINER_A_SYSTEM_PROMPT : MEMORY_MAINTAINER_B_SYSTEM_PROMPT;
4932
+ const basePrompt = buildPhasePrompt(ctx, phase, deps, stageAManifest);
4933
+ let manifestText = "";
4934
+ let messages;
4935
+ for (let round = 0;round < 2; round += 1) {
4936
+ const decision = ctx.shouldContinue();
4937
+ if (decision === "stop")
4938
+ break;
4939
+ const prompt = decision === "finalize" ? `${MEMORY_MAINTAINER_FINALIZE_INSTRUCTION}
4940
+
4941
+ ${basePrompt}` : basePrompt;
4942
+ const completion = await attemptPhaseModelChain(ctx, phase, deps.executor, deps, agentId, system, prompt);
4844
4943
  if (completion) {
4845
4944
  const inputTotal = completion.usage.input + completion.usage.cacheRead + completion.usage.cacheWrite;
4846
4945
  ctx.recordUsage({ inputTokens: inputTotal, outputTokens: completion.usage.output });
@@ -4898,9 +4997,18 @@ function createOc2MaintenanceRunFactory(options) {
4898
4997
  if (!options.executor) {
4899
4998
  throw new Error("memory maintenance: no hidden completion executor wired");
4900
4999
  }
5000
+ const chain = resolveMaintenanceModelChain(options.config(), "opencode");
5001
+ if (!chain) {
5002
+ throw new Error(MAINTENANCE_MODEL_UNCONFIGURED_MESSAGE);
5003
+ }
5004
+ const primarySpec = toModelEntry(chain.primary)?.model ?? "";
5005
+ if (!parseProviderModel(primarySpec)) {
5006
+ throw new Error(`memory maintenance: primary model "${primarySpec}" is not in provider/model form — the hidden executor cannot use it and no model substitution is allowed`);
5007
+ }
4901
5008
  const cfg = options.config();
4902
5009
  const phaseDeps = {
4903
5010
  executor: options.executor,
5011
+ modelChain: chain,
4904
5012
  budget: cfg.budgets,
4905
5013
  parentSessionId: () => signals.parentSessionId,
4906
5014
  directory: () => signals.directory,
@@ -4947,6 +5055,8 @@ var RECONCILIATION_BATCH_SIZE = 100;
4947
5055
 
4948
5056
  class MagicContextMessageIndexHeapHolder {
4949
5057
  reconciledSessions = new Set;
5058
+ reconciledSnapshots = new Map;
5059
+ stalledSessions = new Set;
4950
5060
  reconciliationScheduledSessions = new Set;
4951
5061
  clearAndReindexScheduledSessions = new Map;
4952
5062
  sessionLocks = new Map;
@@ -5029,23 +5139,32 @@ function detectIndexMisalignment(db, sessionId, cursor, finalWatermark, readMess
5029
5139
  return null;
5030
5140
  return `indexed id '${indexedId}' at ordinal ${cursor} but projection has '${projectedId}'`;
5031
5141
  }
5142
+ function logReconciliationStall(sessionId, reason) {
5143
+ if (heapHolder.stalledSessions.has(sessionId))
5144
+ return;
5145
+ heapHolder.stalledSessions.add(sessionId);
5146
+ sessionLog(sessionId, `message FTS reconciliation stalled: ${reason}; will retry`);
5147
+ }
5032
5148
  async function reconcileSessionIndex(db, sessionId, readMessages) {
5033
5149
  if (!await sourceReady(readMessages, sessionId))
5034
5150
  return false;
5035
5151
  await runWithSessionLock(sessionId, async () => {
5036
- if (heapHolder.reconciledSessions.has(sessionId))
5152
+ if (!readMessages.getRevision && heapHolder.reconciledSessions.has(sessionId))
5037
5153
  return;
5038
5154
  let fallbackSnapshot = null;
5039
5155
  try {
5040
5156
  const fullReader = typeof readMessages === "function" ? readMessages : null;
5041
- const finalWatermark = readMessages.getCount ? readMessages.getCount(sessionId) : (fallbackSnapshot = fullReader?.(sessionId) ?? []).length;
5157
+ const revision = readMessages.getRevision?.(sessionId);
5158
+ const previous = heapHolder.reconciledSnapshots.get(sessionId);
5159
+ const finalWatermark = previous && revision === previous.revision ? previous.count : revision !== undefined && readMessages.getCountAfterRevision ? previous && revision > previous.revision ? previous.count + readMessages.getCountAfterRevision(sessionId, previous.revision, revision) : readMessages.getCountAfterRevision(sessionId, -1, revision) : readMessages.getCount ? readMessages.getCount(sessionId) : (fallbackSnapshot = fullReader?.(sessionId) ?? []).length;
5042
5160
  let cursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
5043
- let after;
5044
- const misalignment = detectIndexMisalignment(db, sessionId, cursor, finalWatermark, readMessages, fallbackSnapshot);
5161
+ let after = cursor === previous?.count ? previous.after : undefined;
5162
+ const misalignment = revision !== undefined && previous && revision >= previous.revision ? null : detectIndexMisalignment(db, sessionId, cursor, finalWatermark, readMessages, fallbackSnapshot);
5045
5163
  if (misalignment !== null) {
5046
5164
  sessionLog(sessionId, `message FTS index misaligned (${misalignment}); clearing for full re-index`);
5047
5165
  withSqliteBackgroundWriter(() => clearIndexedMessages(db, sessionId));
5048
5166
  cursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
5167
+ after = undefined;
5049
5168
  }
5050
5169
  while (cursor < finalWatermark) {
5051
5170
  const pageEnd = Math.min(finalWatermark, cursor + RECONCILIATION_BATCH_SIZE);
@@ -5065,6 +5184,22 @@ async function reconcileSessionIndex(db, sessionId, readMessages) {
5065
5184
  }
5066
5185
  if (isMessageIndexReconciledThrough(db, sessionId, finalWatermark)) {
5067
5186
  heapHolder.reconciledSessions.add(sessionId);
5187
+ heapHolder.stalledSessions.delete(sessionId);
5188
+ if (revision !== undefined) {
5189
+ if (!after && finalWatermark > 0 && readMessages.readPage) {
5190
+ const last = readMessages.readPage(sessionId, finalWatermark - 1, 1, finalWatermark).at(-1);
5191
+ if (last?.ordinal === finalWatermark && typeof last.createdAt === "number")
5192
+ after = { timeCreated: last.createdAt, id: last.id };
5193
+ }
5194
+ heapHolder.reconciledSnapshots.set(sessionId, {
5195
+ revision,
5196
+ count: finalWatermark,
5197
+ after
5198
+ });
5199
+ }
5200
+ } else {
5201
+ heapHolder.reconciledSessions.delete(sessionId);
5202
+ logReconciliationStall(sessionId, `gap after ordinal ${cursor} (store count ${finalWatermark})`);
5068
5203
  }
5069
5204
  } finally {
5070
5205
  heapHolder.activeReconcilerBuffers.delete(sessionId);
@@ -5073,30 +5208,42 @@ async function reconcileSessionIndex(db, sessionId, readMessages) {
5073
5208
  return true;
5074
5209
  }
5075
5210
  function scheduleReconciliation(db, sessionId, readMessages) {
5076
- if (heapHolder.reconciledSessions.has(sessionId) || heapHolder.reconciliationScheduledSessions.has(sessionId)) {
5211
+ if (!readMessages.getRevision && heapHolder.reconciledSessions.has(sessionId) || heapHolder.reconciliationScheduledSessions.has(sessionId)) {
5077
5212
  return;
5078
5213
  }
5079
5214
  heapHolder.reconciliationScheduledSessions.add(sessionId);
5080
5215
  scheduleAfterBootQuiet(() => {
5081
5216
  defer(() => {
5217
+ let appendedDuringReconciliation = false;
5218
+ const previousSnapshot = heapHolder.reconciledSnapshots.get(sessionId);
5082
5219
  reconcileSessionIndex(db, sessionId, readMessages).then((ran) => {
5083
- if (ran)
5220
+ if (ran) {
5221
+ const snapshot = heapHolder.reconciledSnapshots.get(sessionId);
5222
+ appendedDuringReconciliation = snapshot !== undefined && snapshot !== previousSnapshot && readMessages.getRevision !== undefined && readMessages.getRevision(sessionId) !== snapshot.revision;
5084
5223
  return;
5224
+ }
5085
5225
  setTimeout(() => {
5086
5226
  heapHolder.reconciliationScheduledSessions.delete(sessionId);
5087
5227
  scheduleReconciliation(db, sessionId, readMessages);
5088
5228
  }, PREPARE_RETRY_MS).unref?.();
5089
5229
  }).catch((error) => {
5090
- logIndexingError(sessionId, "reconciliation", error);
5230
+ heapHolder.reconciledSessions.delete(sessionId);
5231
+ logReconciliationStall(sessionId, error instanceof Error ? error.message : String(error));
5091
5232
  if (isDatabaseLockedError(error))
5092
5233
  setTimeout(() => scheduleReconciliation(db, sessionId, readMessages), 1000).unref();
5093
5234
  }).finally(() => {
5094
5235
  heapHolder.reconciliationScheduledSessions.delete(sessionId);
5236
+ if (appendedDuringReconciliation)
5237
+ scheduleReconciliation(db, sessionId, readMessages);
5095
5238
  });
5096
5239
  });
5097
5240
  });
5098
5241
  }
5099
5242
  function scheduleReconciliationCatchup(db, sessionId, readMessages) {
5243
+ if (readMessages.getRevision) {
5244
+ scheduleReconciliation(db, sessionId, readMessages);
5245
+ return;
5246
+ }
5100
5247
  if (typeof readMessages.getCount !== "function") {
5101
5248
  scheduleReconciliation(db, sessionId, readMessages);
5102
5249
  return;
@@ -5114,6 +5261,7 @@ function scheduleReconciliationCatchup(db, sessionId, readMessages) {
5114
5261
  }
5115
5262
  function scheduleClearAndReindex(db, sessionId, readMessages) {
5116
5263
  heapHolder.reconciledSessions.delete(sessionId);
5264
+ heapHolder.reconciledSnapshots.delete(sessionId);
5117
5265
  heapHolder.reconciliationScheduledSessions.delete(sessionId);
5118
5266
  clearCompletedIncrementalKeys(sessionId);
5119
5267
  const existing = heapHolder.clearAndReindexScheduledSessions.get(sessionId);
@@ -5131,6 +5279,7 @@ function scheduleClearAndReindex(db, sessionId, readMessages) {
5131
5279
  return;
5132
5280
  heapHolder.clearAndReindexScheduledSessions.delete(sessionId);
5133
5281
  heapHolder.reconciledSessions.delete(sessionId);
5282
+ heapHolder.reconciledSnapshots.delete(sessionId);
5134
5283
  clearCompletedIncrementalKeys(sessionId);
5135
5284
  clearIndexedMessages(db, sessionId);
5136
5285
  cleared = true;
@@ -6160,6 +6309,20 @@ function resolveTodowriteAvailability(sessionId) {
6160
6309
  }
6161
6310
 
6162
6311
  // src/hooks/magic-context/degraded-pass-refusal.ts
6312
+ function describeDegradedPassFailure(site, cause) {
6313
+ const details = [site];
6314
+ const seen = new Set;
6315
+ while (cause !== undefined && cause !== null && !seen.has(cause)) {
6316
+ seen.add(cause);
6317
+ const current = cause;
6318
+ const detail = typeof current.site === "string" ? current.site : typeof current.message === "string" ? current.message : String(cause);
6319
+ if (!details.includes(detail))
6320
+ details.push(detail);
6321
+ cause = current.cause;
6322
+ }
6323
+ return `Magic Context could not safely prepare this turn [${userFacingFailureCode("transform_pass_degraded")}] (${details.join(": ")}). This request was not sent.`;
6324
+ }
6325
+
6163
6326
  class DegradedPassRefusalError extends Error {
6164
6327
  site;
6165
6328
  code = "DEGRADED_PASS_REFUSAL";
@@ -6167,7 +6330,7 @@ class DegradedPassRefusalError extends Error {
6167
6330
  estimatedTokens;
6168
6331
  contextLimitTokens;
6169
6332
  constructor(site, options) {
6170
- super(renderUserFacingFailure("transform_pass_degraded", "plain"), {
6333
+ super(describeDegradedPassFailure(site, options?.cause), {
6171
6334
  cause: options?.cause
6172
6335
  });
6173
6336
  this.site = site;
@@ -7092,7 +7255,7 @@ function searchMessagesInSnapshot(args, sessionFirst) {
7092
7255
  const filtered = rows.slice(0, limit);
7093
7256
  return filtered.map((row, rank) => ({
7094
7257
  source: "message",
7095
- content: previewText(row.content),
7258
+ content: matchedSearchSnippet(row.content, args.query) || previewText(row.content),
7096
7259
  score: linearDecayScore(rank, filtered.length),
7097
7260
  messageOrdinal: row.messageOrdinal,
7098
7261
  messageId: row.messageId,
@@ -7167,7 +7330,7 @@ function searchMessagesInSnapshot(args, sessionFirst) {
7167
7330
  const ranked = [...fused.values()].sort((a, b) => b.score !== a.score ? b.score - a.score : a.row.messageOrdinal - b.row.messageOrdinal).slice(0, resultLimit);
7168
7331
  return ranked.map((entry, rank) => ({
7169
7332
  source: "message",
7170
- content: previewText(entry.row.content),
7333
+ content: matchedSearchSnippet(entry.row.content, args.query) || previewText(entry.row.content),
7171
7334
  score: linearDecayScore(rank, ranked.length),
7172
7335
  messageOrdinal: entry.row.messageOrdinal,
7173
7336
  messageId: entry.row.messageId,
@@ -7484,7 +7647,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
7484
7647
  if (options.diagnostics) {
7485
7648
  options.diagnostics.suppressedLiveMessageMatches = outcome.suppressedLiveMessageMatches;
7486
7649
  }
7487
- messageResults = outcome.results;
7650
+ messageResults = outcome.results.filter((result) => result.messageId !== options.excludeMessageId);
7488
7651
  }
7489
7652
  const workspace = resolveSearchWorkspaceContext(db, projectPath);
7490
7653
  const [memoryOutcome, primerResults, noteResults] = await Promise.all([
@@ -7539,6 +7702,12 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
7539
7702
  }).immediate();
7540
7703
  }
7541
7704
  }
7705
+ if (options.autoHint) {
7706
+ return results.map((result) => ({
7707
+ ...result,
7708
+ relevanceScore: cleanSearchText(result.content).length === 0 ? 0 : keywordRelevance(trimmedQuery, result.content)
7709
+ }));
7710
+ }
7542
7711
  return results;
7543
7712
  }
7544
7713
  var SEARCH_NOTE_EXPAND_HINT = "Use mmc_expand(start=N-10, end=N) around any note @msg anchor above to read the surrounding conversation context.";
@@ -8158,22 +8327,22 @@ function truncate(text, limit) {
8158
8327
  return normalized;
8159
8328
  return `${normalized.slice(0, Math.max(0, limit - 1)).trimEnd()}…`;
8160
8329
  }
8161
- function renderFragment(result, charCap, wordRules) {
8330
+ function renderFragment(result, charCap, wordRules, query) {
8162
8331
  switch (result.source) {
8163
8332
  case "memory": {
8164
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8333
+ const compressed = cavemanCompress(cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8165
8334
  return truncate(compressed, charCap);
8166
8335
  }
8167
8336
  case "message": {
8168
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8337
+ const compressed = cavemanCompress(query ? matchedSearchSnippet(result.content, query, charCap) : cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8169
8338
  return truncate(compressed, charCap);
8170
8339
  }
8171
8340
  case "primer": {
8172
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8341
+ const compressed = cavemanCompress(cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8173
8342
  return truncate(compressed, charCap);
8174
8343
  }
8175
8344
  case "note": {
8176
- const compressed = cavemanCompress(result.content, "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8345
+ const compressed = cavemanCompress(cleanSearchText(result.content), "ultra", CURRENT_CAVEMAN_RULES, wordRules);
8177
8346
  return truncate(compressed, charCap);
8178
8347
  }
8179
8348
  }
@@ -8184,7 +8353,7 @@ function buildAutoSearchHint(results, options = {}) {
8184
8353
  const picks = results.slice(0, maxFragments);
8185
8354
  const lines = [];
8186
8355
  for (const result of picks) {
8187
- const fragment = renderFragment(result, fragmentCharCap, options.wordRules ?? "english");
8356
+ const fragment = renderFragment(result, fragmentCharCap, options.wordRules ?? "english", options.query ?? "");
8188
8357
  if (fragment.length === 0)
8189
8358
  continue;
8190
8359
  lines.push(`- ${fragment}`);
@@ -8207,6 +8376,10 @@ ${trimmedBody}…
8207
8376
  }
8208
8377
  return wrapped;
8209
8378
  }
8379
+ function selectAutoSearchResults(results, threshold) {
8380
+ const relevance = (result) => result.relevanceScore ?? result.score;
8381
+ return results.filter((result) => relevance(result) >= threshold).sort((left, right) => relevance(right) - relevance(left));
8382
+ }
8210
8383
 
8211
8384
  // src/hooks/magic-context/transform-message-helpers.ts
8212
8385
  function isMeaningfulUserMessage(msg) {
@@ -8483,6 +8656,9 @@ async function runAutoSearchHint(args) {
8483
8656
  return null;
8484
8657
  const searchOptions = {
8485
8658
  limit: 10,
8659
+ autoHint: true,
8660
+ maxMessageOrdinal: Math.max(0, getLastCompartmentEndMessage(db, sessionId)),
8661
+ excludeMessageId: userMsgId,
8486
8662
  memoryEnabled: options.memoryEnabled,
8487
8663
  visibleMemoryIds: options.visibleMemoryIds ?? null,
8488
8664
  sources: ["memory", "message"]
@@ -8507,11 +8683,15 @@ async function runAutoSearchHint(args) {
8507
8683
  if (results.length === 0) {
8508
8684
  return writeNoHintAndReconcile("empty");
8509
8685
  }
8510
- if (results[0].score < options.scoreThreshold) {
8511
- sessionLog(sessionId, `auto-search: top score ${results[0].score.toFixed(3)} below threshold ${options.scoreThreshold}`);
8686
+ results = selectAutoSearchResults(results, options.scoreThreshold);
8687
+ if (results.length === 0) {
8688
+ sessionLog(sessionId, `auto-search: no fragment meets relevance threshold ${options.scoreThreshold}`);
8512
8689
  return writeNoHintAndReconcile("below-threshold");
8513
8690
  }
8514
- const hintText = buildAutoSearchHint(results, { wordRules: options.wordRules });
8691
+ const hintText = buildAutoSearchHint(results, {
8692
+ wordRules: options.wordRules,
8693
+ query: rawPrompt
8694
+ });
8515
8695
  if (!hintText) {
8516
8696
  return writeNoHintAndReconcile("empty");
8517
8697
  }
@@ -8575,6 +8755,30 @@ function getSessionErrorInfo(properties) {
8575
8755
  };
8576
8756
  }
8577
8757
 
8758
+ // src/hooks/magic-context/diagnostic-log-state.ts
8759
+ var states = new BoundedSessionMap(1000);
8760
+ var scope = (sessionId) => `${getMagicContextStorageDir()}\x00${getHarness()}\x00${sessionId}`;
8761
+ function diagnosticStateChanged(sessionId, category, state) {
8762
+ const key = scope(sessionId);
8763
+ const previous = states.get(key) ?? new Map;
8764
+ if (previous.get(category) === state)
8765
+ return false;
8766
+ previous.set(category, state);
8767
+ states.set(key, previous);
8768
+ return true;
8769
+ }
8770
+ function clearDiagnosticLogState(sessionId) {
8771
+ states.delete(scope(sessionId));
8772
+ }
8773
+
8774
+ // src/hooks/magic-context/nudge-evaluation-log.ts
8775
+ function logNudgeEvaluation(sessionId, phase, line) {
8776
+ const category = `${phase}:${line.split(":", 1)[0]}`;
8777
+ const state = line.split(" ").filter((field) => /^(ctx_reduce|band|dampening|verdict|reason|lease)=/.test(field)).join(" ");
8778
+ if (diagnosticStateChanged(sessionId, category, state))
8779
+ sessionLog(sessionId, line);
8780
+ }
8781
+
8578
8782
  // src/hooks/magic-context/stripped-command.ts
8579
8783
  function matchStrippedMagicContextCommand(parts) {
8580
8784
  if (parts.length !== 1)
@@ -8763,7 +8967,7 @@ function maybeInjectChannel1Nudge(args, sessionId, tool, output) {
8763
8967
  evaluable: state.evaluable,
8764
8968
  generationInvalidated: state.generationInvalidated
8765
8969
  });
8766
- sessionLog(sessionId, formatChannel1Evaluation(decision));
8970
+ logNudgeEvaluation(sessionId, "tool-completion", formatChannel1Evaluation(decision));
8767
8971
  setLastNudgeUndropped(args.db, sessionId, decision.nextLastNudge);
8768
8972
  const nextNudgeState = {
8769
8973
  ...nudgeState,
@@ -8776,7 +8980,7 @@ function maybeInjectChannel1Nudge(args, sessionId, tool, output) {
8776
8980
  setChannel1NudgeState(args.db, sessionId, nextNudgeState);
8777
8981
  return;
8778
8982
  }
8779
- out.output += buildChannel1Reminder(decision.level, decision.undroppedTokens, reclaimableToolOutputCount(state.baselineParts), state.oldestReclaimableToolTags, decision.sticky);
8983
+ out.output += buildChannel1Reminder(decision.level, decision.undroppedTokens, currentReclaimableToolOutputCount(state), state.oldestReclaimableToolTags, decision.sticky);
8780
8984
  setChannel1NudgeState(args.db, sessionId, {
8781
8985
  ...nextNudgeState,
8782
8986
  ordinal: state.realUserTurnCount
@@ -10008,9 +10212,6 @@ class StorageBusyRefusalError extends Error {
10008
10212
  }
10009
10213
  }
10010
10214
 
10011
- // src/hooks/magic-context/system-prompt-hash.ts
10012
- import { createHash as createHash3 } from "node:crypto";
10013
-
10014
10215
  // src/agents/magic-context-prompt.ts
10015
10216
  var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
10016
10217
 
@@ -10152,6 +10353,90 @@ ${BASE_INTRO(memoryEnabled, temporalAwarenessEnabled)}${cavemanWarning}
10152
10353
  ${SELF_TAG_GUIDANCE}${languageGuidance}`;
10153
10354
  }
10154
10355
 
10356
+ // src/features/magic-context/transform-decision-log.ts
10357
+ var canonicalReasons = new Set([
10358
+ "system_hash",
10359
+ "model_change",
10360
+ "ttl_idle",
10361
+ "explicit_flush",
10362
+ "max_mutation_id",
10363
+ "first_render",
10364
+ "pressure_refold",
10365
+ "upgrade_state",
10366
+ "cached_m1_missing",
10367
+ "project_change",
10368
+ "compartment_render_epoch",
10369
+ "m1_delta",
10370
+ "ttl_expiry",
10371
+ "epoch_change",
10372
+ "coverage_fold",
10373
+ "profile_transition",
10374
+ "host_compaction"
10375
+ ]);
10376
+ var piReasonAliases = {
10377
+ pending_mutations: "max_mutation_id",
10378
+ renderer_upgrade: "upgrade_state",
10379
+ cache_invalid: "cached_m1_missing",
10380
+ drift: "pressure_refold"
10381
+ };
10382
+ var sharedReasonAliases = {
10383
+ model_key: "model_change",
10384
+ pressure: "pressure_refold"
10385
+ };
10386
+ var pendingDecisionBySession = new Map;
10387
+ var pendingPiDecisionBySession = new Map;
10388
+ var lastBoundMessageIdBySession = new Map;
10389
+ var scheduledWriteTokensBySession = new Map;
10390
+ var systemHashChangedSessions = new Set;
10391
+ var piSystemHashChangedSessions = new Set;
10392
+ var unbustedPassBySession = new Map;
10393
+ var newestInputAssistantBySession = new Map;
10394
+ var stagedV2DecisionBySession = new Map;
10395
+ function normalizeMaterializeReason(harness, reason, rematerialized) {
10396
+ const raw = typeof reason === "string" ? reason.trim() : "";
10397
+ if (raw.length > 0) {
10398
+ const alias = sharedReasonAliases[raw] ?? (harness === "pi" ? piReasonAliases[raw] : undefined) ?? undefined;
10399
+ if (alias)
10400
+ return alias;
10401
+ if (canonicalReasons.has(raw))
10402
+ return raw;
10403
+ return null;
10404
+ }
10405
+ return rematerialized ? "pressure_refold" : null;
10406
+ }
10407
+ function clearOpenCodePendingTransformDecision(sessionId, inputMessages) {
10408
+ pendingDecisionBySession.delete(sessionId);
10409
+ unbustedPassBySession.delete(sessionId);
10410
+ if (!inputMessages)
10411
+ return;
10412
+ let newestAssistant = "";
10413
+ for (const message of inputMessages) {
10414
+ const id = message.info?.id;
10415
+ if (message.info?.role !== "assistant" || typeof id !== "string")
10416
+ continue;
10417
+ if (id > newestAssistant)
10418
+ newestAssistant = id;
10419
+ }
10420
+ newestInputAssistantBySession.set(sessionId, newestAssistant);
10421
+ }
10422
+ function noteSystemPromptHashChange(sessionId) {
10423
+ systemHashChangedSessions.add(sessionId);
10424
+ }
10425
+ function noteOpenCodeUnbustedPass(sessionId, decision) {
10426
+ unbustedPassBySession.set(sessionId, decision);
10427
+ }
10428
+ var IDLE_EXPIRY_REASONS = new Set([
10429
+ "ttl_idle",
10430
+ "ttl_expiry"
10431
+ ]);
10432
+ function recordPendingTransformDecision(sessionId, decision) {
10433
+ if (!decision.bustedThisPass) {
10434
+ pendingDecisionBySession.delete(sessionId);
10435
+ return;
10436
+ }
10437
+ pendingDecisionBySession.set(sessionId, decision);
10438
+ }
10439
+
10155
10440
  // src/hooks/magic-context/system-prompt-dates.ts
10156
10441
  function replaceHostDates(prompt, replace) {
10157
10442
  const fields = /<(plugin-env|environment|env)>[\s\S]*?<\/\1>|Today's date: [^\r\n<]+/g;
@@ -10169,6 +10454,35 @@ function systemPromptDates(prompt, sticky) {
10169
10454
  return { live: values.length ? JSON.stringify(values) : undefined, stable };
10170
10455
  }
10171
10456
 
10457
+ // src/hooks/magic-context/system-prompt-sticky-date.ts
10458
+ var STICKY_DATE_KEY = "systemPromptStickyDate";
10459
+ function readPersistedSystemPromptStickyDate(db, sessionId) {
10460
+ try {
10461
+ const saved = readReplayEnvelope(db, sessionId, "read")[STICKY_DATE_KEY];
10462
+ return typeof saved === "string" && saved.length > 0 ? saved : undefined;
10463
+ } catch (error) {
10464
+ sessionLog(sessionId, "system prompt sticky date record unreadable:", error);
10465
+ return;
10466
+ }
10467
+ }
10468
+ function persistSystemPromptStickyDate(db, sessionId, stickyDate) {
10469
+ try {
10470
+ const written = updateReplayDocument(db, sessionId, (doc) => {
10471
+ if (doc[STICKY_DATE_KEY] === stickyDate)
10472
+ return false;
10473
+ doc.version = 2;
10474
+ doc[STICKY_DATE_KEY] = stickyDate;
10475
+ return true;
10476
+ });
10477
+ if (!written)
10478
+ sessionLog(sessionId, "system prompt sticky date record not written");
10479
+ return written;
10480
+ } catch (error) {
10481
+ sessionLog(sessionId, "system prompt sticky date record write failed:", error);
10482
+ return false;
10483
+ }
10484
+ }
10485
+
10172
10486
  // src/hooks/magic-context/system-date-refresh.ts
10173
10487
  var channels = new WeakMap;
10174
10488
  var outputUpdates = new WeakMap;
@@ -10239,6 +10553,7 @@ function beginSystemDateRequest(history, sessionId, stage, turnId, identity) {
10239
10553
  systemDone: false,
10240
10554
  messagesSeen: false,
10241
10555
  permitted: undefined,
10556
+ signedThinkingKept: undefined,
10242
10557
  ambiguous: identity === undefined && (turnId === undefined || sameTurn)
10243
10558
  };
10244
10559
  const blocked = [...requests.values()].filter((candidate) => !candidate.explicit && candidate.ambiguous && !(candidate.systemSeen && candidate.messagesSeen) && candidate.turnId === turnId).length;
@@ -10261,6 +10576,10 @@ function systemDateRefreshPermission(history, request) {
10261
10576
  const current = state(history, request);
10262
10577
  return current?.ambiguous ? undefined : current?.permitted;
10263
10578
  }
10579
+ function systemDateSignedThinkingKept(history, request) {
10580
+ const current = state(history, request);
10581
+ return current?.ambiguous ? undefined : current?.signedThinkingKept;
10582
+ }
10264
10583
  function waitForSystemDateRefresh(history, request, apply) {
10265
10584
  const current = state(history, request);
10266
10585
  if (!current)
@@ -10275,7 +10594,7 @@ function retire(history, current) {
10275
10594
  if (unpairable) {
10276
10595
  const apply = current.waiting;
10277
10596
  current.waiting = undefined;
10278
- apply?.(false);
10597
+ apply?.(false, undefined);
10279
10598
  }
10280
10599
  const channel = channels.get(history);
10281
10600
  const requests = channel?.get(current.sessionId);
@@ -10283,14 +10602,15 @@ function retire(history, current) {
10283
10602
  if (requests?.size === 0)
10284
10603
  channel?.delete(current.sessionId);
10285
10604
  }
10286
- function finishSystemDateRefresh(history, request, permitted) {
10605
+ function finishSystemDateRefresh(history, request, permitted, signedThinkingKept) {
10287
10606
  const current = state(history, request);
10288
10607
  if (!current)
10289
10608
  return;
10290
10609
  current.permitted = current.ambiguous ? false : permitted;
10610
+ current.signedThinkingKept = current.ambiguous ? undefined : signedThinkingKept;
10291
10611
  const apply = current.waiting;
10292
10612
  current.waiting = undefined;
10293
- apply?.(current.permitted);
10613
+ apply?.(current.permitted, current.signedThinkingKept);
10294
10614
  retire(history, current);
10295
10615
  }
10296
10616
  function finishSystemDateHook(history, request) {
@@ -10326,6 +10646,15 @@ function createSystemPromptHashHandler(deps) {
10326
10646
  });
10327
10647
  const guidanceEpochs = createPromptSurfaceGuidanceEpochCache(promptSurfaceRuntime);
10328
10648
  const stickyDateBySession = new Map;
10649
+ const recordedStickyDateBySession = new Map;
10650
+ const recordedStickyDate = (sessionId) => {
10651
+ let recorded = recordedStickyDateBySession.get(sessionId);
10652
+ if (recorded === undefined) {
10653
+ recorded = readPersistedSystemPromptStickyDate(deps.db, sessionId) ?? null;
10654
+ recordedStickyDateBySession.set(sessionId, recorded);
10655
+ }
10656
+ return recorded ?? undefined;
10657
+ };
10329
10658
  const processSystemPrompt = async (input, output) => {
10330
10659
  const sessionId = input.sessionID;
10331
10660
  if (!sessionId)
@@ -10394,31 +10723,50 @@ function createSystemPromptHashHandler(deps) {
10394
10723
  const hasPersistedHash = previousHash !== "" && previousHash !== "0";
10395
10724
  if (!hasPersistedHash)
10396
10725
  stickyDateBySession.delete(sessionId);
10397
- const stickyDate = stickyDateBySession.get(sessionId);
10726
+ let stickyDate = stickyDateBySession.get(sessionId);
10727
+ if (stickyDate === undefined && hasPersistedHash) {
10728
+ const recorded = recordedStickyDate(sessionId);
10729
+ const live = systemPromptDates(liveSystemContent).live;
10730
+ if (recorded !== undefined && live !== undefined && recorded !== live && systemPromptFingerprint(systemPromptDates(liveSystemContent, recorded).stable, promptSurface.preset) === previousHash) {
10731
+ stickyDate = recorded;
10732
+ stickyDateBySession.set(sessionId, recorded);
10733
+ }
10734
+ }
10735
+ const setStickyDate = (value) => {
10736
+ stickyDateBySession.set(sessionId, value);
10737
+ if (value !== recordedStickyDate(sessionId)) {
10738
+ if (persistSystemPromptStickyDate(deps.db, sessionId, value))
10739
+ recordedStickyDateBySession.set(sessionId, value);
10740
+ }
10741
+ };
10398
10742
  const dates = systemPromptDates(liveSystemContent, stickyDate);
10399
10743
  const currentDate = dates.live;
10400
10744
  const stableCandidate = dates.stable;
10401
- const stableCandidateHash = createHash3("md5").update(promptSurfaceHashMaterial(stableCandidate, promptSurface.preset)).digest("hex");
10745
+ const stableCandidateHash = systemPromptFingerprint(stableCandidate, promptSurface.preset);
10402
10746
  const contentOrPresetChanged = hasPersistedHash && stableCandidateHash !== previousHash;
10403
10747
  const rewritePermission = systemDateRefreshPermission(deps.historyRefreshSessions, dateRequest);
10748
+ const signedThinkingKept = systemDateSignedThinkingKept(deps.historyRefreshSessions, dateRequest);
10749
+ const prefixBoundModel = isPrefixBoundThinkingModel(liveModel?.providerID, liveModel?.modelID);
10750
+ const thinkingAllowsDate = (kept) => prefixBoundModel ? kept === false : kept !== true;
10751
+ const systemDateMayMove = (rewrite, kept) => (rewrite || idleCacheExpired) && thinkingAllowsDate(kept);
10404
10752
  let deferredDateRefresh = false;
10405
- if (currentDate && stickyDate && currentDate !== stickyDate && isCacheBusting && !idleCacheExpired && !contentOrPresetChanged && !requestMessagesFinal) {
10753
+ if (currentDate && stickyDate && currentDate !== stickyDate && (isCacheBusting || idleCacheExpired && isPrefixBoundThinkingModel(liveModel?.providerID, liveModel?.modelID)) && rewritePermission === undefined && !contentOrPresetChanged && !requestMessagesFinal) {
10406
10754
  const liveElements = [...output.system];
10407
- deferredDateRefresh = waitForSystemDateRefresh(deps.historyRefreshSessions, dateRequest, (permitted) => {
10408
- if (!permitted) {
10755
+ deferredDateRefresh = waitForSystemDateRefresh(deps.historyRefreshSessions, dateRequest, (permitted, keptSignedThinking) => {
10756
+ if (!systemDateMayMove(permitted, keptSignedThinking)) {
10409
10757
  deps.systemPromptRefreshSessions.add(sessionId);
10410
10758
  return;
10411
10759
  }
10412
10760
  try {
10413
10761
  const content = liveElements.join(`
10414
10762
  `);
10415
- const hash = createHash3("md5").update(promptSurfaceHashMaterial(content, promptSurface.preset)).digest("hex");
10763
+ const hash = systemPromptFingerprint(content, promptSurface.preset);
10416
10764
  updateSessionMeta(deps.db, sessionId, {
10417
10765
  systemPromptHash: hash,
10418
10766
  cachedM0SystemHash: hash,
10419
10767
  systemPromptTokens: estimateTokens(content)
10420
10768
  });
10421
- stickyDateBySession.set(sessionId, currentDate);
10769
+ setStickyDate(currentDate);
10422
10770
  output.system.splice(0, output.system.length, ...liveElements);
10423
10771
  publishSystemDateOutput(output.system);
10424
10772
  deps.systemPromptRefreshSessions.delete(sessionId);
@@ -10429,12 +10777,12 @@ function createSystemPromptHashHandler(deps) {
10429
10777
  }
10430
10778
  });
10431
10779
  }
10432
- const dateMayAdvance = idleCacheExpired || contentOrPresetChanged || isCacheBusting && !deferredDateRefresh && (dateRequest ? rewritePermission === true : rewritePermission !== false);
10780
+ const dateMayAdvance = thinkingAllowsDate(signedThinkingKept) && (contentOrPresetChanged || !deferredDateRefresh && systemDateMayMove(isCacheBusting && (dateRequest ? rewritePermission === true : rewritePermission !== false), signedThinkingKept));
10433
10781
  if (currentDate && !stickyDate) {
10434
- stickyDateBySession.set(sessionId, currentDate);
10782
+ setStickyDate(currentDate);
10435
10783
  } else if (currentDate && stickyDate && currentDate !== stickyDate) {
10436
10784
  if (dateMayAdvance) {
10437
- stickyDateBySession.set(sessionId, currentDate);
10785
+ setStickyDate(currentDate);
10438
10786
  sessionLog(sessionId, `system prompt date updated: ${stickyDate} → ${currentDate} (cache-busting pass)`);
10439
10787
  } else {
10440
10788
  let offset = 0;
@@ -10452,7 +10800,7 @@ function createSystemPromptHashHandler(deps) {
10452
10800
  `);
10453
10801
  if (!availability.frozen || !modelKey)
10454
10802
  return;
10455
- const currentHash = createHash3("md5").update(promptSurfaceHashMaterial(systemContent, promptSurface.preset)).digest("hex");
10803
+ const currentHash = systemPromptFingerprint(systemContent, promptSurface.preset);
10456
10804
  recordSystemPromptForRequest(sessionId, currentLkgRequestIdentity(sessionId), currentHash, deps.db, previousHash !== currentHash ? !deps.historyRefreshSessions.has(sessionId) : undefined, deps.historyRefreshSessions, deps.pendingMaterializationSessions);
10457
10805
  if (!sessionMetaEarly) {
10458
10806
  return;
@@ -10460,6 +10808,7 @@ function createSystemPromptHashHandler(deps) {
10460
10808
  const sessionMeta = sessionMetaEarly;
10461
10809
  if (previousHash !== "" && previousHash !== "0" && previousHash !== currentHash) {
10462
10810
  sessionLog(sessionId, `system prompt hash changed: ${previousHash} → ${currentHash} (len=${systemContent.length}), ${idleCacheExpired ? "adopting on idle-expired request" : requestMessagesFinal ? "adopting on the request whose messages are already final" : "triggering flush"}`);
10811
+ noteSystemPromptHashChange(sessionId);
10463
10812
  if (!adoptSystemChange) {
10464
10813
  deps.historyRefreshSessions.add(sessionId);
10465
10814
  deps.systemPromptRefreshSessions.add(sessionId);
@@ -10488,7 +10837,7 @@ function createSystemPromptHashHandler(deps) {
10488
10837
  sessionLog(sessionId, "system prompt meta persist failed (fail-open):", error);
10489
10838
  }
10490
10839
  }
10491
- if (isCacheBusting && !deferredDateRefresh && (contentOrPresetChanged || !currentDate || currentDate === stickyDate || !dateRequest || rewritePermission === true)) {
10840
+ if (isCacheBusting && !deferredDateRefresh && (contentOrPresetChanged && thinkingAllowsDate(signedThinkingKept) || !currentDate || currentDate === stickyDate || !dateRequest && thinkingAllowsDate(signedThinkingKept) || rewritePermission === true && thinkingAllowsDate(signedThinkingKept))) {
10492
10841
  deps.systemPromptRefreshSessions.delete(sessionId);
10493
10842
  }
10494
10843
  };
@@ -10502,6 +10851,7 @@ function createSystemPromptHashHandler(deps) {
10502
10851
  return {
10503
10852
  handler,
10504
10853
  clearSession: (sessionId) => {
10854
+ recordedStickyDateBySession.delete(sessionId);
10505
10855
  clearSystemDateRefresh(deps.historyRefreshSessions, sessionId);
10506
10856
  guidanceEpochs.clear(sessionId);
10507
10857
  clearSystemPromptHashSession(sessionId, {
@@ -10520,10 +10870,16 @@ class MaintenanceLauncher {
10520
10870
  constructor(deps) {
10521
10871
  this.deps = deps;
10522
10872
  }
10873
+ modelConfigured() {
10874
+ return hasMaintenancePrimary(this.deps.getConfig().maintenance);
10875
+ }
10523
10876
  maybeLaunch(signals) {
10524
10877
  if (!this.deps.getConfig().maintenance.enabled) {
10525
10878
  return { launched: false, reason: "maintenance-disabled" };
10526
10879
  }
10880
+ if (!this.modelConfigured()) {
10881
+ return { launched: false, reason: "maintenance-model-unconfigured" };
10882
+ }
10527
10883
  if (this.runInFlight) {
10528
10884
  return { launched: false, reason: "run-in-flight-local" };
10529
10885
  }
@@ -10553,6 +10909,9 @@ class MaintenanceLauncher {
10553
10909
  if (!this.deps.getConfig().maintenance.enabled) {
10554
10910
  return { launched: false, reason: "maintenance-disabled" };
10555
10911
  }
10912
+ if (!this.modelConfigured()) {
10913
+ return { launched: false, reason: "maintenance-model-unconfigured" };
10914
+ }
10556
10915
  if (this.runInFlight) {
10557
10916
  return { launched: false, reason: "run-in-flight-local" };
10558
10917
  }
@@ -10692,63 +11051,6 @@ function hasRecordedSessionProjectIdentity(db, sessionId) {
10692
11051
  return row?.found === 1;
10693
11052
  }
10694
11053
 
10695
- // src/features/magic-context/transform-decision-log.ts
10696
- var canonicalReasons = new Set([
10697
- "system_hash",
10698
- "model_change",
10699
- "ttl_idle",
10700
- "explicit_flush",
10701
- "max_mutation_id",
10702
- "first_render",
10703
- "pressure_refold",
10704
- "upgrade_state",
10705
- "cached_m1_missing",
10706
- "project_change",
10707
- "compartment_render_epoch",
10708
- "m1_delta",
10709
- "ttl_expiry",
10710
- "epoch_change",
10711
- "coverage_fold",
10712
- "profile_transition",
10713
- "host_compaction"
10714
- ]);
10715
- var piReasonAliases = {
10716
- pending_mutations: "max_mutation_id",
10717
- renderer_upgrade: "upgrade_state",
10718
- cache_invalid: "cached_m1_missing",
10719
- drift: "pressure_refold"
10720
- };
10721
- var sharedReasonAliases = {
10722
- model_key: "model_change",
10723
- pressure: "pressure_refold"
10724
- };
10725
- var pendingDecisionBySession = new Map;
10726
- var pendingPiDecisionBySession = new Map;
10727
- var lastBoundMessageIdBySession = new Map;
10728
- var scheduledWriteTokensBySession = new Map;
10729
- function normalizeMaterializeReason(harness, reason, rematerialized) {
10730
- const raw = typeof reason === "string" ? reason.trim() : "";
10731
- if (raw.length > 0) {
10732
- const alias = sharedReasonAliases[raw] ?? (harness === "pi" ? piReasonAliases[raw] : undefined) ?? undefined;
10733
- if (alias)
10734
- return alias;
10735
- if (canonicalReasons.has(raw))
10736
- return raw;
10737
- return null;
10738
- }
10739
- return rematerialized ? "pressure_refold" : null;
10740
- }
10741
- function clearOpenCodePendingTransformDecision(sessionId) {
10742
- pendingDecisionBySession.delete(sessionId);
10743
- }
10744
- function recordPendingTransformDecision(sessionId, decision) {
10745
- if (!decision.bustedThisPass) {
10746
- pendingDecisionBySession.delete(sessionId);
10747
- return;
10748
- }
10749
- pendingDecisionBySession.set(sessionId, decision);
10750
- }
10751
-
10752
11054
  // src/hooks/magic-context/cache-busting-signals.ts
10753
11055
  function canConsumeDeferredOnThisPass(args) {
10754
11056
  if (args.justAwaitedPublication)
@@ -11422,12 +11724,12 @@ function buildTriggerInMemoryTail(db, sessionId, messages) {
11422
11724
  function getProactiveCompartmentTriggerPercentage(executeThresholdPercentage) {
11423
11725
  return Math.max(0, executeThresholdPercentage - PROACTIVE_TRIGGER_OFFSET_PERCENTAGE);
11424
11726
  }
11425
- function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, keepReasoningTokens, clearedReasoningThroughTag, canClearReasoning, liveBudgetCutoff) {
11727
+ function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, keepReasoningTokens, clearedReasoningThroughTag, canClearReasoning, liveBudgetCutoff, eligiblePendingDropTagIds) {
11426
11728
  const totalActiveBytes = activeTags.reduce((sum, tag) => sum + tag.byteSize + tag.reasoningByteSize, 0);
11427
11729
  if (totalActiveBytes === 0)
11428
11730
  return null;
11429
11731
  let droppableBytes = 0;
11430
- const pendingDrops = getPendingOps(db, sessionId).filter((op) => op.operation === "drop");
11732
+ const pendingDrops = getPendingOps(db, sessionId).filter((op) => op.operation === "drop" && eligiblePendingDropTagIds?.has(op.tagId) === true);
11431
11733
  const pendingDropTagIds = new Set(pendingDrops.map((op) => op.tagId));
11432
11734
  if (pendingDrops.length > 0) {
11433
11735
  droppableBytes += activeTags.filter((tag) => pendingDropTagIds.has(tag.tagNumber)).reduce((sum, tag) => sum + tag.byteSize + tag.reasoningByteSize, 0);
@@ -11555,7 +11857,7 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget, usage, executeThr
11555
11857
  function formatProjectedPostDropPercentage(value) {
11556
11858
  return value === null ? "none" : `${value.toFixed(1)}%`;
11557
11859
  }
11558
- function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, keepReasoningTokens, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride, reasoningProjection, reclaimRide, storedTotalsExcludeToolTags) {
11860
+ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, keepReasoningTokens, commitClusterTrigger, preloadedActiveTags, contextLimit, inMemoryTail, taggerFloorOverride, reasoningProjection, reclaimRide, eligiblePendingDropTagIds, storedTotalsExcludeToolTags) {
11559
11861
  if (sessionMeta.compartmentInProgress) {
11560
11862
  sessionLog(sessionId, `compartment trigger: skipped — historian already in progress (usage=${usage.percentage.toFixed(1)}%)`);
11561
11863
  return { shouldFire: false };
@@ -11619,7 +11921,7 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
11619
11921
  return { shouldFire: false };
11620
11922
  }
11621
11923
  const canClearReasoning = reasoningProjection?.canClearReasoning ?? modelAcceptsEmptyContent(reasoningProjection?.providerID);
11622
- const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), keepReasoningTokens, sessionMeta.clearedReasoningThroughTag, canClearReasoning, reasoningProjection?.budgetCutoff);
11924
+ const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), keepReasoningTokens, sessionMeta.clearedReasoningThroughTag, canClearReasoning, reasoningProjection?.budgetCutoff, eligiblePendingDropTagIds);
11623
11925
  const relativePostDropTarget = executeThresholdPercentage * POST_DROP_TARGET_RATIO;
11624
11926
  const rideLabel = reclaimRide ? reclaimRideLabel(reclaimRide) : "ride=none";
11625
11927
  const dropsCanLand = reclaimRide !== undefined && hasReclaimRide(reclaimRide);
@@ -11703,6 +12005,12 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
11703
12005
  };
11704
12006
  }
11705
12007
 
12008
+ // src/hooks/magic-context/compartment-trigger-error.ts
12009
+ function recordCompartmentTriggerError(passOutcome, sessionId, error, log = sessionLog) {
12010
+ passOutcome.record("compartment-trigger-failure");
12011
+ log(sessionId, "compartment trigger failed (non-fatal):", error);
12012
+ }
12013
+
11706
12014
  // src/hooks/magic-context/pass-outcome.ts
11707
12015
  var PASS_DEGRADATION_EFFECTS = {
11708
12016
  "store-generation-rebase-failure": "changes-request",
@@ -11719,6 +12027,8 @@ var PASS_DEGRADATION_EFFECTS = {
11719
12027
  "stale-reduce-strip-exception": "changes-request",
11720
12028
  "image-strip-exception": "changes-request",
11721
12029
  "m0-m1-injection-degradation": "changes-request",
12030
+ "host-instruction-retention-read-failure": "changes-request",
12031
+ "host-instruction-retention-persistence-failure": "changes-request",
11722
12032
  "m0-m1-fallback-failure": "changes-request",
11723
12033
  "compaction-marker-drain-failure": "changes-request",
11724
12034
  "auto-search-timeout": "served",
@@ -11763,6 +12073,37 @@ function createPassOutcome() {
11763
12073
  };
11764
12074
  }
11765
12075
 
12076
+ // src/hooks/magic-context/render-options.ts
12077
+ function createM0RenderOptions(controls, contextUsage, modelKey, resolvedContextLimit, projectPath) {
12078
+ return {
12079
+ projectPath: controls.memoryConfig?.enabled ? projectPath : undefined,
12080
+ memoryEnabled: controls.memoryConfig?.enabled,
12081
+ memoryInjectionBudgetTokens: controls.memoryConfig?.injectionBudgetTokens,
12082
+ temporalAwareness: controls.experimentalTemporalAwareness,
12083
+ historyBudgetTokens: resolveHistoryBudgetTokens(controls.historyBudgetPercentage, contextUsage, controls.executeThresholdPercentage, modelKey, controls.executeThresholdTokens, resolvedContextLimit),
12084
+ historyBudgetPolicyIdentity: historyBudgetPolicyIdentity(controls.historyBudgetPercentage, controls.executeThresholdPercentage, modelKey, controls.executeThresholdTokens)
12085
+ };
12086
+ }
12087
+ function resolveHistoryBudgetTokens(historyBudgetPercentage, contextUsage, executeThresholdPercentage, modelKey, executeThresholdTokens, resolvedContextLimit) {
12088
+ if (!historyBudgetPercentage) {
12089
+ return;
12090
+ }
12091
+ let contextLimit = resolvedContextLimit && resolvedContextLimit > 0 ? resolvedContextLimit : 0;
12092
+ if (contextLimit <= 0) {
12093
+ if (contextUsage.percentage <= 0) {
12094
+ return;
12095
+ }
12096
+ contextLimit = contextUsage.inputTokens / (contextUsage.percentage / 100);
12097
+ }
12098
+ if (!Number.isFinite(contextLimit) || contextLimit <= 0) {
12099
+ return;
12100
+ }
12101
+ return Math.floor(contextLimit * (resolveExecuteThreshold(executeThresholdPercentage ?? 65, modelKey, 65, {
12102
+ tokensConfig: executeThresholdTokens,
12103
+ contextLimit
12104
+ }) / 100) * historyBudgetPercentage);
12105
+ }
12106
+
11766
12107
  // src/hooks/magic-context/temporal-served-projection.ts
11767
12108
  function readLkgTemporalDecisions(db, sessionId, runtime) {
11768
12109
  const slot = getInMemorySlot(sessionId) ?? loadPersistedLkgSlot(db, sessionId);
@@ -11955,6 +12296,13 @@ async function runCompartmentPhaseImpl(args) {
11955
12296
  return snapshot !== null && hasRunnableCompartmentWindow(snapshot);
11956
12297
  }
11957
12298
  async function awaitCompartmentRun(activeRun, reason) {
12299
+ await Promise.resolve();
12300
+ if (activeRun.inlineJoinTimedOutBudgetMs !== undefined && !activeRun.settled) {
12301
+ historianJoinTimedOut = true;
12302
+ historianJoinBudgetMs = activeRun.inlineJoinTimedOutBudgetMs;
12303
+ sessionLog(args.sessionId, "transform: compartment inline join budget already exhausted for this run — not waiting again");
12304
+ return "timed_out";
12305
+ }
11958
12306
  sessionLog(args.sessionId, reason);
11959
12307
  const timeoutMs = resolveHistorianInlineJoinBudget(args.historianTimeoutMs);
11960
12308
  historianJoinBudgetMs = timeoutMs;
@@ -11970,6 +12318,7 @@ async function runCompartmentPhaseImpl(args) {
11970
12318
  clearTimeout(timer);
11971
12319
  }
11972
12320
  if (result === "timeout") {
12321
+ activeRun.inlineJoinTimedOutBudgetMs = timeoutMs;
11973
12322
  historianJoinTimedOut = true;
11974
12323
  sessionLog(args.sessionId, `transform: compartment await timed out after ${timeoutMs}ms — proceeding without waiting`);
11975
12324
  return "timed_out";
@@ -11978,7 +12327,7 @@ async function runCompartmentPhaseImpl(args) {
11978
12327
  justAwaitedPublication = activeRun.published;
11979
12328
  published = published || activeRun.published;
11980
12329
  const historyReprepareShouldBust = activeRun.published && args.deferredHistoryRefreshSessions.has(args.sessionId);
11981
- pendingCompartmentInjection = prepareCompartmentInjection(args.db, args.resolvedSessionId, args.messages, historyReprepareShouldBust, args.projectPath, args.injectionBudgetTokens, args.experimentalTemporalAwareness);
12330
+ pendingCompartmentInjection = prepareCompartmentInjection(args.db, args.resolvedSessionId, args.messages, historyReprepareShouldBust, args.projectPath, args.injectionBudgetTokens, args.experimentalTemporalAwareness, args.coveredHostInstructions);
11982
12331
  if (historyReprepareShouldBust) {
11983
12332
  rebuiltHistoryThisPass = true;
11984
12333
  }
@@ -12177,33 +12526,119 @@ function resolveSchedulerDecision(scheduler, sessionMeta, contextUsage, sessionI
12177
12526
  }
12178
12527
  }
12179
12528
 
12529
+ // src/hooks/magic-context/pending-drop-eligibility.ts
12530
+ function pendingDropVeto(tagNumber, target, protectedTagIds) {
12531
+ if (protectedTagIds.has(tagNumber))
12532
+ return "protected";
12533
+ if (target?.thinkingDropProtected)
12534
+ return "active_thinking";
12535
+ return null;
12536
+ }
12537
+ function capturePendingDropEligibility(targets, protectedTagIds) {
12538
+ const eligible = new Set;
12539
+ for (const [number, target] of targets) {
12540
+ if (pendingDropVeto(number, target, protectedTagIds))
12541
+ continue;
12542
+ if (target.drop) {
12543
+ if (target.canDrop?.() === true)
12544
+ eligible.add(number);
12545
+ } else {
12546
+ const content = target.getContent?.();
12547
+ if (typeof content === "string" && content.length > `[dropped §${number}§]`.length && target.canSetContent?.(`[dropped §${number}§]`) !== false)
12548
+ eligible.add(number);
12549
+ }
12550
+ }
12551
+ return eligible;
12552
+ }
12553
+ function pendingDropEligibilityKey(db, sessionId, input, protectionInputs) {
12554
+ const digests = input.map((message) => message.contentDigest?.() ?? null);
12555
+ if (digests.some((digest) => digest === null))
12556
+ return null;
12557
+ const revision = db.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(tagRevisionKey(sessionId));
12558
+ if (!revision?.value)
12559
+ return null;
12560
+ return JSON.stringify([
12561
+ input.map((message, index) => [
12562
+ message.id,
12563
+ message.role,
12564
+ message.synthetic,
12565
+ digests[index]
12566
+ ]),
12567
+ revision.value,
12568
+ readEpochFloorSnapshot(db, sessionId),
12569
+ sessionDecisionCalibration(db, sessionId).toolsRatio,
12570
+ loadProtectedTailMeta(db, sessionId),
12571
+ [...getMergedReasoningStrippedIds(db, sessionId)].sort(),
12572
+ [...getReasoningRemovalState(db, sessionId).messageIds].sort(),
12573
+ protectionInputs
12574
+ ]);
12575
+ }
12576
+ function createPendingDropEligibilityCache() {
12577
+ const sessions = new Map;
12578
+ return {
12579
+ read(sessionId, key) {
12580
+ const previous = sessions.get(sessionId);
12581
+ if (key === null || previous?.key !== key) {
12582
+ sessions.delete(sessionId);
12583
+ return;
12584
+ }
12585
+ return previous.eligible;
12586
+ },
12587
+ record(sessionId, key, eligible) {
12588
+ sessions.delete(sessionId);
12589
+ if (key === null)
12590
+ return;
12591
+ const oldest = sessions.keys().next().value;
12592
+ if (sessions.size >= 64 && oldest !== undefined)
12593
+ sessions.delete(oldest);
12594
+ sessions.set(sessionId, { key, eligible: new Set(eligible) });
12595
+ }
12596
+ };
12597
+ }
12598
+
12180
12599
  // src/hooks/magic-context/apply-operations.ts
12181
12600
  var RECENT_TOOL_SKELETON_WINDOW = 20;
12182
12601
  function buildReplacementContent(tagId) {
12183
12602
  return `[dropped §${tagId}§]`;
12184
12603
  }
12185
12604
  function applyNewToolDrop(target, options) {
12186
- if (options.persist && (target?.prepareDrop?.() ?? target?.canDrop?.()) === false) {
12605
+ const plan = planNewToolDrop(target, options, !!options.persist);
12606
+ if (!plan)
12187
12607
  return { result: "incomplete", mode: "full" };
12608
+ options.persist?.(plan.mode);
12609
+ return plan.apply();
12610
+ }
12611
+ function planNewToolDrop(target, options, prepare, plannedRemovals) {
12612
+ if (prepare && (target?.prepareDrop?.() ?? target?.canDrop?.()) === false) {
12613
+ return;
12188
12614
  }
12189
12615
  if (!target) {
12190
- options.persist?.("full");
12191
- return { result: "absent", mode: "full" };
12616
+ return { mode: "full", apply: () => ({ result: "absent", mode: "full" }) };
12192
12617
  }
12193
- if (options.inWindow && hasSmallToolInput(target) || options.keepSkeleton === true || target.cannotRemove?.() === true || target.wouldStrandConversationEnd?.() === true) {
12618
+ if (options.inWindow && hasSmallToolInput(target) || options.keepSkeleton === true || target.cannotRemove?.() === true || target.wouldStrandConversationEnd?.(plannedRemovals) === true) {
12194
12619
  const strip = target.hasAttachments?.() === true;
12195
- options.persist?.(strip ? "skeleton_stripped" : "skeleton_real");
12620
+ const mode = strip ? "skeleton_stripped" : "skeleton_real";
12196
12621
  return {
12197
- result: (strip ? target.skeletonStripped?.() : target.skeletonReal?.()) ?? "absent",
12198
- mode: strip ? "skeleton_stripped" : "skeleton_real"
12622
+ mode,
12623
+ apply: () => ({
12624
+ result: (strip ? target.skeletonStripped?.() : target.skeletonReal?.()) ?? "absent",
12625
+ mode
12626
+ })
12199
12627
  };
12200
12628
  }
12201
- options.persist?.("full");
12202
- const result = target.drop?.() ?? "absent";
12203
- if (result === "truncated" && target.hasAttachments?.() === true) {
12204
- return { result: target.skeletonStripped?.() ?? "absent", mode: "skeleton_stripped" };
12205
- }
12206
- return { result, mode: result === "truncated" ? "skeleton_real" : "full" };
12629
+ return {
12630
+ mode: "full",
12631
+ apply: () => {
12632
+ const result = target.drop?.() ?? "absent";
12633
+ if (result === "truncated" && target.hasAttachments?.() === true) {
12634
+ return {
12635
+ result: target.skeletonStripped?.() ?? "absent",
12636
+ mode: "skeleton_stripped"
12637
+ };
12638
+ }
12639
+ return { result, mode: result === "truncated" ? "skeleton_real" : "full" };
12640
+ }
12641
+ };
12207
12642
  }
12208
12643
  function hasSmallToolInput(target) {
12209
12644
  const bytes = target?.inputStringBytes?.() ?? null;
@@ -12285,7 +12720,8 @@ function renderConvertedToolSkeletons(targets, converted) {
12285
12720
  }
12286
12721
  return didMutate;
12287
12722
  }
12288
- function applyPendingOperations(sessionId, db, targets, protectedTagIds, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set, onTagReduced, onBatchComplete) {
12723
+ var PENDING_OPERATION_CHUNK_SIZE = 64;
12724
+ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set, onTagReduced, onBatchComplete, onEligibilitySnapshot) {
12289
12725
  let didMutateMessage = false;
12290
12726
  let diagnostics;
12291
12727
  const reject = (reason) => {
@@ -12294,163 +12730,188 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
12294
12730
  diagnostics.reasons[reason] = (diagnostics.reasons[reason] ?? 0) + 1;
12295
12731
  };
12296
12732
  let admitted = false;
12297
- try {
12298
- db.transaction(() => {
12299
- admitted = true;
12300
- }).immediate();
12301
- {
12302
- const pendingOps = preloadedPendingOps ?? getPendingOps(db, sessionId);
12303
- const neededTagNumbers = new Set(pendingOps.map((op) => op.tagId));
12304
- for (const op of syntheticPendingOps)
12305
- neededTagNumbers.add(op.tagId);
12306
- const tags = preloadedTags ?? getTagsByNumbers(db, sessionId, (() => {
12307
- const newest = getNewestToolTagNumbers(db, sessionId, RECENT_TOOL_SKELETON_WINDOW);
12308
- const numbers = [...neededTagNumbers];
12309
- for (const tagNumber of newest) {
12310
- if (!neededTagNumbers.has(tagNumber))
12311
- numbers.push(tagNumber);
12312
- }
12313
- return numbers;
12314
- })());
12315
- const tagById = new Map(tags.map((tag) => [tag.tagNumber, tag]));
12316
- const tagStatusById = new Map(tags.map((tag) => [tag.tagNumber, tag.status]));
12317
- const tagTypeById = new Map(tags.map((tag) => [tag.tagNumber, tag.type]));
12318
- const opsToApply = [
12319
- ...pendingOps.map((op) => ({ op, synthetic: false })),
12320
- ...syntheticPendingOps.map((op) => ({ op, synthetic: true }))
12321
- ];
12322
- diagnostics = {
12323
- source: pendingOps.length > 0 && syntheticPendingOps.length > 0 ? "mixed" : syntheticPendingOps.length > 0 ? "synthetic" : "pending",
12324
- total: opsToApply.length,
12325
- mutated: 0,
12326
- persistedWithoutMutation: 0,
12327
- reasons: {}
12328
- };
12329
- const skeletonWindow = new Set(getNewestToolTagNumbers(db, sessionId, RECENT_TOOL_SKELETON_WINDOW));
12330
- for (const { op: pendingOp, synthetic } of opsToApply) {
12331
- let operationMutated = false;
12332
- const tagStatus = tagStatusById.get(pendingOp.tagId);
12333
- if (tagStatus === "compacted" || tagStatus === "dropped") {
12334
- reject("already_reduced");
12335
- if (!synthetic)
12336
- removePendingOp(db, sessionId, pendingOp.tagId);
12337
- continue;
12338
- }
12339
- if (protectedTagIds.has(pendingOp.tagId)) {
12340
- reject("protected");
12341
- continue;
12342
- }
12343
- const target = targets.get(pendingOp.tagId);
12344
- if (target?.thinkingDropProtected) {
12345
- reject("active_thinking");
12346
- continue;
12347
- }
12348
- const isToolTag = tagTypeById.get(pendingOp.tagId) === "tool";
12349
- if (synthetic) {
12350
- if (!isToolTag) {
12351
- reject("synthetic_non_tool");
12352
- continue;
12353
- }
12354
- if (target?.canDrop?.() !== true) {
12355
- reject("synthetic_target_not_droppable");
12356
- continue;
12357
- }
12733
+ let startedAt = 0;
12734
+ const mutations = [];
12735
+ let drainChunk;
12736
+ let hasMore = false;
12737
+ do {
12738
+ admitted = false;
12739
+ startedAt = 0;
12740
+ try {
12741
+ db.transaction(() => {
12742
+ admitted = true;
12743
+ startedAt = performance.now();
12744
+ if (drainChunk) {
12745
+ drainChunk();
12746
+ return;
12358
12747
  }
12359
- let shouldPersistDrop = false;
12360
- const persistDrop = (mode) => {
12361
- let startedAt = 0;
12362
- try {
12363
- db.transaction(() => {
12364
- startedAt = performance.now();
12365
- if (mode)
12366
- updateTagDropMode(db, sessionId, pendingOp.tagId, mode);
12367
- updateTagStatus(db, sessionId, pendingOp.tagId, "dropped");
12748
+ const pendingOps = preloadedPendingOps ?? getPendingOps(db, sessionId);
12749
+ onEligibilitySnapshot?.(capturePendingDropEligibility(targets, protectedTagIds));
12750
+ const tags = preloadedTags ?? getTagsByNumbers(db, sessionId, [
12751
+ ...new Set([
12752
+ ...pendingOps.map((op) => op.tagId),
12753
+ ...syntheticPendingOps.map((op) => op.tagId)
12754
+ ])
12755
+ ]);
12756
+ const tagById = new Map(tags.map((tag) => [tag.tagNumber, tag]));
12757
+ const tagStatusById = new Map(tags.map((tag) => [tag.tagNumber, tag.status]));
12758
+ const tagTypeById = new Map(tags.map((tag) => [tag.tagNumber, tag.type]));
12759
+ const opsToApply = [
12760
+ ...pendingOps.map((op) => ({ op, synthetic: false })),
12761
+ ...syntheticPendingOps.map((op) => ({ op, synthetic: true }))
12762
+ ];
12763
+ diagnostics = {
12764
+ source: pendingOps.length > 0 && syntheticPendingOps.length > 0 ? "mixed" : syntheticPendingOps.length > 0 ? "synthetic" : "pending",
12765
+ total: opsToApply.length,
12766
+ mutated: 0,
12767
+ persistedWithoutMutation: 0,
12768
+ reasons: {}
12769
+ };
12770
+ const skeletonWindow = new Set(preloadedTags ? tags.filter((tag) => tag.type === "tool").map((tag) => tag.tagNumber).sort((left, right) => right - left).slice(0, RECENT_TOOL_SKELETON_WINDOW) : getNewestToolTagNumbers(db, sessionId, RECENT_TOOL_SKELETON_WINDOW));
12771
+ const plannedRemovals = new Set;
12772
+ const removedTagIds = new Set;
12773
+ const record = (mutated) => {
12774
+ if (!diagnostics)
12775
+ return;
12776
+ if (mutated) {
12777
+ didMutateMessage = true;
12778
+ diagnostics.mutated += 1;
12779
+ } else
12780
+ diagnostics.persistedWithoutMutation += 1;
12781
+ };
12782
+ let cursor = 0;
12783
+ drainChunk = () => {
12784
+ const chunk = opsToApply.slice(cursor, cursor + PENDING_OPERATION_CHUNK_SIZE);
12785
+ cursor += chunk.length;
12786
+ hasMore = cursor < opsToApply.length;
12787
+ for (const { op: pendingOp, synthetic } of chunk) {
12788
+ const tagStatus = tagStatusById.get(pendingOp.tagId);
12789
+ if (tagStatus === "compacted" || tagStatus === "dropped") {
12790
+ reject("already_reduced");
12368
12791
  if (!synthetic)
12369
12792
  removePendingOp(db, sessionId, pendingOp.tagId);
12370
- }).immediate();
12371
- } finally {
12372
- if (startedAt)
12373
- logSlowWriteTransaction("apply_pending_operation", startedAt);
12374
- }
12375
- };
12376
- if (isToolTag) {
12377
- if (editMarkerTagIds.has(pendingOp.tagId)) {
12378
- const strip = target?.hasAttachments?.() === true;
12379
- if (target?.canDrop?.() === false || target?.prepareDrop?.() === false || !target) {
12380
- reject("edit_marker_incomplete");
12381
12793
  continue;
12382
12794
  }
12383
- persistDrop(strip ? "edit_marker_stripped" : "edit_marker");
12384
- const markResult = (strip ? target?.editMarkerStripped?.() : target?.editMarker?.()) ?? "absent";
12385
- if (markResult === "incomplete" || markResult === "absent") {
12386
- reject(`edit_marker_${markResult}`);
12795
+ if (removedTagIds.has(pendingOp.tagId)) {
12796
+ reject("drop_incomplete");
12387
12797
  continue;
12388
12798
  }
12389
- didMutateMessage = true;
12390
- operationMutated = true;
12391
- onTagReduced?.({ tagNumber: pendingOp.tagId, mode: "edit_marker" });
12392
- shouldPersistDrop = true;
12393
- } else {
12394
- const { result: dropResult, mode: appliedMode } = applyNewToolDrop(target, {
12395
- inWindow: skeletonWindow.has(pendingOp.tagId),
12396
- persist: persistDrop
12397
- });
12398
- if (dropResult === "incomplete" || synthetic && dropResult !== "removed" && dropResult !== "truncated") {
12399
- reject(`drop_${dropResult}`);
12799
+ const target = targets.get(pendingOp.tagId);
12800
+ const veto = pendingDropVeto(pendingOp.tagId, target, protectedTagIds);
12801
+ if (veto) {
12802
+ reject(veto);
12400
12803
  continue;
12401
12804
  }
12402
- if (dropResult === "removed" || dropResult === "truncated") {
12403
- didMutateMessage = true;
12404
- operationMutated = true;
12405
- onTagReduced?.({
12406
- tagNumber: pendingOp.tagId,
12407
- mode: appliedMode === "full" ? "full" : "truncated"
12805
+ const isToolTag = tagTypeById.get(pendingOp.tagId) === "tool";
12806
+ if (synthetic) {
12807
+ if (!isToolTag) {
12808
+ reject("synthetic_non_tool");
12809
+ continue;
12810
+ }
12811
+ if (target?.canDrop?.() !== true) {
12812
+ reject("synthetic_target_not_droppable");
12813
+ continue;
12814
+ }
12815
+ }
12816
+ const persistDrop = (mode) => {
12817
+ markTagDropped(db, sessionId, pendingOp.tagId, mode);
12818
+ if (!synthetic)
12819
+ removePendingOp(db, sessionId, pendingOp.tagId);
12820
+ };
12821
+ if (isToolTag) {
12822
+ if (editMarkerTagIds.has(pendingOp.tagId)) {
12823
+ const strip = target?.hasAttachments?.() === true;
12824
+ if (target?.canDrop?.() === false || target?.prepareDrop?.() === false || !target) {
12825
+ reject("edit_marker_incomplete");
12826
+ continue;
12827
+ }
12828
+ persistDrop(strip ? "edit_marker_stripped" : "edit_marker");
12829
+ mutations.push(() => {
12830
+ const markResult = (strip ? target?.editMarkerStripped?.() : target?.editMarker?.()) ?? "absent";
12831
+ if (markResult === "incomplete" || markResult === "absent") {
12832
+ reject(`edit_marker_${markResult}`);
12833
+ return;
12834
+ }
12835
+ record(true);
12836
+ onTagReduced?.({
12837
+ tagNumber: pendingOp.tagId,
12838
+ mode: "edit_marker"
12839
+ });
12840
+ });
12841
+ } else {
12842
+ const plan = planNewToolDrop(target, { inWindow: skeletonWindow.has(pendingOp.tagId) }, true, plannedRemovals);
12843
+ if (!plan) {
12844
+ reject("drop_incomplete");
12845
+ continue;
12846
+ }
12847
+ persistDrop(plan.mode);
12848
+ if (plan.mode === "full" && target?.drop) {
12849
+ target.notePlannedRemoval?.(plannedRemovals);
12850
+ removedTagIds.add(pendingOp.tagId);
12851
+ }
12852
+ mutations.push(() => {
12853
+ const { result: dropResult, mode: appliedMode } = plan.apply();
12854
+ if (dropResult === "incomplete" || synthetic && dropResult !== "removed" && dropResult !== "truncated") {
12855
+ reject(`drop_${dropResult}`);
12856
+ return;
12857
+ }
12858
+ if (dropResult === "removed" || dropResult === "truncated") {
12859
+ record(true);
12860
+ onTagReduced?.({
12861
+ tagNumber: pendingOp.tagId,
12862
+ mode: appliedMode === "full" ? "full" : "truncated"
12863
+ });
12864
+ } else {
12865
+ reject(`drop_${dropResult}`);
12866
+ record(false);
12867
+ }
12868
+ });
12869
+ }
12870
+ } else if (target) {
12871
+ const replacement = buildReplacementContent(pendingOp.tagId);
12872
+ if (target.canSetContent?.(replacement) === false) {
12873
+ reject("content_unchanged");
12874
+ continue;
12875
+ }
12876
+ persistDrop();
12877
+ mutations.push(() => {
12878
+ const priorContent = target.getContent?.();
12879
+ const changed = target.setContent(replacement);
12880
+ record(changed);
12881
+ if (changed) {
12882
+ const originalCharacters = typeof priorContent === "string" ? priorContent.length : tagById.get(pendingOp.tagId)?.byteSize ?? replacement.length;
12883
+ onTagReduced?.({
12884
+ tagNumber: pendingOp.tagId,
12885
+ mode: "partial",
12886
+ removedCharacters: Math.max(0, originalCharacters - replacement.length)
12887
+ });
12888
+ } else {
12889
+ reject("content_unchanged");
12890
+ }
12408
12891
  });
12409
- } else {
12410
- reject(`drop_${dropResult}`);
12892
+ } else if (!synthetic) {
12893
+ reject("target_absent");
12894
+ persistDrop();
12895
+ mutations.push(() => record(false));
12411
12896
  }
12412
- shouldPersistDrop = true;
12413
12897
  }
12414
- } else if (target) {
12415
- const replacement = buildReplacementContent(pendingOp.tagId);
12416
- const priorContent = target.getContent?.();
12417
- persistDrop();
12418
- const changed = target.setContent(replacement);
12419
- if (changed) {
12420
- didMutateMessage = true;
12421
- operationMutated = true;
12422
- const originalCharacters = typeof priorContent === "string" ? priorContent.length : tagById.get(pendingOp.tagId)?.byteSize ?? replacement.length;
12423
- onTagReduced?.({
12424
- tagNumber: pendingOp.tagId,
12425
- mode: "partial",
12426
- removedCharacters: Math.max(0, originalCharacters - replacement.length)
12427
- });
12428
- } else {
12429
- reject("content_unchanged");
12430
- }
12431
- shouldPersistDrop = true;
12432
- } else if (!synthetic) {
12433
- reject("target_absent");
12434
- persistDrop();
12435
- shouldPersistDrop = true;
12436
- }
12437
- if (!shouldPersistDrop) {
12438
- reject("not_persisted");
12439
- continue;
12440
- }
12441
- if (operationMutated)
12442
- diagnostics.mutated += 1;
12443
- else
12444
- diagnostics.persistedWithoutMutation += 1;
12898
+ };
12899
+ drainChunk();
12900
+ }).immediate();
12901
+ } catch (error) {
12902
+ if (!admitted && /database (?:table )?is locked|sqlite_(busy|locked)/i.test(String(error))) {
12903
+ sessionLog(sessionId, "pending operations write admission busy; retaining remaining operations for retry");
12904
+ hasMore = false;
12905
+ } else {
12906
+ throw error;
12445
12907
  }
12908
+ } finally {
12909
+ if (startedAt)
12910
+ logSlowWriteTransaction("apply_pending_operations", startedAt);
12446
12911
  }
12447
- } catch (error) {
12448
- if (!admitted && /database (?:table )?is locked|sqlite_(busy|locked)/i.test(String(error))) {
12449
- sessionLog(sessionId, "pending operations write admission busy; retaining prior bytes for retry");
12450
- return false;
12451
- }
12452
- throw error;
12453
- }
12912
+ for (const mutate of mutations.splice(0))
12913
+ mutate();
12914
+ } while (hasMore);
12454
12915
  if (diagnostics) {
12455
12916
  onBatchComplete?.(diagnostics);
12456
12917
  if (diagnostics.total > 0 && diagnostics.mutated === 0) {
@@ -12684,10 +13145,41 @@ function createExistingTagResolver(sessionId, tagger, db) {
12684
13145
  }
12685
13146
 
12686
13147
  // src/hooks/magic-context/transform-stage-logger.ts
12687
- function logTransformTiming(sessionId, stage, startMs, extra) {
12688
- const elapsed = (performance.now() - startMs).toFixed(1);
13148
+ import { AsyncLocalStorage } from "node:async_hooks";
13149
+ var SLOW_STAGE_MS = 100;
13150
+ var passes = new AsyncLocalStorage;
13151
+ async function withTransformTimingSummary(run) {
13152
+ const pass = {
13153
+ stages: [],
13154
+ slow: [],
13155
+ closed: false,
13156
+ sessionId: undefined
13157
+ };
13158
+ return passes.run(pass, async () => {
13159
+ try {
13160
+ return await run();
13161
+ } finally {
13162
+ pass.closed = true;
13163
+ if (pass.sessionId)
13164
+ sessionLog(pass.sessionId, `transform stages: ${pass.stages.join(" ")} slow>=${SLOW_STAGE_MS}ms=[${pass.slow.join(",")}]`);
13165
+ }
13166
+ });
13167
+ }
13168
+ function logTransformElapsed(sessionId, stage, elapsedMs, extra) {
13169
+ const elapsed = elapsedMs.toFixed(1);
12689
13170
  const suffix = extra ? ` ${extra}` : "";
12690
- sessionLog(sessionId, `transform stage: stage=${stage} elapsed=${elapsed}ms${suffix}`);
13171
+ const pass = passes.getStore();
13172
+ if (pass && !pass.closed) {
13173
+ pass.sessionId = sessionId;
13174
+ pass.stages.push(`${stage}=${elapsed}ms${extra ? `(${extra})` : ""}`);
13175
+ if (elapsedMs >= SLOW_STAGE_MS)
13176
+ pass.slow.push(stage);
13177
+ }
13178
+ if (elapsedMs >= SLOW_STAGE_MS)
13179
+ sessionLog(sessionId, `transform stage: stage=${stage} elapsed=${elapsed}ms${suffix}`);
13180
+ }
13181
+ function logTransformTiming(sessionId, stage, startMs, extra) {
13182
+ logTransformElapsed(sessionId, stage, performance.now() - startMs, extra);
12691
13183
  }
12692
13184
 
12693
13185
  // src/hooks/magic-context/tag-messages.ts
@@ -13065,13 +13557,19 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13065
13557
  }));
13066
13558
  accAssignTag += performance.now() - _tAssignText;
13067
13559
  const persistedSource = sourceContents.get(tagId);
13068
- if (persistedSource !== undefined) {
13069
- textPart.text = options.normalizeRestoredAssistantText && message.info.role === "assistant" ? options.normalizeRestoredAssistantText(persistedSource) : persistedSource;
13560
+ if (persistedSource !== undefined && !options.refreshSourceContents) {
13561
+ textPart.text = options.normalizeRestoredAssistantText && message.info.role === "assistant" ? options.normalizeRestoredAssistantText(persistedSource, message.info.providerID) : persistedSource;
13070
13562
  } else {
13071
13563
  const sourceContent = stripTagPrefix(textPart.text);
13072
- if (sourceContent.trim().length > 0) {
13564
+ if (sourceContent.trim().length > 0 || options.refreshSourceContents) {
13073
13565
  const _tSaveText = performance.now();
13074
- saveSourceContent(db, sessionId, tagId, sourceContent);
13566
+ if (options.refreshSourceContents) {
13567
+ db.transaction(() => {
13568
+ replaceSourceContent(db, sessionId, tagId, sourceContent);
13569
+ db.prepare("UPDATE tags SET byte_size = ?, token_count = ? WHERE session_id = ? AND tag_number = ?").run(byteSize(sourceContent), estimateTextTagTokenCount(sourceContent), sessionId, tagId);
13570
+ }).immediate();
13571
+ } else
13572
+ saveSourceContent(db, sessionId, tagId, sourceContent);
13075
13573
  accSaveSource += performance.now() - _tSaveText;
13076
13574
  }
13077
13575
  }
@@ -13090,6 +13588,7 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13090
13588
  dropReasoningParts: thinkingParts,
13091
13589
  mutationParts: [{ message, part: textPart }],
13092
13590
  textPrefix: skipPrefixInjection ? "" : prependTag(tagId, ""),
13591
+ canSetContent: (content) => textPart.text !== content,
13093
13592
  setContent: (content, options) => {
13094
13593
  if (textPart.text === content)
13095
13594
  return false;
@@ -13147,26 +13646,20 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13147
13646
  const filePart = part;
13148
13647
  const messageParts = message.parts;
13149
13648
  const contentId = `${messageId}:file${partIndex}`;
13150
- const existingTagId = resolver.resolve(messageId, "file", contentId, fileOrdinal);
13151
- const _tAssignFile = performance.now();
13152
- const tagId = existingTagId ?? tagger.assignTag(sessionId, contentId, "file", byteSize(filePart.url), db, 0, null, 0, null, () => ({
13153
- tokenCount: estimateTextTagTokenCount(filePart.url),
13154
- inputTokenCount: null,
13155
- reasoningTokenCount: null
13156
- }));
13157
- accAssignTag += performance.now() - _tAssignFile;
13158
- if (existingTagId === undefined) {
13159
- const sourceContent = buildFileSourceContent(message.parts);
13160
- if (sourceContent) {
13161
- const _tSaveFile = performance.now();
13162
- saveSourceContent(db, sessionId, tagId, sourceContent);
13163
- accSaveSource += performance.now() - _tSaveFile;
13164
- }
13165
- }
13649
+ const existingTagId = resolver.resolve(messageId, "file", contentId, fileOrdinal) ?? getTagNumberByMessageId(db, sessionId, contentId) ?? undefined;
13650
+ fileOrdinal += 1;
13651
+ if (existingTagId === undefined)
13652
+ continue;
13653
+ const tagId = existingTagId;
13654
+ tagger.bindTag(sessionId, contentId, tagId);
13166
13655
  messageTagNumbers.set(message, Math.max(messageTagNumbers.get(message) ?? 0, tagId));
13167
13656
  targets.set(tagId, {
13168
13657
  message,
13169
13658
  mutationParts: [{ message, part: filePart }],
13659
+ canSetContent: (content) => {
13660
+ const current = messageParts[partIndex];
13661
+ return !(typeof current === "object" && current !== null && ("text" in current) && current.text === content);
13662
+ },
13170
13663
  setContent: (content) => {
13171
13664
  const prev = messageParts[partIndex];
13172
13665
  const prevText = typeof prev === "object" && prev !== null && "text" in prev ? prev.text : "";
@@ -13179,7 +13672,6 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13179
13672
  return true;
13180
13673
  }
13181
13674
  });
13182
- fileOrdinal += 1;
13183
13675
  }
13184
13676
  }
13185
13677
  if (message.info.role === "assistant" && !messageHasTextPart) {
@@ -13208,6 +13700,23 @@ function tagMessages(sessionId, messages, tagger, db, options = {}) {
13208
13700
  normalizationTargets
13209
13701
  };
13210
13702
  }
13703
+ // src/features/magic-context/storage-host-instruction-retention.ts
13704
+ var NAMESPACE3 = "hostInstructionRetention";
13705
+ function isHostInstructionRetentionOn(db, sessionId) {
13706
+ const lane = readReplayEnvelope(db, sessionId)[NAMESPACE3];
13707
+ return typeof lane === "object" && lane !== null && lane.on === true;
13708
+ }
13709
+ function markHostInstructionRetention(db, sessionId) {
13710
+ return updateReplayDocument(db, sessionId, (doc) => {
13711
+ const lane = doc[NAMESPACE3];
13712
+ if (typeof lane === "object" && lane !== null && lane.on === true)
13713
+ return false;
13714
+ doc.version = 2;
13715
+ doc[NAMESPACE3] = { on: true };
13716
+ return true;
13717
+ });
13718
+ }
13719
+
13211
13720
  // src/hooks/magic-context/channel2-cycle.ts
13212
13721
  function rearmChannel2AfterCoverageAdvancingHardFold(input) {
13213
13722
  if (input.compactionOff || !input.foldExecuted || input.previousCoverage === null || input.currentCoverage === null || input.currentCoverage <= input.previousCoverage) {
@@ -13774,7 +14283,7 @@ function buildEditSupersessionReclaim(input) {
13774
14283
  seenFile.add(filePath);
13775
14284
  continue;
13776
14285
  }
13777
- if (input.recentMessageIds && (tag.toolOwnerMessageId === null || input.recentMessageIds.has(tag.toolOwnerMessageId))) {
14286
+ if (tag.tagNumber > input.watermark || input.recentMessageIds && (tag.toolOwnerMessageId === null || input.recentMessageIds.has(tag.toolOwnerMessageId))) {
13778
14287
  continue;
13779
14288
  }
13780
14289
  if (realPendingTagIds.has(tag.tagNumber))
@@ -13822,6 +14331,51 @@ async function waitForTagOwners(db, sessionId, ratio, _waitMs = 250) {
13822
14331
  return prewarmTagOwners(db, sessionId, ratio);
13823
14332
  }
13824
14333
 
14334
+ // src/shared/reclaim-distance.ts
14335
+ var RECLAIM_DISTANCE_USER_TURNS = 3;
14336
+ var RECLAIM_DISTANCE_WINDOW_FRACTION = 0.25;
14337
+ function isReclaimUserTurn(args) {
14338
+ return args.role === "user" && !args.syntheticHead && !args.synthetic && !args.ignored && args.parts.some((part) => {
14339
+ if (part.synthetic || part.ignored)
14340
+ return false;
14341
+ if (part.kind !== "text" && part.kind !== "image" && part.kind !== "file")
14342
+ return false;
14343
+ if (part.kind !== "text")
14344
+ return true;
14345
+ return stripReclaimMcText(part.text ?? "").trim().length > 0;
14346
+ });
14347
+ }
14348
+ function stripReclaimMcText(text) {
14349
+ return text.replace(/^§\d+§\s*/, "").replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, (reminder) => /^(?:Your next step: call ctx_reduce on the outputs you've already used|Still unstamped:|Housekeeping: .* are reclaimable\. Stamp each output with ctx_reduce|.* are reclaimable\. Make a ctx_reduce pass now|.* are still unstamped\. Call ctx_reduce now)/.test(reminder.slice("<system-reminder>".length).trimStart()) ? "" : reminder).replace(/<instruction name="deferred_notes">[\s\S]*?<\/instruction>/g, "");
14350
+ }
14351
+ function farBehindToolBookmark(entries, usableWindow) {
14352
+ let newerTurns = 0;
14353
+ let newerTokens = 0;
14354
+ const farTags = [];
14355
+ let firstYoungTag = Infinity;
14356
+ const seenOutputs = new Set;
14357
+ const tokenDistance = usableWindow > 0 && Number.isFinite(usableWindow) ? usableWindow * RECLAIM_DISTANCE_WINDOW_FRACTION : Infinity;
14358
+ for (let index = entries.length - 1;index >= 0; index--) {
14359
+ const entry = entries[index];
14360
+ if (!entry)
14361
+ continue;
14362
+ const tag = entry.toolOutputTag;
14363
+ if (tag !== undefined && !seenOutputs.has(tag)) {
14364
+ seenOutputs.add(tag);
14365
+ if (newerTurns >= RECLAIM_DISTANCE_USER_TURNS || newerTokens >= tokenDistance) {
14366
+ farTags.push(tag);
14367
+ } else {
14368
+ firstYoungTag = Math.min(firstYoungTag, tag);
14369
+ }
14370
+ }
14371
+ if (entry.userTurn)
14372
+ newerTurns++;
14373
+ if (Number.isFinite(entry.tokens) && entry.tokens > 0)
14374
+ newerTokens += entry.tokens;
14375
+ }
14376
+ return farTags.reduce((bookmark, tag) => tag < firstYoungTag ? Math.max(bookmark, tag) : bookmark, 0);
14377
+ }
14378
+
13825
14379
  // src/hooks/magic-context/tool-reclaim.ts
13826
14380
  function buildSyntheticToolReclaimOps(input) {
13827
14381
  const watermark = Math.max(0, input.watermark);
@@ -13853,10 +14407,74 @@ function buildSyntheticToolReclaimOps(input) {
13853
14407
  }
13854
14408
  return synthetic;
13855
14409
  }
13856
- function advanceToolReclaimWatermarkToCurrentMax(db, sessionId) {
13857
- const maxTagNumber = getMaxTagNumberBySession(db, sessionId);
13858
- advanceToolReclaimWatermark(db, sessionId, maxTagNumber);
13859
- return maxTagNumber;
14410
+ function advanceToolReclaimWatermarkByDistance(db, sessionId, entries, usableWindow) {
14411
+ const bookmark = farBehindToolBookmark(entries, usableWindow);
14412
+ advanceToolReclaimWatermark(db, sessionId, bookmark);
14413
+ return bookmark;
14414
+ }
14415
+ function toolReclaimDistanceEntries(messages, targets) {
14416
+ const outputTags = new Map;
14417
+ for (const [tag, target] of targets) {
14418
+ for (const location of target.mutationParts ?? []) {
14419
+ const part = distancePart(location.part);
14420
+ if (part.kind === "tool_result" || part.kind === "tool")
14421
+ outputTags.set(location.part, tag);
14422
+ }
14423
+ }
14424
+ const entries = [];
14425
+ for (const message of messages) {
14426
+ const parts = message.parts.map(distancePart);
14427
+ let userTurn = isReclaimUserTurn({ ...message.info, parts });
14428
+ for (const [index, part] of parts.entries()) {
14429
+ const authored = isReclaimUserTurn({ role: "user", parts: [part] });
14430
+ entries.push({
14431
+ tokens: message.info.syntheticHead ? 0 : estimateTokens(stripReclaimMcText(part.text ?? "")) + part.imageTokens,
14432
+ userTurn: userTurn && authored,
14433
+ toolOutputTag: outputTags.get(message.parts[index])
14434
+ });
14435
+ if (authored)
14436
+ userTurn = false;
14437
+ }
14438
+ }
14439
+ return entries;
14440
+ }
14441
+ function distancePart(raw) {
14442
+ if (!raw || typeof raw !== "object")
14443
+ return { kind: "structural", imageTokens: 0 };
14444
+ const part = raw;
14445
+ const provenance = { synthetic: part.synthetic === true, ignored: part.ignored === true };
14446
+ if (typeof part.getText === "function") {
14447
+ const text = part.getText();
14448
+ return {
14449
+ ...provenance,
14450
+ kind: String(part.kind),
14451
+ text: typeof text === "string" ? text : undefined,
14452
+ imageTokens: typeof part.imageTokens === "function" ? Number(part.imageTokens()) : 0
14453
+ };
14454
+ }
14455
+ const metadata = { ...provenance, imageTokens: estimatePartImageTokens(raw) };
14456
+ if (part.type === "tool") {
14457
+ const state = part.state;
14458
+ return {
14459
+ ...metadata,
14460
+ kind: "tool",
14461
+ text: `${JSON.stringify(state?.input ?? {})}
14462
+ ${typeof state?.output === "string" ? state.output : JSON.stringify(state?.output ?? "")}`
14463
+ };
14464
+ }
14465
+ if (part.type === "tool_use")
14466
+ return { ...metadata, kind: "tool_use", text: JSON.stringify(part.input ?? {}) };
14467
+ if (part.type === "tool_result")
14468
+ return {
14469
+ ...metadata,
14470
+ kind: "tool_result",
14471
+ text: typeof part.content === "string" ? part.content : JSON.stringify(part.content ?? "")
14472
+ };
14473
+ return {
14474
+ ...metadata,
14475
+ kind: String(part.type),
14476
+ text: typeof part.text === "string" ? part.text : typeof part.thinking === "string" ? part.thinking : undefined
14477
+ };
13860
14478
  }
13861
14479
 
13862
14480
  // src/hooks/magic-context/transform-postprocess-phase.ts
@@ -14012,6 +14630,28 @@ function freezeReasoningOnBustingPass(args) {
14012
14630
  sessionLog(args.sessionId, `proactive thinking strip: busting pass froze reasoning of ${messageIds.length} assistant(s) [${messageIds.join(",")}]`);
14013
14631
  return { strip: { messageIds }, persistenceFailed: false };
14014
14632
  }
14633
+ function servesThinkingBlock(messages) {
14634
+ for (const message of messages) {
14635
+ if (message.info.role !== "assistant")
14636
+ continue;
14637
+ for (const part of message.parts) {
14638
+ if (!isRecord(part) || part.ignored === true)
14639
+ continue;
14640
+ if (part.type === "redacted_thinking")
14641
+ return true;
14642
+ if (part.type !== "reasoning" && part.type !== "thinking")
14643
+ continue;
14644
+ const anthropic = isRecord(part.metadata) ? part.metadata.anthropic : undefined;
14645
+ if (!isRecord(anthropic))
14646
+ continue;
14647
+ if (anthropic.redactedData !== undefined)
14648
+ return true;
14649
+ if (typeof part.text === "string" && part.text !== "")
14650
+ return true;
14651
+ }
14652
+ }
14653
+ return false;
14654
+ }
14015
14655
  function dropMarkerSummaryTag(db, sessionId, summaryMessageId) {
14016
14656
  const tagNumber = getTagNumberByMessageId(db, sessionId, `${summaryMessageId}:p0`);
14017
14657
  if (tagNumber !== null)
@@ -14175,7 +14815,7 @@ function finalizeMessageRepresentation(messages, resolvedProviderID, options) {
14175
14815
  clearedParts = stripClearedReasoning(targetedMessages.filter((message) => !restoredMessages.has(message)));
14176
14816
  }
14177
14817
  }
14178
- const bindingRecoveryParts = options?.skipMergedReasoningStrip ? 0 : stripReasoningFromAssistantIds(messages, resolvedProviderID, options?.frozenThinkingBindingMessageIds ?? new Set, restoredMessages);
14818
+ const bindingRecoveryParts = stripReasoningFromAssistantIds(messages, resolvedProviderID, options?.frozenThinkingBindingMessageIds ?? new Set, restoredMessages);
14179
14819
  const mergedReasoningParts = bindingRecoveryParts + (options?.skipMergedReasoningStrip ? 0 : stripReasoningFromMergedAssistants(messages, resolvedProviderID, {
14180
14820
  mutationExemptMessage: options?.reasoningMutationExemptMessage,
14181
14821
  frozenMessageIds: options?.mergedReasoningStrippedIds,
@@ -14187,6 +14827,25 @@ function finalizeMessageRepresentation(messages, resolvedProviderID, options) {
14187
14827
  }
14188
14828
  return { clearedParts, mergedReasoningParts };
14189
14829
  }
14830
+ function legacyPublishedHeadChanged(args) {
14831
+ if (!args.pendingCompartmentInjection || !args.readLastServedMessages)
14832
+ return false;
14833
+ const served = args.readLastServedMessages();
14834
+ if (served === null)
14835
+ return true;
14836
+ const previous = served[0];
14837
+ if (!Array.isArray(previous?.parts) || !args.pendingCompartmentInjection)
14838
+ return false;
14839
+ const text = previous.parts.find((part) => typeof part === "object" && part !== null && ("type" in part) && part.type === "text" && ("text" in part))?.text;
14840
+ if (typeof text !== "string")
14841
+ return false;
14842
+ const block = `<session-history>
14843
+ ${args.pendingCompartmentInjection.block}
14844
+ </session-history>`;
14845
+ return text !== block && !text.startsWith(`${block}
14846
+
14847
+ `);
14848
+ }
14190
14849
  async function runPostTransformPhase(args) {
14191
14850
  const tPostprocessSetup = performance.now();
14192
14851
  const compactionOff = args.compactionOff === true;
@@ -14233,7 +14892,7 @@ async function runPostTransformPhase(args) {
14233
14892
  let deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
14234
14893
  let materializationRequested = isExplicitFlush || deferredMaterialize;
14235
14894
  const m0M1EnabledForFold = args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory) && (args.fullFeatureMode || compactionOff);
14236
- const frozenThinking = new Set(args.activeThinkingTurn ? getMergedReasoningStrippedIds(args.db, args.sessionId) : []);
14895
+ const frozenThinking = new Set(getMergedReasoningStrippedIds(args.db, args.sessionId));
14237
14896
  const bindingThinking = new Set([...frozenThinking].filter((id) => id.startsWith(THINKING_BINDING_RECOVERY_FROZEN_PREFIX)).map((id) => id.slice(THINKING_BINDING_RECOVERY_FROZEN_PREFIX.length)));
14238
14897
  const retainedThinking = args.activeThinkingTurn ? retainedActiveThinkingParts({
14239
14898
  messages: args.messages,
@@ -14259,6 +14918,7 @@ async function runPostTransformPhase(args) {
14259
14918
  let freezeM0M1 = args.freezeM0M1 === true || activeThinkingPrefixHold;
14260
14919
  let rewritingSignedPrefix = false;
14261
14920
  let thinkingReleasedForFit = false;
14921
+ let thinkingOmissionPersistenceFailed = false;
14262
14922
  const releaseThinkingForRewrite = (forFit = false) => {
14263
14923
  const stripped = freezeReasoningOnBustingPass({
14264
14924
  db: args.db,
@@ -14266,8 +14926,12 @@ async function runPostTransformPhase(args) {
14266
14926
  messages: args.messages,
14267
14927
  alreadyFrozen: bindingThinking
14268
14928
  });
14269
- if (stripped.persistenceFailed)
14929
+ if (stripped.persistenceFailed) {
14930
+ thinkingOmissionPersistenceFailed = true;
14270
14931
  throw new Error("Cannot persist signed thinking omission before prefix rewrite");
14932
+ }
14933
+ for (const id of stripped.strip?.messageIds ?? [])
14934
+ bindingThinking.add(id);
14271
14935
  retainedThinking.clear();
14272
14936
  protectedThinkingMessages.clear();
14273
14937
  activeThinkingTurn = false;
@@ -14277,6 +14941,9 @@ async function runPostTransformPhase(args) {
14277
14941
  rewritingSignedPrefix = true;
14278
14942
  thinkingReleasedForFit ||= forFit;
14279
14943
  };
14944
+ if (args.compactionModeTransition && args.thinkingBindingRecoveryEnabledForModel) {
14945
+ releaseThinkingForRewrite();
14946
+ }
14280
14947
  const foldDueDecision = m0M1EnabledForFold && args.m0M1 && !freezeM0M1 ? mustMaterialize({
14281
14948
  db: args.db,
14282
14949
  sessionId: args.sessionId,
@@ -14312,6 +14979,8 @@ async function runPostTransformPhase(args) {
14312
14979
  };
14313
14980
  if ((foldDueDecision.value || softRefreshOpportunity || firstRenderBust && activeThinkingPrefixHold) && m0M1EnabledForFold && args.m0M1) {
14314
14981
  let committedFoldBustsServedPrefix;
14982
+ let committedFoldChangesHead = false;
14983
+ let committedFoldThinkingIds = [];
14315
14984
  try {
14316
14985
  const previousM1 = args.sessionMeta.cachedM1Bytes?.toString("utf8");
14317
14986
  const foldResult = injectM0M1({
@@ -14338,6 +15007,24 @@ async function runPostTransformPhase(args) {
14338
15007
  m0Text: rendered.m0Bytes.toString(),
14339
15008
  m1Text: rendered.m1Bytes.toString()
14340
15009
  }) : foldBustsServedPrefix(foldDueDecision.reason, servedPrefixBeforeFold, rendered);
15010
+ committedFoldChangesHead = firstRenderBust ? !servedPrefixMatches({
15011
+ messages: servedBeforeFirstRender,
15012
+ m0Text: rendered.m0Bytes.toString(),
15013
+ m1Text: rendered.m1Bytes.toString()
15014
+ }) : foldChangesServedPrefix(servedPrefixBeforeFold, rendered);
15015
+ if (args.thinkingBindingRecoveryEnabledForModel && (compactionOff && !activeThinkingPrefixHold && committedFoldChangesHead || activeThinkingPrefixHold && firstRenderBust && bustsPrefix)) {
15016
+ const omission = freezeReasoningOnBustingPass({
15017
+ db,
15018
+ sessionId: args.sessionId,
15019
+ messages: args.messages,
15020
+ alreadyFrozen: bindingThinking
15021
+ });
15022
+ if (omission.persistenceFailed) {
15023
+ thinkingOmissionPersistenceFailed = true;
15024
+ throw new Error("Cannot persist signed thinking omission before prefix rewrite");
15025
+ }
15026
+ committedFoldThinkingIds = omission.strip?.messageIds ?? [];
15027
+ }
14341
15028
  if (bustsPrefix) {
14342
15029
  if (!conversions.isCurrent(db)) {
14343
15030
  throw new MaterializeContentionError({
@@ -14354,7 +15041,13 @@ async function runPostTransformPhase(args) {
14354
15041
  }
14355
15042
  });
14356
15043
  preparedPrefix = foldResult;
14357
- if (activeThinkingPrefixHold && firstRenderBust && committedFoldBustsServedPrefix) {
15044
+ if (foldResult.m0RematerializedThisPass) {
15045
+ for (const id of committedFoldThinkingIds)
15046
+ bindingThinking.add(id);
15047
+ }
15048
+ if (foldResult.m0RematerializedThisPass && activeThinkingPrefixHold && firstRenderBust && committedFoldBustsServedPrefix) {
15049
+ releaseThinkingForRewrite();
15050
+ } else if (compactionOff && foldResult.m0RematerializedThisPass && !activeThinkingPrefixHold && args.thinkingBindingRecoveryEnabledForModel && committedFoldChangesHead) {
14358
15051
  releaseThinkingForRewrite();
14359
15052
  }
14360
15053
  prefixPreflightFailed = foldResult.materializationContentionRetryExhausted === true;
@@ -14383,6 +15076,8 @@ async function runPostTransformPhase(args) {
14383
15076
  sessionLog(args.sessionId, "channel2 fold-cycle reset failed (ignored):", error);
14384
15077
  }
14385
15078
  } catch (error) {
15079
+ if (thinkingOmissionPersistenceFailed)
15080
+ throw error;
14386
15081
  preparedPrefix = cachedPrefixBeforePreflight;
14387
15082
  prefixPreflightFailed = true;
14388
15083
  failPass("m0-m1-fold-preexecution-degradation", error);
@@ -14390,11 +15085,6 @@ async function runPostTransformPhase(args) {
14390
15085
  }
14391
15086
  sessionLog(args.sessionId, `m[0] HARD fold decision: reason=${m0MaterializeReason ?? foldDueDecision.reason ?? (foldExecutedThisPass ? "drift" : "soft_refresh")} executed=${foldExecutedThisPass} bustsServedPrefix=${foldBustsServedPrefixThisPass}`);
14392
15087
  }
14393
- if (args.normalizeRecoveryTail && (foldBustsServedPrefixThisPass || firstRenderBust)) {
14394
- args.normalizeRecoveryTail();
14395
- args.tags = getTagsBySession(args.db, args.sessionId);
14396
- newTargets = protectNewTagMutations(args.messages, args.targets, retainedThinking, args.thinkingBindingRecoveryEnabledForModel === true);
14397
- }
14398
15088
  logTransformTiming(args.sessionId, "pp.prefixPreflight", tPostprocessSetup, `foldExecuted=${foldExecutedThisPass} m1Refreshed=${publishedM1RefreshedThisPass}`);
14399
15089
  const tPassDecisions = performance.now();
14400
15090
  const frontToolCandidates = args.tags.filter((tag) => tag.type === "tool" && tag.status === "active" && args.targets.get(tag.tagNumber)?.canDrop?.());
@@ -14421,13 +15111,19 @@ async function runPostTransformPhase(args) {
14421
15111
  subagentExecute: !args.fullFeatureMode && args.schedulerDecision === "execute",
14422
15112
  hardFold: foldBustsServedPrefixThisPass || firstRenderBust || idleExpiryRebuild,
14423
15113
  force: emergencyDropEligible && (args.contextUsage.percentage >= 95 || getEmergencyInputSample(args.db, args.sessionId) === 0),
14424
- explicitFlush: isExplicitFlush || deferredMaterialize && !prefixPreflightFailed,
14425
- publishedHistory: publishedM1RefreshedThisPass || !m0M1EnabledForFold && (args.pendingCompartmentInjection?.compartmentCount ?? 0) > 0 && (args.historyRebuiltThisPass || args.rebuiltHistoryFromInitialPrepare || args.canConsumeDeferredLate && args.deferredHistoryWasPendingAtPassStart)
15114
+ explicitFlush: isExplicitFlush && hasPendingMaterializationOrigin(args.pendingMaterializationSessions, args.sessionId, "user_flush"),
15115
+ publishedHistory: !prefixPreflightFailed && (publishedM1RefreshedThisPass || !m0M1EnabledForFold && (args.pendingCompartmentInjection?.compartmentCount ?? 0) > 0 && legacyPublishedHeadChanged(args))
14426
15116
  };
14427
15117
  const publishedWorkDrainAllowed = !compactionOff && (!activeThinkingPrefixHold || firstRenderBust || idleExpiryRebuild || emergencyDropEligible) && hasReclaimRide(rideSignals);
14428
15118
  const shouldApplyPendingOps = publishedWorkDrainAllowed;
14429
15119
  const shouldRunHeuristics = !compactionOff && publishedWorkDrainAllowed && (rideSignals.publishedHistory || materializationRequested || forceMaterialization || foldBustsServedPrefixThisPass || firstRenderBust || heldIdleExpiryRebuild || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
14430
15120
  const isCacheBustingPass = publishedWorkDrainAllowed;
15121
+ if (args.normalizeRecoveryTail && isCacheBustingPass) {
15122
+ args.normalizeRecoveryTail();
15123
+ args.tags = getTagsBySession(args.db, args.sessionId);
15124
+ newTargets = protectNewTagMutations(args.messages, args.targets, retainedThinking, args.thinkingBindingRecoveryEnabledForModel === true);
15125
+ }
15126
+ const reclaimDistance = isCacheBustingPass ? toolReclaimDistanceEntries(args.messages, args.targets) : [];
14431
15127
  const canEditWholePrefix = isCacheBustingPass && !activeThinkingPrefixHold;
14432
15128
  const previousTemporalDecisions = args.temporalCandidates && !compactionOff ? new Map([
14433
15129
  ...args.temporalObservedDecisions ?? [],
@@ -14499,17 +15195,28 @@ async function runPostTransformPhase(args) {
14499
15195
  throw new EmergencyFailClosedError("Magic Context could not read its saved reasoning-removal state for this session", { cause: error });
14500
15196
  }
14501
15197
  }
15198
+ const heuristicsLogChanged = diagnosticStateChanged(args.sessionId, "heuristics", JSON.stringify([
15199
+ args.currentTurnId,
15200
+ shouldRunHeuristics,
15201
+ shouldRunHeuristics ? null : args.schedulerDeferReason
15202
+ ]));
15203
+ const pendingLogChanged = diagnosticStateChanged(args.sessionId, "pending-ops", JSON.stringify([
15204
+ args.currentTurnId,
15205
+ shouldApplyPendingOps,
15206
+ shouldApplyPendingOps ? null : args.schedulerDeferReason,
15207
+ shouldApplyPendingOps ? null : (getPendingOpsCount(args.db, args.sessionId) ?? 0) > 0
15208
+ ]));
14502
15209
  if (shouldRunHeuristics) {
14503
15210
  const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
14504
15211
  const reason = isExplicitFlush ? `pending_materialization origin=${pendingOrigin}` : deferredMaterialize ? "deferred_materialization" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : foldBustsServedPrefixThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into executed m[0] bust, scheduler=${args.schedulerDecision})` : subagentRerun ? `${reclaimRideLabel(rideSignals)} subagent_rerun (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})` : `${reclaimRideLabel(rideSignals)} (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
14505
15212
  sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=${args.currentTurnId}`);
14506
- } else if (args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
15213
+ } else if (heuristicsLogChanged && args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
14507
15214
  sessionLog(args.sessionId, `heuristics WILL NOT RUN — reason=${args.schedulerDeferReason}`);
14508
15215
  }
14509
15216
  if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !materializationRequested && args.fullFeatureMode) {
14510
15217
  sessionLog(args.sessionId, `transform: skipping heuristics (already ran for turn ${args.currentTurnId})`);
14511
15218
  }
14512
- if (!shouldApplyPendingOps && args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
15219
+ if (!shouldApplyPendingOps && pendingLogChanged && args.schedulerDeferReason !== undefined && args.schedulerDeferReason !== null) {
14513
15220
  sessionLog(args.sessionId, `pending ops WILL NOT APPLY — reason=${args.schedulerDeferReason} pendingOps=${formatPendingOpsDepth()} context=${args.contextUsage.percentage.toFixed(1)}%`);
14514
15221
  }
14515
15222
  if (hasPendingUserOps && !shouldApplyPendingOps) {
@@ -14570,7 +15277,7 @@ async function runPostTransformPhase(args) {
14570
15277
  pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, newTargets, new Set([
14571
15278
  ...args.contextUsage.percentage >= 95 ? [] : args.protectedTagIds,
14572
15279
  ...protectedToolTags
14573
- ]), undefined, pendingOps, [], new Set, (reduction) => droppedTokenReductions.push(reduction));
15280
+ ]), undefined, pendingOps, [], new Set, (reduction) => droppedTokenReductions.push(reduction), undefined, args.onPendingDropEligibility);
14574
15281
  if (pendingOpsDidMutate) {
14575
15282
  droppedCount += pendingOps.length;
14576
15283
  for (const pendingOp of pendingOps) {
@@ -14773,6 +15480,7 @@ async function runPostTransformPhase(args) {
14773
15480
  }
14774
15481
  }
14775
15482
  const editReclaim = buildEditSupersessionReclaim({
15483
+ watermark: args.sessionMeta.toolReclaimWatermark ?? 0,
14776
15484
  db: args.db,
14777
15485
  sessionId: args.sessionId,
14778
15486
  targets: newTargets,
@@ -14811,7 +15519,7 @@ async function runPostTransformPhase(args) {
14811
15519
  const tBatchFinalize = performance.now();
14812
15520
  args.batch?.finalize();
14813
15521
  if (toolReclaimApplicationOpportunity) {
14814
- const maxTagNumber = advanceToolReclaimWatermarkToCurrentMax(args.db, args.sessionId);
15522
+ const maxTagNumber = advanceToolReclaimWatermarkByDistance(args.db, args.sessionId, reclaimDistance, args.usableWindow);
14815
15523
  args.sessionMeta.toolReclaimWatermark = Math.max(args.sessionMeta.toolReclaimWatermark ?? 0, maxTagNumber);
14816
15524
  }
14817
15525
  if (autoReclaimTargetCount > 0) {
@@ -14895,6 +15603,30 @@ async function runPostTransformPhase(args) {
14895
15603
  }
14896
15604
  }
14897
15605
  const m0M1Enabled = m0M1EnabledForFold;
15606
+ let retainCoveredInstructions = false;
15607
+ if (m0M1Enabled && args.m0M1 && !compactionOff && args.hostInstructionRows) {
15608
+ const covered = args.coveredHostInstructions ?? [];
15609
+ if (covered.length > 0 || canEditWholePrefix) {
15610
+ let retain = false;
15611
+ try {
15612
+ retain = isHostInstructionRetentionOn(args.db, args.sessionId);
15613
+ } catch (error) {
15614
+ failPass("host-instruction-retention-read-failure", error);
15615
+ }
15616
+ if (!retain && canEditWholePrefix) {
15617
+ let written = false;
15618
+ try {
15619
+ written = markHostInstructionRetention(args.db, args.sessionId);
15620
+ } catch (error) {
15621
+ failPass("host-instruction-retention-persistence-failure", error);
15622
+ }
15623
+ if (!written)
15624
+ failPass("host-instruction-retention-persistence-failure");
15625
+ retain = true;
15626
+ }
15627
+ retainCoveredInstructions = retain;
15628
+ }
15629
+ }
14898
15630
  if (m0M1Enabled && args.m0M1) {
14899
15631
  if (freezeM0M1 && !preparedPrefix) {
14900
15632
  preparedPrefix = prepareCachedM0M1Replay(args.db, args.sessionId);
@@ -14922,6 +15654,17 @@ async function runPostTransformPhase(args) {
14922
15654
  compactionOff
14923
15655
  });
14924
15656
  deliveredPrefix = result;
15657
+ if (retainCoveredInstructions) {
15658
+ const retained = new Set(args.messages);
15659
+ const covered = [...args.coveredHostInstructions ?? []];
15660
+ for (const message of messagesBeforeInjection) {
15661
+ if (!retained.has(message) && isHostRenderedSystemMessage(message)) {
15662
+ markCoveredInstructionRow(message.info);
15663
+ covered.push(message);
15664
+ }
15665
+ }
15666
+ args.messages.splice(result.prependedMessageCount, 0, ...covered);
15667
+ }
14925
15668
  if (result.prefixTrimStatus === "applied") {
14926
15669
  const retainedMessages = new Set(args.messages);
14927
15670
  const trimmedMessageIds = messagesBeforeInjection.filter((message) => !retainedMessages.has(message)).map((message) => message.info.id).filter((id) => typeof id === "string");
@@ -15192,7 +15935,7 @@ async function runPostTransformPhase(args) {
15192
15935
  }
15193
15936
  }
15194
15937
  const mergedReasoningStrippedIds = new Set(replaySnapshot?.mergedReasoningStrippedIds ?? []);
15195
- const thinkingBindingRecoveryMessageIds = new Set;
15938
+ const thinkingBindingRecoveryMessageIds = new Set(bindingThinking);
15196
15939
  let thinkingBindingRecovery = null;
15197
15940
  let proactiveThinkingStrip = null;
15198
15941
  if (!compactionOff) {
@@ -15444,6 +16187,7 @@ async function runPostTransformPhase(args) {
15444
16187
  const hygieneCalibration = sessionDecisionCalibration(args.db, args.sessionId);
15445
16188
  const hygieneUnitsVersion = transitionSessionHygieneUnits(args.db, args.sessionId, bustedThisPass, hygieneCalibration);
15446
16189
  const baseline = refreshTailHygieneBaseline({
16190
+ opencode2: args.opencode2,
15447
16191
  messages: args.messages,
15448
16192
  tags,
15449
16193
  protectedTagNumbers: args.protectedTagNumbers,
@@ -15459,7 +16203,7 @@ async function runPostTransformPhase(args) {
15459
16203
  sessionLog(args.sessionId, formatTailHygienePrefixMismatch(baseline.lastPrefixMismatch, baseline.baselineGeneration));
15460
16204
  }
15461
16205
  const tTailState = performance.now();
15462
- const structuralSignature = tailHygieneStructuralSignature(args.messages);
16206
+ const structuralSignature = tailHygieneStructuralSignature(args.messages, args.opencode2);
15463
16207
  const effective = effectiveTailHygiene(baseline);
15464
16208
  const durableGrace = baseline.evaluable && !baseline.generationInvalidated ? captureChannel1PostReduceGraceBaseline(args.db, args.sessionId, effective.u) : getChannel1NudgeState(args.db, args.sessionId);
15465
16209
  baseline.channel1PostReduceGrace = durableGrace.postReduceGracePending || durableGrace.postReduceGraceBaselineU !== undefined ? {
@@ -15471,7 +16215,7 @@ async function runPostTransformPhase(args) {
15471
16215
  ...baseline,
15472
16216
  usableWindow: args.usableWindow,
15473
16217
  realUserTurnCount: countRealUserMessages(args.messages),
15474
- reducedSinceRefresh: baseline.baselineGeneration !== previous?.baselineGeneration ? false : previous?.reducedSinceRefresh ?? false,
16218
+ reducedSinceRefresh: baseline.baselineGeneration !== previous?.baselineGeneration || (previous?.generationInvalidated === true || previous?.evaluable === false) && baseline.evaluable && !baseline.generationInvalidated ? false : previous?.reducedSinceRefresh ?? false,
15475
16219
  agentDropsAppliedThisPass: pendingOpsDidMutate,
15476
16220
  oldestReclaimableToolTags: postprocessOldestTags(args.db, args.sessionId, args.protectedTagNumbers)
15477
16221
  });
@@ -15509,7 +16253,7 @@ async function runPostTransformPhase(args) {
15509
16253
  const tTailGuard = performance.now();
15510
16254
  if (assertedBaseline) {
15511
16255
  try {
15512
- const servedSignature = tailHygieneStructuralSignature(args.messages);
16256
+ const servedSignature = tailHygieneStructuralSignature(args.messages, args.opencode2);
15513
16257
  if (!sameTailHygieneStructuralSignature(assertedBaseline.structuralSignature, servedSignature)) {
15514
16258
  sessionLog(args.sessionId, `ERROR [tail-hygiene-last-writer-mismatch]: served messages changed after tail-hygiene baseline refresh (expected messages=${assertedBaseline.structuralSignature.messageCount}, parts=[${assertedBaseline.structuralSignature.partCounts.join(",")}], bytes=${assertedBaseline.structuralSignature.totalBytes}; actual messages=${servedSignature.messageCount}, parts=[${servedSignature.partCounts.join(",")}], bytes=${servedSignature.totalBytes})`);
15515
16259
  }
@@ -15517,6 +16261,7 @@ async function runPostTransformPhase(args) {
15517
16261
  sessionLog(args.sessionId, "ERROR [tail-hygiene-last-writer-check-failed]: structural production guard failed open:", error);
15518
16262
  }
15519
16263
  assertTailHygieneContentUnchangedIfEnabled({
16264
+ opencode2: args.opencode2,
15520
16265
  messages: args.messages,
15521
16266
  tags: assertedBaseline.tags,
15522
16267
  protectedTagNumbers: assertedBaseline.protectedTagNumbers,
@@ -15584,15 +16329,27 @@ class UnmanagedOverWindowError extends Error {
15584
16329
  }
15585
16330
 
15586
16331
  // src/hooks/magic-context/unresolved-history-boundary.ts
16332
+ function storedHistoryBoundaryPresence(db, sessionId) {
16333
+ try {
16334
+ const row = db.prepare("SELECT cached_m0_last_baseline_end_message_id AS id FROM session_meta WHERE session_id = ?").get(sessionId);
16335
+ return row?.id ? hasRawSessionMessageById2(sessionId, row.id) : undefined;
16336
+ } catch {
16337
+ return;
16338
+ }
16339
+ }
16340
+
15587
16341
  class UnresolvedHistoryBoundaryError extends Error {
15588
16342
  estimatedTokens;
15589
16343
  contextLimitTokens;
16344
+ boundaryPresent;
15590
16345
  code = "UNRESOLVED_HISTORY_BOUNDARY";
15591
16346
  recoverable = true;
15592
- constructor(estimatedTokens, contextLimitTokens) {
15593
- super(renderUserFacingFailure("history_boundary_unresolved", "plain"));
16347
+ constructor(estimatedTokens, contextLimitTokens, boundaryPresent) {
16348
+ const reason = boundaryPresent === true ? "The boundary row is present in the host store but out of order relative to the loaded history. " : boundaryPresent === false ? "The boundary row is missing from the host store. " : "";
16349
+ super(reason + renderUserFacingFailure("history_boundary_unresolved", "plain"));
15594
16350
  this.estimatedTokens = estimatedTokens;
15595
16351
  this.contextLimitTokens = contextLimitTokens;
16352
+ this.boundaryPresent = boundaryPresent;
15596
16353
  this.name = "UnresolvedHistoryBoundaryError";
15597
16354
  }
15598
16355
  }
@@ -15676,13 +16433,16 @@ function resolveTransformHostSeams(deps) {
15676
16433
  };
15677
16434
  }
15678
16435
  function createTransform(deps) {
16436
+ const pendingDropEligibility = createPendingDropEligibilityCache();
15679
16437
  registerSystemDateRefresh(deps.historyRefreshSessions);
15680
16438
  const finalWireUsage = createFinalWireUsageTracker();
15681
16439
  const host = resolveTransformHostSeams(deps);
15682
16440
  const loadedSessions = new Set;
15683
16441
  const prefixHoldLogTurnIds = new Map;
15684
16442
  const thinkingFitRetries = new Set;
16443
+ const compactionModeTransitionPending = new Set;
15685
16444
  const clearSessionLogState = (sessionId) => {
16445
+ clearDiagnosticLogState(sessionId);
15686
16446
  prefixHoldLogTurnIds.delete(sessionId);
15687
16447
  };
15688
16448
  const unmanagedOverWindowSessions = new Set;
@@ -15703,7 +16463,8 @@ function createTransform(deps) {
15703
16463
  const startTime = performance.now();
15704
16464
  const historianRun = deps.resolveHistorianRun?.();
15705
16465
  const messages = output.messages;
15706
- const originalForThinkingFit = messages.some((message) => message.parts.some((part) => isRecord(part) && ["reasoning", "thinking", "redacted_thinking"].includes(String(part.type)))) ? structuredClone(messages) : null;
16466
+ const originalForThinkingFit = messages.some((message) => message.parts.some((part) => isRecord(part) && ["reasoning", "thinking", "redacted_thinking"].includes(String(part.type)))) ? cloneKeepingCoveredInstructionMarks(messages) : null;
16467
+ const coveredHostInstructions = takeCoveredInstructionRows(messages);
15707
16468
  const passOutcome = createPassOutcome();
15708
16469
  const tSessionId = performance.now();
15709
16470
  const sessionId = findSessionId(messages);
@@ -15726,7 +16487,7 @@ function createTransform(deps) {
15726
16487
  return historianRun?.toastDurationMs === undefined ? params : { ...params, toastDurationMs: historianRun.toastDurationMs };
15727
16488
  };
15728
16489
  beginLkgPass(sessionId);
15729
- clearOpenCodePendingTransformDecision(sessionId);
16490
+ clearOpenCodePendingTransformDecision(sessionId, messages);
15730
16491
  const db = deps.db;
15731
16492
  try {
15732
16493
  const tPrepare = performance.now();
@@ -15801,6 +16562,7 @@ function createTransform(deps) {
15801
16562
  const hasTransitionEffects = transition.recordToWrite !== null || transition.notice !== null || transition.invalidatedM0Baseline || transition.clearedCompartmentInProgress || transition.historianCatchUpSignaled;
15802
16563
  if (hasTransitionEffects) {
15803
16564
  if (transition.invalidatedM0Baseline) {
16565
+ compactionModeTransitionPending.add(sessionId);
15804
16566
  sessionMeta = {
15805
16567
  ...sessionMeta,
15806
16568
  cachedM0Bytes: null,
@@ -16080,9 +16842,10 @@ function createTransform(deps) {
16080
16842
  const persistedUsageFreshForBoundary = persistedUsageBeforeResets && Date.now() - persistedUsageBeforeResets.updatedAt <= 10 * 60 * 1000 && (persistedUsageBeforeResets.lastObservedModelKey === null || currentModelKeyForBoundary === undefined || piModelRefToCanonical(persistedUsageBeforeResets.lastObservedModelKey) === piModelRefToCanonical(currentModelKeyForBoundary)) && (resolvedContextLimit === undefined || persistedUsageBeforeResets.lastUsageContextLimit === 0 || persistedUsageBeforeResets.lastUsageContextLimit === resolvedContextLimit) ? persistedUsageBeforeResets.usage : null;
16081
16843
  const boundaryUsageForProtectedTail = persistedUsageFreshForBoundary ?? contextUsageEarly;
16082
16844
  const boundaryUsageSource = persistedUsageFreshForBoundary ? "persisted" : "live";
16083
- const historyPolicyIdentity = historyBudgetPolicyIdentity(deps.historyBudgetPercentage, deps.executeThresholdPercentage, currentModelKeyForBoundary, deps.executeThresholdTokens);
16084
16845
  const historyContextLimit = resolvedContextLimit ?? (currentModelKeyForBoundary && persistedUsageBeforeResets?.lastObservedModelKey && piModelRefToCanonical(currentModelKeyForBoundary) === piModelRefToCanonical(persistedUsageBeforeResets.lastObservedModelKey) && persistedUsageBeforeResets.lastUsageContextLimit > 0 ? persistedUsageBeforeResets.lastUsageContextLimit : undefined);
16085
- const historyBudgetTokens = resolveHistoryBudgetTokens(deps.historyBudgetPercentage, contextUsageEarly, deps.executeThresholdPercentage, deps.getModelKey?.(sessionId), deps.executeThresholdTokens, historyContextLimit);
16846
+ const memoryProjectDirectory = compartmentDirectory || process.cwd();
16847
+ const renderOptions = createM0RenderOptions(deps, contextUsageEarly, currentModelKeyForBoundary, historyContextLimit, deps.memoryConfig?.enabled ? resolveProjectIdentityForSession(memoryProjectDirectory, deps.allowHomeProject) : undefined);
16848
+ const { historyBudgetTokens, projectPath: projectIdentity } = renderOptions;
16086
16849
  const emergencyCeilingLimit = thresholdContextLimit ?? 0;
16087
16850
  const emergencyCeilingTokens = Number.isFinite(emergencyCeilingLimit) && emergencyCeilingLimit > 0 ? Math.floor(emergencyCeilingLimit * (effectiveExecuteThresholdPercentage / 100)) : undefined;
16088
16851
  const schedulerDecision = compactionOff ? "defer" : resolveSchedulerDecision(deps.scheduler, sessionMeta, contextUsageEarly, sessionId, deps.getModelKey?.(sessionId), resolvedContextLimit);
@@ -16215,8 +16978,6 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16215
16978
  });
16216
16979
  }
16217
16980
  logTransformTiming(sessionId, "emergencyRecoveryBlock", tFirstPass);
16218
- const memoryProjectDirectory = compartmentDirectory || process.cwd();
16219
- const projectIdentity = deps.memoryConfig?.enabled ? resolveProjectIdentityForSession(memoryProjectDirectory, deps.allowHomeProject) : undefined;
16220
16981
  if (deps.memoryConfig?.enabled) {
16221
16982
  maybeSendProjectIdentityWarning(deps, sessionId, memoryProjectDirectory, notificationParams);
16222
16983
  }
@@ -16230,13 +16991,26 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16230
16991
  recordedSessionProjectIdentity.set(sessionId, sessionIdentityForBinding);
16231
16992
  }
16232
16993
  const taggerFloor = compactionOff ? 0 : deriveTaggerLoadFloor(messages, sessionId, db);
16233
- if (!compactionOff && taggerFloor === 0 && messages.length > 0) {
16234
- sessionLog(sessionId, `tag floor: 0 (full-scan fallback) — no leading wire message resolved a tag across ${messages.length} msgs`);
16994
+ const tagFloorMode = compactionOff || messages.length === 0 ? "inactive" : taggerFloor === 0 ? "fallback" : "scoped";
16995
+ if (diagnosticStateChanged(sessionId, "tag-floor", tagFloorMode) && tagFloorMode !== "inactive") {
16996
+ sessionLog(sessionId, taggerFloor === 0 ? `tag floor: 0 (full-scan fallback) — no scoped floor above the safety margin across ${messages.length} msgs` : `tag floor: ${taggerFloor} (scoped load)`);
16235
16997
  }
16236
16998
  const ownerRatio = sessionDecisionCalibration(db, sessionId).proseRatio;
16237
16999
  prewarmTagOwners(db, sessionId, ownerRatio);
16238
17000
  const tagOwnersReady = isTagOwnerSummaryReady(db, sessionId, ownerRatio);
16239
17001
  let triggerBoundarySnapshot;
17002
+ const dropProjectionEmergency = contextUsageEarly.percentage >= 95;
17003
+ const dropProjectionKey = () => pendingDropEligibilityKey(db, sessionId, lkgInput, {
17004
+ currentTurnId,
17005
+ model: modelForBudget,
17006
+ protectedTokens: deps.protectedTokens,
17007
+ protectedTokenTierOverrides: deps.protectedTokenTierOverrides,
17008
+ protectedTools: deps.protectedTools,
17009
+ keepReasoningTokens: deps.keepReasoningTokens,
17010
+ usableSoft: windowGeometry?.usableSoft ?? boundaryContextLimit,
17011
+ emergency: dropProjectionEmergency,
17012
+ clearedReasoningThroughTag: sessionMeta?.clearedReasoningThroughTag
17013
+ });
16240
17014
  if (fullFeatureMode && !compactionOff && historianRunnable && tagOwnersReady && !sessionMeta.compartmentInProgress) {
16241
17015
  const tTrigger = performance.now();
16242
17016
  try {
@@ -16249,7 +17023,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16249
17023
  force: contextUsageEarly.percentage >= forceMaterializationPercentage && (contextUsageEarly.percentage >= 95 || getEmergencyInputSample(db, sessionId) === 0),
16250
17024
  explicitFlush: deps.pendingMaterializationSessions.has(sessionId),
16251
17025
  publishedHistory: isCacheBusting
16252
- });
17026
+ }, pendingDropEligibility.read(sessionId, dropProjectionKey()));
16253
17027
  if (triggerResult.shouldFire) {
16254
17028
  sessionLog(sessionId, `compartment trigger: firing (reason=${triggerResult.reason})`);
16255
17029
  updateSessionMeta(db, sessionId, { compartmentInProgress: true });
@@ -16257,8 +17031,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16257
17031
  triggerBoundarySnapshot = triggerResult.boundarySnapshot;
16258
17032
  }
16259
17033
  } catch (error) {
16260
- passOutcome.record("compartment-trigger-failure");
16261
- sessionLog(sessionId, "compartment trigger failed (non-fatal):", error);
17034
+ recordCompartmentTriggerError(passOutcome, sessionId, error);
16262
17035
  }
16263
17036
  logTransformTiming(sessionId, "compartmentTrigger", tTrigger);
16264
17037
  }
@@ -16269,7 +17042,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16269
17042
  const messagesBeforeInitialPrepare = isCacheBusting && deferredHistoryWasPendingAtPassStart ? [...messages] : null;
16270
17043
  if (fullFeatureMode && !compactionOff) {
16271
17044
  const tInj = performance.now();
16272
- pendingCompartmentInjection = prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectIdentity, deps.memoryConfig?.injectionBudgetTokens, deps.experimentalTemporalAwareness);
17045
+ pendingCompartmentInjection = prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, projectIdentity, deps.memoryConfig?.injectionBudgetTokens, deps.experimentalTemporalAwareness, coveredHostInstructions);
16273
17046
  if (messagesBeforeInitialPrepare) {
16274
17047
  const skippedVisibleMessages = pendingCompartmentInjection?.skippedVisibleMessages ?? 0;
16275
17048
  trimmedMessagesAtCompactionBoundary = messagesBeforeInitialPrepare.slice(0, skippedVisibleMessages);
@@ -16299,6 +17072,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16299
17072
  logTransformTiming(sessionId, "injectTemporalMarkers", tTemporal);
16300
17073
  }
16301
17074
  let taggingSucceeded = false;
17075
+ const refreshSourceContents = deps.storeGeneration === "v2" && fullFeatureMode && !compactionOff && !!(projectIdentity || sessionDirectory) && !unresolvedDirectoryHold && !recovery.prefix && sessionMeta.cachedM0Bytes == null && sessionMeta.cachedM1Bytes == null && deps.refreshSourceContents?.(sessionId) === true;
16302
17076
  let recoveryBatch = null;
16303
17077
  let recoveryNormalized = false;
16304
17078
  const normalizeRecoveryTail = recovery.prefix ? () => {
@@ -16334,7 +17108,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16334
17108
  scopedToolSweep,
16335
17109
  servedMessages: messages,
16336
17110
  protectedThinkingMessages: protectedThinkingMessagesForPass,
16337
- normalizeRestoredAssistantText: deps.normalizeRestoredAssistantText
17111
+ normalizeRestoredAssistantText: deps.normalizeRestoredAssistantText,
17112
+ refreshSourceContents
16338
17113
  });
16339
17114
  targets = result.targets;
16340
17115
  if (thinkingRecovery.restore)
@@ -16415,6 +17190,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16415
17190
  const rawGetNotifParams = runNotificationParams;
16416
17191
  const tCompartmentPhase = performance.now();
16417
17192
  const compartmentPhase = await runCompartmentPhase({
17193
+ coveredHostInstructions,
16418
17194
  hiddenCompletionExecutor: deps.hiddenCompletionExecutor,
16419
17195
  compactionMarkerStrategy: deps.compactionMarkerStrategy,
16420
17196
  canRunCompartments,
@@ -16498,12 +17274,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16498
17274
  db,
16499
17275
  sessionId,
16500
17276
  state: sessionMeta,
16501
- projectPath: projectIdentity,
16502
17277
  projectDirectory: sessionDirectory,
16503
- memoryEnabled: deps.memoryConfig?.enabled,
16504
- memoryInjectionBudgetTokens: deps.memoryConfig?.injectionBudgetTokens,
16505
- historyBudgetTokens,
16506
- historyBudgetPolicyIdentity: historyPolicyIdentity,
17278
+ ...renderOptions,
16507
17279
  hardSignals: m0HardSignals
16508
17280
  }).value;
16509
17281
  const protectionCacheBustingPass = !compactionOff && (schedulerDecision === "execute" || isCacheBusting || contextUsage.percentage >= forceMaterializationPercentage || deps.pendingMaterializationSessions.has(sessionId) || canConsumeDeferredLate && deferredMaterializationSessions.has(sessionId) || protectionFoldWillBust);
@@ -16585,6 +17357,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16585
17357
  fullFeatureMode,
16586
17358
  compactionOff,
16587
17359
  canRunCompartments,
17360
+ hostInstructionRows: deps.storeGeneration === "v2",
16588
17361
  awaitedCompartmentRun,
16589
17362
  phaseJustAwaitedPublication: compartmentPhase.justAwaitedPublication,
16590
17363
  compartmentInProgress,
@@ -16593,6 +17366,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16593
17366
  activeThinkingPrefixHold,
16594
17367
  directoryPrefixHold: unresolvedDirectoryHold,
16595
17368
  forceSignedRebuildForFit: thinkingFitRetries.has(sessionId) || !!recovery.rebuildReason,
17369
+ compactionModeTransition: compactionModeTransitionPending.has(sessionId),
16596
17370
  readLastServedMessages: () => {
16597
17371
  const slot = getInMemorySlot(sessionId) ?? loadPersistedLkgSlot(db, sessionId);
16598
17372
  try {
@@ -16615,12 +17389,14 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16615
17389
  keepReasoningTokens: resolveKeepReasoningTokens(deps.keepReasoningTokens, currentModelKeyForBoundary),
16616
17390
  resolvedModelID: modelForBudget?.modelID,
16617
17391
  protectedTagIds,
17392
+ onPendingDropEligibility: (eligible) => pendingDropEligibility.record(sessionId, dropProjectionKey(), eligible),
16618
17393
  protectedTagNumbers,
16619
17394
  protectedCutoff,
16620
17395
  protectedCount: protectionWindow.status.protectedCount,
16621
17396
  emergencyCeilingTokens,
16622
17397
  pendingCompartmentInjection,
16623
17398
  prefixTrimSourceOrder,
17399
+ coveredHostInstructions,
16624
17400
  hiddenMessagesAtCompactionSeam,
16625
17401
  trimmedMessagesAtCompactionBoundary,
16626
17402
  didMutateFromFlushedStatuses,
@@ -16642,13 +17418,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16642
17418
  passOutcome,
16643
17419
  historyRefreshSessions: deps.historyRefreshSessions,
16644
17420
  m0M1: {
16645
- projectPath: projectIdentity,
16646
17421
  projectDirectory: sessionDirectory,
16647
- memoryEnabled: deps.memoryConfig?.enabled,
16648
- memoryInjectionBudgetTokens: deps.memoryConfig?.injectionBudgetTokens,
16649
- historyBudgetTokens,
16650
- historyBudgetPolicyIdentity: historyPolicyIdentity,
16651
- temporalAwareness: deps.experimentalTemporalAwareness,
17422
+ ...renderOptions,
16652
17423
  hardSignals: m0HardSignals
16653
17424
  }
16654
17425
  });
@@ -16716,7 +17487,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16716
17487
  });
16717
17488
  if (untrimmed.tokens > boundaryContextLimit) {
16718
17489
  sessionLog(sessionId, `history boundary unresolved: prefix trim refused and the untrimmed request estimate ${untrimmed.tokens} (trusted=${untrimmed.trusted}) exceeds the context limit ${boundaryContextLimit}; not sending it`);
16719
- throw new UnresolvedHistoryBoundaryError(untrimmed.tokens, boundaryContextLimit);
17490
+ throw new UnresolvedHistoryBoundaryError(untrimmed.tokens, boundaryContextLimit, storedHistoryBoundaryPresence(db, sessionId));
16720
17491
  }
16721
17492
  }
16722
17493
  if (unmanagedOverWindowPass) {
@@ -16820,7 +17591,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16820
17591
  if (!finalWireEstimate) {
16821
17592
  sessionLog(sessionId, `transform: final-wire telemetry estimate=unavailable trusted=false conversation=unknown tools=unknown system=unknown toolDefinitions=unknown tail=${finalWireTail}`);
16822
17593
  }
16823
- finishSystemDateRefresh(deps.historyRefreshSessions, dateRequest, postTransformResult.bustedThisPass && !activeThinkingPrefixHold || postTransformResult.thinkingReleasedForFit === true);
17594
+ const signedThinkingServed = isPrefixBoundThinkingModel(modelForBudget?.providerID, modelForBudget?.modelID) && servesThinkingBlock(messages);
17595
+ finishSystemDateRefresh(deps.historyRefreshSessions, dateRequest, postTransformResult.bustedThisPass && !activeThinkingPrefixHold && !signedThinkingServed || postTransformResult.thinkingReleasedForFit === true, signedThinkingServed);
17596
+ compactionModeTransitionPending.delete(sessionId);
16824
17597
  if (activeThinkingPrefixHold && !postTransformResult.thinkingReleasedForFit && sessionMeta.cachedM0Bytes != null && sessionMeta.cachedM1Bytes != null) {
16825
17598
  recordHeldHeadForRequest(sessionId, currentLkgRequestIdentity(sessionId), (ownsHistory) => deferDeliveredSystemRefresh(deps, sessionId, ownsHistory));
16826
17599
  }
@@ -16893,6 +17666,24 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16893
17666
  bustedThisPass: true,
16894
17667
  lkgFrozenReleaseReason: recoveryReleaseReason
16895
17668
  });
17669
+ } else {
17670
+ noteOpenCodeUnbustedPass(sessionId, {
17671
+ tsMs: Date.now(),
17672
+ decision: schedulerDecision,
17673
+ materialized: postTransformResult.materialized,
17674
+ materializeReason: normalizeMaterializeReason("opencode", postTransformResult.materializeReason, postTransformResult.materialized),
17675
+ systemHashPrev: postTransformResult.systemHashPrev,
17676
+ systemHashNew: postTransformResult.systemHashNew,
17677
+ m0ToolSetHashPrev: postTransformResult.m0ToolSetHashPrev,
17678
+ m0ToolSetHashNew: postTransformResult.m0ToolSetHashNew,
17679
+ m0ModelKeyPrev: postTransformResult.m0ModelKeyPrev,
17680
+ m0ModelKeyNew: postTransformResult.m0ModelKeyNew,
17681
+ emergency: postTransformResult.emergency,
17682
+ droppedTokens: postTransformResult.droppedTokens,
17683
+ droppedCount: postTransformResult.droppedCount,
17684
+ inputTokens: contextUsage.inputTokens,
17685
+ bustedThisPass: false
17686
+ });
16896
17687
  }
16897
17688
  logTransformTiming(sessionId, "postTransformPhase", tPostProcess);
16898
17689
  const msgTokens = getMessageTokensCache(sessionId);
@@ -16904,6 +17695,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16904
17695
  if (uncachedMessageIds.length > 0) {
16905
17696
  try {
16906
17697
  storedByMessage = getActiveTagTokenTotalsByMessage(db, sessionId, uncachedMessageIds);
17698
+ omitIncompleteFileTokenTotals(db, sessionId, messages.flatMap((message) => typeof message.info.id === "string" ? [{ id: message.info.id, parts: message.parts }] : []), storedByMessage);
16907
17699
  } catch {
16908
17700
  storedByMessage = new Map;
16909
17701
  }
@@ -16960,7 +17752,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16960
17752
  postReduceGraceBaselineU: channel1State.postReduceGraceBaselineU,
16961
17753
  postReduceGracePreLevel: channel1State.postReduceGracePreLevel
16962
17754
  });
16963
- sessionLog(sessionId, formatChannel1Evaluation(channel1Decision));
17755
+ logNudgeEvaluation(sessionId, "transform", formatChannel1Evaluation(channel1Decision));
16964
17756
  const channel2Evaluation = evaluateChannel2(channelBaseline);
16965
17757
  const leaseBefore = getChannel2NudgeState(db, sessionId);
16966
17758
  if (channelBaseline.evaluable && !channelBaseline.generationInvalidated && !channelBaseline.reducedSinceRefresh) {
@@ -16971,7 +17763,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
16971
17763
  }
16972
17764
  }
16973
17765
  const leaseAfter = getChannel2NudgeState(db, sessionId);
16974
- sessionLog(sessionId, formatChannel2Evaluation(channel2Evaluation, {
17766
+ logNudgeEvaluation(sessionId, "transform", formatChannel2Evaluation(channel2Evaluation, {
16975
17767
  leaseBefore,
16976
17768
  leaseAfter,
16977
17769
  gateHoldReason: channelBaseline.reducedSinceRefresh ? "recent-reduce-refresh" : undefined
@@ -17010,7 +17802,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
17010
17802
  sessionLog(sessionId, "memory maintenance launch probe failed (ignored):", error);
17011
17803
  }
17012
17804
  };
17013
- return Object.assign(transform, {
17805
+ const timedTransform = (input, output) => withTransformTimingSummary(() => transform(input, output));
17806
+ return Object.assign(timedTransform, {
17014
17807
  clearSessionLogState(sessionId) {
17015
17808
  clearSessionLogState(sessionId);
17016
17809
  }
@@ -17047,11 +17840,19 @@ function clearMaintenanceSystemSnapshot(sessionId) {
17047
17840
  function readMaintenanceSystemSnapshot(sessionId) {
17048
17841
  return maintenanceSystemSnapshotBySession.get(sessionId);
17049
17842
  }
17843
+ var maintenanceModelUnconfiguredNoted = new Set;
17844
+ function noteMaintenanceModelUnconfigured(projectPath, sessionId) {
17845
+ if (maintenanceModelUnconfiguredNoted.has(projectPath))
17846
+ return;
17847
+ maintenanceModelUnconfiguredNoted.add(projectPath);
17848
+ sessionLog(sessionId, "memory maintenance skipped: neither maintenance.model nor historian.model is configured (set either in the user-level mmc config; the session model is never inherited)");
17849
+ }
17050
17850
  function createMaintenanceTailLauncher(deps) {
17051
17851
  const buildLauncher = (projectPath) => (deps.launcherFactory ?? ((db, path) => getMaintenanceLauncher(db, path, {
17052
17852
  getConfig: () => ({
17053
17853
  maintenance: {
17054
- enabled: deps.getMaintenanceConfig?.()?.enabled ?? false
17854
+ enabled: deps.getMaintenanceConfig?.()?.enabled ?? false,
17855
+ model: deps.getMaintenanceConfig?.()?.model
17055
17856
  }
17056
17857
  }),
17057
17858
  runFactory: (signals) => {
@@ -17089,6 +17890,10 @@ function createMaintenanceTailLauncher(deps) {
17089
17890
  return;
17090
17891
  if (!deps.hiddenCompletionExecutor)
17091
17892
  return;
17893
+ if (!hasMaintenancePrimary(maintenance)) {
17894
+ noteMaintenanceModelUnconfigured(projectPath, input.sessionId);
17895
+ return;
17896
+ }
17092
17897
  const poolCount = countMaintenancePool(deps.db, projectPath);
17093
17898
  const hostSystemText = readMaintenanceSystemSnapshot(input.sessionId);
17094
17899
  buildLauncher(projectPath).maybeLaunch({
@@ -17102,29 +17907,10 @@ function createMaintenanceTailLauncher(deps) {
17102
17907
  ...hostSystemText === undefined ? {} : { hostSystemText }
17103
17908
  });
17104
17909
  } catch (error) {
17105
- sessionLog(input.sessionId, "memory maintenance probe failed (ignored):", error);
17106
- }
17107
- }
17108
- };
17109
- }
17110
- function resolveHistoryBudgetTokens(historyBudgetPercentage, contextUsage, executeThresholdPercentage, modelKey, executeThresholdTokens, resolvedContextLimit) {
17111
- if (!historyBudgetPercentage) {
17112
- return;
17113
- }
17114
- let contextLimit = resolvedContextLimit && resolvedContextLimit > 0 ? resolvedContextLimit : 0;
17115
- if (contextLimit <= 0) {
17116
- if (contextUsage.percentage <= 0) {
17117
- return;
17910
+ sessionLog(input.sessionId, "memory maintenance probe failed (ignored):", error);
17911
+ }
17118
17912
  }
17119
- contextLimit = contextUsage.inputTokens / (contextUsage.percentage / 100);
17120
- }
17121
- if (!Number.isFinite(contextLimit) || contextLimit <= 0) {
17122
- return;
17123
- }
17124
- return Math.floor(contextLimit * (resolveExecuteThreshold(executeThresholdPercentage ?? 65, modelKey, 65, {
17125
- tokensConfig: executeThresholdTokens,
17126
- contextLimit
17127
- }) / 100) * historyBudgetPercentage);
17913
+ };
17128
17914
  }
17129
17915
 
17130
17916
  // src/plugin/rpc-handlers.ts
@@ -17376,6 +18162,7 @@ function runManualMaintenanceCommand(args) {
17376
18162
  }
17377
18163
  const explanations = {
17378
18164
  "maintenance-disabled": "memory maintenance is disabled (maintenance.enabled: false)",
18165
+ "maintenance-model-unconfigured": "memory maintenance has no primary model configured — set maintenance.model in the user-level mmc config (fallback_models alone does not enable maintenance; the chain never inherits the historian or session model)",
17379
18166
  "run-in-flight-local": "a maintenance run is already in flight; next_due_at is due now, so the launcher retries on the next pass",
17380
18167
  "empty-pool": "memory pool is empty (no active/permanent rows) — nothing to maintain"
17381
18168
  };
@@ -18261,7 +19048,7 @@ function registerRpcHandlers(rpcServer, args) {
18261
19048
  });
18262
19049
  const buildManagedCtx = async (db) => {
18263
19050
  const { deriveHistorianChunkTokens, resolveHistorianContextLimit } = await import("./derive-budgets-s1p37t2g.js");
18264
- const { resolveHistorianModel } = await import("./model-resolution-wazv26n0.js");
19051
+ const { resolveHistorianModel } = await import("./model-resolution-cvyrrcjw.js");
18265
19052
  const DEFAULT_HISTORIAN_TIMEOUT_MS = 600000;
18266
19053
  const runConfig = historianRunConfig(config, currentPluginConfigReader(directory)?.poll().effective ?? config);
18267
19054
  const historianModel = resolveHistorianModel(runConfig, "opencode");
@@ -18290,8 +19077,8 @@ function registerRpcHandlers(rpcServer, args) {
18290
19077
  const db = readDatabase();
18291
19078
  if (!db)
18292
19079
  return { ok: false, error: "db unavailable" };
18293
- const { runManagedRecomp } = await import("./recomp-orchestrator-wrjy3qym.js");
18294
- const { sendIgnoredMessage } = await import("./send-session-notification-cz6ev088.js");
19080
+ const { runManagedRecomp } = await import("./recomp-orchestrator-mmpy5cb7.js");
19081
+ const { sendIgnoredMessage } = await import("./send-session-notification-zpqs213d.js");
18295
19082
  log(`[rpc] recomp requested for session ${sessionId}`);
18296
19083
  if (!args.client && !args.hiddenCompletionExecutor) {
18297
19084
  return {
@@ -18340,7 +19127,7 @@ function registerRpcHandlers(rpcServer, args) {
18340
19127
  const db = readDatabase();
18341
19128
  if (!db)
18342
19129
  return { ok: false, error: "db unavailable" };
18343
- const { runManagedWrapup } = await import("./wrapup-orchestrator-bmybc5p5.js");
19130
+ const { runManagedWrapup } = await import("./wrapup-orchestrator-jq589pgr.js");
18344
19131
  const model = liveSessionState.liveModelBySession.get(sessionId);
18345
19132
  const contextLimit = model ? resolveContextLimit(model.providerID, model.modelID, { db, sessionID: sessionId }) : 128000;
18346
19133
  const ctx = {
@@ -18372,11 +19159,14 @@ function registerRpcHandlers(rpcServer, args) {
18372
19159
  const raw = String(params.subcommand ?? "status").toLowerCase();
18373
19160
  const action = raw === "run" || raw === "resume" ? raw : "status";
18374
19161
  if (action === "run") {
18375
- const maintenance = config.maintenance;
19162
+ const maintenance = inheritMaintenanceModelConfig(config);
18376
19163
  const hostSystemText = readMaintenanceSystemSnapshot(sessionId);
18377
19164
  const launcher = getMaintenanceLauncher(db, projectPath, {
18378
19165
  getConfig: () => ({
18379
- maintenance: { enabled: maintenance?.enabled ?? false }
19166
+ maintenance: {
19167
+ enabled: maintenance?.enabled ?? false,
19168
+ model: maintenance?.model
19169
+ }
18380
19170
  }),
18381
19171
  nowMs: Date.now,
18382
19172
  runFactory: createOc2MaintenanceRunFactory({
@@ -18384,7 +19174,7 @@ function registerRpcHandlers(rpcServer, args) {
18384
19174
  projectPath,
18385
19175
  executor: args.hiddenCompletionExecutor,
18386
19176
  config: () => {
18387
- const slice = config.maintenance;
19177
+ const slice = inheritMaintenanceModelConfig(config);
18388
19178
  if (!slice) {
18389
19179
  throw new Error("memory maintenance config unavailable");
18390
19180
  }
@@ -18425,8 +19215,17 @@ function subagentToolRefusal(db, toolId, sessionId, isInternalChild = () => fals
18425
19215
  function hideSubagentTools(draft, db) {
18426
19216
  if (!getOrCreateSessionMeta(db, draft.sessionID).isSubagent)
18427
19217
  return;
19218
+ removePrimaryOnlyTools(draft.tools);
19219
+ }
19220
+ function removePrimaryOnlyTools(tools) {
18428
19221
  for (const id of PRIMARY_ONLY_TOOLS)
18429
- delete draft.tools[id];
19222
+ delete tools[id];
19223
+ }
19224
+ function storedSubagentMode(db, sessionId) {
19225
+ const row = db.prepare("SELECT is_subagent FROM session_meta WHERE session_id = ?").get(sessionId);
19226
+ if (!row || typeof row.is_subagent !== "number")
19227
+ return;
19228
+ return row.is_subagent === 1;
18430
19229
  }
18431
19230
 
18432
19231
  // src/shared/conflict-detector.ts
@@ -18684,7 +19483,58 @@ function readOmoDisabledHooks(directory) {
18684
19483
 
18685
19484
  // src/shared/rpc-server.ts
18686
19485
  import { randomBytes, timingSafeEqual } from "node:crypto";
18687
- import { readdirSync, readFileSync as readFileSync6, unlinkSync } from "node:fs";
19486
+ import { readdirSync, readFileSync as readFileSync6, rmdirSync, unlinkSync } from "node:fs";
19487
+
19488
+ // src/shared/rpc-discovery-cleanup.ts
19489
+ import { promises as fs } from "node:fs";
19490
+ import { join as join4 } from "node:path";
19491
+ async function reapDeadRpcDiscovery(storageDir) {
19492
+ const root = join4(storageDir, "rpc");
19493
+ let directories;
19494
+ try {
19495
+ directories = await fs.readdir(root, { withFileTypes: true });
19496
+ } catch {
19497
+ return;
19498
+ }
19499
+ const records = [];
19500
+ const projectDirs = [];
19501
+ for (const entry of directories) {
19502
+ if (!entry.isDirectory() || !/^[0-9a-f]{16}$/.test(entry.name))
19503
+ continue;
19504
+ const directory = join4(root, entry.name);
19505
+ projectDirs.push(directory);
19506
+ try {
19507
+ for (const name of await fs.readdir(directory)) {
19508
+ const match = /^port-(\d+)(?:-[0-9a-f]+)?\.json$/.exec(name);
19509
+ if (!match)
19510
+ continue;
19511
+ const path = join4(directory, name);
19512
+ try {
19513
+ const content = await fs.readFile(path, "utf8");
19514
+ const record = parseRpcPortFile(content, Number(match[1]));
19515
+ if (record && record.pid === Number(match[1]))
19516
+ records.push({ path, content, pid: record.pid });
19517
+ } catch {}
19518
+ }
19519
+ } catch {}
19520
+ }
19521
+ const processes = records.length ? await inspectProcessesAsync(true) : undefined;
19522
+ for (const record of records) {
19523
+ if (processes?.liveness(record.pid) !== "dead")
19524
+ continue;
19525
+ try {
19526
+ if (await fs.readFile(record.path, "utf8") === record.content)
19527
+ await fs.unlink(record.path);
19528
+ } catch {}
19529
+ }
19530
+ for (const directory of projectDirs) {
19531
+ try {
19532
+ await fs.rmdir(directory);
19533
+ } catch {}
19534
+ }
19535
+ }
19536
+
19537
+ // src/shared/rpc-server.ts
18688
19538
  var MAX_BODY_BYTES = 1048576;
18689
19539
  var WS_AUTH_TIMEOUT_MS = 5000;
18690
19540
  var WS_CLOSE_UNAUTHORIZED = 4401;
@@ -18707,17 +19557,20 @@ function websocketToken(req) {
18707
19557
  }
18708
19558
 
18709
19559
  class MagicContextRpcServer {
19560
+ storageDir;
18710
19561
  server = null;
18711
19562
  port = 0;
18712
19563
  handlers = new Map;
18713
19564
  portFilePath;
18714
19565
  portDir;
18715
19566
  startedAt = Date.now();
19567
+ stopped = false;
18716
19568
  instanceId = randomBytes(8).toString("hex");
18717
19569
  unregisterOwnInstance = null;
18718
19570
  sockets = new Set;
18719
19571
  token = randomBytes(32).toString("hex");
18720
19572
  constructor(storageDir, directory) {
19573
+ this.storageDir = storageDir;
18721
19574
  this.portFilePath = rpcPortFilePath(storageDir, directory, process.pid, this.instanceId);
18722
19575
  this.portDir = rpcPortDir(storageDir, directory);
18723
19576
  }
@@ -18735,6 +19588,10 @@ class MagicContextRpcServer {
18735
19588
  log("rpc server skipped: Bun runtime not available (no TUI consumer)");
18736
19589
  return 0;
18737
19590
  }
19591
+ this.stopped = false;
19592
+ await reapDeadRpcDiscovery(this.storageDir);
19593
+ if (this.stopped)
19594
+ return 0;
18738
19595
  this.startedAt = Date.now();
18739
19596
  const self = this;
18740
19597
  const server = Bun.serve({
@@ -18766,7 +19623,7 @@ class MagicContextRpcServer {
18766
19623
  try {
18767
19624
  this.warnIfOtherLiveInstance();
18768
19625
  this.unregisterOwnInstance ??= registerOwnRpcServerInstance(this.instanceId);
18769
- writeStorageFileAtomicSync(this.portFilePath, JSON.stringify({
19626
+ const publish = () => writeStorageFileAtomicSync(this.portFilePath, JSON.stringify({
18770
19627
  port: this.port,
18771
19628
  pid: process.pid,
18772
19629
  started_at: this.startedAt,
@@ -18774,6 +19631,13 @@ class MagicContextRpcServer {
18774
19631
  token: this.token,
18775
19632
  instance_id: this.instanceId
18776
19633
  }));
19634
+ try {
19635
+ publish();
19636
+ } catch (error) {
19637
+ if (error.code !== "ENOENT")
19638
+ throw error;
19639
+ publish();
19640
+ }
18777
19641
  log(`[rpc] server listening on 127.0.0.1:${this.port}`);
18778
19642
  } catch (err) {
18779
19643
  log(`[rpc] failed to write port file: ${err}`);
@@ -18781,6 +19645,7 @@ class MagicContextRpcServer {
18781
19645
  return this.port;
18782
19646
  }
18783
19647
  stop() {
19648
+ this.stopped = true;
18784
19649
  for (const ws of this.sockets) {
18785
19650
  try {
18786
19651
  if (ws.data.authTimer)
@@ -18797,6 +19662,9 @@ class MagicContextRpcServer {
18797
19662
  try {
18798
19663
  unlinkSync(this.portFilePath);
18799
19664
  } catch {}
19665
+ try {
19666
+ rmdirSync(this.portDir);
19667
+ } catch {}
18800
19668
  this.unregisterOwnInstance?.();
18801
19669
  this.unregisterOwnInstance = null;
18802
19670
  }
@@ -19153,8 +20021,8 @@ var v2CompactionMarkerStrategy = {
19153
20021
  import { randomUUID as randomUUID2 } from "node:crypto";
19154
20022
 
19155
20023
  // src/v2/fold/owner.ts
19156
- import { createHash as createHash4 } from "node:crypto";
19157
- var foldDigest = (value) => createHash4("sha256").update(value).digest("hex");
20024
+ import { createHash as createHash3 } from "node:crypto";
20025
+ var foldDigest = (value) => createHash3("sha256").update(value).digest("hex");
19158
20026
 
19159
20027
  class FoldOwner {
19160
20028
  storage;
@@ -19530,18 +20398,56 @@ function containsHostInstance(value) {
19530
20398
  return false;
19531
20399
  }
19532
20400
  function clonePreservingInstances(value) {
19533
- if (isHostInstance(value))
20401
+ return cloneCounting(value, undefined);
20402
+ }
20403
+ function clonePreservingInstancesMeasured(value) {
20404
+ const meter = { bytes: 0 };
20405
+ const copy = cloneCounting(value, meter);
20406
+ return { copy, bytes: meter.bytes };
20407
+ }
20408
+ function cloneCounting(value, meter) {
20409
+ if (isHostInstance(value)) {
20410
+ if (meter)
20411
+ meter.bytes += instanceBytes(value, new WeakSet);
19534
20412
  return value;
19535
- if (Array.isArray(value))
19536
- return value.map(clonePreservingInstances);
20413
+ }
20414
+ if (Array.isArray(value)) {
20415
+ if (meter)
20416
+ meter.bytes += 16 + 8 * value.length;
20417
+ return value.map((entry) => cloneCounting(entry, meter));
20418
+ }
19537
20419
  if (value && typeof value === "object") {
19538
20420
  const copy = {};
19539
- for (const [key, entry] of Object.entries(value))
19540
- copy[key] = clonePreservingInstances(entry);
20421
+ if (meter)
20422
+ meter.bytes += 32;
20423
+ for (const [key, entry] of Object.entries(value)) {
20424
+ if (meter)
20425
+ meter.bytes += 16;
20426
+ copy[key] = cloneCounting(entry, meter);
20427
+ }
19541
20428
  return copy;
19542
20429
  }
20430
+ if (meter)
20431
+ meter.bytes += typeof value === "string" ? 2 * value.length : 8;
19543
20432
  return value;
19544
20433
  }
20434
+ function instanceBytes(value, seen) {
20435
+ if (typeof value === "string")
20436
+ return 2 * value.length;
20437
+ if (!value || typeof value !== "object")
20438
+ return 8;
20439
+ if (seen.has(value))
20440
+ return 0;
20441
+ seen.add(value);
20442
+ if (ArrayBuffer.isView(value))
20443
+ return value.byteLength;
20444
+ if (value instanceof ArrayBuffer)
20445
+ return value.byteLength;
20446
+ let bytes = 32;
20447
+ for (const entry of Object.values(value))
20448
+ bytes += 16 + instanceBytes(entry, seen);
20449
+ return bytes;
20450
+ }
19545
20451
  function contentKey(value) {
19546
20452
  const plain = (entry) => {
19547
20453
  if (ArrayBuffer.isView(entry)) {
@@ -19597,7 +20503,7 @@ function rebuildFileContent(value, output, attachments) {
19597
20503
  rebuilt.unshift({ type: "text", text: output });
19598
20504
  return { type: "content", value: rebuilt };
19599
20505
  }
19600
- function adaptPayload(draft, admittedIDs = new Set) {
20506
+ function adaptPayload(draft, admittedIDs = new Set, messageTimes = new Map, hiddenTimes = false) {
19601
20507
  const existingHeads = new Map(draft.messages.filter((m) => HEAD_IDS.some((id) => m.id === id)).map((m) => [m.id, m]));
19602
20508
  const source = draft.messages.filter((m) => !existingHeads.has(m.id));
19603
20509
  const results = new Map;
@@ -19707,6 +20613,7 @@ function adaptPayload(draft, admittedIDs = new Set) {
19707
20613
  id: message.id,
19708
20614
  sessionID: draft.sessionID,
19709
20615
  role: message.role,
20616
+ time: message.id ? messageTimes.get(message.id) : undefined,
19710
20617
  ...{
19711
20618
  providerID: draft.model.providerID,
19712
20619
  modelID: draft.model.id,
@@ -19715,7 +20622,19 @@ function adaptPayload(draft, admittedIDs = new Set) {
19715
20622
  },
19716
20623
  parts
19717
20624
  };
20625
+ if (hiddenTimes && mapped.info.time !== undefined) {
20626
+ const time = mapped.info.time;
20627
+ delete mapped.info.time;
20628
+ Object.defineProperty(mapped.info, "time", {
20629
+ value: time,
20630
+ enumerable: false,
20631
+ configurable: true,
20632
+ writable: true
20633
+ });
20634
+ }
19718
20635
  originals.set(mapped, message);
20636
+ if (isCoveredInstructionRow(message))
20637
+ markCoveredInstructionRow(mapped.info);
19719
20638
  if (typeof message.id !== "string")
19720
20639
  bridgesByCarrier.set(mapped, byCallID);
19721
20640
  messages.push(mapped);
@@ -20072,24 +20991,31 @@ ${data.output?.output ?? ""}`
20072
20991
  const sameModel = sameProvider && previousModel?.id === model.id;
20073
20992
  const reuse = sameModel && data.error === undefined;
20074
20993
  const metadata = (state) => state === undefined ? undefined : { [model.providerID]: state };
20994
+ const reasoningInterrupted = data.content?.some((part) => part.type === "reasoning" && part.time !== undefined && part.time.completed === undefined);
20075
20995
  const content = [];
20076
20996
  const results = [];
20077
20997
  for (const part of data.content ?? []) {
20998
+ let native = "native" in part ? part.native : part.type === "tool" ? part.providerState : part.state;
20999
+ if (part.type === "tool" && part.providerResultState !== null && typeof part.providerResultState === "object" && !Array.isArray(part.providerResultState))
21000
+ native = {
21001
+ ...native !== null && typeof native === "object" && !Array.isArray(native) ? native : {},
21002
+ ...part.providerResultState
21003
+ };
20078
21004
  if (part.type === "text") {
20079
21005
  if (part.text !== "")
20080
21006
  content.push({
20081
21007
  type: "text",
20082
21008
  text: part.text,
20083
- providerMetadata: reuse ? metadata(part.state) : undefined
21009
+ providerMetadata: reuse ? metadata(native) : undefined
20084
21010
  });
20085
21011
  continue;
20086
21012
  }
20087
21013
  if (part.type === "reasoning") {
20088
- if (part.text !== "" || reuse && part.state !== undefined)
21014
+ if (part.text !== "" || reuse && !reasoningInterrupted && native !== undefined)
20089
21015
  content.push({
20090
- type: reuse || data.error === undefined ? "reasoning" : "text",
21016
+ type: data.error === undefined && !reasoningInterrupted ? "reasoning" : "text",
20091
21017
  text: part.text,
20092
- providerMetadata: reuse ? metadata(part.state) : undefined
21018
+ providerMetadata: reuse && !reasoningInterrupted ? metadata(native) : undefined
20093
21019
  });
20094
21020
  continue;
20095
21021
  }
@@ -20108,7 +21034,7 @@ ${data.output?.output ?? ""}`
20108
21034
  name: part.name,
20109
21035
  input,
20110
21036
  providerExecuted: part.executed,
20111
- providerMetadata: toolReuse ? metadata(part.providerState) : undefined
21037
+ providerMetadata: toolReuse ? metadata(native) : undefined
20112
21038
  });
20113
21039
  if (!completed)
20114
21040
  continue;
@@ -20119,7 +21045,7 @@ ${data.output?.output ?? ""}`
20119
21045
  id: part.id,
20120
21046
  name: part.name,
20121
21047
  providerExecuted: part.executed,
20122
- providerMetadata: toolReuse ? metadata(part.providerResultState ?? part.providerState) : sameProvider ? metadata(part.providerResultState) : undefined,
21048
+ providerMetadata: (part.executed === true ? sameProvider : reuse) ? metadata(native) : undefined,
20123
21049
  result: state.status === "error" ? { error: state.error, content: toolContent } : single?.type === "text" ? { type: "text", value: single.text } : { type: "content", value: toolContent },
20124
21050
  ...state.status === "error" ? { resultType: "error" } : {}
20125
21051
  };
@@ -20147,13 +21073,50 @@ function copyNativeInput(messages) {
20147
21073
  return copies;
20148
21074
  }
20149
21075
  function isLocalCheckpoint(row) {
20150
- return row.type === "compaction" && row.data.status === "completed" && row.data.providerContext === undefined;
21076
+ return row.type === "compaction" && row.data.status === "completed" && row.data.providerContext === undefined && row.data.native?.messages === undefined;
21077
+ }
21078
+ function isAdmittedLocalCheckpoint(storage, sessionID, cut) {
21079
+ if (!isLocalCheckpoint(cut) || cut.session_id !== sessionID)
21080
+ return false;
21081
+ const admission = storage.admission(sessionID, cut.id);
21082
+ if (!admission?.payload || admission.digest !== foldDigest(admission.payload))
21083
+ return false;
21084
+ try {
21085
+ const snapshot = JSON.parse(admission.payload);
21086
+ return snapshot.source === storage.sourceID && snapshot.sessionID === sessionID && snapshot.admissionID === cut.id && snapshot.summary === cut.data.summary;
21087
+ } catch {
21088
+ return false;
21089
+ }
20151
21090
  }
20152
21091
  var conversational = (row) => RAW_MESSAGE_TYPES.includes(row.type) || row.type === "location-switched";
21092
+ var historyDigest = (reader, sessionID, through) => foldDigest(JSON.stringify(reader.range(sessionID, -1, through).filter(conversational)));
21093
+ var admissionKey = (sessionID) => `native-fold/v2/${encodeURIComponent(sessionID)}`;
21094
+ async function forgetNativeFoldProvenance(storage, sessionID, legacyOnly = false) {
21095
+ const remove = async (key) => {
21096
+ if (storage.remove)
21097
+ await storage.remove(key);
21098
+ else
21099
+ await storage.set(key, null);
21100
+ };
21101
+ if (!legacyOnly)
21102
+ await remove(admissionKey(sessionID));
21103
+ if (!storage.scan)
21104
+ return;
21105
+ let after;
21106
+ do {
21107
+ const page = await storage.scan({ prefix: "native-fold/v1/", after, limit: 100 });
21108
+ for (const { key } of page.entries) {
21109
+ if (key.slice("native-fold/v1/".length).split("/").slice(1).join("/") === sessionID)
21110
+ await remove(key);
21111
+ }
21112
+ after = page.next;
21113
+ } while (after);
21114
+ }
20153
21115
 
20154
21116
  class NativeFoldReplay {
20155
21117
  storage;
20156
21118
  openReader;
21119
+ admissions;
20157
21120
  changed = new Set;
20158
21121
  dirty = new Set;
20159
21122
  unavailable = new Set;
@@ -20161,9 +21124,11 @@ class NativeFoldReplay {
20161
21124
  metadataThrough = new Map;
20162
21125
  loaded = new Map;
20163
21126
  sources = new Map;
20164
- constructor(storage, openReader) {
21127
+ staleHeads = new Set;
21128
+ constructor(storage, openReader, admissions) {
20165
21129
  this.storage = storage;
20166
21130
  this.openReader = openReader;
21131
+ this.admissions = admissions;
20167
21132
  storage.onEvict((sessionID) => this.clear(sessionID));
20168
21133
  }
20169
21134
  account(sessionID) {
@@ -20202,6 +21167,51 @@ class NativeFoldReplay {
20202
21167
  async baseline(sessionID) {
20203
21168
  return this.tail(sessionID)?.baseline;
20204
21169
  }
21170
+ admissionKey(sessionID) {
21171
+ return admissionKey(sessionID);
21172
+ }
21173
+ async removeAdmission(key) {
21174
+ if (this.admissions?.remove)
21175
+ await this.admissions.remove(key);
21176
+ else
21177
+ await this.admissions?.set(key, null);
21178
+ }
21179
+ async removeLegacyAdmissions(sessionID) {
21180
+ if (this.admissions)
21181
+ await forgetNativeFoldProvenance(this.admissions, sessionID, true);
21182
+ }
21183
+ async admits(sessionID, cut, reader) {
21184
+ if (!isLocalCheckpoint(cut) || cut.session_id !== sessionID)
21185
+ return false;
21186
+ if (isAdmittedLocalCheckpoint(this.storage, sessionID, cut))
21187
+ return true;
21188
+ if (!this.admissions)
21189
+ return false;
21190
+ try {
21191
+ const source = reader.hostIdentity();
21192
+ const saved = await this.admissions.get(this.admissionKey(sessionID));
21193
+ if (!saved?.payload || saved.digest !== foldDigest(saved.payload))
21194
+ return false;
21195
+ const snapshot = JSON.parse(saved.payload);
21196
+ if (snapshot.sourceDigest !== foldDigest(source) || snapshot.sessionID !== sessionID || snapshot.admissionID !== cut.id || snapshot.summaryDigest !== foldDigest(cut.data.summary ?? ""))
21197
+ return false;
21198
+ if (snapshot.historyDigest !== historyDigest(reader, sessionID, cut.seq - 1)) {
21199
+ this.staleHeads.add(sessionID);
21200
+ this.invalidate(sessionID);
21201
+ await this.removeAdmission(this.admissionKey(sessionID));
21202
+ return false;
21203
+ }
21204
+ await this.storage.supply(sessionID, cut.id, JSON.stringify({
21205
+ source: this.storage.sourceID,
21206
+ sessionID,
21207
+ admissionID: cut.id,
21208
+ summary: cut.data.summary
21209
+ }));
21210
+ return true;
21211
+ } catch {
21212
+ return false;
21213
+ }
21214
+ }
20205
21215
  rendered(row, model) {
20206
21216
  return restoreRow(row, model, hostUsesMediaAssets() ? {
20207
21217
  asset: hostMediaAsset,
@@ -20279,6 +21289,7 @@ class NativeFoldReplay {
20279
21289
  this.loaded.set(draft.sessionID, through);
20280
21290
  this.unavailable.delete(draft.sessionID);
20281
21291
  this.changed.delete(draft.sessionID);
21292
+ this.staleHeads.delete(draft.sessionID);
20282
21293
  } finally {
20283
21294
  reader.close();
20284
21295
  }
@@ -20305,7 +21316,8 @@ class NativeFoldReplay {
20305
21316
  async supplyHeld(args) {
20306
21317
  const { draft, reader, summary } = args;
20307
21318
  const tail = this.tail(draft.sessionID);
20308
- const id = reader.latestRunningCompaction(draft.sessionID)?.id;
21319
+ const running = reader.latestRunningCompaction(draft.sessionID);
21320
+ const id = running?.id;
20309
21321
  if (!id || !tail || tail.model !== `${draft.model.providerID}/${draft.model.id}`)
20310
21322
  return false;
20311
21323
  const through = reader.latestSequence(draft.sessionID);
@@ -20329,6 +21341,21 @@ class NativeFoldReplay {
20329
21341
  summary
20330
21342
  };
20331
21343
  await this.storage.supply(draft.sessionID, id, JSON.stringify(snapshot));
21344
+ if (this.admissions) {
21345
+ const provenance = {
21346
+ sourceDigest: foldDigest(reader.hostIdentity()),
21347
+ sessionID: draft.sessionID,
21348
+ admissionID: id,
21349
+ summaryDigest: foldDigest(summary),
21350
+ historyDigest: historyDigest(reader, draft.sessionID, (running?.seq ?? through) - 1)
21351
+ };
21352
+ const payload = JSON.stringify(provenance);
21353
+ await this.admissions.set(this.admissionKey(draft.sessionID), {
21354
+ payload,
21355
+ digest: foldDigest(payload)
21356
+ });
21357
+ await this.removeLegacyAdmissions(draft.sessionID);
21358
+ }
20332
21359
  return true;
20333
21360
  }
20334
21361
  async restore(sessionID, cut, model, options = {}) {
@@ -20413,6 +21440,9 @@ class NativeFoldReplay {
20413
21440
  sourceChanged(sessionID) {
20414
21441
  return this.changed.has(sessionID);
20415
21442
  }
21443
+ needsHeadRebuild(sessionID) {
21444
+ return this.staleHeads.has(sessionID);
21445
+ }
20416
21446
  clear(sessionID) {
20417
21447
  this.sources.delete(sessionID);
20418
21448
  this.metadata.delete(sessionID);
@@ -20421,8 +21451,11 @@ class NativeFoldReplay {
20421
21451
  this.unavailable.delete(sessionID);
20422
21452
  this.dirty.delete(sessionID);
20423
21453
  this.changed.delete(sessionID);
21454
+ this.staleHeads.delete(sessionID);
20424
21455
  }
20425
21456
  async forget(sessionID) {
21457
+ if (this.admissions)
21458
+ await forgetNativeFoldProvenance(this.admissions, sessionID);
20426
21459
  await this.storage.forget(sessionID);
20427
21460
  }
20428
21461
  }
@@ -20437,11 +21470,7 @@ class HostFoldPolicy {
20437
21470
  this.deps = deps;
20438
21471
  }
20439
21472
  owned(sessionID, cut, id) {
20440
- const row = this.deps.storage.admission(sessionID, id);
20441
- if (!isLocalCheckpoint(cut) || cut.id !== id || !row?.payload || row.digest !== foldDigest(row.payload))
20442
- return false;
20443
- const snapshot = JSON.parse(row.payload);
20444
- return snapshot.summary === cut.data.summary && snapshot.source === this.deps.storage.sourceID && snapshot.sessionID === sessionID && snapshot.admissionID === id;
21473
+ return cut.id === id && isAdmittedLocalCheckpoint(this.deps.storage, sessionID, cut);
20445
21474
  }
20446
21475
  async idle(sessionID) {
20447
21476
  const { storage, session, threshold } = this.deps;
@@ -20869,6 +21898,25 @@ async function cleanupLegacyHiddenChildren(db, remove, note, options = {}) {
20869
21898
  }
20870
21899
 
20871
21900
  // src/v2/hidden-completion.ts
21901
+ var DEFAULT_DISPOSE_DRAIN_MS = 2000;
21902
+ async function settleWithin(work, ms) {
21903
+ let timer;
21904
+ try {
21905
+ await Promise.race([
21906
+ work.then(() => {
21907
+ return;
21908
+ }, () => {
21909
+ return;
21910
+ }),
21911
+ new Promise((resolve) => {
21912
+ timer = setTimeout(resolve, Math.max(0, ms));
21913
+ })
21914
+ ]);
21915
+ } finally {
21916
+ if (timer)
21917
+ clearTimeout(timer);
21918
+ }
21919
+ }
20872
21920
  var POLL_INTERVAL_MS = 200;
20873
21921
  function modelKey(model) {
20874
21922
  return `${model.providerID}/${model.modelID}`;
@@ -20968,6 +22016,9 @@ function isProviderFailure(error) {
20968
22016
  }
20969
22017
  async function awaitAssistantRow(openReader, readSessionError, localFailure, childID, afterSeq, deadline, signal) {
20970
22018
  for (;; ) {
22019
+ const refusedBefore = localFailure();
22020
+ if (refusedBefore)
22021
+ throw refusedBefore;
20971
22022
  const { assistant, idle } = withReader(openReader, (reader) => ({
20972
22023
  assistant: reader.latestAssistant(childID),
20973
22024
  idle: reader.latestIdle(childID)
@@ -21043,6 +22094,9 @@ async function createV2HiddenCompletionExecutor(host, options) {
21043
22094
  const generation = options.generation ?? "opencode2";
21044
22095
  const roleTails = new Map;
21045
22096
  const note = options.log ?? log;
22097
+ let disposed;
22098
+ const openRuns = new Set;
22099
+ const inFlight = new Set;
21046
22100
  const removeSession = host.removeSession;
21047
22101
  if (!removeSession)
21048
22102
  throw new Error("Magic Context requires OpenCode 2.0.22 session.remove");
@@ -21079,7 +22133,7 @@ async function createV2HiddenCompletionExecutor(host, options) {
21079
22133
  const entry = rows.find((row) => row && typeof row === "object" && row.providerID === model.providerID && row.id === model.modelID);
21080
22134
  if (!entry)
21081
22135
  return model;
21082
- if (entry.variants && typeof entry.variants === "object" && Object.hasOwn(entry.variants, model.variant))
22136
+ if (Array.isArray(entry.variants) ? entry.variants.some((variant) => variant?.id === model.variant) : entry.variants && typeof entry.variants === "object" && Object.hasOwn(entry.variants, model.variant))
21083
22137
  return model;
21084
22138
  const key = `${model.providerID}/${model.modelID}:${model.variant}`;
21085
22139
  if (!warnedVariants.has(key)) {
@@ -21137,10 +22191,17 @@ async function createV2HiddenCompletionExecutor(host, options) {
21137
22191
  return {
21138
22192
  capabilities: V2_HIDDEN_EXECUTOR_CAPABILITIES,
21139
22193
  async open(identity) {
22194
+ if (disposed)
22195
+ throw disposed;
21140
22196
  const role = roleFor(identity);
21141
- const releaseRole = await acquireRole(role);
22197
+ const releaseStore = options.holdStore?.() ?? (() => {});
22198
+ let releaseRole;
21142
22199
  let openedChild;
22200
+ let opened;
21143
22201
  try {
22202
+ releaseRole = await acquireRole(role);
22203
+ if (disposed)
22204
+ throw disposed;
21144
22205
  await options.ensureAgent?.();
21145
22206
  const head = await resolveHead(identity);
21146
22207
  const active = await lifecycle.open(identity, role, head);
@@ -21151,17 +22212,25 @@ async function createV2HiddenCompletionExecutor(host, options) {
21151
22212
  role,
21152
22213
  child: active,
21153
22214
  releaseRole,
22215
+ releaseStore,
21154
22216
  failed: false,
21155
22217
  unsettledFailure: false,
21156
22218
  retired: false
21157
22219
  };
21158
22220
  runs.set(handle, run);
22221
+ opened = run;
22222
+ openRuns.add(run);
22223
+ if (disposed)
22224
+ noteChildOfDisposedInstance(active.id);
21159
22225
  await switchChildModel(run, head);
21160
22226
  return handle;
21161
22227
  } catch (error) {
21162
22228
  if (openedChild)
21163
22229
  lifecycle.retire(openedChild, "hidden-run-open-failed");
21164
- releaseRole();
22230
+ if (opened)
22231
+ openRuns.delete(opened);
22232
+ releaseRole?.();
22233
+ releaseStore();
21165
22234
  throw error;
21166
22235
  }
21167
22236
  },
@@ -21169,6 +22238,15 @@ async function createV2HiddenCompletionExecutor(host, options) {
21169
22238
  const run = runs.get(handle);
21170
22239
  if (!run)
21171
22240
  throw new Error("Unknown hidden completion run");
22241
+ const refuseDisposed = () => {
22242
+ if (!disposed)
22243
+ return;
22244
+ run.failed = true;
22245
+ run.unsettledFailure = true;
22246
+ retire(run, "plugin-instance-disposed");
22247
+ throw disposed;
22248
+ };
22249
+ refuseDisposed();
21172
22250
  if (request.signal?.aborted) {
21173
22251
  await interruptAndRetire(run, "aborted-before-prompt");
21174
22252
  throw new Error("Hidden completion prompt aborted");
@@ -21183,6 +22261,7 @@ async function createV2HiddenCompletionExecutor(host, options) {
21183
22261
  handle.childSessionId = run.child.id;
21184
22262
  }
21185
22263
  await switchChildModel(run, requested);
22264
+ refuseDisposed();
21186
22265
  const baseline = withReader(options.openReader, (reader) => reader.latestSequence(run.child.id));
21187
22266
  const marker = `mc:hidden:${crypto.randomUUID()}:${crypto.randomUUID()}`;
21188
22267
  run.completion = undefined;
@@ -21208,6 +22287,28 @@ async function createV2HiddenCompletionExecutor(host, options) {
21208
22287
  interruptAndRetire(run, "prompt-timeout").finally(() => abortReject(new Error("Hidden completion prompt timed out")));
21209
22288
  }, Math.max(0, deadline - Date.now()));
21210
22289
  request.signal?.addEventListener("abort", onAbort, { once: true });
22290
+ let settle;
22291
+ const entry = {
22292
+ cancel: async (refusal) => {
22293
+ attempt.refusal ??= refusal;
22294
+ noteChildOfDisposedInstance(run.child.id);
22295
+ try {
22296
+ await interruptAndRetire(run, "plugin-instance-disposed");
22297
+ } catch (error) {
22298
+ note(`[magic-context] hidden child ${run.child.id} could not be interrupted on dispose: ${errorText(error)}`);
22299
+ } finally {
22300
+ abortReject(refusal);
22301
+ }
22302
+ },
22303
+ reject: (refusal) => {
22304
+ attempt.refusal ??= refusal;
22305
+ abortReject(refusal);
22306
+ },
22307
+ settled: new Promise((resolve) => {
22308
+ settle = resolve;
22309
+ })
22310
+ };
22311
+ inFlight.add(entry);
21211
22312
  try {
21212
22313
  await Promise.race([
21213
22314
  host.prompt({ sessionID: run.child.id, text: marker }),
@@ -21278,6 +22379,8 @@ async function createV2HiddenCompletionExecutor(host, options) {
21278
22379
  clearTimeout(deadlineTimer);
21279
22380
  request.signal?.removeEventListener("abort", onAbort);
21280
22381
  options.hook.releaseAttempt(marker);
22382
+ inFlight.delete(entry);
22383
+ settle();
21281
22384
  }
21282
22385
  },
21283
22386
  async collect(handle) {
@@ -21299,9 +22402,27 @@ async function createV2HiddenCompletionExecutor(host, options) {
21299
22402
  }
21300
22403
  } finally {
21301
22404
  runs.delete(handle);
22405
+ openRuns.delete(run);
21302
22406
  run.releaseRole();
22407
+ run.releaseStore();
21303
22408
  }
21304
22409
  await lifecycle.finish(run.child, run.retired);
22410
+ },
22411
+ async dispose() {
22412
+ disposed ??= new HiddenCompletionRefusal("hidden_instance_disposed", HIDDEN_RUN_DISPOSED_REASON, true);
22413
+ const refusal = disposed;
22414
+ for (const run of openRuns)
22415
+ noteChildOfDisposedInstance(run.child.id);
22416
+ const entries = [...inFlight];
22417
+ if (entries.length === 0)
22418
+ return;
22419
+ note(`[magic-context] plugin instance disposed with ${entries.length} hidden run(s) in flight; cancelling them`);
22420
+ const bound = options.disposeDrainMs ?? DEFAULT_DISPOSE_DRAIN_MS;
22421
+ const deadline = Date.now() + bound;
22422
+ await settleWithin(Promise.allSettled(entries.map((entry) => entry.cancel(refusal))), bound);
22423
+ for (const entry of entries)
22424
+ entry.reject(refusal);
22425
+ await settleWithin(Promise.allSettled(entries.map((entry) => entry.settled)), deadline - Date.now());
21305
22426
  }
21306
22427
  };
21307
22428
  }
@@ -21531,26 +22652,70 @@ function generateReplayAnchor(messages) {
21531
22652
  return;
21532
22653
  return { id, tail: clonePreservingInstances(messages.slice(index + 1)) };
21533
22654
  }
22655
+ var DEFAULT_GENERATE_REPLAY_LIMITS = Object.freeze({
22656
+ maxSessions: 16,
22657
+ sessionMaxBytes: 128 * 1024 * 1024,
22658
+ totalMaxBytes: 256 * 1024 * 1024
22659
+ });
21534
22660
 
21535
22661
  class V2GenerateReplay {
21536
22662
  prefixes = new Map;
22663
+ totalBytes = 0;
22664
+ limits;
22665
+ constructor(limits = DEFAULT_GENERATE_REPLAY_LIMITS) {
22666
+ if (!Number.isSafeInteger(limits.maxSessions) || limits.maxSessions < 1 || !Number.isSafeInteger(limits.sessionMaxBytes) || limits.sessionMaxBytes < 1 || !Number.isSafeInteger(limits.totalMaxBytes) || limits.totalMaxBytes < 1)
22667
+ throw new Error("Generate replay limits must be positive integers");
22668
+ this.limits = { ...limits };
22669
+ }
21537
22670
  capture(draft, anchor) {
22671
+ this.forget(draft.sessionID);
21538
22672
  if (!anchor) {
21539
- this.prefixes.delete(draft.sessionID);
21540
22673
  sessionLog(draft.sessionID, "generate replay capture skipped: no-anchor");
21541
22674
  return;
21542
22675
  }
22676
+ const parts = {
22677
+ anchor: clonePreservingInstancesMeasured(anchor),
22678
+ system: clonePreservingInstancesMeasured(draft.system),
22679
+ messages: clonePreservingInstancesMeasured(draft.messages),
22680
+ tools: clonePreservingInstancesMeasured(draft.tools)
22681
+ };
22682
+ const bytes = 256 + parts.anchor.bytes + parts.system.bytes + parts.messages.bytes + parts.tools.bytes;
22683
+ if (bytes > this.limits.sessionMaxBytes || bytes > this.limits.totalMaxBytes) {
22684
+ sessionLog(draft.sessionID, `generate replay capture skipped: over-session-cap (${bytes} > ${Math.min(this.limits.sessionMaxBytes, this.limits.totalMaxBytes)} bytes)`);
22685
+ return;
22686
+ }
22687
+ while (this.prefixes.size > 0 && (this.prefixes.size >= this.limits.maxSessions || this.totalBytes + bytes > this.limits.totalMaxBytes)) {
22688
+ const oldest = this.prefixes.keys().next().value;
22689
+ if (oldest === undefined)
22690
+ break;
22691
+ this.forget(oldest);
22692
+ }
21543
22693
  this.prefixes.set(draft.sessionID, {
21544
- anchor: clonePreservingInstances(anchor),
22694
+ anchor: parts.anchor.copy,
21545
22695
  model: `${draft.model.providerID}/${draft.model.id}`,
21546
22696
  agent: draft.agent,
21547
- system: clonePreservingInstances(draft.system),
21548
- messages: clonePreservingInstances(draft.messages),
21549
- tools: clonePreservingInstances(draft.tools)
22697
+ system: parts.system.copy,
22698
+ messages: parts.messages.copy,
22699
+ tools: parts.tools.copy,
22700
+ bytes
21550
22701
  });
22702
+ this.totalBytes += bytes;
21551
22703
  }
21552
22704
  forget(sessionID) {
22705
+ const prefix = this.prefixes.get(sessionID);
22706
+ if (!prefix)
22707
+ return;
21553
22708
  this.prefixes.delete(sessionID);
22709
+ this.totalBytes -= prefix.bytes;
22710
+ }
22711
+ stats() {
22712
+ return {
22713
+ totalBytes: this.totalBytes,
22714
+ sessions: [...this.prefixes].map(([sessionId, prefix]) => ({
22715
+ sessionId,
22716
+ bytes: prefix.bytes
22717
+ }))
22718
+ };
21554
22719
  }
21555
22720
  apply(draft) {
21556
22721
  const prefix = this.prefixes.get(draft.sessionID);
@@ -21560,6 +22725,8 @@ class V2GenerateReplay {
21560
22725
  };
21561
22726
  if (!prefix)
21562
22727
  return skip("no-prefix");
22728
+ this.prefixes.delete(draft.sessionID);
22729
+ this.prefixes.set(draft.sessionID, prefix);
21563
22730
  if (prefix.model !== `${draft.model.providerID}/${draft.model.id}`)
21564
22731
  return skip("model-mismatch");
21565
22732
  if (prefix.agent !== draft.agent)
@@ -21588,9 +22755,9 @@ function hiddenTerminalError(event) {
21588
22755
  }
21589
22756
 
21590
22757
  // src/v2/hooks/lkg-system.ts
21591
- import { createHash as createHash5 } from "node:crypto";
22758
+ import { createHash as createHash4 } from "node:crypto";
21592
22759
  function identity(slot) {
21593
- return createHash5("sha256").update(JSON.stringify({
22760
+ return createHash4("sha256").update(JSON.stringify({
21594
22761
  capturedAt: slot.capturedAt,
21595
22762
  captureSequence: slot.captureSequence,
21596
22763
  rowVersion: slot.rowVersion,
@@ -21603,21 +22770,25 @@ function identity(slot) {
21603
22770
 
21604
22771
  class V2LkgSystemReplay {
21605
22772
  systems = new BoundedSessionMap(1000);
21606
- capture(sessionId, slot, input, served) {
22773
+ capture(sessionId, slot, input, served, head) {
21607
22774
  this.systems.set(sessionId, {
21608
22775
  slot: identity(slot),
21609
- input: JSON.stringify(input),
21610
- served: structuredClone(served)
22776
+ input: hostInputKey(input),
22777
+ served: structuredClone(served),
22778
+ head: head ? structuredClone(head) : null
21611
22779
  });
21612
22780
  }
21613
22781
  restore(sessionId, slot, input, target) {
21614
22782
  const saved = this.systems.get(sessionId);
21615
- if (!slot || !saved || saved.slot !== identity(slot) || saved.input !== JSON.stringify(input))
21616
- return false;
22783
+ if (!slot || !saved || saved.slot !== identity(slot) || saved.input !== hostInputKey(input))
22784
+ return;
21617
22785
  target.splice(0, target.length, ...structuredClone(saved.served));
21618
- return true;
22786
+ return { head: saved.head ? structuredClone(saved.head) : null };
21619
22787
  }
21620
22788
  }
22789
+ function hostInputKey(input) {
22790
+ return JSON.stringify({ system: input.system, checkpoint: input.checkpoint });
22791
+ }
21621
22792
 
21622
22793
  // src/v2/hooks/model-limit-cache.ts
21623
22794
  var warmStarted = false;
@@ -22278,6 +23449,22 @@ function* readV2RawMessagePagesForConversion(openReader, sessionID, pageRows = C
22278
23449
  function createV2RawMessageReader(openReader) {
22279
23450
  const servedBoundaryCache = new Map;
22280
23451
  return {
23452
+ getRevision: (sessionID) => {
23453
+ const reader = openReader();
23454
+ try {
23455
+ return reader.latestSequence(sessionID);
23456
+ } finally {
23457
+ reader.close();
23458
+ }
23459
+ },
23460
+ getCountAfterRevision: (sessionID, after, through) => {
23461
+ const reader = openReader();
23462
+ try {
23463
+ return reader.messageCountAfterSequence(sessionID, after, through);
23464
+ } finally {
23465
+ reader.close();
23466
+ }
23467
+ },
22281
23468
  readPage: (sessionID, afterOrdinal, limit, finalWatermark, after) => {
22282
23469
  const reader = openReader();
22283
23470
  try {
@@ -22553,7 +23740,7 @@ function resolveCtxExpandMode(args, domain) {
22553
23740
  }
22554
23741
 
22555
23742
  // src/tools/ctx-expand/render.ts
22556
- import { createHash as createHash6 } from "node:crypto";
23743
+ import { createHash as createHash5 } from "node:crypto";
22557
23744
  function isRecord4(value) {
22558
23745
  return value !== null && typeof value === "object" && !Array.isArray(value);
22559
23746
  }
@@ -22777,7 +23964,7 @@ function renderItemByTag(db, sessionId, number, textIndexDomain = "part") {
22777
23964
  const index = scoped ? Number(scoped[2]) : 0;
22778
23965
  const piText = message.parts.filter((part) => isRecord4(part) && part.type === "text");
22779
23966
  const part = message.parts[index];
22780
- const matching = derived ? piText.filter((part) => isRecord4(part) && typeof part.text === "string" && createHash6("sha256").update(part.text).digest("hex") === derived[3]) : [];
23967
+ const matching = derived ? piText.filter((part) => isRecord4(part) && typeof part.text === "string" && createHash5("sha256").update(part.text).digest("hex") === derived[3]) : [];
22781
23968
  const selected = derived ? matching[Number(derived[4])] : textIndexDomain === "text" ? piText[index] : part;
22782
23969
  if (!selected)
22783
23970
  return `Tag ${number}'s original text part is no longer in stored history.`;
@@ -23745,7 +24932,7 @@ function createCtxReduceTool(deps) {
23745
24932
  args = unwrapImitatedReducedArgs(args, ["drop"], { drop: "string" });
23746
24933
  const sessionId = toolContext.sessionID;
23747
24934
  if (!args.drop) {
23748
- return "Error: 'drop' must be provided.";
24935
+ return `Error: 'drop' must be provided as a string of tag numbers, for example {"drop": "3-5,8"}.`;
23749
24936
  }
23750
24937
  let dropIds = [];
23751
24938
  try {
@@ -24127,7 +25314,28 @@ function persistV2UsageReading(args) {
24127
25314
  }
24128
25315
 
24129
25316
  // src/v2/hooks/context.ts
25317
+ function applyCheckpointHead(draft, head) {
25318
+ const { checkpoint, submitted } = head;
25319
+ const first = draft.messages.find((message) => message.id === HEAD_IDS[0]);
25320
+ const baseline = first?.content.find((part) => part.type === "text")?.text;
25321
+ if (typeof baseline !== "string")
25322
+ return false;
25323
+ for (const part of checkpoint.content)
25324
+ if (part.type === "text" && typeof part.text === "string") {
25325
+ part.text = part.text.replace(`<summary>
25326
+ ${submitted}
25327
+ </summary>`, `<summary>
25328
+ ${baseline}
25329
+ </summary>`);
25330
+ }
25331
+ const volatile = draft.messages.find((message) => message.id === HEAD_IDS[1]);
25332
+ if (volatile && first)
25333
+ volatile.content.push(...first.content.filter((part) => part.type !== "text"));
25334
+ draft.messages.splice(0, draft.messages.length, checkpoint, ...draft.messages.filter((message) => message !== first));
25335
+ return true;
25336
+ }
24130
25337
  var HIDDEN_SESSION_ERROR_GRACE_MS = 50;
25338
+ var STORE_POOL_DISPOSE_WAIT_MS = 1000;
24131
25339
 
24132
25340
  class V2LkgAdmissionReplay extends Error {
24133
25341
  }
@@ -24349,11 +25557,12 @@ async function registerContext(context) {
24349
25557
  }
24350
25558
  const folds = new FoldOwner(context.storage);
24351
25559
  const nativeFoldMemory = !compactionOff && process.env.MMC_OC2_INVISIBLE_FOLD === "1" ? nativeFoldCache(() => storage.require()) : undefined;
24352
- const nativeFoldReplay = nativeFoldMemory ? new NativeFoldReplay(nativeFoldMemory, () => openStoreReader()) : undefined;
25560
+ const nativeFoldReplay = nativeFoldMemory ? new NativeFoldReplay(nativeFoldMemory, () => openStoreReader(), context.storage) : undefined;
24353
25561
  setOutputReserveConfig(config.output_reserve);
24354
25562
  const queriedModels = new Set;
24355
25563
  const rawLimits = new Map;
24356
25564
  const hiddenSessionErrors = new Map;
25565
+ const committedSourceRefreshes = new Map;
24357
25566
  const liveModels = new Map;
24358
25567
  const promptSurfaceRuntime = createPromptSurfaceRuntime({
24359
25568
  harness: "opencode2",
@@ -24467,6 +25676,7 @@ async function registerContext(context) {
24467
25676
  ensureAgent: () => hiddenAgentsReady ??= context.agent.reload(),
24468
25677
  modelCatalog: () => Promise.resolve(context.model.list()),
24469
25678
  openReader: openStoreReader,
25679
+ holdStore: () => readerPool.hold(),
24470
25680
  resolveStepCap: resolveHiddenStepCap
24471
25681
  });
24472
25682
  };
@@ -24552,11 +25762,17 @@ async function registerContext(context) {
24552
25762
  }
24553
25763
  });
24554
25764
  const pagedRead = createV2RawMessageReader(openStoreReader);
25765
+ let orphanSweep;
25766
+ let orphanSweepTimer;
24555
25767
  const prepareHistorySession = (sessionID) => {
24556
25768
  if (!rawProviders.has(sessionID))
24557
25769
  rawProviders.set(sessionID, setBoundedRawMessageProvider2(sessionID, createV2RawMessageProvider(pagedRead, sessionID)));
24558
25770
  };
24559
25771
  if (db && isDatabasePersisted(db)) {
25772
+ const sweepDb = db;
25773
+ orphanSweepTimer = scheduleAfterBootQuiet(() => {
25774
+ orphanSweep = sweepOrphanedOpenCodeMessageIndexesCooperatively(sweepDb, () => new Database(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"), { readonly: true, fileMustExist: true })).catch((error) => log("[magic-context] v2 orphan sweep failed:", error));
25775
+ });
24560
25776
  const backfillDb = db;
24561
25777
  scheduleAfterBootQuiet(() => {
24562
25778
  runV2SessionProjectBackfill(backfillDb, openStoreReader, config.allow_home_project).catch((error) => log("[session-project-backfill] OpenCode 2 backfill failed:", error));
@@ -24675,88 +25891,122 @@ async function registerContext(context) {
24675
25891
  }) : undefined;
24676
25892
  const usageController = new AbortController;
24677
25893
  const usageDone = (async () => {
24678
- try {
24679
- for await (const value of context.event.subscribe({ signal: usageController.signal })) {
24680
- if (usageController.signal.aborted)
24681
- break;
24682
- const event = value;
24683
- if (!event.data?.sessionID)
24684
- continue;
24685
- const sessionID = event.data.sessionID;
24686
- if (event.type?.startsWith("session.revert.") || event.type === "session.message.content.updated") {
24687
- nativeFoldReplay?.onEvent(event);
24688
- restoredRows.forget(sessionID);
24689
- }
24690
- if (event.type?.startsWith("session.revert.") && db) {
24691
- const database = db;
24692
- withoutSqliteTransformPass(() => scheduleClearAndReindex(database, sessionID, pagedRead));
24693
- }
24694
- if (event.type === "session.error" || event.type === "session.execution.failed") {
24695
- const error = hiddenTerminalError(event);
24696
- if (error !== undefined)
24697
- hiddenSessionErrors.set(sessionID, error);
24698
- if (error !== undefined && db && !compactionOff) {
25894
+ let retry = 0;
25895
+ while (!usageController.signal.aborted) {
25896
+ const subscribedAt = Date.now();
25897
+ try {
25898
+ for await (const value of context.event.subscribe({
25899
+ signal: usageController.signal
25900
+ })) {
25901
+ if (usageController.signal.aborted)
25902
+ break;
25903
+ const event = value;
25904
+ try {
25905
+ if (event.type === "provider.updated" || event.type === "model.updated") {
25906
+ queriedModels.clear();
25907
+ continue;
25908
+ }
25909
+ if (!event.data?.sessionID)
25910
+ continue;
25911
+ const sessionID = event.data.sessionID;
25912
+ if (event.type?.startsWith("session.revert.") || event.type === "session.message.content.updated") {
25913
+ nativeFoldReplay?.onEvent(event);
25914
+ restoredRows.forget(sessionID);
25915
+ }
25916
+ if (event.type === "session.revert.committed") {
25917
+ committedSourceRefreshes.set(sessionID, {});
25918
+ const database = db;
25919
+ if (database)
25920
+ withoutSqliteTransformPass(() => scheduleClearAndReindex(database, sessionID, pagedRead));
25921
+ }
25922
+ if (event.type === "session.error" || event.type === "session.execution.failed") {
25923
+ const error = hiddenTerminalError(event);
25924
+ if (error !== undefined)
25925
+ hiddenSessionErrors.set(sessionID, error);
25926
+ if (error !== undefined && db && !compactionOff) {
25927
+ const model = liveModels.get(sessionID);
25928
+ try {
25929
+ armLatestThinkingRecoveryFromError({
25930
+ db,
25931
+ sessionId: sessionID,
25932
+ error,
25933
+ providerID: model?.providerID,
25934
+ modelID: model?.modelID
25935
+ });
25936
+ } catch (armError) {
25937
+ log("[magic-context] v2 latest-thinking recovery arm failed", armError);
25938
+ }
25939
+ }
25940
+ continue;
25941
+ }
25942
+ if (event.type === "session.deleted") {
25943
+ committedSourceRefreshes.delete(sessionID);
25944
+ clearLkgMeasuredRequest(sessionID);
25945
+ deletedSessions.add(sessionID);
25946
+ transform?.clearSessionLogState(sessionID);
25947
+ if (db) {
25948
+ markSessionCleanupPending(db, sessionID);
25949
+ clearSession(db, sessionID, false, true);
25950
+ }
25951
+ rawProviders.get(sessionID)?.();
25952
+ rawProviders.delete(sessionID);
25953
+ usage.delete(sessionID);
25954
+ hiddenSessionErrors.delete(sessionID);
25955
+ storageNoticeBySession.delete(sessionID);
25956
+ liveModels.delete(sessionID);
25957
+ variants.delete(sessionID);
25958
+ agents.delete(sessionID);
25959
+ channel1.delete(sessionID);
25960
+ historyRefreshSessions.delete(sessionID);
25961
+ clearPendingMaterialization(pendingMaterializationSessions, sessionID);
25962
+ lastHeuristicsTurnId.delete(sessionID);
25963
+ restoredRows.forget(sessionID);
25964
+ if (nativeFoldReplay)
25965
+ await nativeFoldReplay.forget(sessionID);
25966
+ else
25967
+ await forgetNativeFoldProvenance(context.storage, sessionID);
25968
+ generateReplay.forget(sessionID);
25969
+ systemPromptRefreshSessions.delete(sessionID);
25970
+ systemPrompt?.clearSession(sessionID);
25971
+ clearMaintenanceSystemSnapshot(sessionID);
25972
+ tagger.cleanup(sessionID);
25973
+ sessionDirectories.delete(sessionID);
25974
+ forkSeedSettled.delete(sessionID);
25975
+ continue;
25976
+ }
25977
+ if (event.type !== "session.execution.succeeded")
25978
+ continue;
24699
25979
  const model = liveModels.get(sessionID);
24700
- try {
24701
- armLatestThinkingRecoveryFromError({
24702
- db,
24703
- sessionId: sessionID,
24704
- error,
24705
- providerID: model?.providerID,
24706
- modelID: model?.modelID
25980
+ if (model) {
25981
+ await recordUsage({
25982
+ sessionID,
25983
+ model: { providerID: model.providerID, id: model.modelID }
24707
25984
  });
24708
- } catch (armError) {
24709
- log("[magic-context] v2 latest-thinking recovery arm failed", armError);
25985
+ if (!compactionOff && typeof await nativeFoldReplay?.baseline(sessionID) === "string")
25986
+ hostFolds?.idle(sessionID);
24710
25987
  }
25988
+ } catch (error) {
25989
+ log(`[magic-context] v2 event handler failed (type=${event.type ?? "unknown"}, session=${event.data?.sessionID ?? "none"})`, error);
24711
25990
  }
24712
- continue;
24713
- }
24714
- if (event.type === "session.deleted") {
24715
- clearLkgMeasuredRequest(sessionID);
24716
- deletedSessions.add(sessionID);
24717
- transform?.clearSessionLogState(sessionID);
24718
- if (db) {
24719
- markSessionCleanupPending(db, sessionID);
24720
- clearSession(db, sessionID);
24721
- }
24722
- rawProviders.get(sessionID)?.();
24723
- rawProviders.delete(sessionID);
24724
- usage.delete(sessionID);
24725
- hiddenSessionErrors.delete(sessionID);
24726
- storageNoticeBySession.delete(sessionID);
24727
- liveModels.delete(sessionID);
24728
- variants.delete(sessionID);
24729
- agents.delete(sessionID);
24730
- channel1.delete(sessionID);
24731
- historyRefreshSessions.delete(sessionID);
24732
- clearPendingMaterialization(pendingMaterializationSessions, sessionID);
24733
- lastHeuristicsTurnId.delete(sessionID);
24734
- restoredRows.forget(sessionID);
24735
- await nativeFoldReplay?.forget(sessionID);
24736
- generateReplay.forget(sessionID);
24737
- systemPromptRefreshSessions.delete(sessionID);
24738
- systemPrompt?.clearSession(sessionID);
24739
- clearMaintenanceSystemSnapshot(sessionID);
24740
- tagger.cleanup(sessionID);
24741
- sessionDirectories.delete(sessionID);
24742
- forkSeedSettled.delete(sessionID);
24743
- continue;
24744
- }
24745
- if (event.type !== "session.execution.succeeded")
24746
- continue;
24747
- const model = liveModels.get(sessionID);
24748
- if (model) {
24749
- await recordUsage({
24750
- sessionID,
24751
- model: { providerID: model.providerID, id: model.modelID }
24752
- });
24753
- if (!compactionOff && typeof await nativeFoldReplay?.baseline(sessionID) === "string")
24754
- hostFolds?.idle(sessionID);
24755
25991
  }
25992
+ } catch (error) {
25993
+ if (!usageController.signal.aborted)
25994
+ log("[magic-context] v2 usage subscription failed", error);
25995
+ }
25996
+ if (usageController.signal.aborted)
25997
+ break;
25998
+ if (Date.now() - subscribedAt >= 30000)
25999
+ retry = 0;
26000
+ const ceiling = Math.min(30000, 250 * 2 ** retry);
26001
+ retry = Math.min(retry + 1, 7);
26002
+ try {
26003
+ await delay(ceiling * (0.5 + Math.random() * 0.5), undefined, {
26004
+ signal: usageController.signal
26005
+ });
26006
+ } catch (error) {
26007
+ if (!usageController.signal.aborted)
26008
+ throw error;
24756
26009
  }
24757
- } catch (error) {
24758
- if (!usageController.signal.aborted)
24759
- log("[magic-context] v2 usage subscription failed", error);
24760
26010
  }
24761
26011
  })();
24762
26012
  const materialize = (draft) => {
@@ -24829,20 +26079,57 @@ async function registerContext(context) {
24829
26079
  reader.close();
24830
26080
  }
24831
26081
  });
26082
+ const restoreAfterCheckpoint = (args) => {
26083
+ const { db, reader, draft, cut, boundaryRepair } = args;
26084
+ const boundaryID = db.prepare("SELECT cached_m0_last_baseline_end_message_id AS id FROM session_meta WHERE session_id = ?").get(draft.sessionID)?.id ?? (boundaryRepair?.kind === "repaired" || boundaryRepair?.kind === "baseline-reset" ? boundaryRepair.anchorEndMessageId : null);
26085
+ const servedBoundary = boundaryID ? servedBoundaryRow(reader, draft.sessionID, boundaryID) : null;
26086
+ const boundary = servedBoundary?.seq ?? reader.sequenceForId(draft.sessionID, boundaryID) ?? (reader.earliestSequence(draft.sessionID) ?? 0) - 1;
26087
+ const present = new Set(args.messages.map((message) => message.id));
26088
+ const restored = restoredRows.rows(reader, draft.sessionID, boundary, cut.seq).filter((row) => !present.has(row.id)).flatMap((row) => restoreRow(row, draft.model, hostUsesMediaAssets() ? {
26089
+ asset: hostMediaAsset,
26090
+ unavailable: (detail) => sessionLog(draft.sessionID, `v2 restore: attachment replaced by a note row=${detail.rowID} name=${JSON.stringify(detail.name ?? null)} mediaType=${detail.mediaType} reason=${JSON.stringify(detail.reason)}`)
26091
+ } : undefined));
26092
+ const covered = reader.instructionRowsThrough(draft.sessionID, Math.min(boundary, cut.seq)).flatMap((row) => restoreRow(row, draft.model)).map((message) => markCoveredInstructionRow(message));
26093
+ return [
26094
+ ...covered,
26095
+ ...restored,
26096
+ ...args.messages.filter((message) => message !== args.incoming)
26097
+ ];
26098
+ };
26099
+ const temporalTimes = config.temporal_awareness === true;
26100
+ const anchorTimesOnly = !temporalTimes;
26101
+ const timeIds = (messages) => {
26102
+ if (temporalTimes)
26103
+ return messages.flatMap((message) => message.id ? [message.id] : []);
26104
+ const ids = [];
26105
+ for (const message of [...messages].reverse()) {
26106
+ if (message.id)
26107
+ ids.push(message.id);
26108
+ if (message.role === "assistant")
26109
+ break;
26110
+ }
26111
+ return ids;
26112
+ };
24832
26113
  const runManagedContext = async (draft) => {
24833
26114
  rememberHostMedia(draft.messages);
24834
26115
  if (hiddenChildHook.apply(draft))
24835
26116
  return;
24836
26117
  if (deletedSessions.has(draft.sessionID))
24837
26118
  return;
24838
- const systemAtEntry = structuredClone(draft.system);
26119
+ let systemAtEntry = structuredClone(draft.system);
24839
26120
  const slotAtEntry = getSlot(draft.sessionID);
26121
+ let checkpointAtEntry;
26122
+ let replayHead;
26123
+ const hostInput = () => checkpointAtEntry === undefined ? undefined : { system: systemAtEntry, checkpoint: checkpointAtEntry };
24840
26124
  const restoreLkgSystem = () => {
24841
26125
  retirePendingSystemPromptDelivery(draft.sessionID);
24842
- if (!lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), systemAtEntry, draft.system)) {
26126
+ const input = hostInput();
26127
+ const restored = input && lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), input, draft.system);
26128
+ if (!restored) {
24843
26129
  sessionLog(draft.sessionID, "lkg_system_state_mismatch");
24844
26130
  throw new Error("LKG system identity is unavailable or changed");
24845
26131
  }
26132
+ replayHead = restored.head;
24846
26133
  };
24847
26134
  const isMagicContextSynthetic = (id) => isAdmittedSynthetic(context, draft.sessionID, id);
24848
26135
  const newest = draft.messages.at(-1);
@@ -24851,6 +26138,24 @@ async function registerContext(context) {
24851
26138
  return;
24852
26139
  }
24853
26140
  await dropStorageNotices(draft.messages, isMagicContextSynthetic);
26141
+ let hostMessagesAtEntry = [...draft.messages];
26142
+ const passTimes = new Map;
26143
+ const readTimes = (reader, messages) => {
26144
+ const ids = timeIds(messages);
26145
+ const missing = ids.filter((id) => !passTimes.has(id));
26146
+ if (missing.length) {
26147
+ const read = reader.messageTimes(draft.sessionID, missing);
26148
+ for (const id of missing)
26149
+ passTimes.set(id, read.get(id) ?? null);
26150
+ }
26151
+ const times = new Map;
26152
+ for (const id of ids) {
26153
+ const time = passTimes.get(id);
26154
+ if (time)
26155
+ times.set(id, time);
26156
+ }
26157
+ return times;
26158
+ };
24854
26159
  liveModels.set(draft.sessionID, {
24855
26160
  providerID: draft.model.providerID,
24856
26161
  modelID: draft.model.id
@@ -24862,8 +26167,9 @@ async function registerContext(context) {
24862
26167
  applyV2PromptSurfaceTools(draft, promptSurfaceRuntime, config.prompt_surface);
24863
26168
  const admissionDb = db ?? storage.current();
24864
26169
  const replayFits = (messages) => {
24865
- const system = structuredClone(draft.system);
24866
- if (!admissionDb || !draft.tools || !lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), draft.system, system))
26170
+ const system = [];
26171
+ const input = hostInput();
26172
+ if (!admissionDb || !draft.tools || !input || !lkgSystems.restore(draft.sessionID, getSlot(draft.sessionID), input, system))
24867
26173
  return false;
24868
26174
  const limit = lkgReplayLimit({
24869
26175
  db: admissionDb,
@@ -24898,15 +26204,75 @@ async function registerContext(context) {
24898
26204
  })
24899
26205
  }).fit === "under";
24900
26206
  };
26207
+ const buildReplayInput = async () => {
26208
+ let messages = [...hostMessagesAtEntry];
26209
+ const admitted = new Set;
26210
+ let times;
26211
+ try {
26212
+ const reader = openStoreReader();
26213
+ try {
26214
+ const cut = reader.latestCompaction(draft.sessionID);
26215
+ const localCut = cut && isLocalCheckpoint(cut) ? cut : undefined;
26216
+ const incoming = localCut && messages.find((message) => message.id === localCut.id);
26217
+ if (localCut && !incoming || cut && nativeFoldReplay)
26218
+ return;
26219
+ checkpointAtEntry = incoming || null;
26220
+ const modeDb = db ?? storage.current();
26221
+ const subagent = modeDb ? storedSubagentMode(modeDb, draft.sessionID) : undefined;
26222
+ if (subagent === undefined)
26223
+ return;
26224
+ if (subagent)
26225
+ removePrimaryOnlyTools(draft.tools);
26226
+ const candidates = syntheticCandidates(context, draft.sessionID, reader.syntheticMessageIDs(draft.sessionID));
26227
+ for (const message of messages)
26228
+ if (message.id && candidates.has(message.id) && await isAdmittedSynthetic(context, draft.sessionID, message.id))
26229
+ admitted.add(message.id);
26230
+ const replayDb = db ?? storage.current();
26231
+ if (localCut && incoming && replayDb)
26232
+ messages = restoreAfterCheckpoint({
26233
+ db: replayDb,
26234
+ reader,
26235
+ draft,
26236
+ messages,
26237
+ cut: localCut,
26238
+ incoming,
26239
+ boundaryRepair: undefined
26240
+ });
26241
+ else if (localCut)
26242
+ return;
26243
+ times = readTimes(reader, messages);
26244
+ } finally {
26245
+ reader.close();
26246
+ }
26247
+ } catch (error) {
26248
+ sessionLog(draft.sessionID, "lkg replay input unavailable", error);
26249
+ return;
26250
+ }
26251
+ const replayDraft = { ...draft, messages };
26252
+ return {
26253
+ draft: replayDraft,
26254
+ mapped: adaptPayload(replayDraft, admitted, times, anchorTimesOnly)
26255
+ };
26256
+ };
26257
+ const adoptReplay = (replayed) => {
26258
+ draft.messages.splice(0, draft.messages.length, ...replayed.messages);
26259
+ if (replayHead)
26260
+ applyCheckpointHead(draft, replayHead);
26261
+ };
24901
26262
  let postFold = false;
24902
26263
  try {
24903
26264
  if (!compactionOff && admissionDb)
24904
26265
  await withAsyncPrivilegedWriter(admissionDb, () => {
24905
26266
  return;
24906
26267
  }, {
24907
- beforeRetry: (_error) => {
26268
+ beforeRetry: async (_error) => {
26269
+ hostMessagesAtEntry = [...draft.messages];
26270
+ systemAtEntry = structuredClone(draft.system);
24908
26271
  let replayBlocked = false;
24909
- const mapped = adaptPayload(draft);
26272
+ const input = await buildReplayInput();
26273
+ if (!input)
26274
+ return;
26275
+ const { mapped } = input;
24910
26276
  try {
24911
26277
  const overflowDb = db;
24912
26278
  if (overflowDb !== undefined && overflowDb !== null && (isEmergencyRecoveryArmed(draft.sessionID) || getOverflowState(overflowDb, draft.sessionID).needsEmergencyRecovery)) {
@@ -24927,6 +26293,7 @@ async function registerContext(context) {
24927
26293
  restoreLkgSystem();
24928
26294
  mapped.messages.splice(0, mapped.messages.length, ...replay.messages);
24929
26295
  mapped.commit();
26296
+ adoptReplay(input.draft);
24930
26297
  sessionLog(draft.sessionID, "lkg_replay_served");
24931
26298
  throw new V2LkgAdmissionReplay;
24932
26299
  } else {
@@ -24943,6 +26310,8 @@ async function registerContext(context) {
24943
26310
  sessionLog(draft.sessionID, "lkg_replay_declined");
24944
26311
  }
24945
26312
  });
26313
+ hostMessagesAtEntry = [...draft.messages];
26314
+ systemAtEntry = structuredClone(draft.system);
24946
26315
  if (admissionDb)
24947
26316
  hideSubagentTools(draft, admissionDb);
24948
26317
  recordV2ToolDefinitions(draft);
@@ -25046,7 +26415,11 @@ async function registerContext(context) {
25046
26415
  contextUsageMap: usage,
25047
26416
  compactionOff,
25048
26417
  storeGeneration: "v2",
25049
- normalizeRestoredAssistantText: stripCopiedTagNotation,
26418
+ normalizeRestoredAssistantText: (text, providerID) => {
26419
+ const normalized = stripCopiedTagNotation(text);
26420
+ return normalized === "" && !modelAcceptsEmptyContent(providerID) ? text : normalized;
26421
+ },
26422
+ refreshSourceContents: (sessionID) => committedSourceRefreshes.has(sessionID),
25050
26423
  hostCleanupCompactionMarkers: () => ({
25051
26424
  verified: true,
25052
26425
  removedLineages: 0,
@@ -25073,7 +26446,7 @@ async function registerContext(context) {
25073
26446
  sessionDirectoryBySession: sessionDirectories,
25074
26447
  projectPath: directory,
25075
26448
  agentBySession: agents,
25076
- maintenanceConfig: config.maintenance ? () => config.maintenance : undefined,
26449
+ maintenanceConfig: config.maintenance ? () => inheritMaintenanceModelConfig(config) : undefined,
25077
26450
  hiddenCompletionExecutor,
25078
26451
  historianRunnable: !compactionOff && hiddenCompletionExecutor !== undefined && config.historian?.disable !== true,
25079
26452
  historianModel: historianModels.primary,
@@ -25091,8 +26464,14 @@ async function registerContext(context) {
25091
26464
  },
25092
26465
  ...createHostSeams(context, readAllForConversion, pagedRead, liveModels)
25093
26466
  });
26467
+ const refreshToken = committedSourceRefreshes.get(draft.sessionID);
26468
+ if (refreshToken) {
26469
+ clearCachedM0(db, draft.sessionID);
26470
+ restoredRows.forget(draft.sessionID);
26471
+ }
25094
26472
  const admitted = new Set;
25095
26473
  const reader = openStoreReader();
26474
+ let messageTimes;
25096
26475
  let checkpoint;
25097
26476
  let submitted;
25098
26477
  try {
@@ -25107,12 +26486,14 @@ async function registerContext(context) {
25107
26486
  historyRefreshSessions.add(draft.sessionID);
25108
26487
  requestPendingMaterialization(pendingMaterializationSessions, draft.sessionID, "boundary_repair");
25109
26488
  }
25110
- const incoming = cut && draft.messages.find((message) => message.id === cut.id);
26489
+ const localCut = cut && isLocalCheckpoint(cut) ? cut : undefined;
26490
+ const incoming = localCut && draft.messages.find((message) => message.id === localCut.id);
25111
26491
  postFold = cut !== undefined;
25112
- if (cut && !incoming)
26492
+ checkpointAtEntry = incoming || null;
26493
+ if (localCut && !incoming)
25113
26494
  throw new Error("The host checkpoint disappeared from the context draft");
25114
26495
  let nativeRestored;
25115
- if (cut && nativeFoldReplay && isLocalCheckpoint(cut)) {
26496
+ if (cut && nativeFoldReplay && await nativeFoldReplay.admits(draft.sessionID, cut, reader)) {
25116
26497
  try {
25117
26498
  nativeRestored = await nativeFoldReplay.restore(draft.sessionID, cut, `${draft.model.providerID}/${draft.model.id}`, { bounded: true });
25118
26499
  } catch (error) {
@@ -25121,7 +26502,7 @@ async function registerContext(context) {
25121
26502
  nativeRestored = await nativeFoldReplay.restoreRead(draft.sessionID, cut, draft.model);
25122
26503
  }
25123
26504
  }
25124
- if (nativeRestored && nativeFoldReplay?.sourceChanged(draft.sessionID)) {
26505
+ if (cut && nativeFoldReplay?.sourceChanged(draft.sessionID)) {
25125
26506
  historyRefreshSessions.add(draft.sessionID);
25126
26507
  requestPendingMaterialization(pendingMaterializationSessions, draft.sessionID, "host_history_change");
25127
26508
  }
@@ -25132,30 +26513,33 @@ async function registerContext(context) {
25132
26513
  return !id || !present.has(id);
25133
26514
  });
25134
26515
  draft.messages.splice(0, draft.messages.length, ...hidden, ...draft.messages.filter((message) => message !== incoming));
25135
- } else if (cut && incoming) {
25136
- const identity = await folds.observe({
25137
- sessionID: draft.sessionID,
25138
- cutSeq: cut.seq,
25139
- summary: cut.data.summary ?? "",
25140
- rendered: incoming,
25141
- onHard: (reason) => {
25142
- log(`[magic-context] HARD reason=${reason} session=${draft.sessionID}`);
25143
- materialize(draft);
25144
- requestPendingMaterialization(pendingMaterializationSessions, draft.sessionID, "host_compaction");
25145
- }
25146
- });
25147
- checkpoint = structuredClone(identity.rendered ?? incoming);
25148
- submitted = identity.rendered ? identity.renderedSummary ?? identity.submitted : cut.data.summary ?? "";
25149
- const boundaryID = db.prepare("SELECT cached_m0_last_baseline_end_message_id AS id FROM session_meta WHERE session_id = ?").get(draft.sessionID)?.id ?? (boundaryRepair?.kind === "repaired" || boundaryRepair?.kind === "baseline-reset" ? boundaryRepair.anchorEndMessageId : null);
25150
- const servedBoundary = boundaryID ? servedBoundaryRow(reader, draft.sessionID, boundaryID) : null;
25151
- const boundary = servedBoundary?.seq ?? reader.sequenceForId(draft.sessionID, boundaryID) ?? (reader.earliestSequence(draft.sessionID) ?? 0) - 1;
25152
- const present = new Set(draft.messages.map((message) => message.id));
25153
- const restored = restoredRows.rows(reader, draft.sessionID, boundary, cut.seq).filter((row) => !present.has(row.id)).flatMap((row) => restoreRow(row, draft.model, hostUsesMediaAssets() ? {
25154
- asset: hostMediaAsset,
25155
- unavailable: (detail) => sessionLog(draft.sessionID, `v2 restore: attachment replaced by a note row=${detail.rowID} name=${JSON.stringify(detail.name ?? null)} mediaType=${detail.mediaType} reason=${JSON.stringify(detail.reason)}`)
25156
- } : undefined));
25157
- draft.messages.splice(0, draft.messages.length, ...restored, ...draft.messages.filter((message) => message !== incoming));
26516
+ } else if (localCut && cut && incoming) {
26517
+ if (!nativeFoldReplay) {
26518
+ const identity = await folds.observe({
26519
+ sessionID: draft.sessionID,
26520
+ cutSeq: cut.seq,
26521
+ summary: cut.data.summary ?? "",
26522
+ rendered: incoming,
26523
+ onHard: (reason) => {
26524
+ log(`[magic-context] HARD reason=${reason} session=${draft.sessionID}`);
26525
+ materialize(draft);
26526
+ requestPendingMaterialization(pendingMaterializationSessions, draft.sessionID, "host_compaction");
26527
+ }
26528
+ });
26529
+ checkpoint = structuredClone(identity.rendered ?? incoming);
26530
+ submitted = identity.rendered ? identity.renderedSummary ?? identity.submitted : cut.data.summary ?? "";
26531
+ }
26532
+ draft.messages.splice(0, draft.messages.length, ...restoreAfterCheckpoint({
26533
+ db,
26534
+ reader,
26535
+ draft,
26536
+ messages: draft.messages,
26537
+ cut: localCut,
26538
+ incoming,
26539
+ boundaryRepair
26540
+ }));
25158
26541
  }
26542
+ messageTimes = readTimes(reader, draft.messages);
25159
26543
  } finally {
25160
26544
  reader.close();
25161
26545
  }
@@ -25167,31 +26551,18 @@ async function registerContext(context) {
25167
26551
  nativeFoldReplay.invalidate(draft.sessionID, true);
25168
26552
  }
25169
26553
  }
25170
- const mapped = adaptPayload(draft, admitted);
26554
+ const mapped = adaptPayload(draft, admitted, messageTimes, anchorTimesOnly);
25171
26555
  bindSystemDateRequestIdentity(mapped, draft);
25172
26556
  await transform({}, mapped);
25173
26557
  mapped.commit();
26558
+ if (refreshToken && committedSourceRefreshes.get(draft.sessionID) === refreshToken)
26559
+ committedSourceRefreshes.delete(draft.sessionID);
25174
26560
  if (db) {
25175
26561
  await deliverPendingChannel2(context, db, draft.sessionID, channel1.get(draft.sessionID));
25176
26562
  }
25177
- if (checkpoint && submitted !== undefined) {
25178
- const head = draft.messages.find((message) => message.id === HEAD_IDS[0]);
25179
- const baseline = head?.content.find((part) => part.type === "text")?.text;
25180
- if (typeof baseline === "string") {
25181
- for (const part of checkpoint.content)
25182
- if (part.type === "text" && typeof part.text === "string") {
25183
- part.text = part.text.replace(`<summary>
25184
- ${submitted}
25185
- </summary>`, `<summary>
25186
- ${baseline}
25187
- </summary>`);
25188
- }
25189
- const volatile = draft.messages.find((message) => message.id === HEAD_IDS[1]);
25190
- if (volatile && head)
25191
- volatile.content.push(...head.content.filter((part) => part.type !== "text"));
25192
- draft.messages.splice(0, draft.messages.length, checkpoint, ...draft.messages.filter((message) => message !== head));
25193
- }
25194
- }
26563
+ const head = replayHead !== undefined ? replayHead : checkpoint && submitted !== undefined ? { checkpoint, submitted } : null;
26564
+ const servedHead = head && structuredClone(head);
26565
+ const headApplied = head ? applyCheckpointHead(draft, head) : false;
25195
26566
  if (nativeMessages && !checkpoint) {
25196
26567
  try {
25197
26568
  await nativeFoldReplay?.capture(draft, nativeMessages);
@@ -25202,7 +26573,7 @@ ${baseline}
25202
26573
  }
25203
26574
  const capturedSlot = getSlot(draft.sessionID);
25204
26575
  if (capturedSlot && (!slotAtEntry || capturedSlot.capturedAt !== slotAtEntry.capturedAt || capturedSlot.captureSequence !== slotAtEntry.captureSequence || capturedSlot.jsonPrefix !== slotAtEntry.jsonPrefix)) {
25205
- lkgSystems.capture(draft.sessionID, capturedSlot, systemAtEntry, draft.system);
26576
+ lkgSystems.capture(draft.sessionID, capturedSlot, { system: systemAtEntry, checkpoint: checkpointAtEntry ?? null }, draft.system, headApplied ? servedHead : null);
25206
26577
  }
25207
26578
  } catch (error) {
25208
26579
  if (error instanceof V2ContextRefusal)
@@ -25228,7 +26599,10 @@ ${baseline}
25228
26599
  replayBlocked = true;
25229
26600
  sessionLog(draft.sessionID, "lkg_emergency_armed");
25230
26601
  } else {
25231
- const replayMapped = adaptPayload(draft);
26602
+ const input = await buildReplayInput();
26603
+ if (!input)
26604
+ throw new StorageBusyRefusalError(error, "v2-context");
26605
+ const replayMapped = input.mapped;
25232
26606
  const keys = resolveLkgModelKeys(replayMapped.messages);
25233
26607
  const replay = replayLkg({
25234
26608
  sessionId: draft.sessionID,
@@ -25242,6 +26616,8 @@ ${baseline}
25242
26616
  restoreLkgSystem();
25243
26617
  replayMapped.messages.splice(0, replayMapped.messages.length, ...replay.messages);
25244
26618
  replayMapped.commit();
26619
+ adoptReplay(input.draft);
26620
+ sessionLog(draft.sessionID, "lkg_replay_served");
25245
26621
  return;
25246
26622
  } else {
25247
26623
  sessionLog(draft.sessionID, replay.reason);
@@ -25386,17 +26762,23 @@ ${baseline}
25386
26762
  }, 0);
25387
26763
  return {
25388
26764
  async dispose() {
26765
+ usageController.abort();
26766
+ if (orphanSweepTimer)
26767
+ clearTimeout(orphanSweepTimer);
26768
+ await hiddenCompletionExecutor?.dispose();
26769
+ await usageDone;
26770
+ await orphanSweep;
25389
26771
  rpcStopped = true;
25390
26772
  rpcServer.stop();
25391
26773
  tools?.dispose();
25392
- usageController.abort();
25393
- await usageDone;
25394
26774
  deletedSessions.clear();
26775
+ committedSourceRefreshes.clear();
25395
26776
  for (const release of rawProviders.values())
25396
26777
  release();
25397
26778
  rawProviders.clear();
25398
26779
  restoredRows.clear();
25399
- readerPool.close();
26780
+ if (!await readerPool.closeWhenIdle(STORE_POOL_DISPOSE_WAIT_MS))
26781
+ log(`[magic-context] v2 store reader pool still held by ${readerPool.holdCount()} hidden run(s) at dispose; it closes when they finish`);
25400
26782
  clearSyntheticCandidates(context);
25401
26783
  }
25402
26784
  };