@cortexkit/opencode-magic-context 0.43.2 → 0.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. package/README.md +18 -2
  2. package/dist/agents/magic-context-prompt.d.ts +2 -0
  3. package/dist/agents/magic-context-prompt.d.ts.map +1 -1
  4. package/dist/{announcement-1a8bvswd.js → announcement-n8hs7kjw.js} +2 -2
  5. package/dist/config/index.d.ts +13 -0
  6. package/dist/config/index.d.ts.map +1 -1
  7. package/dist/config/live-child-output-cap.d.ts +18 -0
  8. package/dist/config/live-child-output-cap.d.ts.map +1 -0
  9. package/dist/config/project-security.d.ts +6 -3
  10. package/dist/config/project-security.d.ts.map +1 -1
  11. package/dist/config/schema/magic-context.d.ts +28 -1
  12. package/dist/config/schema/magic-context.d.ts.map +1 -1
  13. package/dist/{conflict-warning-hook-hyk9y29x.js → conflict-warning-hook-d14ah73v.js} +6 -6
  14. package/dist/{derive-budgets-b8ybssh9.js → derive-budgets-gd2270s0.js} +3 -3
  15. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  16. package/dist/features/magic-context/compartment-embedding.d.ts +3 -2
  17. package/dist/features/magic-context/compartment-embedding.d.ts.map +1 -1
  18. package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
  19. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/curate-category-rotation.d.ts.map +1 -1
  21. package/dist/features/magic-context/dreamer/curate-memory-safety.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/failed-invocation-evidence.d.ts +13 -0
  23. package/dist/features/magic-context/dreamer/failed-invocation-evidence.d.ts.map +1 -0
  24. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts.map +1 -1
  25. package/dist/features/magic-context/dreamer/lease.d.ts +5 -2
  26. package/dist/features/magic-context/dreamer/lease.d.ts.map +1 -1
  27. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  28. package/dist/features/magic-context/dreamer/memory-claim-safety.d.ts.map +1 -1
  29. package/dist/features/magic-context/dreamer/module-apply.d.ts +1 -0
  30. package/dist/features/magic-context/dreamer/module-apply.d.ts.map +1 -1
  31. package/dist/features/magic-context/dreamer/open-opencode-db.d.ts +2 -0
  32. package/dist/features/magic-context/dreamer/open-opencode-db.d.ts.map +1 -1
  33. package/dist/features/magic-context/dreamer/primer-seed.d.ts +11 -5
  34. package/dist/features/magic-context/dreamer/primer-seed.d.ts.map +1 -1
  35. package/dist/features/magic-context/dreamer/refresh-primers.d.ts +2 -2
  36. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  37. package/dist/features/magic-context/dreamer/retrospective-learnings.d.ts.map +1 -1
  38. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +1 -1
  39. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  40. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  41. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +2 -0
  42. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  43. package/dist/features/magic-context/dreamer/verify.d.ts +19 -0
  44. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  45. package/dist/features/magic-context/fail-closed-block.d.ts +7 -0
  46. package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
  47. package/dist/features/magic-context/index.d.ts +1 -0
  48. package/dist/features/magic-context/index.d.ts.map +1 -1
  49. package/dist/features/magic-context/install-instance-id.d.ts +33 -0
  50. package/dist/features/magic-context/install-instance-id.d.ts.map +1 -0
  51. package/dist/features/magic-context/memory/constants.d.ts.map +1 -1
  52. package/dist/features/magic-context/memory/embedding-backfill.d.ts.map +1 -1
  53. package/dist/features/magic-context/memory/project-identity.d.ts +7 -0
  54. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  55. package/dist/features/magic-context/memory/single-store-embedding-drain.d.ts +35 -0
  56. package/dist/features/magic-context/memory/single-store-embedding-drain.d.ts.map +1 -0
  57. package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
  58. package/dist/features/magic-context/message-index.d.ts +23 -0
  59. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  60. package/dist/features/magic-context/migrations.d.ts +7 -0
  61. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  62. package/dist/features/magic-context/mural/mural-font.generated.d.ts.map +1 -1
  63. package/dist/features/magic-context/overflow-detection.d.ts +31 -8
  64. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  65. package/dist/features/magic-context/project-embedding-registry.d.ts +40 -1
  66. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  67. package/dist/features/magic-context/search.d.ts.map +1 -1
  68. package/dist/features/magic-context/session-cache-ttl.d.ts +10 -0
  69. package/dist/features/magic-context/session-cache-ttl.d.ts.map +1 -0
  70. package/dist/features/magic-context/session-decision-calibration.d.ts.map +1 -1
  71. package/dist/features/magic-context/storage-db.d.ts +1 -1
  72. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  73. package/dist/features/magic-context/storage-meta-persisted.d.ts +20 -5
  74. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  75. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  76. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  77. package/dist/features/magic-context/storage-notes.d.ts +1 -0
  78. package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
  79. package/dist/features/magic-context/storage-primers.d.ts.map +1 -1
  80. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  81. package/dist/features/magic-context/storage-unavailable-reason.d.ts +17 -0
  82. package/dist/features/magic-context/storage-unavailable-reason.d.ts.map +1 -0
  83. package/dist/features/magic-context/storage.d.ts +1 -1
  84. package/dist/features/magic-context/storage.d.ts.map +1 -1
  85. package/dist/features/magic-context/store-generation-rebase.d.ts +33 -1
  86. package/dist/features/magic-context/store-generation-rebase.d.ts.map +1 -1
  87. package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -1
  88. package/dist/features/magic-context/transform-decision-log.d.ts +1 -1
  89. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  90. package/dist/features/magic-context/types.d.ts +8 -3
  91. package/dist/features/magic-context/types.d.ts.map +1 -1
  92. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
  93. package/dist/hooks/magic-context/apply-operations.d.ts +105 -9
  94. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  95. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  96. package/dist/hooks/magic-context/compartment-parser.d.ts +2 -0
  97. package/dist/hooks/magic-context/compartment-parser.d.ts.map +1 -1
  98. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +1 -0
  99. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  100. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  101. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  102. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  103. package/dist/hooks/magic-context/compartment-runner-types.d.ts +2 -0
  104. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  105. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  106. package/dist/hooks/magic-context/context-limit-resolution.d.ts +31 -0
  107. package/dist/hooks/magic-context/context-limit-resolution.d.ts.map +1 -0
  108. package/dist/hooks/magic-context/embed-history-runner.d.ts +0 -1
  109. package/dist/hooks/magic-context/embed-history-runner.d.ts.map +1 -1
  110. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  111. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  112. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
  113. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  114. package/dist/hooks/magic-context/format-embed-status.d.ts.map +1 -1
  115. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  116. package/dist/hooks/magic-context/historian-host-runner.d.ts +233 -0
  117. package/dist/hooks/magic-context/historian-host-runner.d.ts.map +1 -0
  118. package/dist/hooks/magic-context/hook.d.ts +1 -3
  119. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  120. package/dist/hooks/magic-context/image-token-estimate.d.ts +9 -0
  121. package/dist/hooks/magic-context/image-token-estimate.d.ts.map +1 -1
  122. package/dist/hooks/magic-context/inject-compartments.d.ts +60 -1
  123. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  124. package/dist/hooks/magic-context/lkg-slot.d.ts +6 -0
  125. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  126. package/dist/hooks/magic-context/module-client.d.ts +21 -0
  127. package/dist/hooks/magic-context/module-client.d.ts.map +1 -0
  128. package/dist/hooks/magic-context/module-state-sync.d.ts +6 -2
  129. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  130. package/dist/hooks/magic-context/module-tool-backends.d.ts +47 -0
  131. package/dist/hooks/magic-context/module-tool-backends.d.ts.map +1 -0
  132. package/dist/hooks/magic-context/module-transport.d.ts +1 -1
  133. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  134. package/dist/hooks/magic-context/opencode-v1-store-fixture.d.ts +12 -0
  135. package/dist/hooks/magic-context/opencode-v1-store-fixture.d.ts.map +1 -0
  136. package/dist/hooks/magic-context/persist-filtered-noise.d.ts.map +1 -1
  137. package/dist/hooks/magic-context/read-session-chunk.d.ts +28 -0
  138. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  139. package/dist/hooks/magic-context/read-session-db.d.ts +5 -1
  140. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  141. package/dist/hooks/magic-context/read-session-raw.d.ts +10 -0
  142. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  143. package/dist/hooks/magic-context/rust-mode-transform.d.ts +35 -0
  144. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  145. package/dist/hooks/magic-context/rust-refusal-recovery.d.ts +18 -0
  146. package/dist/hooks/magic-context/rust-refusal-recovery.d.ts.map +1 -1
  147. package/dist/hooks/magic-context/rust-served-m0.d.ts +20 -0
  148. package/dist/hooks/magic-context/rust-served-m0.d.ts.map +1 -0
  149. package/dist/hooks/magic-context/store-ahead-refusal.d.ts +40 -0
  150. package/dist/hooks/magic-context/store-ahead-refusal.d.ts.map +1 -0
  151. package/dist/hooks/magic-context/strip-content.d.ts +5 -5
  152. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  153. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  154. package/dist/hooks/magic-context/tag-messages.d.ts +19 -0
  155. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  156. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  157. package/dist/hooks/magic-context/tool-drop-target.d.ts +14 -0
  158. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  159. package/dist/hooks/magic-context/tool-input-size.d.ts +21 -0
  160. package/dist/hooks/magic-context/tool-input-size.d.ts.map +1 -0
  161. package/dist/hooks/magic-context/tool-sweep-policy.d.ts.map +1 -1
  162. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +124 -11
  163. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  164. package/dist/hooks/magic-context/transform.d.ts +14 -0
  165. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  166. package/dist/{index-pa67brzn.js → index-0rp6pj54.js} +3 -3
  167. package/dist/{index-4b30nf6z.js → index-32b096cc.js} +1 -1
  168. package/dist/{index-wgzyeyf5.js → index-3bygzk2d.js} +23 -7
  169. package/dist/{index-jgnag7sa.js → index-a9vbtdzv.js} +4 -4
  170. package/dist/{index-bmzt6xgy.js → index-cz88kw0n.js} +13 -3
  171. package/dist/{index-6j8th2hd.js → index-d107az47.js} +2 -2
  172. package/dist/{index-g6hpfkqa.js → index-jtdrvmcn.js} +3290 -286
  173. package/dist/{index-9r1cbh9e.js → index-kr5qehbd.js} +1 -1
  174. package/dist/{index-febg06dy.js → index-kwe03yde.js} +1 -1
  175. package/dist/{index-tdrv6nd0.js → index-s6b7h12g.js} +352 -71
  176. package/dist/{index-6z9g64js.js → index-s70wtd8k.js} +4 -1
  177. package/dist/{index-0ccmyzbj.js → index-stb5fg12.js} +2 -2
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +5230 -5663
  180. package/dist/{message-time-backfill-0ccvyk9n.js → message-time-backfill-q374fxc5.js} +4 -4
  181. package/dist/plugin/dream-timer.d.ts +2 -0
  182. package/dist/plugin/dream-timer.d.ts.map +1 -1
  183. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  184. package/dist/plugin/messages-transform.d.ts.map +1 -1
  185. package/dist/plugin/native-compaction-guard.d.ts +22 -0
  186. package/dist/plugin/native-compaction-guard.d.ts.map +1 -0
  187. package/dist/plugin/rpc-handlers.d.ts +11 -0
  188. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  189. package/dist/{read-session-chunk-53a7qbrh.js → read-session-chunk-fkdv2g5b.js} +8 -4
  190. package/dist/{recomp-orchestrator-adsgqgse.js → recomp-orchestrator-k4h5n0p3.js} +9 -9
  191. package/dist/{safe-notification-target-vrkjrbgb.js → safe-notification-target-50gm9c58.js} +3 -3
  192. package/dist/{send-session-notification-e28r4xx2.js → send-session-notification-g2k03zyn.js} +5 -5
  193. package/dist/shared/cache-ttl-display.d.ts +3 -1
  194. package/dist/shared/cache-ttl-display.d.ts.map +1 -1
  195. package/dist/shared/harness.d.ts +11 -0
  196. package/dist/shared/harness.d.ts.map +1 -1
  197. package/dist/shared/index.d.ts +1 -0
  198. package/dist/shared/index.d.ts.map +1 -1
  199. package/dist/shared/logger.d.ts.map +1 -1
  200. package/dist/shared/model-cache-ttl.d.ts +9 -0
  201. package/dist/shared/model-cache-ttl.d.ts.map +1 -0
  202. package/dist/shared/model-suggestion-retry.d.ts +13 -1
  203. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  204. package/dist/shared/prompt-async-transport.d.ts +25 -0
  205. package/dist/shared/prompt-async-transport.d.ts.map +1 -0
  206. package/dist/shared/rpc-server.d.ts +1 -0
  207. package/dist/shared/rpc-server.d.ts.map +1 -1
  208. package/dist/shared/rpc-types.d.ts +17 -1
  209. package/dist/shared/rpc-types.d.ts.map +1 -1
  210. package/dist/shared/rpc-utils.d.ts +3 -0
  211. package/dist/shared/rpc-utils.d.ts.map +1 -1
  212. package/dist/shared/sqlite-write-locker-test-support.d.ts +7 -0
  213. package/dist/shared/sqlite-write-locker-test-support.d.ts.map +1 -0
  214. package/dist/shared/status-summary.d.ts +9 -1
  215. package/dist/shared/status-summary.d.ts.map +1 -1
  216. package/dist/shared/status-view.d.ts +1 -1
  217. package/dist/shared/status-view.d.ts.map +1 -1
  218. package/dist/shared/tag-transcript.d.ts.map +1 -1
  219. package/dist/shared/user-facing-codes.d.ts +10 -5
  220. package/dist/shared/user-facing-codes.d.ts.map +1 -1
  221. package/dist/shared/window-geometry.d.ts +6 -3
  222. package/dist/shared/window-geometry.d.ts.map +1 -1
  223. package/dist/tools/ctx-expand/render.d.ts.map +1 -1
  224. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  225. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  226. package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
  227. package/dist/tools/ctx-search/tools.d.ts.map +1 -1
  228. package/dist/v2/fold/boundary.d.ts +61 -0
  229. package/dist/v2/fold/boundary.d.ts.map +1 -0
  230. package/dist/v2/fold/restore.d.ts.map +1 -1
  231. package/dist/v2/hidden-completion.d.ts +16 -3
  232. package/dist/v2/hidden-completion.d.ts.map +1 -1
  233. package/dist/v2/hooks/context.d.ts +45 -14
  234. package/dist/v2/hooks/context.d.ts.map +1 -1
  235. package/dist/v2/hooks/hidden-child.d.ts +6 -0
  236. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  237. package/dist/v2/hooks/payload.d.ts.map +1 -1
  238. package/dist/v2/hooks/rpc-live-state.d.ts +1 -1
  239. package/dist/v2/hooks/rpc-live-state.d.ts.map +1 -1
  240. package/dist/v2/hooks/rust-mode.d.ts +47 -0
  241. package/dist/v2/hooks/rust-mode.d.ts.map +1 -0
  242. package/dist/v2/hooks/session-project-backfill.d.ts +15 -0
  243. package/dist/v2/hooks/session-project-backfill.d.ts.map +1 -0
  244. package/dist/v2/hooks/storage-gate.d.ts +42 -0
  245. package/dist/v2/hooks/storage-gate.d.ts.map +1 -0
  246. package/dist/v2/hooks/storage-notice.d.ts +29 -0
  247. package/dist/v2/hooks/storage-notice.d.ts.map +1 -0
  248. package/dist/v2/hooks/store.d.ts +16 -0
  249. package/dist/v2/hooks/store.d.ts.map +1 -1
  250. package/dist/v2/hooks/tools.d.ts +11 -2
  251. package/dist/v2/hooks/tools.d.ts.map +1 -1
  252. package/dist/v2/hooks/types.d.ts +4 -0
  253. package/dist/v2/hooks/types.d.ts.map +1 -1
  254. package/dist/v2/hooks/usage-persist.d.ts +31 -0
  255. package/dist/v2/hooks/usage-persist.d.ts.map +1 -0
  256. package/dist/v2/server.js +27201 -22695
  257. package/dist/v2/store-reader.d.ts +9 -0
  258. package/dist/v2/store-reader.d.ts.map +1 -1
  259. package/dist/wrapup-orchestrator-35y56636.js +18 -0
  260. package/package.json +1 -1
  261. package/src/agents/magic-context-prompt.test.ts +125 -0
  262. package/src/agents/magic-context-prompt.ts +15 -10
  263. package/src/config/index.ts +40 -0
  264. package/src/config/live-child-output-cap.test.ts +75 -0
  265. package/src/config/live-child-output-cap.ts +70 -0
  266. package/src/config/live-run-config.test.ts +24 -11
  267. package/src/config/misplaced-agent-model.test.ts +61 -0
  268. package/src/config/project-security.test.ts +17 -0
  269. package/src/config/project-security.ts +28 -4
  270. package/src/config/schema/magic-context.test.ts +16 -1
  271. package/src/config/schema/magic-context.ts +35 -6
  272. package/src/shared/cache-ttl-display.ts +14 -20
  273. package/src/shared/harness.ts +14 -0
  274. package/src/shared/index.ts +1 -0
  275. package/src/shared/logger.test.ts +63 -2
  276. package/src/shared/logger.ts +23 -5
  277. package/src/shared/model-cache-ttl.test.ts +40 -0
  278. package/src/shared/model-cache-ttl.ts +58 -0
  279. package/src/shared/model-suggestion-retry.test.ts +115 -4
  280. package/src/shared/model-suggestion-retry.ts +57 -12
  281. package/src/shared/prompt-async-transport.test.ts +217 -0
  282. package/src/shared/prompt-async-transport.ts +242 -0
  283. package/src/shared/prompt-surface-a1-golden.md +17 -17
  284. package/src/shared/rpc-server.ts +13 -1
  285. package/src/shared/rpc-types.ts +18 -1
  286. package/src/shared/rpc-utils.ts +28 -0
  287. package/src/shared/sqlite-transaction-mode-guard.test.ts +198 -0
  288. package/src/shared/sqlite-write-locker-test-support.ts +62 -0
  289. package/src/shared/status-detail-text.test.ts +23 -0
  290. package/src/shared/status-summary.ts +25 -1
  291. package/src/shared/status-view.ts +1 -1
  292. package/src/shared/tag-transcript.ts +82 -19
  293. package/src/shared/user-facing-codes.ts +12 -5
  294. package/src/shared/window-geometry.ts +6 -3
  295. package/dist/v2/hooks/provider-admission.d.ts +0 -22
  296. package/dist/v2/hooks/provider-admission.d.ts.map +0 -1
  297. package/dist/wrapup-orchestrator-8xzbpvm8.js +0 -18
