@cortexkit/opencode-magic-context 0.49.5 → 0.49.7

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 (156) hide show
  1. package/dist/auto-search-worker.js +10 -7
  2. package/dist/{compaction-marker-candidates-dd638ypn.js → compaction-marker-candidates-a0edbqrr.js} +2 -2
  3. package/dist/compaction-marker-candidates-worker.js +2 -2
  4. package/dist/{conflict-warning-hook-ae8nmv7c.js → conflict-warning-hook-myk5hbt9.js} +5 -5
  5. package/dist/{context-yg023c5r.js → context-ffr7e0g7.js} +46 -34
  6. package/dist/{embedding-backfill-aj488s8x.js → embedding-backfill-re16xncd.js} +6 -6
  7. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  8. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts +6 -3
  9. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts.map +1 -1
  10. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts +7 -1
  11. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts.map +1 -1
  12. package/dist/features/magic-context/dreamer/map-memories.d.ts +2 -2
  13. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  14. package/dist/features/magic-context/dreamer/primer-seed.d.ts +2 -0
  15. package/dist/features/magic-context/dreamer/primer-seed.d.ts.map +1 -1
  16. package/dist/features/magic-context/dreamer/refresh-primers.d.ts +2 -2
  17. package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
  18. package/dist/features/magic-context/storage-meta-persisted.d.ts +10 -3
  19. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  20. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  21. package/dist/features/magic-context/storage-replay-document.d.ts +4 -0
  22. package/dist/features/magic-context/storage-replay-document.d.ts.map +1 -1
  23. package/dist/hooks/magic-context/apply-operations.d.ts +7 -0
  24. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  26. package/dist/hooks/magic-context/history-boundary-repair.d.ts.map +1 -1
  27. package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
  28. package/dist/hooks/magic-context/note-nudger.d.ts +5 -3
  29. package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
  30. package/dist/hooks/magic-context/postprocess-read-cache.d.ts.map +1 -1
  31. package/dist/hooks/magic-context/read-session-chunk.d.ts +7 -0
  32. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/replay-committed-drops.d.ts +9 -0
  34. package/dist/hooks/magic-context/replay-committed-drops.d.ts.map +1 -0
  35. package/dist/hooks/magic-context/rust-lkg-freeze-registry.d.ts +2 -2
  36. package/dist/hooks/magic-context/rust-lkg-freeze-registry.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/rust-mode-transform.d.ts +3 -0
  38. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  39. package/dist/hooks/magic-context/rust-served-raw.d.ts +29 -0
  40. package/dist/hooks/magic-context/rust-served-raw.d.ts.map +1 -0
  41. package/dist/hooks/magic-context/strip-content.d.ts +23 -24
  42. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/tag-messages.d.ts +2 -0
  44. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/tool-drop-target.d.ts +2 -0
  46. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  47. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  48. package/dist/{index-m4p77myp.js → index-0gyq3djm.js} +1 -1
  49. package/dist/{index-jpm52v9x.js → index-37q80veb.js} +1 -1
  50. package/dist/{index-znzgze2v.js → index-4btknbqh.js} +9 -8
  51. package/dist/{index-v4bqjy56.js → index-5tbvdff4.js} +59 -28
  52. package/dist/{index-7jzrrxap.js → index-9yyqq3mm.js} +1 -1
  53. package/dist/{index-qvr78ej6.js → index-a8acx4gc.js} +2 -2
  54. package/dist/{index-gcdb3rqw.js → index-ax2jhztn.js} +1 -1
  55. package/dist/{index-2mqps3c1.js → index-ebnngykq.js} +145 -94
  56. package/dist/{index-41gqa557.js → index-g8qbdb03.js} +1 -1
  57. package/dist/{index-fst3t0d9.js → index-j58gqrn2.js} +65 -65
  58. package/dist/{index-xfbfrngb.js → index-j5hce1ab.js} +2 -2
  59. package/dist/{index-kb9nn0a0.js → index-j8epsc0g.js} +35 -14
  60. package/dist/{index-7zg9dvx0.js → index-n5a170gs.js} +227 -38
  61. package/dist/{index-fjtgekd4.js → index-n7kwfw2r.js} +4 -4
  62. package/dist/{index-dd18gej8.js → index-rwmpkss5.js} +3 -3
  63. package/dist/{index-7w18gg78.js → index-rzmjkdd6.js} +1 -1
  64. package/dist/{index-c0b01zrc.js → index-sf94at64.js} +3 -3
  65. package/dist/{index-yxawqmdd.js → index-sh91t19a.js} +1 -1
  66. package/dist/{index-x3y1np1h.js → index-tagss15p.js} +857 -125
  67. package/dist/{index-yqps2zsv.js → index-tmtty2x5.js} +1 -1
  68. package/dist/{index-bhk710rw.js → index-vt4sf4ep.js} +1 -1
  69. package/dist/{index-6m7rdv7y.js → index-w4mw92w3.js} +1 -1
  70. package/dist/{index-7ndnvw7a.js → index-w6bd03dc.js} +1 -1
  71. package/dist/{index-p2hs3rps.js → index-w6vr754t.js} +4 -4
  72. package/dist/{index-3wckxwfp.js → index-wq16ahsn.js} +5 -5
  73. package/dist/index.js +36 -36
  74. package/dist/{message-index-bounded-pv6ct15d.js → message-index-bounded-04rycpx4.js} +9 -9
  75. package/dist/{message-index-jqa7qd0s.js → message-index-rqtse28y.js} +9 -9
  76. package/dist/{message-time-backfill-8x06r9kx.js → message-time-backfill-a5ytnp53.js} +1 -1
  77. package/dist/migration-worker.js +6 -6
  78. package/dist/plugin/messages-transform.d.ts.map +1 -1
  79. package/dist/{project-embedding-registry-fcmszatg.js → project-embedding-registry-k0sd9k7v.js} +5 -5
  80. package/dist/raw-ordinal-warmup-worker.js +17 -15
  81. package/dist/{read-session-chunk-cwgjwjd0.js → read-session-chunk-h1btx938.js} +7 -5
  82. package/dist/{read-session-raw-z38cn0as.js → read-session-raw-vdf4wh78.js} +2 -2
  83. package/dist/{recomp-orchestrator-xw9wt5bm.js → recomp-orchestrator-trcgmm23.js} +20 -20
  84. package/dist/{search-v1t47s2q.js → search-3rbdx6hw.js} +16 -16
  85. package/dist/{send-session-notification-yp9m5g4p.js → send-session-notification-2tp44tfa.js} +4 -4
  86. package/dist/shared/processed-image-eligibility.d.ts +22 -0
  87. package/dist/shared/processed-image-eligibility.d.ts.map +1 -0
  88. package/dist/shared/recovery-reasoning-prefix.d.ts +9 -0
  89. package/dist/shared/recovery-reasoning-prefix.d.ts.map +1 -0
  90. package/dist/shared/sqlite.d.ts +1 -1
  91. package/dist/shared/sqlite.d.ts.map +1 -1
  92. package/dist/shared/tag-transcript.d.ts +9 -0
  93. package/dist/shared/tag-transcript.d.ts.map +1 -1
  94. package/dist/{sqlite-mhjkerzq.js → sqlite-j3tvg8r0.js} +1 -1
  95. package/dist/{storage-memory-07fx57k6.js → storage-memory-8168bgef.js} +2 -2
  96. package/dist/{storage-tags-0ssbmzg9.js → storage-tags-61z5j2f9.js} +2 -2
  97. package/dist/tools/ctx-expand/search-archive.d.ts +4 -0
  98. package/dist/tools/ctx-expand/search-archive.d.ts.map +1 -0
  99. package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
  100. package/dist/{transform-postprocess-phase-ttra554y.js → transform-postprocess-phase-7qts7h54.js} +20 -20
  101. package/dist/v2/auto-search-worker.js +10 -7
  102. package/dist/v2/{compaction-marker-candidates-1s21e2fz.js → compaction-marker-candidates-6nypjkpf.js} +2 -2
  103. package/dist/v2/compaction-marker-candidates-worker.js +2 -2
  104. package/dist/v2/{context-6en6a8ar.js → context-xq4rtywr.js} +1019 -233
  105. package/dist/v2/{embedding-backfill-9hbkfvnz.js → embedding-backfill-xd9ygzgd.js} +6 -6
  106. package/dist/v2/hooks/payload.d.ts.map +1 -1
  107. package/dist/v2/{message-index-h8ssgq3q.js → message-index-8e5z2xx8.js} +9 -9
  108. package/dist/v2/{message-index-bounded-c0810p5w.js → message-index-bounded-5vh1h2g7.js} +9 -9
  109. package/dist/v2/{message-time-backfill-cje68egj.js → message-time-backfill-2z365239.js} +1 -1
  110. package/dist/v2/migration-worker.js +6 -6
  111. package/dist/v2/{project-embedding-registry-42th7k1z.js → project-embedding-registry-b77awytr.js} +5 -5
  112. package/dist/v2/raw-ordinal-warmup-worker.js +17 -15
  113. package/dist/v2/{read-session-chunk-n86v9xfg.js → read-session-chunk-4sat83cx.js} +7 -5
  114. package/dist/v2/{read-session-raw-3b3ehga4.js → read-session-raw-a3hw9jsp.js} +2 -2
  115. package/dist/v2/{recomp-orchestrator-krvsbnds.js → recomp-orchestrator-n11zv1f1.js} +19 -19
  116. package/dist/v2/{search-048v8y02.js → search-mvgqtkkz.js} +16 -16
  117. package/dist/v2/{send-session-notification-a4h2azxa.js → send-session-notification-ppgc8qdz.js} +4 -4
  118. package/dist/v2/{server-cvgn49tr.js → server-1rfgbjfn.js} +1 -1
  119. package/dist/v2/{server-3bc6k4k4.js → server-7srtwsa4.js} +5 -5
  120. package/dist/v2/{server-7jzrrxap.js → server-9yyqq3mm.js} +1 -1
  121. package/dist/v2/{server-2htmbqbv.js → server-brhj8qtd.js} +1 -1
  122. package/dist/v2/{server-3dqjhchy.js → server-dd0nja67.js} +1 -1
  123. package/dist/v2/{server-8wcf79fe.js → server-fpqe39as.js} +1 -1
  124. package/dist/v2/{server-cjz51jm2.js → server-fw31krgq.js} +3 -3
  125. package/dist/v2/{server-4n2tknpc.js → server-gtv9wbhq.js} +227 -38
  126. package/dist/v2/{server-8pqnnmf9.js → server-hcvcxzx7.js} +2 -2
  127. package/dist/v2/{server-kb9nn0a0.js → server-j8epsc0g.js} +35 -14
  128. package/dist/v2/{server-rygvffsf.js → server-jdwd03ep.js} +4 -4
  129. package/dist/v2/{server-q6j5dasr.js → server-kdrezdy0.js} +1 -1
  130. package/dist/v2/{server-e2v4m8xe.js → server-mv1w7t6z.js} +61 -30
  131. package/dist/v2/{server-hetyb88z.js → server-nfan6zb6.js} +65 -65
  132. package/dist/v2/{server-4enr7s6x.js → server-qcw43339.js} +1 -1
  133. package/dist/v2/{server-5zrpr764.js → server-sy4b1sra.js} +1 -1
  134. package/dist/v2/{server-9a6v0wth.js → server-v4fwha43.js} +9 -8
  135. package/dist/v2/{server-pcygfdbs.js → server-w3zeywp1.js} +1 -1
  136. package/dist/v2/{server-czb2rkpk.js → server-wkdgjjch.js} +1 -1
  137. package/dist/v2/{server-9290a1mb.js → server-x08d1xf3.js} +1 -1
  138. package/dist/v2/server.js +4 -4
  139. package/dist/v2/{sqlite-mhjkerzq.js → sqlite-j3tvg8r0.js} +1 -1
  140. package/dist/v2/{storage-memory-07fx57k6.js → storage-memory-8168bgef.js} +2 -2
  141. package/dist/v2/{storage-tags-3a4cavqb.js → storage-tags-j2fzq3sw.js} +2 -2
  142. package/dist/v2/{wrapup-orchestrator-r2v7kgy3.js → wrapup-orchestrator-s92ebfzv.js} +19 -19
  143. package/dist/{wrapup-orchestrator-z7agncp8.js → wrapup-orchestrator-df61jmz9.js} +21 -21
  144. package/package.json +3 -3
  145. package/src/shared/processed-image-eligibility.test.ts +68 -0
  146. package/src/shared/processed-image-eligibility.ts +41 -0
  147. package/src/shared/processed-image-position-review.json +20 -0
  148. package/src/shared/processed-image-position-review.test.ts +19 -0
  149. package/src/shared/recovery-reasoning-prefix.test.ts +34 -0
  150. package/src/shared/recovery-reasoning-prefix.ts +35 -0
  151. package/src/shared/sqlite-acquisition-routing.test.ts +4 -3
  152. package/src/shared/sqlite-foreground-wait.test.ts +140 -0
  153. package/src/shared/sqlite-pass-scope.test.ts +4 -4
  154. package/src/shared/sqlite-writer-diagnostics.test.ts +31 -0
  155. package/src/shared/sqlite.ts +64 -23
  156. package/src/shared/tag-transcript.ts +118 -0