@@ -0,0 +1,198 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { readdirSync, readFileSync } from "node:fs";
3
+ import { join, relative, resolve } from "node:path";
4
+ import ts from "typescript";
5
+
6
+ /**
7
+ * A deferred transaction (`db.transaction(fn)()`, `.deferred()`, `.default()`)
8
+ * starts with no lock. If it reads before it writes, the write must upgrade a read
9
+ * snapshot to a write lock, and SQLite never runs the busy handler for that
10
+ * upgrade: under another process's write it fails at once with SQLITE_BUSY, or
11
+ * with SQLITE_BUSY_SNAPSHOT when another commit landed after the read, and
12
+ * busy_timeout never applies. Many OpenCode and Pi processes share one context.db,
13
+ * so every transaction that writes must start with `.immediate()` (or
14
+ * `.exclusive()`), which takes the write lock at BEGIN where busy_timeout covers it.
15
+ *
16
+ * Only read-only transactions may stay deferred. Each one is listed here, keyed
17
+ * by file and the nearest named enclosing function, with the reason it never
18
+ * writes. A read-only snapshot must not take the write lock, because that would
19
+ * block every writer for the length of the read.
20
+ */
21
+ const READ_ONLY_DEFERRED_TRANSACTIONS: Record<string, string> = {
22
+ "packages/plugin/src/v2/store-reader.ts#window":
23
+ "reads the latest compaction and the rows after it as one consistent snapshot of the OpenCode 2 store; never writes",
24
+ "packages/pi-plugin/src/inject-compartments-pi.ts#readFrozenM0InputsPi":
25
+ "reads the m[0] render sources and their watermarks as one consistent snapshot; never writes",
26
+ };
27
+
28
+ const REPOSITORY_ROOT = resolve(import.meta.dir, "../../../..");
29
+ const SOURCE_ROOTS = ["packages/plugin/src", "packages/pi-plugin/src"];
30
+ const LOCKING_MODES = new Set(["immediate", "exclusive"]);
31
+
32
+ function sourceFiles(directory: string): string[] {
33
+ const result: string[] = [];
34
+ for (const entry of readdirSync(directory, { withFileTypes: true })) {
35
+ const path = join(directory, entry.name);
36
+ if (entry.isDirectory()) {
37
+ if (entry.name === "node_modules") continue;
38
+ result.push(...sourceFiles(path));
39
+ } else if (
40
+ /\.tsx?$/.test(entry.name) &&
41
+ !/\.test\.tsx?$/.test(entry.name) &&
42
+ !/\.d\.ts$/.test(entry.name)
43
+ ) {
44
+ result.push(path);
45
+ }
46
+ }
47
+ return result;
48
+ }
49
+
50
+ function isTransactionCall(node: ts.Node): node is ts.CallExpression {
51
+ return (
52
+ ts.isCallExpression(node) &&
53
+ ts.isPropertyAccessExpression(node.expression) &&
54
+ node.expression.name.text === "transaction"
55
+ );
56
+ }
57
+
58
+ /** True when `node` is the receiver of a called `.immediate()` / `.exclusive()`. */
59
+ function isCalledWithLockingMode(node: ts.Node): boolean {
60
+ const access = node.parent;
61
+ return (
62
+ access !== undefined &&
63
+ ts.isPropertyAccessExpression(access) &&
64
+ access.expression === node &&
65
+ LOCKING_MODES.has(access.name.text) &&
66
+ access.parent !== undefined &&
67
+ ts.isCallExpression(access.parent) &&
68
+ access.parent.expression === access
69
+ );
70
+ }
71
+
72
+ function enclosingFunctionName(node: ts.Node): string {
73
+ for (let current = node.parent; current; current = current.parent) {
74
+ if (
75
+ (ts.isFunctionDeclaration(current) || ts.isMethodDeclaration(current)) &&
76
+ current.name
77
+ ) {
78
+ return current.name.getText();
79
+ }
80
+ if (
81
+ (ts.isArrowFunction(current) || ts.isFunctionExpression(current)) &&
82
+ current.parent &&
83
+ (ts.isVariableDeclaration(current.parent) || ts.isPropertyAssignment(current.parent))
84
+ ) {
85
+ return current.parent.name.getText();
86
+ }
87
+ }
88
+ return "<module>";
89
+ }
90
+
91
+ /**
92
+ * A transaction stored in a variable is locking only when every use of that
93
+ * variable calls `.immediate()` or `.exclusive()` on it.
94
+ */
95
+ function storedTransactionLocks(call: ts.CallExpression, source: ts.SourceFile): boolean {
96
+ const declaration = call.parent;
97
+ if (!ts.isVariableDeclaration(declaration) || !ts.isIdentifier(declaration.name)) return false;
98
+ const name = declaration.name.text;
99
+ let scope: ts.Node = source;
100
+ for (let current: ts.Node | undefined = declaration.parent; current; current = current.parent) {
101
+ if (ts.isBlock(current)) {
102
+ scope = current;
103
+ break;
104
+ }
105
+ }
106
+ const uses: ts.Identifier[] = [];
107
+ const visit = (node: ts.Node): void => {
108
+ if (ts.isIdentifier(node) && node.text === name && node !== declaration.name) {
109
+ uses.push(node);
110
+ }
111
+ ts.forEachChild(node, visit);
112
+ };
113
+ visit(scope);
114
+ return uses.length > 0 && uses.every(isCalledWithLockingMode);
115
+ }
116
+
117
+ interface TransactionScan {
118
+ deferredSites: Map<string, string[]>;
119
+ lockingSites: number;
120
+ }
121
+
122
+ function scanTransactionModes(files: Array<{ path: string; text: string }>): TransactionScan {
123
+ const deferredSites = new Map<string, string[]>();
124
+ let lockingSites = 0;
125
+ for (const file of files) {
126
+ if (!file.text.includes(".transaction(")) continue;
127
+ const source = ts.createSourceFile(file.path, file.text, ts.ScriptTarget.Latest, true);
128
+ const visit = (node: ts.Node): void => {
129
+ if (isTransactionCall(node)) {
130
+ if (isCalledWithLockingMode(node) || storedTransactionLocks(node, source)) {
131
+ lockingSites += 1;
132
+ } else {
133
+ const key = `${file.path}#${enclosingFunctionName(node)}`;
134
+ const line = source.getLineAndCharacterOfPosition(node.getStart(source)).line;
135
+ const locations = deferredSites.get(key) ?? [];
136
+ locations.push(`${file.path}:${line + 1}`);
137
+ deferredSites.set(key, locations);
138
+ }
139
+ }
140
+ ts.forEachChild(node, visit);
141
+ };
142
+ visit(source);
143
+ }
144
+ return { deferredSites, lockingSites };
145
+ }
146
+
147
+ function repositorySources(): Array<{ path: string; text: string }> {
148
+ return SOURCE_ROOTS.flatMap((root) =>
149
+ sourceFiles(resolve(REPOSITORY_ROOT, root)).map((path) => ({
150
+ path: relative(REPOSITORY_ROOT, path),
151
+ text: readFileSync(path, "utf8"),
152
+ })),
153
+ );
154
+ }
155
+
156
+ describe("SQLite transaction lock mode", () => {
157
+ it("starts every writing transaction with .immediate() or .exclusive()", () => {
158
+ const { deferredSites, lockingSites } = scanTransactionModes(repositorySources());
159
+ // The scan must actually see the codebase's transactions.
160
+ expect(lockingSites).toBeGreaterThan(50);
161
+
162
+ const unlisted = [...deferredSites]
163
+ .filter(([key]) => !(key in READ_ONLY_DEFERRED_TRANSACTIONS))
164
+ .flatMap(([, locations]) => locations);
165
+ expect(unlisted).toEqual([]);
166
+
167
+ // One deferred transaction per listed function, so a second one added
168
+ // beside a read-only snapshot is not waved through by the same entry.
169
+ const repeated = [...deferredSites].filter(([, locations]) => locations.length > 1);
170
+ expect(repeated).toEqual([]);
171
+
172
+ // A listed entry whose transaction is gone or now locks must be removed.
173
+ const stale = Object.keys(READ_ONLY_DEFERRED_TRANSACTIONS).filter(
174
+ (key) => !deferredSites.has(key),
175
+ );
176
+ expect(stale).toEqual([]);
177
+ });
178
+
179
+ it("recognises each deferred and locking shape", () => {
180
+ const text = `
181
+ function plainCall(db) { db.transaction(() => write())(); }
182
+ function explicitDeferred(db) { db.transaction(() => write()).deferred(); }
183
+ function stored(db) { const tx = db.transaction(() => write()); tx(); }
184
+ function storedMixed(db) { const tx = db.transaction(() => write()); tx.immediate(); tx(); }
185
+ function immediate(db) { db.transaction(() => write()).immediate(); }
186
+ function chained(db) { return db\n.transaction(() => write())\n.exclusive(); }
187
+ function storedImmediate(db) { const tx = db.transaction(() => write()); return tx.immediate(); }
188
+ `;
189
+ const { deferredSites, lockingSites } = scanTransactionModes([{ path: "x.ts", text }]);
190
+ expect([...deferredSites.keys()].sort()).toEqual([
191
+ "x.ts#explicitDeferred",
192
+ "x.ts#plainCall",
193
+ "x.ts#stored",
194
+ "x.ts#storedMixed",
195
+ ]);
196
+ expect(lockingSites).toBe(3);
197
+ });
198
+ });
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Holds a SQLite write lock from a separate process, for lock-contention tests.
3
+ *
4
+ * Run directly as `bun sqlite-write-locker-test-support.ts <db> <holdMs>`, the file
5
+ * opens the database, takes the write lock with BEGIN IMMEDIATE, prints `LOCKED`,
6
+ * holds the lock for `holdMs`, commits and prints `RELEASED`. Tests start it
7
+ * through `startSqliteWriteLocker`.
8
+ *
9
+ * The lock has to come from a different process. A second connection in the
10
+ * test's own process cannot release its lock while the test's main thread is
11
+ * blocked inside SQLite's busy wait, so the wait would always time out and a test
12
+ * could never observe a writer that waits and then succeeds.
13
+ */
14
+ import { Database } from "bun:sqlite";
15
+
16
+ export interface SqliteWriteLocker {
17
+ /** Resolves with the locker's exit code after it has committed and exited. */
18
+ exited: Promise<number>;
19
+ }
20
+
21
+ /** Start the locker and resolve once it reports that it holds the write lock. */
22
+ export async function startSqliteWriteLocker(
23
+ dbPath: string,
24
+ holdMs: number,
25
+ ): Promise<SqliteWriteLocker> {
26
+ const child = Bun.spawn(["bun", import.meta.path, dbPath, String(holdMs)], {
27
+ stdout: "pipe",
28
+ stderr: "pipe",
29
+ });
30
+ const reader = child.stdout.getReader();
31
+ const decoder = new TextDecoder();
32
+ let seen = "";
33
+ while (!seen.includes("LOCKED\n")) {
34
+ const chunk = await reader.read();
35
+ if (chunk.done) {
36
+ const stderr = await new Response(child.stderr).text();
37
+ throw new Error(`sqlite write locker exited before locking: ${stderr}`);
38
+ }
39
+ seen += decoder.decode(chunk.value, { stream: true });
40
+ }
41
+ reader.releaseLock();
42
+ return { exited: child.exited };
43
+ }
44
+
45
+ function main(): void {
46
+ const [dbPath, holdArg] = process.argv.slice(2);
47
+ const holdMs = Number(holdArg);
48
+ if (!dbPath || !Number.isFinite(holdMs) || holdMs < 0) {
49
+ process.stderr.write("usage: sqlite-write-locker-test-support.ts <db> <holdMs>\n");
50
+ process.exit(2);
51
+ }
52
+ const db = new Database(dbPath);
53
+ db.exec("PRAGMA busy_timeout = 5000");
54
+ db.exec("BEGIN IMMEDIATE");
55
+ process.stdout.write("LOCKED\n");
56
+ Bun.sleepSync(holdMs);
57
+ db.exec("COMMIT");
58
+ db.close();
59
+ process.stdout.write("RELEASED\n");
60
+ }
61
+
62
+ if (import.meta.main) main();
@@ -217,6 +217,29 @@ describe("status detail text", () => {
217
217
  );
218
218
  });