@@ -38,7 +38,7 @@ import {
38
38
  SqliteAcquisitionBusyError2,
39
39
  withAsyncPrivilegedWriter2,
40
40
  indexCoordinationInput2
41
- } from "./index-kb9nn0a0.js";
41
+ } from "./index-j8epsc0g.js";
42
42
  import {
43
43
  shouldSkipHomeProjectMemory,
44
44
  ProjectIdentityError,
@@ -53,7 +53,7 @@ import {
53
53
  storedPathBelongsToIdentity,
54
54
  beginBootQuietPeriod,
55
55
  scheduleAfterBootQuiet
56
- } from "./index-41gqa557.js";
56
+ } from "./index-g8qbdb03.js";
57
57
  import {
58
58
  recordSessionProjectIdentity,
59
59
  hasRecordedSessionProjectIdentity,
@@ -80,7 +80,7 @@ import {
80
80
  drainCommitBacklogForProject2,
81
81
  embedSessionCompartmentChunks2,
82
82
  getEmbeddingCoverageStatus2
83
- } from "./index-c0b01zrc.js";
83
+ } from "./index-sf94at64.js";
84
84
  import {
85
85
  hasTrustedAbsoluteWall,
86
86
  applyProvenInputFloor,
@@ -110,6 +110,7 @@ import {
110
110
  import {
111
111
  protectedToolTokenCount,
112
112
  peelLeadingMcTagNotation,
113
+ isThinkingPart,
113
114
  isRecord,
114
115
  contentTagOwnerMessageId,
115
116
  normalizeTodoStateJson,
@@ -142,9 +143,10 @@ import {
142
143
  getDroppedTagsByNumbers2,
143
144
  getMaxDroppedTagNumber2,
144
145
  getTagById2
145
- } from "./index-yqps2zsv.js";
146
+ } from "./index-tmtty2x5.js";
146
147
  import {
147
- observeTemporalDecisions
148
+ observeTemporalDecisions,
149
+ stableStringify
148
150
  } from "./index-1bt88epp.js";
149
151
  import {
150
152
  withContentLanguageDirective,
@@ -164,7 +166,7 @@ import {
164
166
  extractInMemoryMessageViews2,
165
167
  buildInMemoryTailRawMessages2,
166
168
  runSessionWarmupWorker
167
- } from "./index-jpm52v9x.js";
169
+ } from "./index-37q80veb.js";
168
170
  import {
169
171
  openCodeDbExists,
170
172
  withReadOnlySessionDb,
@@ -172,10 +174,11 @@ import {
172
174
  latestPersistedMessageForRecovery,
173
175
  latestRealUserTurnIdFromOpenCodeDb,
174
176
  findLastAssistantModelFromOpenCodeDb
175
- } from "./index-qvr78ej6.js";
177
+ } from "./index-a8acx4gc.js";
176
178
  import {
177
179
  expandToolPart,
178
180
  estimateTrueRawMessageTokens,
181
+ isTextPart,
179
182
  toolPartHasUserAnswer,
180
183
  DreamTokenBudgetExceeded,
181
184
  isEditTool,
@@ -185,6 +188,8 @@ import {
185
188
  sessionDecisionCalibration,
186
189
  getProtectionWindowForSession,
187
190
  ensureSessionMetaRow,
191
+ withReplayEnvelopeSnapshot,
192
+ invalidateReplayEnvelopeSnapshot,
188
193
  isRustMarkerAdmissionFenced,
189
194
  setRustMarkerAdmissionFence,
190
195
  readReplayEnvelope,
@@ -268,11 +273,16 @@ import {
268
273
  createFinalWireUsageTracker,
269
274
  estimateFinalWireInputTokens,
270
275
  estimateAppendedWireTokens,
276
+ partHasCompletedResult,
277
+ extractToolCallObservation,
278
+ ToolMutationBatch,
279
+ createToolDropTarget,
271
280
  setRawMessageProvider2,
272
281
  cleanUserText2,
273
282
  withRawSessionMessageCache2,
274
283
  readRawSessionMessages2,
275
284
  visitRawSessionMessages2,
285
+ visitRawSessionMessagesAsync2,
276
286
  prepareRawSessionOrdinals2,
277
287
  primeTailRawMessageCache2,
278
288
  primeInMemoryTailRawMessageCache2,
@@ -284,7 +294,7 @@ import {
284
294
  readRawSessionMessageById2,
285
295
  readSessionChunk2,
286
296
  readRawSessionSeedTail2
287
- } from "./index-7zg9dvx0.js";
297
+ } from "./index-n5a170gs.js";
288
298
  import {
289
299
  getMeasuredToolDefinitionTokens
290
300
  } from "./index-h2wc01qk.js";
@@ -315,20 +325,20 @@ import {
315
325
  runSqliteOptimize,
316
326
  openDatabase,
317
327
  openCurrentDatabase
318
- } from "./index-znzgze2v.js";
328
+ } from "./index-4btknbqh.js";
319
329
  import {
320
330
  registerOwnRpcServerInstance,
321
331
  rpcPortDir,
322
332
  rpcPortFilePath,
323
333
  parseRpcPortFile,
324
334
  inspectProcessesAsync
325
- } from "./index-6m7rdv7y.js";
335
+ } from "./index-w4mw92w3.js";
326
336
  import {
327
337
  configureContextDatabasePragmas2
328
338
  } from "./index-fb3zxn06.js";
329
339
  import {
330
340
  canonicalProjectDirectory
331
- } from "./index-7w18gg78.js";
341
+ } from "./index-rzmjkdd6.js";
332
342
  import {
333
343
  unescapeXml,
334
344
  resolveWorkspaceShareCategories,
@@ -337,7 +347,7 @@ import {
337
347
  resolveStoredPathWorkspaceIdentity,
338
348
  storedPathBelongsToWorkspace,
339
349
  computeWorkspaceEpochFingerprint
340
- } from "./index-xfbfrngb.js";
350
+ } from "./index-j5hce1ab.js";
341
351
  import {
342
352
  V2_MEMORY_CATEGORIES,
343
353
  CATEGORY_PRIORITY
@@ -394,6 +404,8 @@ import {
394
404
  resolveLkgModelKeys,
395
405
  createLkgEntryProjector,
396
406
  captureLkgSlot,
407
+ validateAnthropicReasoningRuns,
408
+ validateLkgSeam,
397
409
  replayLkg,
398
410
  coldStartRawServedIndex,
399
411
  coldStartUncapturedReplay,
@@ -509,7 +521,7 @@ import {
509
521
  snapRangeToCompartments,
510
522
  getActiveCompartmentRun,
511
523
  startCompartmentAgent
512
- } from "./index-v4bqjy56.js";
524
+ } from "./index-5tbvdff4.js";
513
525
  import {
514
526
  SubcClient,
515
527
  connectionFileExists,
@@ -538,7 +550,7 @@ import {
538
550
  indexSingleMessage2,
539
551
  indexMessagesAfterOrdinal2,
540
552
  sweepOrphanedOpenCodeMessageIndexes2
541
- } from "./index-3wckxwfp.js";
553
+ } from "./index-wq16ahsn.js";
542
554
  import {
543
555
  renderUserFacingFailure,
544
556
  userFacingFailureCode,
@@ -582,7 +594,7 @@ import {
582
594
  readGitFileChangeTimesSince,
583
595
  verificationFileExists,
584
596
  normalizeVerificationFiles
585
- } from "./index-fjtgekd4.js";
597
+ } from "./index-n7kwfw2r.js";
586
598
  import {
587
599
  registerNotificationSink2,
588
600
  pushNotification2,
@@ -600,7 +612,7 @@ import {
600
612
  } from "./index-4dhv7mqz.js";
601
613
  import {
602
614
  cosineSimilarity
603
- } from "./index-7ndnvw7a.js";
615
+ } from "./index-w6bd03dc.js";
604
616
  import {
605
617
  computeCueContentHash,
606
618
  hasMuralCueColumns,
@@ -625,7 +637,7 @@ import {
625
637
  mergeMemoryStats2,
626
638
  archiveMemory2,
627
639
  getMemoryCountsByStatus2
628
- } from "./index-7jzrrxap.js";
640
+ } from "./index-9yyqq3mm.js";
629
641
  import {
630
642
  renderSingleStoreMigrationRequiredRefusal,
631
643
  SingleStoreMigrationRequiredError,
@@ -641,23 +653,25 @@ import {
641
653
  SubcModuleTransport,
642
654
  indexCommitsForProject,
643
655
  embedUnembeddedCommits,
656
+ withMessageFtsSessionFilter,
644
657
  createUnifiedSearchDiagnostics2,
645
658
  parseIdShapedQuery2,
646
659
  resolveMemoriesByIdsForSearch2,
647
660
  unifiedSearch2,
648
661
  formatSearchResults2
649
- } from "./index-fst3t0d9.js";
662
+ } from "./index-j58gqrn2.js";
650
663
  import {
651
664
  flushIgnoredMessages2,
652
665
  clearIgnoredMessages2,
653
666
  observeIgnoredNotificationEvent2,
654
667
  sendStatusNotification2
655
- } from "./index-bhk710rw.js";
668
+ } from "./index-vt4sf4ep.js";
656
669
  import {
657
670
  setRecompStarting2,
658
671
  setRecompTerminal2
659
- } from "./index-dd18gej8.js";
672
+ } from "./index-rwmpkss5.js";
660
673
  import {
674
+ makeToolCompositeKey,
661
675
  searchMessageHistoryOffThread,
662
676
  findSessionId,
663
677
  findLastUserMessageId,
@@ -706,7 +720,7 @@ import {
706
720
  abortSessionFailClosed2,
707
721
  evaluateEmergencyFailClosed2,
708
722
  runPostTransformPhase2
709
- } from "./index-2mqps3c1.js";
723
+ } from "./index-ebnngykq.js";
710
724
  import {
711
725
  ANNOUNCEMENT_VERSION2,
712
726
  ANNOUNCEMENT_FEATURES2,
@@ -2797,6 +2811,25 @@ async function runHiddenSingleShotPrompt(args) {
2797
2811
  });
2798
2812
  promptSettled = true;
2799
2813
  return { validated: run.validated, completion: run.output, childSessionId: handle.id };