219
219
 
220
+ test("says which runner ran the session's completions and why", () => {
221
+ const status = formatStatusDetailMarkdown({
222
+ ...STATUS_FIXTURE,
223
+ historianRunner: {
224
+ runner: "host",
225
+ source: "default_for_harness",
226
+ harness: "opencode",
227
+ observed: "last_completion",
228
+ },
229
+ dreamerRunner: {
230
+ runner: "broca",
231
+ source: "configured",
232
+ harness: "opencode",
233
+ observed: "resolved_for_route",
234
+ },
235
+ });
236
+
237
+ expect(status).toMatch(
238
+ /^- \*\*Historian runner:\*\* host \(default for harness opencode\)$/m,
239
+ );
240
+ expect(status).toContain("- **Dreamer runner:** broca (configured) · no completion yet");
241
+ });
242
+
220
243
  test("does not expose module routing in the summary", () => {
221
244
  const rustStatus = formatStatusDetailMarkdown({
222
245
  ...STATUS_FIXTURE,
@@ -1,5 +1,5 @@
1
1
  import { formatCacheTtlDisplay } from "./cache-ttl-display";
2
- import type { StatusDetail } from "./rpc-types";
2
+ import type { RunnerStatus, StatusDetail } from "./rpc-types";
3
3
  import { renderUserFacingFailure, type UserFacingFailureKey } from "./user-facing-codes";
4
4
 
5
5
  export type StatusCompressionState = "off" | "compressing" | "ready" | "waiting";
@@ -32,6 +32,8 @@ export interface UserStatusSummary {
32
32
  detail: string;
33
33
  };
34
34
  compactionMarker?: StatusDetail["compactionMarker"];
35
+ historianRunner?: RunnerStatus;
36
+ dreamerRunner?: RunnerStatus;
35
37
  warnings: UserFacingFailureKey[];
36
38
  hiddenVariantWarnings?: string[];
37
39
  }
@@ -96,6 +98,8 @@ export function statusSummaryFromDetail(detail: StatusDetail): UserStatusSummary
96
98
  total: 0,
97
99
  },
98
100
  historianRefusal: detail.historianRefusal,
101
+ historianRunner: detail.historianRunner,
102
+ dreamerRunner: detail.dreamerRunner,
99
103
  compactionMarker: detail.compactionMarker,
100
104
  warnings: [...new Set(warnings)],
101
105
  hiddenVariantWarnings: detail.hiddenVariantWarnings ?? [],
@@ -122,6 +126,20 @@ function compressionText(summary: UserStatusSummary): string {
122
126
  }
123
127
  }
124
128
 
129
+ /**
130
+ * `host (default for harness opencode)` or `broca (configured)`, plus a note when
131
+ * no completion has run yet in the module's current process and the value is
132
+ * only what the session's route resolves to.
133
+ */
134
+ export function runnerText(status: RunnerStatus): string {
135
+ const why =
136
+ status.source === "configured"
137
+ ? "configured"
138
+ : `default for harness ${status.harness || "unknown"}`;
139
+ const observed = status.observed === "last_completion" ? "" : " · no completion yet";
140
+ return `${status.runner} (${why})${observed}`;
141
+ }
142
+
125
143
  function reclaimableText(summary: UserStatusSummary): string {
126
144
  const count = Math.max(0, Math.floor(summary.reclaimable.toolOutputCount));
127
145
  if (count === 0) return "none";
@@ -170,6 +188,12 @@ export function renderUserStatusSummary(
170
188
  ],
171
189
  ["Search indexing", embeddingText(summary)],
172
190
  ];
191
+ if (summary.historianRunner) {
192
+ values.push(["Historian runner", runnerText(summary.historianRunner)]);
193
+ }
194
+ if (summary.dreamerRunner) {
195
+ values.push(["Dreamer runner", runnerText(summary.dreamerRunner)]);
196
+ }
173
197
  if (summary.historianRefusal) {
174
198
  values.push([
175
199
  "Historian refusal",
@@ -124,7 +124,7 @@ export interface StatusViewSource {
124
124
  readonly protectedTagCount: number;
125
125
  readonly isSubagent: boolean;
126
126
  readonly cacheTtl: string;
127
- readonly cacheTtlSource?: "config" | "session" | "default";
127
+ readonly cacheTtlSource?: import("./cache-ttl-display").CacheTtlDisplaySource;
128
128
  readonly cacheTtlModelKey?: string;
129
129
  readonly lastResponseTime: number;
130
130
  readonly cacheRemainingMs: number;
@@ -66,6 +66,7 @@ import {
66
66
  stripWellFormedLeadingTagPrefix,
67
67
  } from "../hooks/magic-context/tag-content-primitives";
68
68
  import type { TagTarget } from "../hooks/magic-context/tag-messages";
69
+ import { toolInputStringBytes } from "../hooks/magic-context/tool-input-size";
69
70
  import type { Transcript, TranscriptMessage, TranscriptPart } from "./transcript";
70
71
 
71
72
  export const TEXT_TAG_IDENTITY_MARKER = ":mc-text-v1:";
@@ -161,6 +162,12 @@ interface ToolOccurrence {
161
162
  message: { info: { id?: string; role: string } };
162
163
  part: TranscriptPart;
163
164
  kind: "tool_use" | "tool_result";
165
+ /**
166
+ * The call's real input, captured the first time this pass overwrote it
167
+ * with the legacy marker, so a later real-argument render in the same pass
168
+ * can put it back.
169
+ */
170
+ originalInput?: Record<string, unknown>;
164
171
  }
165
172
 
166
173
  interface TagTranscriptTiming {
@@ -1093,10 +1100,13 @@ function buildAggregateTarget(
1093
1100
  const truncate = (): "truncated" | "absent" => {
1094
1101
  // Keep the tool call and its result, but replace the call arguments with
1095
1102
  // a non-executable marker and the result content with the dropped marker.
1103
+ // Legacy render, replayed only for `drop_mode = 'truncated'` tags until a
1104
+ // HARD fold converts them; new drops use skeletonReal().
1096
1105
  const sentinel = `[dropped \u00a7${tagId}\u00a7]`;
1097
1106
  let any = false;
1098
1107
  for (const occ of occurrences) {
1099
1108
  if (occ.kind === "tool_use" && occ.part.setToolInput) {
1109
+ occ.originalInput ??= occ.part.getToolInput?.() ?? undefined;
1100
1110
  if (occ.part.setToolInput(droppedInputMarker(tagId))) any = true;
1101
1111
  } else if (setToolContentOrText(occ.part, sentinel)) {
1102
1112
  any = true;
@@ -1105,6 +1115,38 @@ function buildAggregateTarget(
1105
1115
  return any ? "truncated" : "absent";
1106
1116
  };
1107
1117
 
1118
+ const complete = (): boolean =>
1119
+ occurrences.some((occ) => occ.kind === "tool_use") &&
1120
+ occurrences.some((occ) => occ.kind === "tool_result");
1121
+
1122
+ const skeletonReal = (): "truncated" | "absent" | "incomplete" => {
1123
+ // Keep the tool call with the arguments the host gave it and replace
1124
+ // only the result content with the dropped marker. Nothing is written
1125
+ // into the argument position unless an earlier render this pass did,
1126
+ // in which case the real input goes back.
1127
+ if (!complete()) return "incomplete";
1128
+ const sentinel = `[dropped \u00a7${tagId}\u00a7]`;
1129
+ let any = false;
1130
+ for (const occ of occurrences) {
1131
+ if (occ.kind === "tool_use") {
1132
+ if (occ.originalInput && occ.part.setToolInput?.(occ.originalInput)) any = true;
1133
+ } else if (setToolContentOrText(occ.part, sentinel)) {
1134
+ any = true;
1135
+ }
1136
+ }
1137
+ return any ? "truncated" : "absent";
1138
+ };
1139
+
1140
+ // Adapters without structural removal (or arcs that must keep their pair
1141
+ // beside native reasoning) cannot remove the call; drop() would keep it.
1142
+ const cannotRemove = (): boolean => {
1143
+ if (requiresToolArcSkeleton) return true;
1144
+ const authorization = occurrences.map((occ) => occ.part.canRemove?.());
1145
+ return !occurrences.every(
1146
+ (occ, index) => occ.part.remove && authorization[index] !== false,
1147
+ );
1148
+ };
1149
+
1108
1150
  return {
1109
1151
  measureReclaim(skeleton) {
1110
1152
  let beforeTools = 0;
@@ -1125,10 +1167,8 @@ function buildAggregateTarget(
1125
1167
  : (occ.part.getText() ?? "");
1126
1168
  beforeTools += estimateTokens(before);
1127
1169
  if (skeleton || !removable) {
1128
- const after =
1129
- occ.kind === "tool_use"
1130
- ? JSON.stringify(droppedInputMarker(tagId))
1131
- : `[dropped §${tagId}§]`;
1170
+ // A kept call keeps its real arguments; only the result shrinks.
1171
+ const after = occ.kind === "tool_use" ? before : `[dropped §${tagId}§]`;
1132
1172
  afterTools += estimateTokens(after);
1133
1173
  }
1134
1174
  }
@@ -1163,10 +1203,7 @@ function buildAggregateTarget(
1163
1203
  return occurrences[0]?.part.getText() ?? null;
1164
1204
  },
1165
1205
  drop(): "removed" | "truncated" | "absent" | "incomplete" {
1166
- const complete =
1167
- occurrences.some((occ) => occ.kind === "tool_use") &&
1168
- occurrences.some((occ) => occ.kind === "tool_result");
1169
- if (!complete) return "incomplete";
1206
+ if (!complete()) return "incomplete";
1170
1207
  if (!requiresToolArcSkeleton) {
1171
1208
  const authorization = occurrences.map((occ) => occ.part.canRemove?.());
1172
1209
  // A failed durable marker is not permission to substitute a new
@@ -1178,19 +1215,23 @@ function buildAggregateTarget(
1178
1215
  )
1179
1216
  ) {
1180
1217
  // If removing this call's result would leave the provider
1181
- // request ending on an assistant turn, keep a call skeleton
1182
- // plus placeholder result instead. "truncated" tells callers
1183
- // to persist that mode, so later passes serve the same bytes.
1218
+ // request ending on an assistant turn, keep the call with its
1219
+ // REAL arguments plus the placeholder result instead.
1220
+ // "truncated" tells callers to persist that mode
1221
+ // (`skeleton_real`), so later passes serve the same bytes.
1184
1222
  // (The sentinel fallback below keeps call and result in place,
1185
1223
  // so it needs no exception.)
1186
- if (conversationEnd?.wouldStrand(occurrences)) return truncate();
1224
+ if (conversationEnd?.wouldStrand(occurrences)) return skeletonReal();
1187
1225
  let removed = false;
1188
1226
  for (const occ of occurrences) removed = occ.part.remove?.() || removed;
1189
1227
  if (removed) conversationEnd?.noteRemoved(occurrences);
1190
1228
  return removed ? "removed" : "absent";
1191
1229
  }
1192
1230
  }
1193
- // Adapters without structural removal retain paired sentinels.
1231
+ // Adapters without structural removal retain paired sentinels. This
1232
+ // writes a marker into the call's arguments, so only replays of
1233
+ // existing `full` tags reach it: new drops check cannotRemove() and
1234
+ // use skeletonReal(), and a HARD fold converts the existing ones.
1194
1235
  const sentinel = `[dropped \u00a7${tagId}\u00a7]`;
1195
1236
  let any = false;
1196
1237
  for (const occ of occurrences) {
@@ -1199,6 +1240,18 @@ function buildAggregateTarget(
1199
1240
  return any ? "removed" : "absent";
1200
1241
  },
1201
1242
  truncate,
1243
+ skeletonReal,
1244
+ cannotRemove,
1245
+ inputStringBytes(): number | null {
1246
+ for (const occ of occurrences) {
1247
+ if (occ.kind !== "tool_use") continue;
1248
+ return toolInputStringBytes(occ.originalInput ?? occ.part.getToolInput?.() ?? null);
1249
+ }
1250
+ return null;
1251
+ },
1252
+ wouldStrandConversationEnd(): boolean {
1253
+ return conversationEnd?.wouldStrand(occurrences) ?? false;
1254
+ },
1202
1255
  editMarker(): "truncated" | "absent" {
1203
1256
  // Edit-marker: preserve the tool_use input's filePath + a region
1204
1257
  // hint of the diff, sentinelize the result half. Separate from
@@ -1222,12 +1275,7 @@ function buildAggregateTarget(
1222
1275
  return any ? "truncated" : "absent";
1223
1276
  },
1224
1277
  // Open invocations still belong to the current turn; only complete arcs reclaim.
1225
- canDrop(): boolean {
1226
- return (
1227
- occurrences.some((occ) => occ.kind === "tool_use") &&
1228
- occurrences.some((occ) => occ.kind === "tool_result")
1229
- );
1230
- },
1278
+ canDrop: complete,
1231
1279
  requiresToolArcSkeleton,
1232
1280
  // Non-mutating read of the invocation input (the tool_use occurrence
1233
1281
  // carries the arguments). Used by smart-drops supersession selection.
@@ -1310,11 +1358,26 @@ function buildToolTarget(
1310
1358
  return replaced ? "removed" : "absent";
1311
1359
  },
1312
1360
  truncate(): "truncated" | "absent" {
1361
+ // Legacy render, replayed only for unconverted `truncated` tags.
1313
1362
  const changed = part.setToolInput
1314
1363
  ? part.setToolInput(droppedInputMarker(tagId))
1315
1364
  : setToolContentOrText(part, `[dropped \u00a7${tagId}\u00a7]`);
1316
1365
  return changed ? "truncated" : "absent";
1317
1366
  },
1367
+ skeletonReal(): "truncated" | "absent" {
1368
+ // An invocation part keeps its real arguments untouched; a result
1369
+ // part's content becomes the dropped marker.
1370
+ if (part.setToolInput) return "truncated";
1371
+ return setToolContentOrText(part, `[dropped \u00a7${tagId}\u00a7]`)
1372
+ ? "truncated"
1373
+ : "absent";
1374
+ },
1375
+ // drop() replaces an invocation part's arguments with a marker, so a
1376
+ // new drop of one keeps its real arguments instead.
1377
+ cannotRemove: () => part.setToolInput !== undefined,
1378
+ inputStringBytes(): number | null {
1379
+ return part.setToolInput ? toolInputStringBytes(part.getToolInput?.() ?? null) : 0;
1380
+ },
1318
1381
  message: {
1319
1382
  info: { id: message.info.id, role: message.info.role },
1320
1383
  parts: [],
@@ -33,6 +33,11 @@ export const USER_FACING_FAILURES = {
33
33
  sentence: "Memory maintenance could not reach its model.",
34
34
  action: "Check the model connection, then run /ctx-dream again.",
35
35
  },
36
+ dream_step_limit: {
37
+ code: "MC-D10",
38
+ sentence: "Memory maintenance stopped at its hidden agent step limit.",
39
+ action: "This task needs less work per run; changing the model connection will not help.",
40
+ },
36
41
  dream_empty_completion: {
37
42
  code: "MC-D03",
38
43
  sentence: "Memory maintenance received no usable response.",
@@ -199,6 +204,12 @@ export const USER_FACING_FAILURES = {
199
204
  sentence: "Magic Context is temporarily unavailable.",
200
205
  action: "Retry in a moment.",
201
206
  },
207
+ store_ahead_of_binary: {
208
+ code: "MC-C13",
209
+ sentence:
210
+ "Magic Context refused to start: its store (store.db) was migrated by a newer ck-mc build than the one running.",
211
+ action: "Update ck-mc, or roll back by restoring ck-mc together with context.db and store.db from the same backup.",
212
+ },
202
213
  compaction_marker_missing: {
203
214
  code: "MC-C11",
204
215
  sentence:
@@ -215,11 +226,6 @@ export const USER_FACING_FAILURES = {
215
226
  sentence: "Memory authority is inconsistent between the host and module.",
216
227
  action: "Run `ck doctor drain-authority` before changing Rust mode.",
217
228
  },
218
- rust_mode_unsupported: {
219
- code: "MC-S06",
220
- sentence: "Experimental Rust transform mode is not available on this OpenCode host.",
221
- action: 'Magic Context is running its TypeScript mode instead; set `transform_mode` to "ts" to stop requesting Rust.',
222
- },
223
229
  dreamer_task_failing: {
224
230
  code: "MC-S05",
225
231
  sentence: "A background maintenance task keeps failing on its schedule.",
@@ -278,6 +284,7 @@ export function capabilityRefusalCode(capability: CapabilityRefusal): string {
278
284
  const DREAM_FAILURE_KEYS = {
279
285
  provider_timeout: "dream_provider_timeout",
280
286
  provider_error: "dream_provider_error",
287
+ step_limit: "dream_step_limit",
281
288
  empty_completion: "dream_empty_completion",
282
289
  no_models: "dream_no_models",
283
290
  child_aborted: "dream_child_aborted",
@@ -645,9 +645,12 @@ export function hasTrustedAbsoluteWall(geometry: WindowGeometryResult): boolean
645
645
  }
646
646
 
647
647
  /**
648
- * Successful requests can disprove static catalog metadata, but cannot
649
- * disprove a provider, overlay, or observed-overflow wall. A reading beyond
650
- * that wall is malformed usage accounting and must not enlarge the geometry.
648
+ * Successful requests can disprove static catalog metadata, but do not widen a
649
+ * provider, overlay, or observed-overflow wall here. A provider or overlay wall
650
+ * is the configured limit: a reading beyond it is real pressure against that
651
+ * limit (the usage handlers count it in full), not proof that the geometry
652
+ * should grow. An observed-overflow wall that a larger accepted request
653
+ * disproves is cleared by the usage handlers instead.
651
654
  */
652
655
  export function applyProvenInputFloor(
653
656
  geometry: WindowGeometryResult,
@@ -1,22 +0,0 @@
1
- export interface ProviderAdmissionInput {
2
- /** Input + cached-read + cached-write tokens of the newest assistant reply. */
3
- inputTokens: number;
4
- /** The provider's own context window for the outgoing model, when the catalog knows it. */
5
- rawContextLimit: number | undefined;
6
- /** True when the host wrote a compaction after the reply the tokens were read from. */
7
- hostCompactionReducedUsage: boolean;
8
- }
9
- /**
10
- * Whether the OpenCode 2 context hook must stop a request before it reaches the
11
- * provider.
12
- *
13
- * The provider's own context window is the only admission boundary here. Every
14
- * other kind of pressure — in particular usage that fits the window but not the
15
- * room reserved for the reply — has to be admitted, because the work that
16
- * relieves it (compacting history into a compartment, and the high-pressure
17
- * handling around it) all happens further down this same pass. A request stopped
18
- * here runs none of it, so a session refused for pressure Magic Context could
19
- * have removed is refused again on every following turn.
20
- */
21
- export declare function refusesBeforeProvider(input: ProviderAdmissionInput): boolean;
22
- //# sourceMappingURL=provider-admission.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"provider-admission.d.ts","sourceRoot":"","sources":["../../../src/v2/hooks/provider-admission.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,sBAAsB;IACnC,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,2FAA2F;IAC3F,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,uFAAuF;IACvF,0BAA0B,EAAE,OAAO,CAAC;CACvC;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAkB5E"}
@@ -1,18 +0,0 @@
1
- import {
2
- runManagedWrapup2
3
- } from "./index-pa67brzn.js";
4
- import"./index-g6hpfkqa.js";
5
- import"./index-sd3egckz.js";
6
- import"./index-0ccmyzbj.js";
7
- import"./index-jgnag7sa.js";
8
- import"./index-tdrv6nd0.js";
9
- import"./index-y5145x8k.js";
10
- import"./index-bmzt6xgy.js";
11
- import"./index-9r1cbh9e.js";
12
- import"./index-jdxxq8cz.js";
13
- import"./index-febg06dy.js";
14
- import"./index-wgzyeyf5.js";
15
- import"./index-6z9g64js.js";
16
- export {
17
- runManagedWrapup2 as runManagedWrapup
18
- };