2814
+ } catch (error) {
2815
+ if (args.onFailureOutput) {
2816
+ let timer;
2817
+ try {
2818
+ const completion = await Promise.race([
2819
+ args.executor.collect(handle, 200),
2820
+ new Promise((resolve) => {
2821
+ timer = setTimeout(() => resolve(null), 5000);
2822
+ })
2823
+ ]);
2824
+ if (completion)
2825
+ args.onFailureOutput(completion);
2826
+ } catch (readError) {
2827
+ log2(`${args.callContext}: failed to collect interrupted output: ${String(readError)}`);
2828
+ } finally {
2829
+ clearTimeout(timer);
2830
+ }
2831
+ }
2832
+ throw error;
2800
2833
  } finally {
2801
2834
  await args.executor.close(handle, {
2802
2835
  promptSettled,
@@ -6626,31 +6659,33 @@ function snapshotMaintainDocsFiles(docsDir) {
6626
6659
  import { createHash as createHash5 } from "node:crypto";
6627
6660
 
6628
6661
  // src/features/magic-context/dreamer/map-memories-prompt.ts
6662
+ import { execFile as execFile2 } from "node:child_process";
6629
6663
  import { existsSync as existsSync4, statSync } from "node:fs";
6630
6664
  import path3 from "node:path";
6665
+ import { promisify as promisify2 } from "node:util";
6631
6666
  var MAP_MEMORIES_SYSTEM_PROMPT = `You are a memory mapper for the magic-context system. You map project memories to the repository files that back them.
6632
6667
 
6633
6668
  A memory's BACKING FILES are the file(s) whose code the memory makes a claim about — the files you would open to check whether the memory is accurate. You do NOT judge accuracy, rewrite, or remove anything. You only LOCATE backing files.
6634
6669
 
6635
- Tools (read-only): read, grep, glob. Request line ranges rather than full files; use offset/limit for longer files. Each memory may come with "Likely files" already named in it and confirmed to exist — confirm those FIRST (cheap) instead of searching. Use search/grep to FIND code only when no likely files are given. Do not guess — confirm a file exists and genuinely backs the memory before listing it. Keep reads minimal: you do not need to read a whole file to confirm it backs a one-line claim.
6670
+ Tools (read-only): read, grep, glob. Use at most 3 tool calls per memory, including searches and reads. Never read the same file twice in a batch; reuse what you already learned. Never repeat an identical search or use broad searches such as "fn " or ".*". Request one useful line range, not repeated slices. Each memory may come with "Likely files" from paths it names or a literal identifier search, confirmed to exist — confirm those FIRST (cheap) instead of searching. Use search/grep to FIND code only when no likely files are given. Do not guess — confirm a file exists and genuinely backs the memory before listing it. You are locating code, not exhaustively verifying the claim. If the call budget runs out before you can decide, leave that id unmapped and move on; uncertainty is not evidence of file-independence.
6636
6671
 
6637
6672
  For each memory decide ONE of:
6638
- - Backing files found → the COMPLETE set of repo-relative paths whose code the memory is about.
6673
+ - Backing files found → the specific repo-relative paths whose code the memory is about; do not chase every caller or related implementation.
6639
6674
  - File-independent → the memory describes EXTERNAL behavior (a provider / API / platform / protocol limit, e.g. "Anthropic returns 400 on empty content"), or a pure process / workflow / philosophy rule, with NO specific local file that backs it. A BEHAVIORAL claim (when to act, how to work, who decides, or tool-usage discipline) is file-independent even when it cites file paths or commands as examples: a named file is not the file backing the rule.
6640
6675
 
6641
- Output ONE XML manifest at the very end and NOTHING else — no narration, no per-memory commentary, no reasoning:
6676
+ Output ONE XML manifest and NOTHING else — no narration, no per-memory commentary, no reasoning. Open <mappings> before investigating. Emit each <memory> element as soon as you decide its mapping, before investigating the next memory, so an interruption cannot lose completed work. Close </mappings> when finished:
6642
6677
  <mappings>
6643
6678
  <memory id="N" files="path/a.ts,path/b.ts"/>
6644
6679
  <memory id="M" independent="true"/>
6645
6680
  </mappings>
6646
6681
 
6647
6682
  Rules:
6648
- - Every input memory id MUST appear exactly once.
6683
+ - Every decided input memory id MUST appear exactly once. Omit uncertain ids rather than inventing backing files or declaring them independent.
6649
6684
  - files: repo-relative, comma-separated, no spaces inside a path. Only files that actually exist and genuinely back the memory.
6650
6685
  - A BACKING FILE is CODE that implements or handles the claim — not a file that merely mentions it. A path named inside a process directive is an action target or example, not evidence that the file backs the directive. A markdown doc (.md), a PARITY/notes file, or a test that only DESCRIBES an external fact is NOT a backing file. If the only place a memory's fact appears is prose/docs/a test (no code implements or handles it), mark it independent="true".
6651
6686
  - Many CONSTRAINTS are HYBRID: "external system does X, and OUR code handles it here." Map those to the HANDLING code (you can verify the handling, even though you can't verify the external behavior). Only mark independent when there is NO local code that implements or handles the fact.
6652
6687
  - Prefer the most specific file(s); do not pad with tangential files. Most memories map to one file; some to a few.
6653
- - When you genuinely cannot find any local backing and it is not clearly external, still emit the memory with independent="true" (do not drop it).`;
6688
+ - Mark independent="true" only for the file-independent cases above; an investigation that runs out of calls stays unmapped.`;
6654
6689
  var MAX_SEED_PATHS_PER_MEMORY = 3;
6655
6690
  var PATH_PATTERN = "`?((?:[\\w.-]+\\/)+[\\w.-]+\\.(?:ts|tsx|js|jsx|mjs|cjs|rs|go|py|json|jsonc|sql|toml|sh))`?";
6656
6691
  function extractMemoryCandidatePaths(content, repoDir) {
@@ -6672,10 +6707,65 @@ function extractMemoryCandidatePaths(content, repoDir) {
6672
6707
  }
6673
6708
  return [...found];
6674
6709
  }
6710
+ var execFileAsync2 = promisify2(execFile2);
6711
+ async function seedIdentifierCandidates(memories, repoDir) {
6712
+ const identifiers = new Map(memories.filter((memory) => memory.candidates.length === 0).map((memory) => [
6713
+ memory.id,
6714
+ [
6715
+ ...new Set(memory.content.match(/\b(?:[A-Z][A-Za-z0-9_]{3,}|[a-z][a-z0-9]*[A-Z][A-Za-z0-9_]*|[a-z][a-z0-9]*_[A-Za-z0-9_]{2,})\b/g) ?? [])
6716
+ ].slice(0, 3)
6717
+ ]));
6718
+ const terms = [...new Set([...identifiers.values()].flat())];
6719
+ if (terms.length === 0)
6720
+ return memories;
6721
+ let stdout;
6722
+ try {
6723
+ const result = await execFileAsync2("git", [
6724
+ "-c",
6725
+ "core.quotePath=false",
6726
+ "grep",
6727
+ "--no-color",
6728
+ "-n",
6729
+ "-I",
6730
+ "-F",
6731
+ ...terms.flatMap((term) => ["-e", term]),
6732
+ "--",
6733
+ ...["ts", "tsx", "js", "jsx", "mjs", "cjs", "rs", "go", "py", "sql", "sh"].map((extension) => `*.${extension}`)
6734
+ ], {
6735
+ cwd: repoDir,
6736
+ encoding: "utf8",
6737
+ timeout: 2000,
6738
+ maxBuffer: 256 * 1024,
6739
+ windowsHide: true,
6740
+ killSignal: "SIGKILL"
6741
+ });
6742
+ stdout = result.stdout;
6743
+ } catch {
6744
+ return memories;
6745
+ }
6746
+ const matches = stdout.split(`
6747
+ `).flatMap((line) => {
6748
+ const match = line.match(/^([^:]+):\d+:(.*)$/);
6749
+ return match ? [{ file: match[1], text: match[2] }] : [];
6750
+ });
6751
+ return memories.map((memory) => {
6752
+ const names = identifiers.get(memory.id);
6753
+ if (!names?.length)
6754
+ return memory;
6755
+ const files = new Map;
6756
+ for (const match of matches) {
6757
+ const score = names.filter((name) => match.text.includes(name)).length;
6758
+ if (score)
6759
+ files.set(match.file, Math.max(files.get(match.file) ?? 0, score));
6760
+ }
6761
+ const candidates = [...files].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, MAX_SEED_PATHS_PER_MEMORY).map(([file]) => file);
6762
+ return candidates.length ? { ...memory, candidates } : memory;
6763
+ });
6764
+ }
6675
6765
  function buildMapMemoriesPrompt(projectPath, memories) {
6676
6766
  const list = memories.map((m) => {
6677
6767
  const seed = m.candidates.length ? `
6678
- Likely files (named in the memory, confirmed to exist): ${m.candidates.join(", ")}` : "";
6768
+ Likely files (candidate paths, confirmed to exist): ${m.candidates.join(", ")}` : "";
6679
6769
  return `[${m.id}] ${m.category}
6680
6770
  ${m.content}${seed}`;
6681
6771
  }).join(`
@@ -6685,13 +6775,13 @@ ${m.content}${seed}`;
6685
6775
 
6686
6776
  Project: ${projectPath}
6687
6777
 
6688
- For each memory below, find the repo file(s) it makes a claim about, or mark it file-independent. Behavioral process/workflow directives stay file-independent even when they name files. When "Likely files" are listed, those paths are named in the memory and confirmed to exist — START there only for code claims: confirm each actually backs the claim (a quick read/outline), drop any that don't, add others only if genuinely needed. Search from scratch only when no likely files are given. Then output ONE <mappings> manifest covering every id.
6778
+ For each memory below, find the repo file(s) it makes a claim about, or mark it file-independent. Behavioral process/workflow directives stay file-independent even when they name files. When "Likely files" are listed, those paths either occur in the memory or match its identifiers in a bounded literal source search — START there only for code claims: confirm each actually backs the claim (a quick read/outline), drop any that don't, add others only if genuinely needed. Search from scratch only when no likely files are given. Use at most 3 tool calls per memory, reuse prior reads, and emit each decided mapping immediately in ONE <mappings> manifest. Leave uncertain ids unmapped and move on.
6689
6779
 
6690
6780
  <memories>
6691
6781
  ${list}
6692
6782
  </memories>`;
6693
6783
  }
6694
- var MEMORY_ELEMENT_PATTERN = "<memory\\b([^>]*)(?:\\/>|>([\\s\\S]*?)<\\/memory>)";
6784
+ var MEMORY_ELEMENT_PATTERN = "<memory\\b([^<>]*)(?:\\/>|>([\\s\\S]*?)<\\/memory>)";
6695
6785
  var NESTED_FILE_PATTERN = "<file\\b([^>]*)\\/?>";
6696
6786
  function extractNestedFilePaths(inner) {
6697
6787
  const files = [];
@@ -6749,12 +6839,78 @@ function validateMapMemoriesManifest(text, expectedIds) {
6749
6839
  assertNoDuplicateManifestIds(parsed.filter((entry) => expectedIds.has(entry.id)).map((entry) => entry.id), "mappings");
6750
6840
  return parsed;
6751
6841
  }
6842
+ function parsePartialMapMemoriesManifest(text, expectedIds) {
6843
+ const start = text.indexOf("<mappings>");
6844
+ if (start < 0)
6845
+ return [];
6846
+ const entries = new Map;
6847
+ const conflicts = new Set;
6848
+ for (const match of text.slice(start).matchAll(new RegExp(MEMORY_ELEMENT_PATTERN, "gi"))) {
6849
+ try {
6850
+ const entry = parseMapMemoriesManifest(`<mappings>${match[0]}</mappings>`)[0];
6851
+ if (!entry || !expectedIds.has(entry.id) || conflicts.has(entry.id))
6852
+ continue;
6853
+ const previous = entries.get(entry.id);
6854
+ if (previous && JSON.stringify(previous) !== JSON.stringify(entry)) {
6855
+ entries.delete(entry.id);
6856
+ conflicts.add(entry.id);
6857
+ } else {
6858
+ entries.set(entry.id, entry);
6859
+ }
6860
+ } catch {}
6861
+ }
6862
+ return [...entries.values()];
6863
+ }
6752
6864
 
6753
6865
  // src/features/magic-context/dreamer/map-memories.ts
6754
- var MAP_BATCH_SIZE = 20;
6866
+ var MAP_BATCH_SIZE = 5;
6755
6867
  var MAP_BATCH_FLOOR_MS = 240000;
6756
6868
  var CONSECUTIVE_TIMEOUT_LIMIT2 = 2;
6757
6869
  var MAX_INDEPENDENT_REQUEUE_PER_RUN = MAP_BATCH_SIZE;
6870
+ function retryKey(project) {
6871
+ return `map-memories:retry:${project}`;
6872
+ }
6873
+ function readRetries(db, project) {
6874
+ try {
6875
+ const parsed = JSON.parse(getDreamState(db, retryKey(project)) ?? "{}");
6876
+ if (!isRecord(parsed))
6877
+ return {};
6878
+ const retries = {};
6879
+ for (const [id, value] of Object.entries(parsed)) {
6880
+ if (isRecord(value) && typeof value.content === "string" && typeof value.failures === "number" && typeof value.deferUntil === "number") {
6881
+ retries[id] = {
6882
+ content: value.content,
6883
+ failures: value.failures,
6884
+ deferUntil: value.deferUntil
6885
+ };
6886
+ }
6887
+ }
6888
+ return retries;
6889
+ } catch {
6890
+ return {};
6891
+ }
6892
+ }
6893
+ function contentKey(memory) {
6894
+ return createHash5("sha256").update(`${memory.category}
6895
+ ${memory.content}`).digest("hex");
6896
+ }
6897
+ function isDeferred(memory, retries) {
6898
+ const retry = retries[memory.id];
6899
+ return !!retry && retry.content === contentKey(memory) && retry.deferUntil > Date.now();
6900
+ }
6901
+ function assistantText(messages) {
6902
+ return messages.filter((message) => isRecord(message) && (message.role === "assistant" || isRecord(message.info) && message.info.role === "assistant")).map((message) => extractLatestAssistantText([message]) ?? (isRecord(message) && Array.isArray(message.content) ? message.content.filter(isRecord).filter((part) => part.type === "text" && typeof part.text === "string").map((part) => part.text).join(`
6903
+ `) : "")).join(`
6904
+ `);
6905
+ }
6906
+ function currentManifest(text) {
6907
+ const start = text.lastIndexOf("<mappings>");
6908
+ return start < 0 ? text : text.slice(start);
6909
+ }
6910
+ function logBatchUsage(messages, committed, startedAt) {
6911
+ const steps = messages.filter((message) => isRecord(message) && (message.role === "assistant" || isRecord(message.info) && message.info.role === "assistant")).length;
6912
+ log2(`[dreamer] map-memories batch: steps=${steps} committed=${committed} steps_per_memory=${committed ? (steps / committed).toFixed(2) : "n/a"} elapsed_ms=${Date.now() - startedAt}`);
6913
+ }
6758
6914
  function computeMapBatchSliceMs(remainingMs, batchesRemaining) {
6759
6915
  return Math.min(remainingMs, Math.max(MAP_BATCH_FLOOR_MS, Math.floor(remainingMs / batchesRemaining)));
6760
6916
  }
@@ -6776,7 +6932,7 @@ function toMapInput(memory, repoDir) {
6776
6932
  candidates: extractMemoryCandidatePaths(memory.content, repoDir)
6777
6933
  };
6778
6934
  }
6779
- function selectMapMemoryInputs(db, projectIdentity, repoDir) {
6935
+ function selectMapMemoryInputs(db, projectIdentity, repoDir, includeDeferred = false) {
6780
6936
  const active = getMemoriesByProject2(db, projectIdentity);
6781
6937
  const activeIds = active.map((m) => m.id);
6782
6938
  const unmapped = new Set(getUnmappedMemoryIds(db, activeIds));
@@ -6795,7 +6951,8 @@ function selectMapMemoryInputs(db, projectIdentity, repoDir) {
6795
6951
  if (requeue.length >= MAX_INDEPENDENT_REQUEUE_PER_RUN)
6796
6952
  break;
6797
6953
  }
6798
- return [...unmappedInputs, ...requeue];
6954
+ const retries = readRetries(db, projectIdentity);
6955
+ return [...unmappedInputs, ...requeue].filter((memory) => includeDeferred || !isDeferred(memory, retries));
6799
6956
  }
6800
6957
  async function mapMemories(args) {
6801
6958
  const result = {
@@ -6805,14 +6962,21 @@ async function mapMemories(args) {
6805
6962
  remaining: 0,
6806
6963
  complete: true
6807
6964
  };
6808
- const inputs = selectMapMemoryInputs(args.db, args.projectIdentity, args.sessionDirectory);
6965
+ const allInputs = selectMapMemoryInputs(args.db, args.projectIdentity, args.sessionDirectory, true);
6966
+ const retries = readRetries(args.db, args.projectIdentity);
6967
+ const activeIds = new Set(allInputs.map((memory) => String(memory.id)));
6968
+ for (const id of Object.keys(retries))
6969
+ if (!activeIds.has(id))
6970
+ delete retries[id];
6971
+ const inputs = allInputs.filter((memory) => !isDeferred(memory, retries));
6972
+ result.remaining = allInputs.length;
6973
+ result.complete = result.remaining === 0;
6809
6974
  if (inputs.length === 0)
6810
6975
  return result;
6811
6976
  const batches = [];
6812
6977
  for (let i = 0;i < inputs.length; i += MAP_BATCH_SIZE) {
6813
6978
  batches.push({ inputs: inputs.slice(i, i + MAP_BATCH_SIZE), isOmissionRetry: false });
6814
6979
  }
6815
- result.remaining = inputs.length;
6816
6980
  const abortController = new AbortController;
6817
6981
  const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, (reason) => abortController.abort(new Error(reason)), args.leaseAcquisition);
6818
6982
  try {
@@ -6835,6 +6999,24 @@ async function mapMemories(args) {
6835
6999
  break;
6836
7000
  const outcome = await mapOneBatch(args, batch.inputs, sliceMs, abortController.signal);
6837
7001
  const committed = outcome.mapped + outcome.independent;
7002
+ runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
7003
+ const committedIds = new Set(outcome.committedIds);
7004
+ for (const memory of batch.inputs) {
7005
+ if (committedIds.has(memory.id)) {
7006
+ delete retries[memory.id];
7007
+ continue;
7008
+ }
7009
+ const content = contentKey(memory);
7010
+ const prior = retries[memory.id];
7011
+ const failures = (prior?.content === content ? prior.failures : 0) + 1;
7012
+ retries[memory.id] = {
7013
+ content,
7014
+ failures,
7015
+ deferUntil: failures < 2 ? 0 : Date.now() + Math.min(24, 2 ** (failures - 2)) * 3600000
7016
+ };
7017
+ }
7018
+ setDreamState(args.db, retryKey(args.projectIdentity), JSON.stringify(retries));
7019
+ });
6838
7020
  result.mapped += outcome.mapped;
6839
7021
  result.independent += outcome.independent;
6840
7022
  result.remaining -= committed;
@@ -6844,8 +7026,8 @@ async function mapMemories(args) {
6844
7026
  }
6845
7027
  if (outcome.requeue?.length) {
6846
7028
  if (!batch.isOmissionRetry) {
6847
- batches.splice(i + 1, 0, {
6848
- inputs: outcome.requeue,
7029
+ batches.push({
7030
+ inputs: outcome.requeue.filter((memory) => !isDeferred(memory, retries)),
6849
7031
  isOmissionRetry: true
6850
7032
  });
6851
7033
  log2(`[dreamer] map-memories: committed ${committed}/${batch.inputs.length} mapping(s); requeueing ${outcome.requeue.length} omitted id(s) in a targeted retry`);
@@ -6853,12 +7035,12 @@ async function mapMemories(args) {
6853
7035
  log2(`[dreamer] map-memories: targeted retry still omitted ${outcome.requeue.length} id(s); leaving them unmapped for the next run`);
6854
7036
  }
6855
7037
  }
6856
- if (outcome.failure?.class === "timeout") {
7038
+ if (outcome.failure?.class === "timeout" && committed === 0) {
6857
7039
  consecutiveTimeouts += 1;
6858
7040
  timeoutStreakElapsedMs.push(outcome.failure.elapsedMs);
6859
7041
  if (consecutiveTimeouts >= CONSECUTIVE_TIMEOUT_LIMIT2) {
6860
7042
  result.stopReason = "timeout-circuit-breaker";
6861
- log2(`[dreamer] map-memories starvation: circuit breaker tripped after ${consecutiveTimeouts} consecutive batch timeouts (model too slow for its time slice); per-batch elapsed [${timeoutStreakElapsedMs.join("ms, ")}ms] vs ${sliceMs}ms slice; stopping with ${result.remaining} mapping(s) remaining`);
7043
+ log2(`[dreamer] map-memories starvation: circuit breaker tripped after ${consecutiveTimeouts} consecutive batch timeouts with no committed mappings (investigation made no durable progress); per-batch elapsed [${timeoutStreakElapsedMs.join("ms, ")}ms] vs ${sliceMs}ms slice; stopping with ${result.remaining} mapping(s) remaining`);
6862
7044
  break;
6863
7045
  }
6864
7046
  } else {
@@ -6878,12 +7060,13 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
6878
7060
  let promptSettled = false;
6879
7061
  const startedAt = Date.now();
6880
7062
  let budgetFinalized = false;
7063
+ let failedCompletion;
6881
7064
  const onBudgetUpdate = (state) => {
6882
7065
  budgetFinalized ||= state.finalizeFired;
6883
7066
  args.onBudgetUpdate?.(state);
6884
7067
  };
6885
7068
  try {
6886
- const prompt = buildMapMemoriesPrompt(args.projectIdentity, batch);
7069
+ const prompt = buildMapMemoriesPrompt(args.projectIdentity, await seedIdentifierCandidates(batch, args.sessionDirectory));
6887
7070
  if (args.hiddenCompletionExecutor) {
6888
7071
  const run = await runHiddenSingleShotPrompt({
6889
7072
  executor: args.hiddenCompletionExecutor,
@@ -6899,14 +7082,18 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
6899
7082
  fallbackModels: args.fallbackModels,
6900
7083
  timeoutMs: sliceMs,
6901
7084
  signal,
6902
- parse: (text) => validateMapMemoriesManifest(text, new Set(batch.map((memory) => memory.id)))
7085
+ onFailureOutput: (completion) => {
7086
+ failedCompletion = completion;
7087
+ },
7088
+ parse: (text, completion) => validateMapMemoriesManifest(currentManifest(assistantText(completion.messages ?? []) || text), new Set(batch.map((memory) => memory.id)))
6903
7089
  });
6904
7090
  recordInvocation2(args, startedAt, {
6905
7091
  status: "completed",
6906
7092
  messages: run.completion.messages ?? []
6907
7093
  });
6908
- const outcome = await applyParsedBatchMappings(args, batch, run.validated, budgetFinalized);
6909
- const returnedIds = new Set(run.validated.map((entry) => entry.id));
7094
+ const outcome = await applyParsedBatchMappings(args, batch, run.validated, budgetFinalized, true);
7095
+ logBatchUsage(run.completion.messages ?? [], outcome.mapped + outcome.independent, startedAt);
7096
+ const returnedIds = new Set(outcome.committedIds);
6910
7097
  return {
6911
7098
  ...outcome,
6912
7099
  requeue: budgetFinalized ? [] : batch.filter((memory) => !returnedIds.has(memory.id))
@@ -6949,7 +7136,7 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
6949
7136
  fetchOutput: async () => {
6950
7137
  const messagesResponse = await client.session.messages({
6951
7138
  path: { id: agentSessionId },
6952
- query: { directory: args.sessionDirectory, limit: 100 }
7139
+ query: { directory: args.sessionDirectory, limit: 200 }
6953
7140
  });
6954
7141
  return normalizeSDKResponse(messagesResponse, [], {
6955
7142
  preferResponseOnMissingData: true
@@ -6959,7 +7146,7 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
6959
7146
  if (hasLengthCappedOutput(messages)) {
6960
7147
  throw new Error("map-memories returned length-capped output");
6961
7148
  }
6962
- const text = extractLatestAssistantText(messages);
7149
+ const text = currentManifest(assistantText(messages));
6963
7150
  if (!text)
6964
7151
  throw new Error("map-memories returned no output");
6965
7152
  return validateMapMemoriesManifest(text, new Set(batch.map((memory) => memory.id)));
@@ -6967,8 +7154,9 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
6967
7154
  });
6968
7155
  promptSettled = true;
6969
7156
  recordInvocation2(args, startedAt, { status: "completed", messages: run.output });
6970
- const outcome = await applyParsedBatchMappings(args, batch, run.validated, budgetFinalized);
6971
- const returnedIds = new Set(run.validated.filter((entry) => batch.some((memory) => memory.id === entry.id)).map((entry) => entry.id));
7157
+ const outcome = await applyParsedBatchMappings(args, batch, run.validated, budgetFinalized, true);
7158
+ logBatchUsage(run.output, outcome.mapped + outcome.independent, startedAt);
7159
+ const returnedIds = new Set(outcome.committedIds);
6972
7160
  return {
6973
7161
  ...outcome,
6974
7162
  requeue: budgetFinalized ? [] : batch.filter((memory) => !returnedIds.has(memory.id))
@@ -6976,18 +7164,23 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
6976
7164
  } catch (error) {
6977
7165
  const desc = describeError(error);
6978
7166
  log2(`[dreamer] map-memories batch failed: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
7167
+ const messages = failedCompletion?.messages ?? await readFailedChildMessages(args.client, agentSessionId, args.sessionDirectory) ?? [];
6979
7168
  recordInvocation2(args, startedAt, {
6980
7169
  status: failedInvocationStatus(error),
6981
7170
  error,
6982
- messages: await readFailedChildMessages(args.client, agentSessionId, args.sessionDirectory)
7171
+ messages
6983
7172
  });
6984
- if (error instanceof DreamerModuleFailureError || error instanceof DreamTokenBudgetExceeded)
7173
+ if (error instanceof DreamerModuleFailureError)
6985
7174
  throw error;
6986
7175
  if (signal.aborted)
6987
7176
  throw error;
7177
+ const recovered = parsePartialMapMemoriesManifest(assistantText(messages) || failedCompletion?.text || "", new Set(batch.map((memory) => memory.id)));
7178
+ const outcome = await applyParsedBatchMappings(args, batch, recovered, budgetFinalized, true);
7179
+ logBatchUsage(messages, outcome.mapped + outcome.independent, startedAt);
7180
+ if (error instanceof DreamTokenBudgetExceeded)
7181
+ throw error;
6988
7182
  return {
6989
- mapped: 0,
6990
- independent: 0,
7183
+ ...outcome,
6991
7184
  failure: {
6992
7185
  class: isTimeoutClassError2(error) ? "timeout" : "other",
6993
7186
  elapsedMs: Date.now() - startedAt
@@ -7006,7 +7199,7 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
7006
7199
  });
7007
7200
  }
7008
7201
  }
7009
- async function applyParsedBatchMappings(args, batch, parsed, budgetFinalized = false) {
7202
+ async function applyParsedBatchMappings(args, batch, parsed, budgetFinalized = false, allowPartial = false) {
7010
7203
  const batchIds = new Set(batch.map((memory) => memory.id));
7011
7204
  const valid = parsed.filter((entry) => batchIds.has(entry.id));
7012
7205
  const unknown = parsed.filter((entry) => !batchIds.has(entry.id));
@@ -7014,14 +7207,14 @@ async function applyParsedBatchMappings(args, batch, parsed, budgetFinalized = f
7014
7207
  log2(`[dreamer] map-memories warning: dropping ${unknown.length} unknown mapping entr${unknown.length === 1 ? "y" : "ies"} outside the current batch (${unknown.map((entry) => entry.id).join(", ")})`);
7015
7208
  }
7016
7209
  assertNoDuplicateManifestIds(valid.map((entry) => entry.id), "mappings");
7017
- if (!budgetFinalized && valid.length * 2 < batch.length) {
7210
+ if (!allowPartial && !budgetFinalized && valid.length * 2 < batch.length) {
7018
7211
  throw new Error(`mappings manifest covers ${valid.length}/${batch.length} batch ids after filtering unknown entries; rejecting mostly-wrong manifest`);
7019
7212
  }
7020
7213
  if (budgetFinalized && valid.length < batch.length) {
7021
7214
  log2(`[dreamer] map-memories: accepted partial manifest after token budget: ${valid.length}/${batch.length}`);
7022
7215
  }
7023
7216
  if (valid.length === 0)
7024
- return { mapped: 0, independent: 0 };
7217
+ return { mapped: 0, independent: 0, committedIds: [] };
7025
7218
  const planned = [];
7026
7219
  const batchById = new Map(batch.map((memory) => [memory.id, memory]));
7027
7220
  for (const p of valid) {
@@ -7070,9 +7263,10 @@ async function applyParsedBatchMappings(args, batch, parsed, budgetFinalized = f
7070
7263
  });
7071
7264
  }
7072
7265
  if (planned.length === 0)
7073
- return { mapped: 0, independent: 0 };
7266
+ return { mapped: 0, independent: 0, committedIds: [] };
7074
7267
  let mapped = 0;
7075
7268
  let independent = 0;
7269
+ const committedIds = [];
7076
7270
  if (args.moduleRoute) {
7077
7271
  const identities = getModuleMemoryIdentities(args.db, args.projectIdentity, planned.map((item) => item.id));
7078
7272
  const rows = planned.map((item) => {
@@ -7110,19 +7304,22 @@ async function applyParsedBatchMappings(args, batch, parsed, budgetFinalized = f
7110
7304
  const accepted = new Set(result.accepted.filter((id) => typeof id === "number"));
7111
7305
  for (const item of planned) {
7112
7306
  const identity = identities.get(item.id);
7113
- if (identity && accepted.has(identity.moduleId))
7307
+ if (identity && accepted.has(identity.moduleId)) {
7114
7308
  item.independent ? independent += 1 : mapped += 1;
7309
+ committedIds.push(item.id);
7310
+ }
7115
7311
  }
7116
- return { mapped, independent };
7312
+ return { mapped, independent, committedIds };
7117
7313
  }
7118
7314
  const now = Date.now();
7119
7315
  runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
7120
7316
  for (const item of planned) {
7121
7317
  recordMemoryMapping(args.db, item.id, item.files, now, item.mappingOrigin);
7122
7318
  item.independent ? independent += 1 : mapped += 1;
7319
+ committedIds.push(item.id);
7123
7320
  }
7124
7321
  });
7125
- return { mapped, independent };
7322
+ return { mapped, independent, committedIds };
7126
7323
  }
7127
7324
  function recordInvocation2(args, startedAt, params) {
7128
7325
  if (!args.parentSessionId)
@@ -7390,32 +7587,41 @@ async function promotePrimers(args) {
7390
7587
  // src/features/magic-context/dreamer/primer-seed.ts
7391
7588
  var PRIMER_SEED_CAP_TOKENS = 4000;
7392
7589
  function renderUserAndToolOrientation(sessionId, startOrdinal, endOrdinal, capTokens) {
7590
+ const renderer = orientationRenderer(capTokens);
7591
+ visitRawSessionMessages2(sessionId, startOrdinal, endOrdinal, renderer.visit, {
7592
+ summary: true
7593
+ });
7594
+ return renderer.result();
7595
+ }
7596
+ function orientationRenderer(capTokens) {
7393
7597
  const lines = [];
7394
7598
  let tokens = 0;
7395
7599
  let sawMessage = false;
7396
- visitRawSessionMessages2(sessionId, startOrdinal, endOrdinal, (msg) => {
7397
- sawMessage = true;
7398
- const out = [];
7399
- if (msg.role === "user" && hasMeaningfulUserText2(msg.parts)) {
7400
- const text = extractTexts2(msg.parts).map((t) => cleanUserText2(t)).map(normalizeText).filter((t) => t.length > 0).join(" / ");
7401
- if (text)
7402
- out.push(`U: ${text}`);
7403
- }
7404
- for (const tc of extractToolCallSummaries(msg.parts))
7405
- out.push(tc);
7406
- for (const line of out) {
7407
- const lineTokens = estimateTokens(line);
7408
- if (tokens + lineTokens > capTokens && lines.length > 0) {
7409
- lines.push("… (orientation truncated; investigate the current source directly)");
7410
- return false;
7600
+ return {
7601
+ visit: (msg) => {
7602
+ sawMessage = true;
7603
+ const out = [];
7604
+ if (msg.role === "user" && hasMeaningfulUserText2(msg.parts)) {
7605
+ const text = extractTexts2(msg.parts).map((t) => cleanUserText2(t)).map(normalizeText).filter((t) => t.length > 0).join(" / ");
7606
+ if (text)
7607
+ out.push(`U: ${text}`);
7608
+ }
7609
+ for (const tc of extractToolCallSummaries(msg.parts))
7610
+ out.push(tc);
7611
+ for (const line of out) {
7612
+ const lineTokens = estimateTokens(line);
7613
+ if (tokens + lineTokens > capTokens && lines.length > 0) {
7614
+ lines.push("… (orientation truncated; investigate the current source directly)");
7615
+ return false;
7616
+ }
7617
+ lines.push(line);
7618
+ tokens += lineTokens;
7411
7619
  }
7412
- lines.push(line);
7413
- tokens += lineTokens;
7414
- }
7415
- return true;
7416
- }, { summary: true });
7417
- return sawMessage ? lines.join(`
7418
- `) : null;
7620
+ return true;
7621
+ },
7622
+ result: () => sawMessage ? lines.join(`
7623
+ `) : null
7624
+ };
7419
7625
  }
7420
7626
  function selectPrimerOriginCandidate(db, primer) {
7421
7627
  return getPrimerCandidatesByIds(db, primer.sourceCandidateIds).filter((candidate) => candidate.projectPath === primer.projectPath).sort((a, b) => b.sourceMessageTime - a.sourceMessageTime || b.id - a.id)[0];
@@ -7449,16 +7655,37 @@ function closedBookOriginP1(db, sessionId, originStartMessage) {
7449
7655
  return { orientation, sessionId };
7450
7656
  }
7451
7657
  function buildPrimerSeed(db, primer) {
7658
+ return buildPrimerSeedUsing(db, selectPrimerOriginCandidate(db, primer), renderUserAndToolOrientation);
7659
+ }
7660
+ async function buildPrimerSeedAsync(db, primer) {
7452
7661
  const mostRecent = selectPrimerOriginCandidate(db, primer);
7662
+ let orientation = null;
7663
+ if (mostRecent && typeof mostRecent.sourceCompartmentStart === "number" && typeof mostRecent.sourceCompartmentEnd === "number") {
7664
+ try {
7665
+ const renderer = orientationRenderer(PRIMER_SEED_CAP_TOKENS);
7666
+ await visitRawSessionMessagesAsync2(mostRecent.sessionId, mostRecent.sourceCompartmentStart, mostRecent.sourceCompartmentEnd, renderer.visit, { summary: true });
7667
+ orientation = renderer.result();
7668
+ } catch {
7669
+ orientation = null;
7670
+ }
7671
+ }
7672
+ return buildPrimerSeedUsing(db, mostRecent, () => orientation);
7673
+ }
7674
+ function buildPrimerSeedUsing(db, mostRecent, render) {
7453
7675
  if (!mostRecent || typeof mostRecent.sourceCompartmentStart !== "number" || typeof mostRecent.sourceCompartmentEnd !== "number") {
7454
- return { kind: "closed-book", orientation: "", prePost: "", sessionId: null };
7676
+ return {
7677
+ kind: "closed-book",
7678
+ orientation: "",
7679
+ prePost: "",
7680
+ sessionId: null
7681
+ };
7455
7682
  }
7456
7683
  const sessionId = mostRecent.sessionId;
7457
7684
  const start = mostRecent.sourceCompartmentStart;
7458
7685
  const end = mostRecent.sourceCompartmentEnd;
7459
7686
  let orientation = null;
7460
7687
  try {
7461
- orientation = renderUserAndToolOrientation(sessionId, start, end, PRIMER_SEED_CAP_TOKENS);
7688
+ orientation = render(sessionId, start, end, PRIMER_SEED_CAP_TOKENS);
7462
7689
  } catch {
7463
7690
  orientation = null;
7464
7691
  }
@@ -7589,14 +7816,14 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
7589
7816
  provider = null;
7590
7817
  }
7591
7818
  }
7592
- const seed = withRawSessionMessageCache2(() => {
7819
+ const seed = await (async () => {
7593
7820
  const unregister = provider && originSessionId ? setRawMessageProvider2(originSessionId, provider) : null;
7594
7821
  try {
7595
- return buildPrimerSeed(args.db, primer);
7822
+ return provider?.iterateMessageRangeAsync ? await buildPrimerSeedAsync(args.db, primer) : withRawSessionMessageCache2(() => buildPrimerSeed(args.db, primer));
7596
7823
  } finally {
7597
7824
  unregister?.();
7598
7825
  }
7599
- });
7826
+ })();
7600
7827
  let agentSessionId = null;
7601
7828
  let promptSettled = false;
7602
7829
  const startedAt = Date.now();
@@ -7612,7 +7839,10 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
7612
7839
  prompt,
7613
7840
  title: "magic-context-dream-refresh-primers",
7614
7841
  callContext: "dreamer:refresh-primers",
7615
- metadata: { tokenBudget: args.tokenBudget, onBudgetUpdate: args.onBudgetUpdate },
7842
+ metadata: {
7843
+ tokenBudget: args.tokenBudget,
7844
+ onBudgetUpdate: args.onBudgetUpdate
7845
+ },
7616
7846
  model: args.model,
7617
7847
  fallbackModels: args.fallbackModels,
7618
7848
  language: args.language,
@@ -7678,7 +7908,10 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
7678
7908
  validateOutput: (messages) => parseAnswer(messages, primer.answer)
7679
7909
  });
7680
7910
  promptSettled = true;
7681
- recordInvocation3(args, startedAt, { status: "completed", messages: run.output });
7911
+ recordInvocation3(args, startedAt, {
7912
+ status: "completed",
7913
+ messages: run.output
7914
+ });
7682
7915
  const answer = run.validated.trim();
7683
7916
  if (!answer)
7684
7917
  return false;
@@ -7693,7 +7926,10 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
7693
7926
  } catch (error) {
7694
7927
  const desc = describeError(error);
7695
7928
  log2(`[dreamer] refresh-primers failed (primer #${primer.id}): ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
7696
- recordInvocation3(args, startedAt, { status: failedInvocationStatus(error), error });
7929
+ recordInvocation3(args, startedAt, {
7930
+ status: failedInvocationStatus(error),
7931
+ error
7932
+ });
7697
7933
  throw error;
7698
7934
  } finally {
7699
7935
  if (agentSessionId && args.client)
@@ -8210,9 +8446,9 @@ function evaluateTaskGate(task, ctx) {
8210
8446
  import { createHash as createHash6 } from "node:crypto";
8211
8447
 
8212
8448
  // src/features/magic-context/dreamer/verify-diff.ts
8213
- import { execFile as execFile2 } from "node:child_process";
8214
- import { promisify as promisify2 } from "node:util";
8215
- var exec = promisify2(execFile2);
8449
+ import { execFile as execFile3 } from "node:child_process";
8450
+ import { promisify as promisify3 } from "node:util";
8451
+ var exec = promisify3(execFile3);
8216
8452
  var VERIFY_DIFF_BUDGET_TOKENS = 12000;
8217
8453
  var MAX_DIFF_BYTES = 4 * 1024 * 1024;
8218
8454
  async function git2(root, args) {
@@ -15706,8 +15942,8 @@ function registerRpcHandlers(rpcServer, args) {
15706
15942
  const db = readDatabase();
15707
15943
  if (!db)
15708
15944
  return { ok: false, error: "db unavailable" };
15709
- const { runManagedRecomp } = await importPluginModule(() => import("./recomp-orchestrator-xw9wt5bm.js"));
15710
- const { sendIgnoredMessage } = await importPluginModule(() => import("./send-session-notification-yp9m5g4p.js"));
15945
+ const { runManagedRecomp } = await importPluginModule(() => import("./recomp-orchestrator-trcgmm23.js"));
15946
+ const { sendIgnoredMessage } = await importPluginModule(() => import("./send-session-notification-2tp44tfa.js"));
15711
15947
  log2(`[rpc] recomp requested for session ${sessionId}`);
15712
15948
  if (!args.client && !args.hiddenCompletionExecutor) {
15713
15949
  return {
@@ -15776,7 +16012,7 @@ function registerRpcHandlers(rpcServer, args) {
15776
16012
  const db = readDatabase();
15777
16013
  if (!db)
15778
16014
  return { ok: false, error: "db unavailable" };
15779
- const { runManagedWrapup } = await importPluginModule(() => import("./wrapup-orchestrator-z7agncp8.js"));
16015
+ const { runManagedWrapup } = await importPluginModule(() => import("./wrapup-orchestrator-df61jmz9.js"));
15780
16016
  const model = liveSessionState.liveModelBySession.get(sessionId);
15781
16017
  const contextLimit = model ? resolveContextLimit(model.providerID, model.modelID, { db, sessionID: sessionId }) : 128000;
15782
16018
  const ctx = {
@@ -16215,11 +16451,11 @@ function clone(value) {
16215
16451
  return value;
16216
16452
  return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, clone(item)]));
16217
16453
  }
16218
- function isThinkingPart(part) {
16454
+ function isThinkingPart2(part) {
16219
16455
  return isRecord(part) && ["thinking", "reasoning", "redacted_thinking"].includes(String(part.type));
16220
16456
  }
16221
16457
  function replayableOriginal(part) {
16222
- if (!isThinkingPart(part) || !isRecord(part))
16458
+ if (!isThinkingPart2(part) || !isRecord(part))
16223
16459
  return false;
16224
16460
  const metadata = isRecord(part.metadata) && isRecord(part.metadata.anthropic) ? part.metadata.anthropic : {};
16225
16461
  const signature = part.signature ?? part.thinkingSignature ?? metadata.signature ?? part.data ?? metadata.redactedData;
@@ -16527,7 +16763,7 @@ function createPassOutcome() {
16527
16763
  }
16528
16764
 
16529
16765
  // src/hooks/magic-context/rust-mode-transform.ts
16530
- import { createHash as createHash11, randomUUID as randomUUID6 } from "node:crypto";
16766
+ import { createHash as createHash12, randomUUID as randomUUID6 } from "node:crypto";
16531
16767
 
16532
16768
  // src/features/magic-context/memory/single-store-embedding-drain.ts
16533
16769
  function isWatermarkRow(row) {
@@ -19059,13 +19295,235 @@ function resolveRustLkgReplayParticipant(sessionId) {
19059
19295
  return latest;
19060
19296
  return alive.length === 1 ? alive[0] : undefined;
19061
19297
  }
19062
- function noteExternalLkgReplay(participant, sessionId, inputCount) {
19298
+ function noteExternalLkgReplay(participant, sessionId, inputMessages, servedMessages) {
19063
19299
  if (!participant)
19064
19300
  return;
19065
- participant.enterFreezeFromExternalServe(sessionId, inputCount);
19301
+ participant.enterFreezeFromExternalServe(sessionId, inputMessages, servedMessages);
19066
19302
  sessionLog2(sessionId, "lkg_external_replay_froze_rust_adapter");
19067
19303
  }
19068
19304
 
19305
+ // src/hooks/magic-context/rust-served-raw.ts
19306
+ import { createHash as createHash11 } from "node:crypto";
19307
+ class RustServedRawConflict extends EmergencyFailClosedError {
19308
+ reason;
19309
+ messageIds;
19310
+ firstBlockId;
19311
+ constructor(reason, messageIds, firstBlockId) {
19312
+ super(`Rust served-raw conflict: ${reason} at ${firstBlockId}`);
19313
+ this.reason = reason;
19314
+ this.messageIds = messageIds;
19315
+ this.firstBlockId = firstBlockId;
19316
+ }
19317
+ }
19318
+ function partDigest(part) {
19319
+ const serialized = JSON.stringify(part);
19320
+ return createHash11("sha256").update(stableStringify(serialized === undefined ? undefined : JSON.parse(serialized))).digest("hex");
19321
+ }
19322
+ function records(doc) {
19323
+ if (doc.rustServedRaw === undefined)
19324
+ return [];
19325
+ if (!Array.isArray(doc.rustServedRaw))
19326
+ throw new EmergencyFailClosedError("Invalid Rust served-raw evidence");
19327
+ for (const row of doc.rustServedRaw) {
19328
+ if (!row || typeof row.messageId !== "string" || !Number.isSafeInteger(row.index) || row.index < 0 || row.partId !== undefined && typeof row.partId !== "string" || typeof row.digest !== "string" || !/^[a-f0-9]{64}$/.test(row.digest) || !Array.isArray(row.blockIds) || !row.blockIds.every((id) => typeof id === "string")) {
19329
+ throw new EmergencyFailClosedError("Invalid Rust served-raw part");
19330
+ }
19331
+ }
19332
+ return doc.rustServedRaw;
19333
+ }
19334
+ function rustRawRebuild(db, sessionId) {
19335
+ const value = readReplayEnvelope(db, sessionId).rustRawRebuild;
19336
+ if (value === undefined)
19337
+ return;
19338
+ if (!value || typeof value.identity !== "string" || !/^[a-f0-9]{64}$/.test(value.identity) || !["source_removed", "source_changed", "candidate_loss", "candidate_conflict"].includes(value.reason) || !Array.isArray(value.messageIds) || !value.messageIds.every((id) => typeof id === "string") || typeof value.firstBlockId !== "string" || typeof value.pending !== "boolean") {
19339
+ throw new EmergencyFailClosedError("Invalid Rust raw-rebuild request");
19340
+ }
19341
+ return value;
19342
+ }
19343
+ function servedRawBlockIds(db, sessionId) {
19344
+ return records(readReplayEnvelope(db, sessionId)).flatMap((row) => row.blockIds);
19345
+ }
19346
+ function sourcePart(row, message) {
19347
+ return row.partId === undefined ? message?.parts[row.index] : message?.parts.find((part) => part?.id === row.partId);
19348
+ }
19349
+ function conflict(row, reason) {
19350
+ return new RustServedRawConflict(reason, [row.messageId], row.blockIds[0] ?? `${row.messageId}#0`);
19351
+ }
19352
+ function checkRustServedRawIngress(db, sessionId, input) {
19353
+ const rows = records(readReplayEnvelope(db, sessionId));
19354
+ if (!rows.length)
19355
+ return;
19356
+ const byId = new Map(input.map((message) => [message.info.id, message]));
19357
+ const changed = rows.filter((row) => partDigest(sourcePart(row, byId.get(row.messageId))) !== row.digest);
19358
+ const first = changed[0];
19359
+ if (!first)
19360
+ return;
19361
+ throw new RustServedRawConflict(sourcePart(first, byId.get(first.messageId)) === undefined ? "source_removed" : "source_changed", [...new Set(changed.map((row) => row.messageId))], first.blockIds[0] ?? `${first.messageId}#0`);
19362
+ }
19363
+ function requestRustRawRebuild(db, sessionId, error) {
19364
+ if (!updateReplayDocument(db, sessionId, (doc) => {
19365
+ const previous = doc.rustRawRebuild;
19366
+ if (previous?.pending && previous.reason === error.reason && previous.firstBlockId === error.firstBlockId && error.messageIds.every((id) => previous.messageIds.includes(id)))
19367
+ return false;
19368
+ const messageIds = [
19369
+ ...new Set([
19370
+ ...previous?.pending ? previous.messageIds : [],
19371
+ ...error.messageIds
19372
+ ])
19373
+ ];
19374
+ const identity = partDigest([
19375
+ previous?.identity ?? "",
19376
+ error.reason,
19377
+ messageIds,
19378
+ error.firstBlockId
19379
+ ]);
19380
+ doc.version = 2;
19381
+ doc.rustRawRebuild = {
19382
+ identity,
19383
+ reason: error.reason,
19384
+ messageIds,
19385
+ firstBlockId: error.firstBlockId,
19386
+ pending: true
19387
+ };
19388
+ return true;
19389
+ }))
19390
+ throw new EmergencyFailClosedError("Cannot persist Rust raw-rebuild request");
19391
+ }
19392
+ function noteRustServedRaw(db, sessionId, input, served) {
19393
+ const additions = [];
19394
+ const byId = new Map(served.filter((message) => typeof message?.info?.id === "string").map((message) => [message.info.id, message]));
19395
+ for (const message of input) {
19396
+ const visible = byId.get(message.info.id);
19397
+ if (!visible)
19398
+ continue;
19399
+ let offset = 0;
19400
+ for (const [index, value] of message.parts.entries()) {
19401
+ if (!value || typeof value !== "object")
19402
+ continue;
19403
+ const part = value;
19404
+ const count = encodeOpenCodeMessagesToCk([{ ...message, parts: [part] }])[0].ck.content.length;
19405
+ const actual = typeof part.id === "string" ? visible.parts.find((candidate) => candidate?.id === part.id) : visible.parts[index];
19406
+ const status = part.state?.status;
19407
+ const reachesProvider = !(part.type === "text" && part.ignored === true) && ![
19408
+ "compaction",
19409
+ "step-start",
19410
+ "step-finish",
19411
+ "snapshot",
19412
+ "patch",
19413
+ "agent",
19414
+ "retry"
19415
+ ].includes(String(part.type)) && (part.type !== "tool" || status === "completed" || status === "error");
19416
+ if (reachesProvider && count > 0) {
19417
+ const digest = partDigest(part);
19418
+ if (actual === part || partDigest(actual) === digest) {
19419
+ additions.push({
19420
+ messageId: message.info.id,
19421
+ index,
19422
+ ...typeof part.id === "string" ? { partId: part.id } : {},
19423
+ digest,
19424
+ blockIds: Array.from({ length: count }, (_, i) => `${message.info.id}#${offset + i}`)
19425
+ });
19426
+ }
19427
+ }
19428
+ offset += count;
19429
+ }
19430
+ }
19431
+ if (!additions.length)
19432
+ return;
19433
+ if (!updateReplayDocument(db, sessionId, (doc) => {
19434
+ const rows = records(doc);
19435
+ const key = (row) => stableStringify([row.messageId, row.partId ?? row.index]);
19436
+ const merged = new Map(rows.map((row) => [key(row), row]));
19437
+ for (const row of additions)
19438
+ merged.set(key(row), row);
19439
+ const next = [...merged.values()];
19440
+ if (stableStringify(rows) === stableStringify(next))
19441
+ return false;
19442
+ doc.version = 2;
19443
+ doc.rustServedRaw = next;
19444
+ return true;
19445
+ }))
19446
+ throw new EmergencyFailClosedError("Cannot persist Rust served-raw evidence");
19447
+ }
19448
+ function preserveRustServedRaw(db, sessionId, output, input = output, reconstruct = new Set, covered = new Set) {
19449
+ const rows = records(readReplayEnvelope(db, sessionId));
19450
+ if (!rows.length)
19451
+ return false;
19452
+ const sources = new Map(input.map((message) => [message.info.id, message]));
19453
+ const byId = new Map(output.map((message) => [message.info.id, message]));
19454
+ let repaired = false;
19455
+ for (const row of rows) {
19456
+ if (covered.has(row.messageId))
19457
+ continue;
19458
+ const original = sources.get(row.messageId);
19459
+ const source = sourcePart(row, original);
19460
+ if (!original || !source)
19461
+ throw conflict(row, "source_removed");
19462
+ if (partDigest(source) !== row.digest)
19463
+ throw conflict(row, "source_changed");
19464
+ let message = byId.get(row.messageId);
19465
+ if (!message) {
19466
+ if (!reconstruct.has(row.messageId))
19467
+ throw conflict(row, "candidate_loss");
19468
+ const sourceIndex = input.indexOf(original);
19469
+ const next = output.findIndex((candidate) => input.findIndex((entry) => entry.info.id === candidate.info.id) > sourceIndex);
19470
+ message = structuredClone(original);
19471
+ output.splice(next < 0 ? output.length : next, 0, message);
19472
+ byId.set(row.messageId, message);
19473
+ repaired = true;
19474
+ }
19475
+ const parts = message.parts;
19476
+ if (row.partId === undefined) {
19477
+ const candidate = parts[row.index];
19478
+ if (partDigest(candidate) === row.digest)
19479
+ continue;
19480
+ const reversibleTag = source.type === "text" && typeof source.text === "string" && typeof candidate?.text === "string" && /^§\d+§ /.test(candidate.text) && candidate.text.replace(/^§\d+§ /, "") === source.text && partDigest({ ...candidate, text: source.text }) === row.digest;
19481
+ if (!reversibleTag) {
19482
+ if (!reconstruct.has(row.messageId))
19483
+ throw conflict(row, "candidate_conflict");
19484
+ message.parts = structuredClone(original.parts);
19485
+ repaired = true;
19486
+ continue;
19487
+ }
19488
+ parts[row.index] = structuredClone(source);
19489
+ continue;
19490
+ }
19491
+ const matches = parts.flatMap((part, i) => part.id === row.partId ? [i] : []);
19492
+ if (matches.length > 1)
19493
+ throw conflict(row, "candidate_conflict");
19494
+ const index = matches[0];
19495
+ if (index !== undefined) {
19496
+ if (partDigest(parts[index]) !== row.digest)
19497
+ parts[index] = structuredClone(source);
19498
+ } else if (["reasoning", "thinking", "redacted_thinking"].includes(String(source.type)) || reconstruct.has(row.messageId)) {
19499
+ parts.splice(row.index, 0, structuredClone(source));
19500
+ repaired = true;
19501
+ } else
19502
+ throw conflict(row, "candidate_loss");
19503
+ }
19504
+ return repaired;
19505
+ }
19506
+ function releaseRustServedRaw(db, sessionId, output, rebuiltIdentity) {
19507
+ const snapshot = readReplayEnvelope(db, sessionId);
19508
+ if (!records(snapshot).length && !snapshot.rustRawRebuild?.pending)
19509
+ return;
19510
+ const byId = new Map(output.map((message) => [message.info.id, message]));
19511
+ if (!updateReplayDocument(db, sessionId, (doc) => {
19512
+ const rows = records(doc);
19513
+ const kept = rows.filter((row) => partDigest(sourcePart(row, byId.get(row.messageId))) === row.digest);
19514
+ const recovery = doc.rustRawRebuild;
19515
+ const acknowledged = recovery?.pending && recovery.identity === rebuiltIdentity;
19516
+ if (kept.length === rows.length && !acknowledged)
19517
+ return false;
19518
+ doc.version = 2;
19519
+ doc.rustServedRaw = kept;
19520
+ if (acknowledged)
19521
+ doc.rustRawRebuild = { ...recovery, pending: false };
19522
+ return true;
19523
+ }))
19524
+ throw new EmergencyFailClosedError("Cannot release Rust served-raw evidence");
19525
+ }
19526
+
19069
19527
  // src/hooks/magic-context/storage-busy-refusal.ts
19070
19528
  var STORAGE_BUSY_MESSAGE = "Magic Context's database is busy (another process held it too long); send your message again.";
19071
19529
  function describeStorageBusyCause(cause) {
@@ -19505,10 +19963,10 @@ function messageCacheSignature(message) {
19505
19963
  const parts = Array.isArray(message.parts) ? message.parts : [];
19506
19964
  const serializedParts = JSON.stringify(parts) ?? "null";
19507
19965
  const serializedMessage = JSON.stringify(message) ?? "null";
19508
- return `${messageIdOf(message) ?? ""}:${parts.length}:${Buffer.byteLength(serializedParts)}:${createHash11("sha256").update(serializedMessage).digest("hex")}`;
19966
+ return `${messageIdOf(message) ?? ""}:${parts.length}:${Buffer.byteLength(serializedParts)}:${createHash12("sha256").update(serializedMessage).digest("hex")}`;
19509
19967
  }
19510
19968
  function advanceWireFingerprint(previous, encoded) {
19511
- return createHash11("sha256").update(previous).update("\\0").update(JSON.stringify(encoded) ?? "null").digest("hex");
19969
+ return createHash12("sha256").update(previous).update("\\0").update(JSON.stringify(encoded) ?? "null").digest("hex");
19512
19970
  }
19513
19971
  function buildWireFingerprint(encoded) {
19514
19972
  let fingerprint = "rust-wire-v1";
@@ -20048,7 +20506,8 @@ function buildTransformBody(args) {
20048
20506
  args.providerId ? `provider:${args.providerId}` : "",
20049
20507
  args.modelKey ? `model:${args.modelKey}` : "",
20050
20508
  args.variant ? `variant:${args.variant}` : "",
20051
- args.systemPromptHash ? `system:${args.systemPromptHash}` : ""
20509
+ args.systemPromptHash ? `system:${args.systemPromptHash}` : "",
20510
+ args.rawRebuild ? `raw_replay:${args.rawRebuild.identity}` : ""
20052
20511
  ].filter(Boolean).join("|"),
20053
20512
  system_prompt_hash: args.systemPromptHash,
20054
20513
  adopted_system_prompt_hash: args.passInputs.adopted_system_prompt_hash,
@@ -20056,6 +20515,14 @@ function buildTransformBody(args) {
20056
20515
  is_subagent: args.passInputs.is_subagent === true,
20057
20516
  messages: args.input,
20058
20517
  native_messages: args.nativeMessages,
20518
+ served_raw_block_ids: args.servedRawBlockIds ?? [],
20519
+ ...args.rawRebuild?.pending ? {
20520
+ raw_replay_rebuild: {
20521
+ identity: args.rawRebuild.identity,
20522
+ reason: args.rawRebuild.reason,
20523
+ message_ids: args.rawRebuild.messageIds
20524
+ }
20525
+ } : {},
20059
20526
  tool_input_key_orders: args.toolInputKeyOrders ?? toolInputKeyOrders(args.input),
20060
20527
  ...args.fullArrayFingerprint ? { full_array_fingerprint: args.fullArrayFingerprint } : {},
20061
20528
  ...args.tailDelta ? {
@@ -20246,6 +20713,7 @@ function createRustModeTransform(deps, options) {
20246
20713
  throw error;
20247
20714
  } finally {
20248
20715
  clock.clearTimeout(timer);
20716
+ invalidateReplayEnvelopeSnapshot(deps.db, args.sessionId);
20249
20717
  }
20250
20718
  };
20251
20719
  const callTransformWithStallProbe = async (args, attemptTimeoutMs) => {
@@ -20354,6 +20822,24 @@ function createRustModeTransform(deps, options) {
20354
20822
  logTransformTiming(sessionId, "rust.ordinal_rebuild", startedAt, detail);
20355
20823
  }
20356
20824
  };
20825
+ const recordRawConflict = (sessionId, error) => {
20826
+ requestRustRawRebuild(deps.db, sessionId, error);
20827
+ dropSlot(sessionId, `raw_replay_${error.reason}`);
20828
+ const state = ensureState(states, sessionId);
20829
+ state.forceFullWire = true;
20830
+ state.parked = false;
20831
+ sessionLog2(sessionId, `raw_replay_rebuild_requested reason=${error.reason} first_changed=${error.firstBlockId}`);
20832
+ };
20833
+ const observeRawReplay = (sessionId, input, served) => {
20834
+ try {
20835
+ checkRustServedRawIngress(deps.db, sessionId, input);
20836
+ noteRustServedRaw(deps.db, sessionId, input, served);
20837
+ } catch (error) {
20838
+ if (error instanceof RustServedRawConflict)
20839
+ recordRawConflict(sessionId, error);
20840
+ throw error;
20841
+ }
20842
+ };
20357
20843
  const replayLastGood = (sessionId, currentMessages, output, systemPromptTokens) => {
20358
20844
  try {
20359
20845
  if (states.get(sessionId)?.markerAdmissionFenced || isRustMarkerAdmissionFenced(deps.db, sessionId))
@@ -20440,6 +20926,7 @@ function createRustModeTransform(deps, options) {
20440
20926
  ownDirtyRevision: lkgDirtyRevision(sessionId)
20441
20927
  }));
20442
20928
  const replayInputCount = currentMessages.length;
20929
+ observeRawReplay(sessionId, currentMessages, replay.messages);
20443
20930
  replaceMessagesInPlace(output, replay.messages);
20444
20931
  ensureState(states, sessionId).lkgLatestServedDigest = lkgServedArrayDigest(JSON.stringify(replay.messages));
20445
20932
  enterLkgReplayFreeze(ensureState(states, sessionId), replayInputCount);
@@ -20503,7 +20990,10 @@ function createRustModeTransform(deps, options) {
20503
20990
  const passStampBySession = new Map;
20504
20991
  const replayParticipant = {
20505
20992
  lastPassStamp: (sessionId) => states.has(sessionId) ? passStampBySession.get(sessionId) : undefined,
20506
- enterFreezeFromExternalServe: (sessionId, inputCount) => enterLkgReplayFreeze(ensureState(states, sessionId), inputCount),
20993
+ enterFreezeFromExternalServe: (sessionId, inputMessages, servedMessages) => {
20994
+ observeRawReplay(sessionId, inputMessages, servedMessages);
20995
+ enterLkgReplayFreeze(ensureState(states, sessionId), inputMessages.length);
20996
+ },
20507
20997
  replayFits: (sessionId, messages, inputMessages) => {
20508
20998
  try {
20509
20999
  const fit = lkgReplayFits({
@@ -20649,6 +21139,24 @@ function createRustModeTransform(deps, options) {
20649
21139
  bindSystemDateRequest(output, dateRequest);
20650
21140
  const passObservedAtMs = Date.now();
20651
21141
  const state = ensureState(states, sessionId);
21142
+ let rawRebuild;
21143
+ let rawReadError;
21144
+ try {
21145
+ rawRebuild = rustRawRebuild(deps.db, sessionId);
21146
+ try {
21147
+ checkRustServedRawIngress(deps.db, sessionId, messages);
21148
+ } catch (error) {
21149
+ if (!(error instanceof RustServedRawConflict) || !rawRebuild?.pending)
21150
+ throw error;
21151
+ requestRustRawRebuild(deps.db, sessionId, error);
21152
+ rawRebuild = rustRawRebuild(deps.db, sessionId);
21153
+ }
21154
+ } catch (error) {
21155
+ if (error instanceof RustServedRawConflict)
21156
+ throw error;
21157
+ rawReadError = error;
21158
+ }
21159
+ const reconstructRaw = new Set(rawRebuild?.messageIds ?? []);
20652
21160
  let entrySlot = getSlot(sessionId);
20653
21161
  try {
20654
21162
  entrySlot = loadPersistedLkgSlot(deps.db, sessionId, true) ?? entrySlot;
@@ -20687,6 +21195,7 @@ function createRustModeTransform(deps, options) {
20687
21195
  let decision = "error";
20688
21196
  let materializeReason = "none";
20689
21197
  let frozenReleaseReason = null;
21198
+ let frozenReleaseFirstChanged = "unknown";
20690
21199
  let schedulerDecision;
20691
21200
  let responseCommitted;
20692
21201
  let responsePrefixBustPermitted;
@@ -20712,7 +21221,7 @@ function createRustModeTransform(deps, options) {
20712
21221
  let recoveryProjectRoot = options.projectRoot ?? deps.directory ?? "";
20713
21222
  const passUsageSnapshot = loadContextUsage(deps.contextUsageMap, deps.db, sessionId);
20714
21223
  requestInputTokens = Math.max(0, Math.floor(passUsageSnapshot.inputTokens));
20715
- let preflightError;
21224
+ let preflightError = rawReadError;
20716
21225
  let markerAdmissionRecovery = state.markerAdmissionFenced;
20717
21226
  try {
20718
21227
  markerAdmissionRecovery ||= isRustMarkerAdmissionFenced(deps.db, sessionId);
@@ -20906,7 +21415,7 @@ function createRustModeTransform(deps, options) {
20906
21415
  decision,
20907
21416
  committed: responseCommitted,
20908
21417
  prefixBustPermitted: responsePrefixBustPermitted,
20909
- reason: materializeReason,
21418
+ reason: applied && served && frozenReleaseReason ? `lkg_frozen_release:${frozenReleaseReason};first_changed=${frozenReleaseFirstChanged};materialize_reason=${materializeReason}` : materializeReason,
20910
21419
  schedulerDecision,
20911
21420
  schedulerDeferReason,
20912
21421
  historianNoFire,
@@ -20928,7 +21437,7 @@ function createRustModeTransform(deps, options) {
20928
21437
  materializeReason: materializeReason === "none" ? null : materializeReason,
20929
21438
  inputTokens: requestInputTokens,
20930
21439
  tsMs: passObservedAtMs,
20931
- lkgFrozenReleaseReason: applied && served ? frozenReleaseReason ?? undefined : undefined
21440
+ lkgFrozenReleaseReason: applied && served && frozenReleaseReason ? `${frozenReleaseReason};first_changed=${frozenReleaseFirstChanged}` : undefined
20932
21441
  });
20933
21442
  }
20934
21443
  };
@@ -20963,7 +21472,7 @@ function createRustModeTransform(deps, options) {
20963
21472
  sessionLog2(sessionId, `rust module stages (slow pass): ${detail}`);
20964
21473
  }
20965
21474
  };
20966
- if (state.parked) {
21475
+ if (state.parked && !preflightError) {
20967
21476
  state.passesSincePark += 1;
20968
21477
  if (!emergencyFailClosed && passUsageSnapshot.percentage < RUST_PARK_PROBE_PRESSURE_BYPASS_PCT && state.passCount % RUST_PARK_RETRY_INTERVAL !== 0) {
20969
21478
  decision = "parked";
@@ -21248,7 +21757,7 @@ function createRustModeTransform(deps, options) {
21248
21757
  const id = messageIdOf(message) ?? `index:${todoStart + offset}`;
21249
21758
  const parts = message.parts?.filter((part) => isRecord3(part) && part.type === "tool" && part.tool === "todowrite");
21250
21759
  if (parts?.length) {
21251
- todoCalls.set(id, createHash11("sha256").update(JSON.stringify(parts)).digest("hex"));
21760
+ todoCalls.set(id, createHash12("sha256").update(JSON.stringify(parts)).digest("hex"));
21252
21761
  } else {
21253
21762
  todoCalls.delete(id);
21254
21763
  }
@@ -21394,6 +21903,8 @@ function createRustModeTransform(deps, options) {
21394
21903
  };
21395
21904
  let body = buildTransformBody({
21396
21905
  sessionId,
21906
+ rawRebuild,
21907
+ servedRawBlockIds: servedRawBlockIds(deps.db, sessionId),
21397
21908
  input: encodedInput,
21398
21909
  nativeMessages: wireDelta ? messages.slice(wireDelta.rawStart) : messages,
21399
21910
  toolInputKeyOrders: toolInputKeyOrders(encodedInput),
@@ -21593,6 +22104,8 @@ function createRustModeTransform(deps, options) {
21593
22104
  const retryWireBuildStartedAt = performance.now();
21594
22105
  body = buildTransformBody({
21595
22106
  sessionId,
22107
+ rawRebuild,
22108
+ servedRawBlockIds: servedRawBlockIds(deps.db, sessionId),
21596
22109
  input: retryEncodedInput,
21597
22110
  nativeMessages: messages,
21598
22111
  toolInputKeyOrders: toolInputKeyOrders(retryEncodedInput),
@@ -21652,6 +22165,13 @@ function createRustModeTransform(deps, options) {
21652
22165
  sessionLog2(sessionId, `signed thinking reset fence: ${fenced.length} assistant(s) [${fenced.join(",")}]`);
21653
22166
  }
21654
22167
  const cacheBustingPass = moduleDecisionBusts;
22168
+ if (rawRebuild?.pending && !moduleDecisionBusts) {
22169
+ throw new EmergencyFailClosedError("Rust raw-rebuild request was not authorized by the module");
22170
+ }
22171
+ if (rawRebuild?.pending) {
22172
+ frozenReleaseReason = `raw_replay_${rawRebuild.reason}`;
22173
+ frozenReleaseFirstChanged = rawRebuild.firstBlockId;
22174
+ }
21655
22175
  let frozenReplayReleased = false;
21656
22176
  if (markerAdmissionRecovery && !moduleDecisionBusts)
21657
22177
  throw new RustTransformProtocolError("rust marker admission recovery: supported prefix_bust_permitted=true required; upgrade ck-mc if unsupported");
@@ -21683,6 +22203,7 @@ function createRustModeTransform(deps, options) {
21683
22203
  let appliedMessages = moduleMessages;
21684
22204
  let markerStrategyFailure;
21685
22205
  let replayedFrozenRepresentation = false;
22206
+ let reconstructedRaw = false;
21686
22207
  const boundaryId = response.boundary_id;
21687
22208
  if (typeof boundaryId === "string" && boundaryId.length > 0) {
21688
22209
  assertNativeBoundary(moduleMessages, sessionId, boundaryId);
@@ -21727,7 +22248,7 @@ function createRustModeTransform(deps, options) {
21727
22248
  }
21728
22249
  if (recoveryFenceRebuild) {
21729
22250
  frozenReplayReleased = true;
21730
- frozenReleaseReason = "lkg_recovery_fence_unproven";
22251
+ frozenReleaseReason ??= "lkg_recovery_fence_unproven";
21731
22252
  frozenReleaseLastServed = { messages: null, proven: false };
21732
22253
  }
21733
22254
  if (state.lkgRepresentationFrozen && !shouldAdoptModuleAfterFreeze(moduleDecisionBusts, frozenReplayReleased)) {
@@ -21792,6 +22313,10 @@ function createRustModeTransform(deps, options) {
21792
22313
  if (!replayedFrozenRepresentation) {
21793
22314
  const outputCloneStartedAt = performance.now();
21794
22315
  appliedMessages = cloneModuleNativeOutput(moduleMessages);
22316
+ if (!moduleDecisionBusts || rawRebuild?.pending && rawRebuild.reason.startsWith("candidate")) {
22317
+ const covered = moduleDecisionBusts && typeof response.coverage_ordinal === "number" ? new Set([...state.idOrdinalMemo].filter(([, ordinal]) => ordinal <= Number(response.coverage_ordinal)).map(([id]) => id)) : new Set;
22318
+ reconstructedRaw = preserveRustServedRaw(deps.db, sessionId, appliedMessages, messages, reconstructRaw, covered);
22319
+ }
21795
22320
  timings.outputClone += performance.now() - outputCloneStartedAt;
21796
22321
  }
21797
22322
  pendingWireCache.nativeOutput = moduleMessages;
@@ -21850,7 +22375,7 @@ function createRustModeTransform(deps, options) {
21850
22375
  prefixPermissionSupported: permissionSupported,
21851
22376
  moduleReasoningTrimOnly: response.reasoning_trim_only === true,
21852
22377
  moduleSignedThinkingReset: response.signed_thinking_reset === true,
21853
- ...permissionSupported && (passStartedFrozen || frozenReleaseReason || coldStartLastServed) ? { frozenReleaseLastServed } : {},
22378
+ ...moduleDecisionBusts && (passStartedFrozen || frozenReleaseReason || coldStartLastServed) ? { frozenReleaseLastServed } : {},
21854
22379
  trailingBlankSourceDecisions,
21855
22380
  trailingBlankNewestAssistantId: typeof trailingBlankNewestAssistantId === "string" ? trailingBlankNewestAssistantId : undefined,
21856
22381
  tagger: deps.tagger,
@@ -21861,6 +22386,23 @@ function createRustModeTransform(deps, options) {
21861
22386
  if (markerStrategyFailure)
21862
22387
  throw markerStrategyFailure;
21863
22388
  }
22389
+ if (!moduleDecisionBusts && !replayedFrozenRepresentation) {
22390
+ reconstructedRaw = preserveRustServedRaw(deps.db, sessionId, appliedMessages, messages, reconstructRaw) || reconstructedRaw;
22391
+ replayRustModeBindingMismatchStrips2({
22392
+ db: deps.db,
22393
+ sessionId,
22394
+ messages: appliedMessages,
22395
+ resolvedProviderID: model?.providerID
22396
+ });
22397
+ if (servedRawBlockIds(deps.db, sessionId).length > 0 && (!validateLkgSeam([], appliedMessages, model?.providerID ?? null) || model?.providerID === "anthropic" && !validateAnthropicReasoningRuns(appliedMessages.map((message) => ({
22398
+ ...message,
22399
+ parts: message.parts.filter((part) => !isRecord3(part) || !["text", "reasoning"].includes(String(part.type)) || part.text !== "")
22400
+ }))))) {
22401
+ throw new RustServedRawConflict("candidate_conflict", [
22402
+ ...new Set(servedRawBlockIds(deps.db, sessionId).map((id) => id.replace(/#\d+$/, "")))
22403
+ ], servedRawBlockIds(deps.db, sessionId)[0] ?? "unknown");
22404
+ }
22405
+ }
21864
22406
  if (typeof boundaryId === "string" && boundaryId.length > 0) {
21865
22407
  assertNativeBoundary(appliedMessages, sessionId, boundaryId);
21866
22408
  }
@@ -21896,6 +22438,24 @@ function createRustModeTransform(deps, options) {
21896
22438
  }
21897
22439
  }
21898
22440
  logStage(sessionId, "apply", applyStartedAt, timings);
22441
+ if (frozenReleaseReason && frozenReleaseLastServed.messages && [...frozenReleaseLastServed.messages, ...appliedMessages].every((message) => isRecord3(message) && isRecord3(message.info) && Array.isArray(message.parts))) {
22442
+ frozenReleaseFirstChanged = "none";
22443
+ const byId = new Map(appliedMessages.map((message) => [message.info.id, message]));
22444
+ for (const before of frozenReleaseLastServed.messages) {
22445
+ const after = byId.get(before.info.id);
22446
+ const index = before.parts.findIndex((part, i) => JSON.stringify(part) !== JSON.stringify(after?.parts[i]));
22447
+ if (!after || index >= 0) {
22448
+ const blockIndex = index > 0 ? encodeOpenCodeMessagesToCk([
22449
+ { ...before, parts: before.parts.slice(0, index) }
22450
+ ])[0].ck.content.length : 0;
22451
+ frozenReleaseFirstChanged = `${before.info.id}#${blockIndex}`;
22452
+ break;
22453
+ }
22454
+ }
22455
+ }
22456
+ if (replayedFrozenRepresentation || reconstructedRaw) {
22457
+ noteRustServedRaw(deps.db, sessionId, messages, appliedMessages);
22458
+ }
21899
22459
  const lkgInputIds = messages.map((message) => message.info.id);
21900
22460
  const lkgInputKeys = resolveLkgModelKeys(messages);
21901
22461
  const applyReplaceStartedAt = performance.now();
@@ -22153,6 +22713,9 @@ function createRustModeTransform(deps, options) {
22153
22713
  }
22154
22714
  }
22155
22715
  }
22716
+ if (moduleDecisionBusts) {
22717
+ releaseRustServedRaw(deps.db, sessionId, output.messages, rawRebuild?.identity);
22718
+ }
22156
22719
  } catch (error) {
22157
22720
  if (markerDefinitelyNoCut) {
22158
22721
  try {
@@ -22290,7 +22853,12 @@ function createRustModeTransform(deps, options) {
22290
22853
  const adapter = {
22291
22854
  run: async (sessionId, messages, output, sessionMeta) => {
22292
22855
  try {
22293
- await withSqliteTransformPass2(() => run(sessionId, messages, output, sessionMeta));
22856
+ await withReplayEnvelopeSnapshot(deps.db, sessionId, () => withSqliteTransformPass2(() => run(sessionId, messages, output, sessionMeta)));
22857
+ } catch (error) {
22858
+ if (error instanceof RustServedRawConflict) {
22859
+ recordRawConflict(sessionId, error);
22860
+ }
22861
+ throw error;
22294
22862
  } finally {
22295
22863
  try {
22296
22864
  withoutSqliteTransformPass2(() => resolveHostRunner()?.pump(sessionId));
@@ -24394,7 +24962,7 @@ function createRustRefusalRecovery(options) {
24394
24962
  }
24395
24963
 
24396
24964
  // src/hooks/magic-context/system-prompt-hash.ts
24397
- import { createHash as createHash12 } from "node:crypto";
24965
+ import { createHash as createHash13 } from "node:crypto";
24398
24966
 
24399
24967
  // src/hooks/magic-context/system-prompt-dates.ts
24400
24968
  function replaceHostDates(prompt, replace) {
@@ -24507,7 +25075,7 @@ function createSystemPromptHashHandler(deps) {
24507
25075
  const dates = systemPromptDates(liveSystemContent, stickyDate);
24508
25076
  const currentDate = dates.live;
24509
25077
  const stableCandidate = dates.stable;
24510
- const stableCandidateHash = createHash12("md5").update(promptSurfaceHashMaterial(stableCandidate, promptSurface.preset)).digest("hex");
25078
+ const stableCandidateHash = createHash13("md5").update(promptSurfaceHashMaterial(stableCandidate, promptSurface.preset)).digest("hex");
24511
25079
  const contentOrPresetChanged = hasPersistedHash && stableCandidateHash !== previousHash;
24512
25080
  const rewritePermission = systemDateRefreshPermission(deps.historyRefreshSessions, dateRequest);
24513
25081
  let deferredDateRefresh = false;
@@ -24521,7 +25089,7 @@ function createSystemPromptHashHandler(deps) {
24521
25089
  try {
24522
25090
  const content = liveElements.join(`
24523
25091
  `);
24524
- const hash = createHash12("md5").update(promptSurfaceHashMaterial(content, promptSurface.preset)).digest("hex");
25092
+ const hash = createHash13("md5").update(promptSurfaceHashMaterial(content, promptSurface.preset)).digest("hex");
24525
25093
  updateSessionMeta(deps.db, sessionId, {
24526
25094
  systemPromptHash: hash,
24527
25095
  cachedM0SystemHash: hash,
@@ -24561,7 +25129,7 @@ function createSystemPromptHashHandler(deps) {
24561
25129
  `);
24562
25130
  if (!availability.frozen || !modelKey)
24563
25131
  return;
24564
- const currentHash = createHash12("md5").update(promptSurfaceHashMaterial(systemContent, promptSurface.preset)).digest("hex");
25132
+ const currentHash = createHash13("md5").update(promptSurfaceHashMaterial(systemContent, promptSurface.preset)).digest("hex");
24565
25133
  recordSystemPromptForRequest(sessionId, currentLkgRequestIdentity(sessionId), currentHash, deps.db, previousHash !== currentHash ? !deps.historyRefreshSessions.has(sessionId) : undefined, deps.historyRefreshSessions, deps.pendingMaterializationSessions);
24566
25134
  if (!sessionMetaEarly) {
24567
25135
  return;
@@ -24621,6 +25189,114 @@ function createSystemPromptHashHandler(deps) {
24621
25189
  };
24622
25190
  }
24623
25191
 
25192
+ // src/shared/recovery-reasoning-prefix.ts
25193
+ function recoveryReasoningPrefixes(messages, partsKey) {
25194
+ const prefixes = [];
25195
+ for (let index = 0;index < messages.length; index++) {
25196
+ const message = messages[index];
25197
+ const parts = message?.[partsKey];
25198
+ if (!Array.isArray(parts))
25199
+ continue;
25200
+ for (let p = 0;p < parts.length; p++) {
25201
+ const type = parts[p]?.type;
25202
+ if (type !== "thinking" && type !== "reasoning" && type !== "redactedThinking" && type !== "redacted_thinking")
25203
+ continue;
25204
+ prefixes.push(JSON.stringify([
25205
+ ...messages.slice(0, index),
25206
+ { ...message, [partsKey]: parts.slice(0, p + 1) }
25207
+ ]));
25208
+ }
25209
+ }
25210
+ return prefixes;
25211
+ }
25212
+
25213
+ // src/hooks/magic-context/replay-committed-drops.ts
25214
+ function replayCommittedDrops(db, sessionId, messages) {
25215
+ const original = messages;
25216
+ const reasoningPrefixes = recoveryReasoningPrefixes(messages, "parts");
25217
+ if (reasoningPrefixes.length)
25218
+ messages = structuredClone(messages);
25219
+ const tags = getTagsBySession2(db, sessionId).filter((tag) => tag.status === "dropped");
25220
+ const toolTags = new Map(tags.filter((tag) => tag.type === "tool").map((tag) => [makeToolCompositeKey(tag.toolOwnerMessageId ?? "", tag.messageId), tag]));
25221
+ const textTags = new Map(tags.filter((tag) => tag.type !== "tool").map((tag) => [tag.messageId, tag]));
25222
+ const byNumber = new Map(tags.map((tag) => [tag.tagNumber, tag]));
25223
+ const index = new Map;
25224
+ const owners = new Map;
25225
+ const resolvedOwners = new Map;
25226
+ const ambiguousCalls = new Set;
25227
+ const targets = new Map;
25228
+ let precedingThinking = [];
25229
+ const toolThinking = new Map;
25230
+ const batch = new ToolMutationBatch(messages);
25231
+ for (const message of messages) {
25232
+ if (message.info.role === "user")
25233
+ precedingThinking = [];
25234
+ const thinking = message.parts.filter(isThinkingPart);
25235
+ for (let p = 0;p < message.parts.length; p++) {
25236
+ const part = message.parts[p];
25237
+ const observation = extractToolCallObservation(part);
25238
+ if (observation) {
25239
+ const { callId, kind } = observation;
25240
+ const pending = owners.get(callId) ?? [];
25241
+ if (pending.length > 1)
25242
+ ambiguousCalls.add(callId);
25243
+ const hostingKey = makeToolCompositeKey(message.info.id ?? "", callId);
25244
+ const owner = kind === "invocation" || part.type === "tool" || toolTags.has(hostingKey) ? message.info.id ?? "" : pending.shift() ?? resolvedOwners.get(callId) ?? message.info.id ?? "";
25245
+ if (kind === "invocation")
25246
+ pending.push(owner);
25247
+ else
25248
+ resolvedOwners.set(callId, owner);
25249
+ owners.set(callId, pending);
25250
+ const key = makeToolCompositeKey(owner, callId);
25251
+ if (message.info.role === "tool" && !toolThinking.has(key))
25252
+ toolThinking.set(key, precedingThinking);
25253
+ const entry = index.get(key) ?? { occurrences: [], hasResult: false };
25254
+ entry.occurrences.push({ message, part, kind });
25255
+ entry.hasResult ||= kind === "result" && partHasCompletedResult(part);
25256
+ index.set(key, entry);
25257
+ } else {
25258
+ const prefix = isTextPart(part) ? /^§(\d+)§\s/.exec(part.text) : null;
25259
+ const tag = (prefix ? byNumber.get(Number(prefix[1])) : undefined) ?? textTags.get(`${message.info.id}:p${p}`) ?? textTags.get(`${message.info.id}:file${p}`);
25260
+ if (tag && tag.type !== "tool")
25261
+ targets.set(tag.tagNumber, {
25262
+ message,
25263
+ setContent(content) {
25264
+ if (isTextPart(part)) {
25265
+ if (part.text === content)
25266
+ return false;
25267
+ part.text = content;
25268
+ } else
25269
+ message.parts[p] = { type: "text", text: content };
25270
+ return true;
25271
+ }
25272
+ });
25273
+ }
25274
+ }
25275
+ if (message.info.role === "assistant" && !message.parts.some(isTextPart))
25276
+ precedingThinking = thinking;
25277
+ }
25278
+ const arcsByCall = new Map;
25279
+ for (const entry of index.values()) {
25280
+ const callId = extractToolCallObservation(entry.occurrences[0]?.part)?.callId ?? "";
25281
+ arcsByCall.set(callId, (arcsByCall.get(callId) ?? 0) + 1);
25282
+ }
25283
+ for (const [key, entry] of index) {
25284
+ const callId = extractToolCallObservation(entry.occurrences[0]?.part)?.callId ?? "";
25285
+ if (ambiguousCalls.has(callId))
25286
+ continue;
25287
+ const tag = toolTags.get(key) ?? (arcsByCall.get(callId) === 1 ? toolTags.get(makeToolCompositeKey("", callId)) : undefined);
25288
+ if (tag)
25289
+ targets.set(tag.tagNumber, createToolDropTarget(key, toolThinking.get(key) ?? [], index, batch, tag.tagNumber));
25290
+ }
25291
+ applyFlushedStatuses(sessionId, db, targets, tags);
25292
+ batch.finalize();
25293
+ if (JSON.stringify(recoveryReasoningPrefixes(messages, "parts")) !== JSON.stringify(reasoningPrefixes))
25294
+ return false;
25295
+ if (messages !== original)
25296
+ original.splice(0, original.length, ...messages);
25297
+ return true;
25298
+ }
25299
+
24624
25300
  // src/plugin/messages-transform.ts
24625
25301
  var ASSISTANT_TERMINAL_RETRY_MESSAGE = "The conversation ends with a completed assistant response and cannot be resubmitted as-is — send a new message to continue.";
24626
25302
 
@@ -24763,7 +25439,6 @@ function tryMessagesTransformLkgReplay(args) {
24763
25439
  sessionLog2(sessionId, "lkg_emergency_armed");
24764
25440
  } else {
24765
25441
  const inputMessages = output.messages;
24766
- const inputCount = inputMessages.length;
24767
25442
  const keys = resolveLkgModelKeys(inputMessages);
24768
25443
  const replay = replayLkg({
24769
25444
  sessionId,
@@ -24782,6 +25457,10 @@ function tryMessagesTransformLkgReplay(args) {
24782
25457
  sessionLog2(sessionId, "lkg_restart_rebuild_required");
24783
25458
  return false;
24784
25459
  }
25460
+ if (replay.ok && !rust && !replayCommittedDrops(db, sessionId, replay.messages)) {
25461
+ sessionLog2(sessionId, "lkg_reasoning_prefix_changed");
25462
+ return false;
25463
+ }
24785
25464
  let tsFit = true;
24786
25465
  if (replay.ok && !rust && keys.providerKey && keys.modelKey) {
24787
25466
  const model = {
@@ -24831,8 +25510,8 @@ function tryMessagesTransformLkgReplay(args) {
24831
25510
  return false;
24832
25511
  retirePendingSystemPromptDelivery(sessionId);
24833
25512
  args.onLkgReplay?.();
25513
+ noteExternalLkgReplay(rust, sessionId, inputMessages, replay.messages);
24834
25514
  replaceMessagesInPlace2(output, replay.messages);
24835
- noteExternalLkgReplay(rust, sessionId, inputCount);
24836
25515
  sessionLog2(sessionId, "lkg_replay_served");
24837
25516
  return true;
24838
25517
  } else {
@@ -25228,7 +25907,7 @@ function resolveCtxExpandMode(args, domain) {
25228
25907
  }
25229
25908
 
25230
25909
  // src/tools/ctx-expand/render.ts
25231
- import { createHash as createHash13 } from "node:crypto";
25910
+ import { createHash as createHash14 } from "node:crypto";
25232
25911
  function isRecord4(value) {
25233
25912
  return value !== null && typeof value === "object" && !Array.isArray(value);
25234
25913
  }
@@ -25452,11 +26131,61 @@ function renderItemByTag(db, sessionId, number, textIndexDomain = "part") {
25452
26131
  const index = scoped ? Number(scoped[2]) : 0;
25453
26132
  const piText = message.parts.filter((part) => isRecord4(part) && part.type === "text");
25454
26133
  const part = message.parts[index];
25455
- const matching = derived ? piText.filter((part) => isRecord4(part) && typeof part.text === "string" && createHash13("sha256").update(part.text).digest("hex") === derived[3]) : [];
26134
+ const matching = derived ? piText.filter((part) => isRecord4(part) && typeof part.text === "string" && createHash14("sha256").update(part.text).digest("hex") === derived[3]) : [];
25456
26135
  const selected = derived ? matching[Number(derived[4])] : textIndexDomain === "text" ? piText[index] : part;
25457
26136
  return selected ? renderPartFull(selected) ?? "" : `Tag ${number}'s original text part is no longer in stored history.`;
25458
26137
  }
25459
26138
 
26139
+ // src/tools/ctx-expand/search-archive.ts
26140
+ function renderSearchArchive(db, sessionId, start, end, tokenBudget, archiveOnly = false) {
26141
+ return withMessageFtsSessionFilter(db, sessionId, (sessionFirst) => {
26142
+ let rawIds;
26143
+ const rows = db.prepare(sessionFirst ? `SELECT f.message_ordinal AS ordinal, f.message_id AS id, f.role, f.content
26144
+ FROM message_fts_rowid_map AS m
26145
+ JOIN message_history_fts AS f ON f.rowid = m.fts_rowid
26146
+ WHERE m.session_id = ?1 AND m.message_ordinal BETWEEN ?2 AND ?3
26147
+ AND f.session_id = ?1 AND f.message_ordinal BETWEEN ?2 AND ?3
26148
+ ORDER BY m.message_ordinal` : `SELECT message_ordinal AS ordinal, message_id AS id, role, content
26149
+ FROM message_history_fts
26150
+ WHERE session_id = ?1 AND message_ordinal BETWEEN ?2 AND ?3
26151
+ ORDER BY CAST(message_ordinal AS INTEGER)`);
26152
+ const blocks = [];
26153
+ let tokens = 0;
26154
+ let lastOrdinal = start - 1;
26155
+ let truncated = false;
26156
+ for (const row of rows.iterate(sessionId, start, end)) {
26157
+ if (!row.content)
26158
+ continue;
26159
+ if (!archiveOnly) {
26160
+ rawIds ??= readRawSessionMessageIdOrdinalsForRange2(sessionId, start, end);
26161
+ if (rawIds.get(row.id) === row.ordinal)
26162
+ continue;
26163
+ }
26164
+ const block = `[${row.ordinal}] ${row.role === "user" ? "U" : "A"}: ${row.content}`;
26165
+ const cost = estimateTokens(block);
26166
+ if (blocks.length > 0 && tokens + cost > tokenBudget) {
26167
+ truncated = true;
26168
+ break;
26169
+ }
26170
+ blocks.push(block);
26171
+ tokens += cost;
26172
+ lastOrdinal = row.ordinal;
26173
+ }
26174
+ if (blocks.length === 0)
26175
+ return null;
26176
+ const text = [
26177
+ "From the search archive: indexed text only; no surrounding messages or tool output.",
26178
+ "",
26179
+ ...blocks
26180
+ ];
26181
+ if (truncated) {
26182
+ text.push("", `Truncated at message ${lastOrdinal} (budget: ~${tokenBudget} tokens). Call ctx_expand(start=${lastOrdinal + 1}, end=${end}) for more archived text.`);
26183
+ }
26184
+ return text.join(`
26185
+ `);
26186
+ });
26187
+ }
26188
+
25460
26189
  // src/tools/ctx-expand/tools.ts
25461
26190
  var ctxExpandArgsShape = {
25462
26191
  tag: tool.schema.union([tool.schema.number(), tool.schema.string()]).optional().describe("Tag number from a §N§ tag or a [dropped §N§] placeholder, not a message ordinal. Returns that one item in full. Use alone."),
@@ -25490,7 +26219,7 @@ function createCtxExpandTool(deps) {
25490
26219
  return renderItemByTag(deps.db, sessionId, mode.tag);
25491
26220
  }
25492
26221
  if (mode.kind === "message") {
25493
- return renderMessageByOrdinal(sessionId, mode.message);
26222
+ return renderSearchArchive(deps.db, sessionId, mode.message, mode.message, CTX_EXPAND_TOKEN_BUDGET) ?? renderMessageByOrdinal(sessionId, mode.message);
25494
26223
  }
25495
26224
  const { start, end, verbose } = mode;
25496
26225
  const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, sessionId);
@@ -25498,6 +26227,9 @@ function createCtxExpandTool(deps) {
25498
26227
  return `Range ${start}-${end} is entirely within the live tail (after the last compacted message ${lastCompartmentEnd}); those messages are already visible in context.`;
25499
26228
  }
25500
26229
  const effectiveEnd = lastCompartmentEnd >= 0 ? Math.min(end, lastCompartmentEnd) : end;
26230
+ const archived = renderSearchArchive(deps.db, sessionId, start, effectiveEnd, CTX_EXPAND_TOKEN_BUDGET);
26231
+ if (archived)
26232
+ return archived;
25501
26233
  if (verbose) {
25502
26234
  const v = renderVerboseRange(sessionId, start, effectiveEnd, CTX_EXPAND_TOKEN_BUDGET, deps.expandTools);
25503
26235
  if (!v.text) {
@@ -26353,9 +27085,9 @@ function isMissingError(error) {
26353
27085
  }
26354
27086
 
26355
27087
  // ../retina-local-fs/src/provider.ts
26356
- import { execFile as execFile3 } from "node:child_process";
26357
- import { promisify as promisify3 } from "node:util";
26358
- var execFileAsync2 = promisify3(execFile3);
27088
+ import { execFile as execFile4 } from "node:child_process";
27089
+ import { promisify as promisify4 } from "node:util";
27090
+ var execFileAsync3 = promisify4(execFile4);
26359
27091
  function parseSemver(value) {
26360
27092
  const match = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(value);
26361
27093
  if (!match) {
@@ -27004,7 +27736,7 @@ function formatCtxReduceReply(stampedCount, selfStampCount = 0) {
27004
27736
  return parts.join(" ");
27005
27737
  }
27006
27738
  // src/tools/ctx-reduce/tools.ts
27007
- import { createHash as createHash14 } from "node:crypto";
27739
+ import { createHash as createHash15 } from "node:crypto";
27008
27740
  import { tool as tool4 } from "@opencode-ai/plugin";
27009
27741
 
27010
27742
  // src/features/magic-context/range-parser.ts
@@ -27068,11 +27800,11 @@ function createCtxReduceTool(deps) {
27068
27800
  const stableId = `oc-${sessionId}-${callId}`;
27069
27801
  if (Buffer.byteLength(stableId) <= 128)
27070
27802
  return stableId;
27071
- return `oc-${createHash14("sha256").update(stableId).digest("hex")}`;
27803
+ return `oc-${createHash15("sha256").update(stableId).digest("hex")}`;
27072
27804
  }
27073
27805
  fallbackCommandSequence += 1;
27074
27806
  const monotonicId = `oc-${sessionId}-${fallbackCommandSequence}`;
27075
- return Buffer.byteLength(monotonicId) <= 128 ? monotonicId : `oc-${createHash14("sha256").update(monotonicId).digest("hex")}`;
27807
+ return Buffer.byteLength(monotonicId) <= 128 ? monotonicId : `oc-${createHash15("sha256").update(monotonicId).digest("hex")}`;
27076
27808
  };
27077
27809
  return tool4({
27078
27810
  description: CTX_REDUCE_DESCRIPTION,