@cortexkit/opencode-magic-context 0.49.6 → 0.49.8

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 (255) hide show
  1. package/dist/auto-search-worker.js +10 -7
  2. package/dist/compaction-marker-candidates-worker.js +2 -2
  3. package/dist/{compaction-marker-candidates-cz72pm1t.js → compaction-marker-candidates-xxz35vwp.js} +3 -3
  4. package/dist/{conflict-warning-hook-1jq1rxx7.js → conflict-warning-hook-w3crzrar.js} +8 -8
  5. package/dist/{context-ae3gxdye.js → context-x0ccfv0f.js} +88 -53
  6. package/dist/{derive-budgets-j4ry8j8n.js → derive-budgets-3nbxsyss.js} +2 -2
  7. package/dist/embedding-backfill-3h2m5n0q.js +21 -0
  8. package/dist/embedding-worker-process.js +6 -2
  9. package/dist/embedding-worker.js +6 -5
  10. package/dist/features/magic-context/compaction-marker-candidates.d.ts.map +1 -1
  11. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  12. package/dist/features/magic-context/dreamer/cron.d.ts +2 -0
  13. package/dist/features/magic-context/dreamer/cron.d.ts.map +1 -1
  14. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts +6 -3
  15. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts.map +1 -1
  16. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts +7 -1
  17. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts.map +1 -1
  18. package/dist/features/magic-context/dreamer/map-memories.d.ts +2 -2
  19. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/primer-seed.d.ts +2 -0
  21. package/dist/features/magic-context/dreamer/primer-seed.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/provider-output-failure.d.ts +1 -0
  23. package/dist/features/magic-context/dreamer/provider-output-failure.d.ts.map +1 -1
  24. package/dist/features/magic-context/dreamer/refresh-primers.d.ts +2 -2
  25. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  26. package/dist/features/magic-context/memory/embedding-worker-client.d.ts.map +1 -1
  27. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  28. package/dist/features/magic-context/migration-worker-client.d.ts.map +1 -1
  29. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  30. package/dist/features/magic-context/smart-notes/wake-plane.d.ts.map +1 -1
  31. package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
  32. package/dist/features/magic-context/storage-meta-persisted.d.ts +10 -3
  33. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  34. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  35. package/dist/features/magic-context/storage-replay-document.d.ts +4 -0
  36. package/dist/features/magic-context/storage-replay-document.d.ts.map +1 -1
  37. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  38. package/dist/history-owner-ty29fz0f.js +244 -0
  39. package/dist/hooks/auto-update-checker/checker.d.ts.map +1 -1
  40. package/dist/hooks/magic-context/apply-operations.d.ts +7 -0
  41. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  42. package/dist/hooks/magic-context/auto-search-worker-client.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  44. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/edit-marker.d.ts +2 -0
  46. package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
  47. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  48. package/dist/hooks/magic-context/history-boundary-repair.d.ts.map +1 -1
  49. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  50. package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
  51. package/dist/hooks/magic-context/module-transport.d.ts +1 -0
  52. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  53. package/dist/hooks/magic-context/note-nudger.d.ts +5 -3
  54. package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
  55. package/dist/hooks/magic-context/postprocess-read-cache.d.ts.map +1 -1
  56. package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts.map +1 -1
  57. package/dist/hooks/magic-context/read-session-chunk.d.ts +15 -4
  58. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  59. package/dist/hooks/magic-context/replay-committed-drops.d.ts +9 -0
  60. package/dist/hooks/magic-context/replay-committed-drops.d.ts.map +1 -0
  61. package/dist/hooks/magic-context/rust-lkg-freeze-registry.d.ts +2 -2
  62. package/dist/hooks/magic-context/rust-lkg-freeze-registry.d.ts.map +1 -1
  63. package/dist/hooks/magic-context/rust-mode-transform.d.ts +4 -0
  64. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  65. package/dist/hooks/magic-context/rust-refusal-recovery.d.ts.map +1 -1
  66. package/dist/hooks/magic-context/rust-served-raw.d.ts +29 -0
  67. package/dist/hooks/magic-context/rust-served-raw.d.ts.map +1 -0
  68. package/dist/hooks/magic-context/strip-content.d.ts +23 -24
  69. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  70. package/dist/hooks/magic-context/tag-messages.d.ts +2 -0
  71. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  72. package/dist/hooks/magic-context/tool-drop-target.d.ts +2 -0
  73. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  74. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  75. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  76. package/dist/hooks/magic-context/unresolved-history-boundary.d.ts +5 -1
  77. package/dist/hooks/magic-context/unresolved-history-boundary.d.ts.map +1 -1
  78. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  79. package/dist/{index-g9exahnx.js → index-0jz47061.js} +6 -3
  80. package/dist/{index-4mjhqadz.js → index-150zz6fh.js} +1 -1
  81. package/dist/{index-ch08qwgd.js → index-2rw244rh.js} +88 -81
  82. package/dist/{index-6q5h70h2.js → index-4hb8nt93.js} +3 -3
  83. package/dist/{index-j55vn694.js → index-7bjgyaj1.js} +4 -4
  84. package/dist/{index-h2wc01qk.js → index-8kk7yh6m.js} +2 -2
  85. package/dist/{index-vztbgcdk.js → index-9g1c4bt9.js} +304 -92
  86. package/dist/{index-7q1m1qjk.js → index-a43xq1pg.js} +5 -5
  87. package/dist/{index-tqf7yg27.js → index-a4b0gbyg.js} +1 -1
  88. package/dist/{index-vnjhmkwk.js → index-angx1s0k.js} +4 -3
  89. package/dist/{index-1xaw2pq8.js → index-b4gcb3rk.js} +8 -8
  90. package/dist/{index-z1tjp257.js → index-b64n4d0h.js} +1 -1
  91. package/dist/{index-1bt88epp.js → index-bd9cjab3.js} +1 -1
  92. package/dist/{index-gbmqa9x9.js → index-bmwfzz28.js} +9 -6
  93. package/dist/{index-qx53vezw.js → index-gjvjh960.js} +1 -1
  94. package/dist/{index-zgzdm6dg.js → index-gzg9ekc1.js} +155 -103
  95. package/dist/{index-vh3e2mvr.js → index-hxrvx6cy.js} +121 -51
  96. package/dist/{index-w23dh319.js → index-jw4gbfkv.js} +1 -1
  97. package/dist/index-knvkbfvh.js +25 -0
  98. package/dist/{index-vkbqdnkj.js → index-kvw6xew3.js} +6 -3
  99. package/dist/{index-bg5qqene.js → index-mp2kghkv.js} +3 -27
  100. package/dist/{index-nsjyysj0.js → index-mvvephtj.js} +5 -1
  101. package/dist/{index-cm4hmxyk.js → index-n78avt2p.js} +1 -1
  102. package/dist/{index-hr64sth2.js → index-pgy3h49n.js} +4 -4
  103. package/dist/{index-a796ct3s.js → index-pjgzdezw.js} +13 -9
  104. package/dist/{index-9m7bn21d.js → index-q28hsbpg.js} +15 -3
  105. package/dist/{index-ab3bgm2m.js → index-q76br5zn.js} +3 -3
  106. package/dist/{index-xqyj5c85.js → index-qgp5vnt4.js} +5 -5
  107. package/dist/{index-9s58tq95.js → index-rg1cezmj.js} +22 -22
  108. package/dist/{index-f3dnvnw6.js → index-s178h9z8.js} +4 -3
  109. package/dist/{index-mj1fgfrk.js → index-w1ejb9qr.js} +939 -160
  110. package/dist/{index-k6xvbj2e.js → index-w28y7d0z.js} +2 -0
  111. package/dist/{index-0nnd4bry.js → index-wafzvyhg.js} +63 -19
  112. package/dist/{index-ck6y3td2.js → index-xf6k8szp.js} +4 -4
  113. package/dist/{index-1j8jcjpa.js → index-xpn05jxq.js} +4 -4
  114. package/dist/{index-s0gsmthp.js → index-ydjgz36f.js} +7 -7
  115. package/dist/{index-besxhcsh.js → index-zf9nydbd.js} +50 -39
  116. package/dist/index.js +53 -52
  117. package/dist/{logger-ewak5q1s.js → logger-wn328tfg.js} +1 -1
  118. package/dist/{message-index-bounded-630j53ps.js → message-index-bounded-hxjp56qk.js} +16 -16
  119. package/dist/{message-index-c84wm2g0.js → message-index-zs882h8e.js} +16 -16
  120. package/dist/{message-time-backfill-8kj57qe3.js → message-time-backfill-nb5hhnrt.js} +3 -3
  121. package/dist/migration-worker.js +11 -11
  122. package/dist/plugin/boot-quiet.d.ts.map +1 -1
  123. package/dist/plugin/dream-timer.d.ts.map +1 -1
  124. package/dist/plugin/messages-transform.d.ts.map +1 -1
  125. package/dist/plugin/rpc-handlers.d.ts +2 -0
  126. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  127. package/dist/{project-embedding-registry-vv59t7ah.js → project-embedding-registry-vy7sv9jt.js} +11 -11
  128. package/dist/raw-ordinal-warmup-worker.js +17 -15
  129. package/dist/{read-session-chunk-t3vjd0h0.js → read-session-chunk-t9r7r0sg.js} +13 -11
  130. package/dist/{read-session-raw-gf7eytnm.js → read-session-raw-gm6xj30v.js} +3 -3
  131. package/dist/recomp-orchestrator-gr36zvd2.js +60 -0
  132. package/dist/{safe-notification-target-q0cyrx3x.js → safe-notification-target-jdynm677.js} +2 -2
  133. package/dist/{search-kth2p6cc.js → search-qjen1pmz.js} +24 -24
  134. package/dist/{send-session-notification-3j6krd4w.js → send-session-notification-q8ngbap3.js} +6 -6
  135. package/dist/shared/history-owner.d.ts +12 -0
  136. package/dist/shared/history-owner.d.ts.map +1 -0
  137. package/dist/shared/off-thread-migration-clock.d.ts +8 -1
  138. package/dist/shared/off-thread-migration-clock.d.ts.map +1 -1
  139. package/dist/shared/processed-image-eligibility.d.ts +22 -0
  140. package/dist/shared/processed-image-eligibility.d.ts.map +1 -0
  141. package/dist/shared/recovery-reasoning-prefix.d.ts +9 -0
  142. package/dist/shared/recovery-reasoning-prefix.d.ts.map +1 -0
  143. package/dist/shared/redaction.d.ts.map +1 -1
  144. package/dist/shared/rpc-server.d.ts.map +1 -1
  145. package/dist/shared/sqlite.d.ts +3 -1
  146. package/dist/shared/sqlite.d.ts.map +1 -1
  147. package/dist/shared/tag-transcript.d.ts +9 -0
  148. package/dist/shared/tag-transcript.d.ts.map +1 -1
  149. package/dist/shared/user-facing-codes.d.ts +2 -2
  150. package/dist/{sqlite-d7edbk1s.js → sqlite-4pqyynrs.js} +3 -1
  151. package/dist/{storage-memory-af5zdz98.js → storage-memory-j3v3hc83.js} +2 -2
  152. package/dist/{storage-tags-dyj7mmbq.js → storage-tags-a513rkj3.js} +5 -5
  153. package/dist/tools/ctx-expand/search-archive.d.ts +4 -0
  154. package/dist/tools/ctx-expand/search-archive.d.ts.map +1 -0
  155. package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
  156. package/dist/{transform-postprocess-phase-bv3kb5s1.js → transform-postprocess-phase-yv463b7y.js} +30 -30
  157. package/dist/v2/auto-search-worker.js +10 -7
  158. package/dist/v2/{compaction-marker-candidates-6gqp5wrc.js → compaction-marker-candidates-a15w3mqh.js} +3 -3
  159. package/dist/v2/compaction-marker-candidates-worker.js +2 -2
  160. package/dist/v2/{context-p8f2shp1.js → context-wd82v9z6.js} +1133 -278
  161. package/dist/v2/{derive-budgets-enckmg7y.js → derive-budgets-0rmpmxjw.js} +3 -3
  162. package/dist/v2/embedding-backfill-vr7wdtrf.js +20 -0
  163. package/dist/v2/embedding-worker-process.js +6 -2
  164. package/dist/v2/embedding-worker.js +6 -5
  165. package/dist/v2/hidden-completion.d.ts.map +1 -1
  166. package/dist/v2/history-owner-2cr9py37.js +243 -0
  167. package/dist/v2/hooks/context.d.ts.map +1 -1
  168. package/dist/v2/hooks/payload.d.ts.map +1 -1
  169. package/dist/v2/hooks/store.d.ts +1 -0
  170. package/dist/v2/hooks/store.d.ts.map +1 -1
  171. package/dist/v2/{logger-pj02s7sr.js → logger-te6e1j72.js} +1 -1
  172. package/dist/v2/{message-index-bounded-yzxmf6vp.js → message-index-bounded-madg2kfr.js} +16 -16
  173. package/dist/v2/{message-index-3ws17x1g.js → message-index-yd94vt9n.js} +16 -16
  174. package/dist/v2/{message-time-backfill-5nf10c65.js → message-time-backfill-rz1pnpaj.js} +3 -3
  175. package/dist/v2/migration-worker.js +11 -11
  176. package/dist/v2/{project-embedding-registry-rsnf2263.js → project-embedding-registry-ja23aygk.js} +11 -11
  177. package/dist/v2/raw-ordinal-warmup-worker.js +17 -15
  178. package/dist/v2/{read-session-chunk-vtb0w2kd.js → read-session-chunk-7qs791f3.js} +13 -11
  179. package/dist/v2/{read-session-raw-gpcddemt.js → read-session-raw-h4azh85b.js} +3 -3
  180. package/dist/v2/recomp-orchestrator-ee91r9s6.js +59 -0
  181. package/dist/v2/{safe-notification-target-y3p1hce9.js → safe-notification-target-936374xx.js} +2 -2
  182. package/dist/v2/search-pn15rr52.js +46 -0
  183. package/dist/v2/{send-session-notification-5aj2j7vf.js → send-session-notification-6n7chhyp.js} +6 -6
  184. package/dist/v2/{server-09g9pkvx.js → server-08k4zkfk.js} +50 -39
  185. package/dist/v2/{server-ras2sxnc.js → server-44ryn9rb.js} +9 -6
  186. package/dist/v2/{server-158ehmk2.js → server-4easnf78.js} +19 -19
  187. package/dist/v2/{server-ww9nr8pe.js → server-4gz0xkrc.js} +5 -5
  188. package/dist/v2/{server-d6g4whc2.js → server-4qr18rfg.js} +3 -3
  189. package/dist/v2/{server-f9py7s7a.js → server-4rs8sm06.js} +5 -5
  190. package/dist/v2/{server-yezz0cp2.js → server-63ha7f0f.js} +3 -27
  191. package/dist/v2/{server-3t0q2cqx.js → server-7dv9wt9r.js} +1 -1
  192. package/dist/v2/{server-cw6521wn.js → server-7e087rvk.js} +2 -0
  193. package/dist/v2/{server-hb6xhh9q.js → server-988cqjme.js} +6 -3
  194. package/dist/v2/{server-keswwkvv.js → server-9a6bwc12.js} +4 -4
  195. package/dist/v2/{server-t4k4qexw.js → server-9e5r8y60.js} +5 -1
  196. package/dist/v2/{server-7ekna9zs.js → server-adfte03x.js} +2 -2
  197. package/dist/v2/{server-9zqewm6g.js → server-ak7w74j9.js} +4 -4
  198. package/dist/v2/{server-387vkhjq.js → server-bx59ezg6.js} +4 -3
  199. package/dist/v2/{server-676xw7at.js → server-ckrb5rm8.js} +1 -1
  200. package/dist/v2/{server-wrem2nmz.js → server-cxsr0ng6.js} +15 -3
  201. package/dist/v2/{server-t528t8qm.js → server-hn9fb3v0.js} +2 -2
  202. package/dist/v2/{server-qn23p4h7.js → server-j3dm74ey.js} +9 -9
  203. package/dist/v2/{server-yd01snxq.js → server-jjsf29aq.js} +4 -4
  204. package/dist/v2/server-knvkbfvh.js +25 -0
  205. package/dist/v2/{server-cm4hmxyk.js → server-n78avt2p.js} +1 -1
  206. package/dist/v2/{server-btgnsv7w.js → server-njnx39q2.js} +6 -3
  207. package/dist/v2/{server-6a9mxnb2.js → server-npm52h2q.js} +4 -3
  208. package/dist/v2/{server-vb7pbd9p.js → server-nveratm5.js} +1 -1
  209. package/dist/v2/{server-7skbfb81.js → server-q360kdb8.js} +121 -51
  210. package/dist/v2/{server-kzns2hbz.js → server-s6jqh8bj.js} +1 -1
  211. package/dist/v2/{server-6byqfbqf.js → server-shme41gj.js} +1 -1
  212. package/dist/v2/{server-0nnd4bry.js → server-wafzvyhg.js} +63 -19
  213. package/dist/v2/{server-fby0cxbq.js → server-xj4mewze.js} +304 -92
  214. package/dist/v2/{server-aa9w15cs.js → server-y5g32dhq.js} +88 -81
  215. package/dist/v2/{server-x2r63c0x.js → server-yak3sxya.js} +7 -7
  216. package/dist/v2/{server-4tn95znb.js → server-zrwaj29a.js} +2 -2
  217. package/dist/v2/server.js +9 -8
  218. package/dist/v2/{sqlite-d7edbk1s.js → sqlite-4pqyynrs.js} +3 -1
  219. package/dist/v2/{storage-memory-af5zdz98.js → storage-memory-j3v3hc83.js} +2 -2
  220. package/dist/v2/{storage-tags-d47bpaqa.js → storage-tags-spa92sgj.js} +5 -5
  221. package/dist/v2/store-reader.d.ts.map +1 -1
  222. package/dist/v2/{wrapup-orchestrator-cahk37n7.js → wrapup-orchestrator-5wxy1ggv.js} +38 -35
  223. package/dist/wrapup-orchestrator-gv08c6f9.js +47 -0
  224. package/package.json +3 -3
  225. package/src/config/compaction-accessor-guard.test.ts +3 -0
  226. package/src/features/magic-context/dreamer/cron.ts +8 -0
  227. package/src/shared/history-owner.test.ts +60 -0
  228. package/src/shared/history-owner.ts +43 -0
  229. package/src/shared/host-stall-profiler-node.ts +3 -1
  230. package/src/shared/host-stall-profiler.ts +3 -1
  231. package/src/shared/off-thread-migration-clock.test.ts +80 -10
  232. package/src/shared/off-thread-migration-clock.ts +37 -13
  233. package/src/shared/processed-image-eligibility.test.ts +68 -0
  234. package/src/shared/processed-image-eligibility.ts +41 -0
  235. package/src/shared/processed-image-position-review.json +20 -0
  236. package/src/shared/processed-image-position-review.test.ts +19 -0
  237. package/src/shared/recovery-reasoning-prefix.test.ts +34 -0
  238. package/src/shared/recovery-reasoning-prefix.ts +35 -0
  239. package/src/shared/redaction.test.ts +16 -0
  240. package/src/shared/redaction.ts +8 -1
  241. package/src/shared/root-async-context.probe.mjs +36 -0
  242. package/src/shared/root-async-context.test.ts +49 -0
  243. package/src/shared/rpc-server.ts +27 -23
  244. package/src/shared/sqlite-busy-budget-review.test.ts +291 -0
  245. package/src/shared/sqlite-foreground-wait.test.ts +253 -1
  246. package/src/shared/sqlite-writer-diagnostics.test.ts +31 -0
  247. package/src/shared/sqlite.ts +112 -30
  248. package/src/shared/tag-transcript.ts +118 -0
  249. package/src/shared/user-facing-codes.ts +2 -2
  250. package/dist/embedding-backfill-dtjmyktb.js +0 -21
  251. package/dist/recomp-orchestrator-1d08g57a.js +0 -60
  252. package/dist/v2/embedding-backfill-cg4rv90f.js +0 -20
  253. package/dist/v2/recomp-orchestrator-v64r4s4r.js +0 -59
  254. package/dist/v2/search-bpa4fxq1.js +0 -46
  255. package/dist/wrapup-orchestrator-mqp0v195.js +0 -47
@@ -0,0 +1,34 @@
1
+ import { expect, test } from "bun:test";
2
+ import { recoveryReasoningPrefixes } from "./recovery-reasoning-prefix";
3
+
4
+ for (const key of ["content", "parts"] as const) {
5
+ test(`recovery reasoning ${key}: exact preceding messages and same-message parts`, () => {
6
+ const messages = [
7
+ { role: "user", [key]: [{ type: "text", text: "original" }] },
8
+ {
9
+ role: "assistant",
10
+ [key]: [
11
+ { type: "text", text: "before" },
12
+ { type: "thinking", thinkingSignature: "first" },
13
+ { type: "text", text: "between" },
14
+ { type: "redacted_thinking", data: "opaque" },
15
+ { type: "text", text: "after" },
16
+ ],
17
+ },
18
+ ];
19
+ const original = recoveryReasoningPrefixes(messages, key);
20
+ expect(original).toHaveLength(2);
21
+ const edited = structuredClone(messages);
22
+ edited[0]![key]![0]!.text = "changed";
23
+ expect(recoveryReasoningPrefixes(edited, key)).not.toEqual(original);
24
+ const parts = structuredClone(messages);
25
+ parts[1]![key]![2]!.text = "changed";
26
+ expect(recoveryReasoningPrefixes(parts, key)[0]).toBe(original[0]);
27
+ expect(recoveryReasoningPrefixes(parts, key)[1]).not.toBe(original[1]);
28
+ const suffix = structuredClone(messages);
29
+ suffix[1]![key]![4]!.text = "changed";
30
+ expect(recoveryReasoningPrefixes(suffix, key)).toEqual(original);
31
+ suffix[1]![key]!.splice(3, 1);
32
+ expect(recoveryReasoningPrefixes(suffix, key)).not.toEqual(original);
33
+ });
34
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Serialize each request prefix ending at a thinking/reasoning part, including
3
+ * earlier messages and earlier parts of that message. Comparing these snapshots
4
+ * detects edits to bytes authenticated by a kept signature, or missing blocks.
5
+ * Include reasoning without a visible signature too: a host may carry its
6
+ * provider signature in fields this helper does not interpret.
7
+ */
8
+ export function recoveryReasoningPrefixes(
9
+ messages: readonly unknown[],
10
+ partsKey: "parts" | "content",
11
+ ): string[] {
12
+ const prefixes: string[] = [];
13
+ for (let index = 0; index < messages.length; index++) {
14
+ const message = messages[index] as Record<string, unknown> | null;
15
+ const parts = message?.[partsKey];
16
+ if (!Array.isArray(parts)) continue;
17
+ for (let p = 0; p < parts.length; p++) {
18
+ const type = (parts[p] as { type?: string } | null)?.type;
19
+ if (
20
+ type !== "thinking" &&
21
+ type !== "reasoning" &&
22
+ type !== "redactedThinking" &&
23
+ type !== "redacted_thinking"
24
+ )
25
+ continue;
26
+ prefixes.push(
27
+ JSON.stringify([
28
+ ...messages.slice(0, index),
29
+ { ...message, [partsKey]: parts.slice(0, p + 1) },
30
+ ]),
31
+ );
32
+ }
33
+ }
34
+ return prefixes;
35
+ }
@@ -132,3 +132,19 @@ describe("redaction gaps: unambiguous secret key names and header/URL credential
132
132
  expect(apiKey).toContain("x-api-key");
133
133
  });
134
134
  });
135
+
136
+ describe("public diagnostic credential shapes", () => {
137
+ test("redacts unquoted colon credentials without removing scalar diagnostics", () => {
138
+ expect(redactSecretText("password: colonSecret700 token: anotherSecret700")).toBe(
139
+ "password: <REDACTED:credential> token: <REDACTED:credential>",
140
+ );
141
+ expect(redactSecretText("token: 1234567 secret: false")).toBe(
142
+ "token: 1234567 secret: false",
143
+ );
144
+ });
145
+ test("redacts hyphenated and underscored GitHub token payloads completely", () => {
146
+ expect(redactSecretText("ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-extra_payload")).toBe(
147
+ "<GITHUB_TOKEN_REDACTED>",
148
+ );
149
+ });
150
+ });
@@ -152,7 +152,7 @@ const SECRET_TEXT_PATTERNS: Array<{
152
152
  replacement: "<GITHUB_PAT_REDACTED>",
153
153
  },
154
154
  {
155
- pattern: /\b(?:gh[opsu]|ghr)_[A-Za-z0-9]{30,}/g,
155
+ pattern: /\b(?:gh[opsu]|ghr)_[A-Za-z0-9_-]{30,}/g,
156
156
  replacement: "<GITHUB_TOKEN_REDACTED>",
157
157
  },
158
158
  {
@@ -190,6 +190,13 @@ const SECRET_TEXT_PATTERNS: Array<{
190
190
  replacement: (full: string, prefix: string, value: string) =>
191
191
  isNonSecretScalarValue(value) ? full : `${prefix}<REDACTED:api_key>`,
192
192
  },
193
+ {
194
+ // Unquoted diagnostic prose also uses colon-delimited credentials.
195
+ pattern:
196
+ /\b((?:api[_-]?key|client[_-]?secret|access[_-]?token|token|secret|password|passwd|pwd)\s*:\s*)([^\s'"`,;<>]{6,})/gi,
197
+ replacement: (full: string, prefix: string, value: string) =>
198
+ isNonSecretScalarValue(value) ? full : `${prefix}<REDACTED:credential>`,
199
+ },
193
200
  {
194
201
  // Credentials embedded in a URL: scheme://user:password@host.
195
202
  pattern: /\b([a-z][a-z0-9+.-]*:\/\/[^\s/:@]+:)([^\s/@]+)(@)/gi,
@@ -0,0 +1,36 @@
1
+ import assert from "node:assert/strict";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
3
+ import { setTimeout as delay, setImmediate as tick } from "node:timers/promises";
4
+ import { Worker } from "node:worker_threads";
5
+ import { inRootAsyncContext } from "./sqlite";
6
+
7
+ const scope = new AsyncLocalStorage();
8
+ const gc = globalThis.Bun ? () => Bun.gc(true) : globalThis.gc;
9
+ const references = {};
10
+ const resources = [];
11
+ const timerStores = {};
12
+ const ambientTick = () => { timerStores.ambient = scope.getStore() !== undefined; };
13
+ const rootTick = () => { timerStores.root = scope.getStore() !== undefined; };
14
+ function create(name, root, worker) {
15
+ const payload = { synthetic: name };
16
+ references[name] = new WeakRef(payload);
17
+ scope.run(payload, () => {
18
+ const make = worker
19
+ ? () => new Worker(new URL("worker.mjs", import.meta.url))
20
+ : () => setInterval(root ? rootTick : ambientTick, 5);
21
+ resources.push(root ? inRootAsyncContext(make) : make());
22
+ assert.equal(scope.getStore(), payload, "Root execution must restore the caller's store");
23
+ });
24
+ }
25
+ create("ambientWorker", false, true);
26
+ create("rootWorker", true, true);
27
+ create("ambientTimer", false, false);
28
+ create("rootTimer", true, false);
29
+ await delay(30);
30
+ for (let i = 0; i < 12; i++) { await tick(); gc(); await tick(); }
31
+ const retained = Object.fromEntries(Object.entries(references).map(([key, ref]) => [key, Number(ref.deref() !== undefined)]));
32
+ for (const resource of resources) {
33
+ if (resource instanceof Worker) await resource.terminate();
34
+ else clearInterval(resource);
35
+ }
36
+ console.log(JSON.stringify({ runtime: globalThis.Bun ? `Bun ${Bun.version}` : process.version, timerStores, retained }));
@@ -0,0 +1,49 @@
1
+ import { expect, test } from "bun:test";
2
+ import { rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { createTestTempDirFromPath } from "./test-temp-dir";
6
+
7
+ for (const runtime of ["Node", "Bun"] as const) {
8
+ test(`root resources do not inherit request stores (${runtime})`, async () => {
9
+ const directory = createTestTempDirFromPath(join(tmpdir(), "root-context-"));
10
+ try {
11
+ const entry = join(directory, "probe.mjs");
12
+ const build = await Bun.build({
13
+ entrypoints: [new URL("root-async-context.probe.mjs", import.meta.url).pathname],
14
+ target: "node",
15
+ format: "esm",
16
+ external: ["bun:sqlite", "node:sqlite"],
17
+ });
18
+ expect(build.success).toBe(true);
19
+ await writeFile(entry, await build.outputs[0].text());
20
+ await writeFile(
21
+ join(directory, "worker.mjs"),
22
+ `import { parentPort } from 'node:worker_threads'; parentPort.on('message', () => {});`,
23
+ );
24
+ const child = Bun.spawn(
25
+ [...(runtime === "Node" ? ["node", "--expose-gc"] : [process.execPath]), entry],
26
+ {
27
+ stdout: "pipe",
28
+ stderr: "pipe",
29
+ windowsHide: true,
30
+ },
31
+ );
32
+ const [stdout, stderr, exit] = await Promise.all([
33
+ new Response(child.stdout).text(),
34
+ new Response(child.stderr).text(),
35
+ child.exited,
36
+ ]);
37
+ expect(exit, stderr).toBe(0);
38
+ const result = JSON.parse(stdout);
39
+ console.log(`${runtime} ALS propagation: ${stdout.trim()}`);
40
+ expect(result.timerStores).toEqual({ ambient: true, root: false });
41
+ expect(result.retained.rootWorker).toBe(0);
42
+ expect(result.retained.rootTimer).toBe(0);
43
+ expect(result.retained.ambientTimer).toBe(1);
44
+ if (runtime === "Node") expect(result.retained.ambientWorker).toBe(1);
45
+ } finally {
46
+ await rm(directory, { recursive: true, force: true });
47
+ }
48
+ });
49
+ }
@@ -133,31 +133,33 @@ export class MagicContextRpcServer {
133
133
  }
134
134
  this.startedAt = Date.now();
135
135
  const self = this;
136
- const server = Bun.serve<WsData>({
137
- port: 0,
138
- hostname: "127.0.0.1",
139
- fetch(req, srv) {
140
- return self.handleFetch(req, srv);
141
- },
142
- websocket: {
143
- open(ws) {
144
- // Close the socket if it doesn't authenticate promptly. A
145
- // never-authenticated socket holds no sink and is harmless,
146
- // but we don't want to keep raw connections open forever.
147
- ws.data.authTimer = setTimeout(() => {
148
- if (!ws.data.authed) ws.close(WS_CLOSE_UNAUTHORIZED, "auth timeout");
149
- }, WS_AUTH_TIMEOUT_MS);
136
+ const server = inRootAsyncContext(() =>
137
+ Bun.serve<WsData>({
138
+ port: 0,
139
+ hostname: "127.0.0.1",
140
+ fetch(req, srv) {
141
+ return self.handleFetch(req, srv);
150
142
  },
151
- message(ws, raw) {
152
- self.handleWsMessage(ws, raw);
143
+ websocket: {
144
+ open(ws) {
145
+ // Close the socket if it doesn't authenticate promptly. A
146
+ // never-authenticated socket holds no sink and is harmless,
147
+ // but we don't want to keep raw connections open forever.
148
+ ws.data.authTimer = setTimeout(() => {
149
+ if (!ws.data.authed) ws.close(WS_CLOSE_UNAUTHORIZED, "auth timeout");
150
+ }, WS_AUTH_TIMEOUT_MS);
151
+ },
152
+ message(ws, raw) {
153
+ self.handleWsMessage(ws, raw);
154
+ },
155
+ close(ws) {
156
+ if (ws.data.authTimer) clearTimeout(ws.data.authTimer);
157
+ ws.data.unregister?.();
158
+ self.sockets.delete(ws);
159
+ },
153
160
  },
154
- close(ws) {
155
- if (ws.data.authTimer) clearTimeout(ws.data.authTimer);
156
- ws.data.unregister?.();
157
- self.sockets.delete(ws);
158
- },
159
- },
160
- });
161
+ }),
162
+ );
161
163
 
162
164
  this.server = server;
163
165
  this.port = server.port ?? 0;
@@ -429,3 +431,5 @@ function json(body: unknown, status = 200): Response {
429
431
  headers: { "Content-Type": "application/json" },
430
432
  });
431
433
  }
434
+
435
+ import { inRootAsyncContext } from "./sqlite";
@@ -0,0 +1,291 @@
1
+ import { expect, test } from "bun:test";
2
+ import { rmSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import {
6
+ Database,
7
+ guardSqliteTransformPass,
8
+ SqliteAcquisitionBusyError,
9
+ withSqliteBackgroundWriter,
10
+ withSqliteTransformPass,
11
+ } from "./sqlite";
12
+ import { createTestTempDirFromPath } from "./test-temp-dir";
13
+
14
+ function fixture() {
15
+ const dir = createTestTempDirFromPath(join(tmpdir(), "mc-busy-review-"));
16
+ const path = join(dir, "context.db");
17
+ const db = new Database(path);
18
+ db.exec("PRAGMA busy_timeout=5000; CREATE TABLE result(id INTEGER PRIMARY KEY, n INTEGER)");
19
+ db.exec("INSERT INTO result VALUES (1, 0)");
20
+ return {
21
+ db,
22
+ path,
23
+ close() {
24
+ db.close();
25
+ rmSync(dir, { recursive: true, force: true });
26
+ },
27
+ };
28
+ }
29
+
30
+ async function lock(path: string, mode: "read" | "write" | "exclusive", holdMs: number) {
31
+ const child = Bun.spawn(
32
+ [
33
+ "bun",
34
+ "--eval",
35
+ `import { Database } from "bun:sqlite";
36
+ const db = new Database(process.argv[1]);
37
+ db.exec(process.argv[2] === "read" ? "BEGIN; SELECT * FROM result"
38
+ : process.argv[2] === "write" ? "BEGIN IMMEDIATE" : "BEGIN EXCLUSIVE");
39
+ console.log("LOCKED");
40
+ Bun.sleepSync(Number(process.argv[3]));
41
+ db.exec("COMMIT");
42
+ db.close();`,
43
+ path,
44
+ mode,
45
+ String(holdMs),
46
+ ],
47
+ { stdout: "pipe", stderr: "pipe", windowsHide: true },
48
+ );
49
+ const reader = child.stdout.getReader();
50
+ let output = "";
51
+ while (!output.includes("LOCKED\n")) {
52
+ const chunk = await reader.read();
53
+ if (chunk.done) {
54
+ throw new Error(`locker failed: ${await new Response(child.stderr).text()}`);
55
+ }
56
+ output += new TextDecoder().decode(chunk.value);
57
+ }
58
+ reader.releaseLock();
59
+ return { exited: child.exited };
60
+ }
61
+
62
+ for (const method of ["run", "get", "all", "exec"] as const) {
63
+ test(`a rollback-journal commit BUSY retries ${method} exactly once after the reader leaves`, async () => {
64
+ const { db, path, close } = fixture();
65
+ const sql = "UPDATE result SET n = n + 1 WHERE id = 1";
66
+ const statement = db.prepare(`${sql} RETURNING n`);
67
+ const { exited } = await lock(path, "read", 150);
68
+ try {
69
+ await withSqliteTransformPass(() => {
70
+ if (method === "exec") db.exec(sql);
71
+ else statement[method]();
72
+ });
73
+ expect(db.prepare("SELECT * FROM result").all()).toEqual([{ id: 1, n: 1 }]);
74
+ expect(db.inTransaction).toBe(false);
75
+ } finally {
76
+ expect(await exited).toBe(0);
77
+ close();
78
+ }
79
+ });
80
+ }
81
+
82
+ for (const scope of ["foreground", "background", "unscoped"] as const) {
83
+ test(`exec in ${scope} does not wait on an unrelated attached database schema`, async () => {
84
+ const main = fixture();
85
+ const aux = fixture();
86
+ main.db.prepare("ATTACH DATABASE ? AS aux").run(aux.path);
87
+ const { exited } = await lock(aux.path, "exclusive", 2500);
88
+ try {
89
+ const started = performance.now();
90
+ const operation = () => main.db.exec("UPDATE main.result SET n = n + 1");
91
+ if (scope === "foreground") {
92
+ await withSqliteTransformPass(() => {
93
+ guardSqliteTransformPass({ assert() {}, remainingMs: () => 75 });
94
+ operation();
95
+ });
96
+ } else if (scope === "background") withSqliteBackgroundWriter(operation);
97
+ else operation();
98
+ expect(performance.now() - started).toBeLessThan(1500);
99
+ expect(main.db.prepare("SELECT n FROM main.result").get()).toEqual({ n: 1 });
100
+ } finally {
101
+ expect(await exited).toBe(0);
102
+ main.close();
103
+ aux.close();
104
+ }
105
+ }, 10_000);
106
+ }
107
+
108
+ for (const location of ["main", "aux"] as const) {
109
+ test(`BUSY retries leave single-statement effects atomic in ${location}, including AFTER triggers`, async () => {
110
+ const main = fixture();
111
+ const aux = fixture();
112
+ main.db.prepare("ATTACH DATABASE ? AS aux").run(aux.path);
113
+ main.db.exec("CREATE TABLE audit(n INTEGER)");
114
+ main.db.exec(`CREATE TEMP TRIGGER audit_insert AFTER INSERT ON ${location}.result
115
+ BEGIN INSERT INTO audit VALUES (new.n); END`);
116
+ main.db.exec(`CREATE TEMP TRIGGER audit_update AFTER UPDATE ON ${location}.result
117
+ BEGIN INSERT INTO audit VALUES (new.n); END`);
118
+ main.db.exec(`CREATE TEMP TRIGGER audit_delete AFTER DELETE ON ${location}.result
119
+ BEGIN INSERT INTO audit VALUES (old.n); END`);
120
+ const forms = [
121
+ `INSERT INTO ${location}.result VALUES (2, 10)`,
122
+ `INSERT OR IGNORE INTO ${location}.result VALUES (2, 20)`,
123
+ `INSERT OR REPLACE INTO ${location}.result VALUES (2, 30)`,
124
+ `INSERT INTO ${location}.result VALUES (2, 40) ON CONFLICT(id) DO UPDATE SET n=n+1`,
125
+ `UPDATE ${location}.result SET n=n+1 WHERE id=2`,
126
+ `DELETE FROM ${location}.result WHERE id=2`,
127
+ ];
128
+ try {
129
+ for (const sql of forms) {
130
+ const statement = main.db.prepare(`${sql} RETURNING *`);
131
+ const blocker = new Database(location === "main" ? main.path : aux.path);
132
+ blocker.exec("BEGIN IMMEDIATE");
133
+ main.db.exec("PRAGMA busy_timeout=0");
134
+ const before = main.db
135
+ .prepare(`SELECT * FROM ${location}.result ORDER BY id`)
136
+ .all();
137
+ const beforeAudit = main.db.prepare("SELECT * FROM audit").all();
138
+ try {
139
+ expect(() => statement.all()).toThrow("locked");
140
+ expect(
141
+ main.db.prepare(`SELECT * FROM ${location}.result ORDER BY id`).all(),
142
+ ).toEqual(before);
143
+ expect(main.db.prepare("SELECT * FROM audit").all()).toEqual(beforeAudit);
144
+ expect(main.db.inTransaction).toBe(false);
145
+ } finally {
146
+ blocker.exec("ROLLBACK");
147
+ blocker.close();
148
+ }
149
+ const { exited } = await lock(
150
+ location === "main" ? main.path : aux.path,
151
+ "write",
152
+ 60,
153
+ );
154
+ try {
155
+ await withSqliteTransformPass(() => statement.all());
156
+ } finally {
157
+ expect(await exited).toBe(0);
158
+ }
159
+ }
160
+ expect(main.db.prepare(`SELECT * FROM ${location}.result ORDER BY id`).all()).toEqual([
161
+ { id: 1, n: 0 },
162
+ ]);
163
+ expect(main.db.prepare("SELECT * FROM audit").all()).toEqual([
164
+ { n: 10 },
165
+ { n: 30 },
166
+ { n: 31 },
167
+ { n: 32 },
168
+ { n: 32 },
169
+ ]);
170
+ } finally {
171
+ main.close();
172
+ aux.close();
173
+ }
174
+ }, 10_000);
175
+ }
176
+
177
+ test("an attached DML-only committed prefix is not replayed after a later BUSY", () => {
178
+ const main = fixture();
179
+ const free = fixture();
180
+ const blocked = fixture();
181
+ try {
182
+ main.db.prepare("ATTACH DATABASE ? AS free").run(free.path);
183
+ main.db.prepare("ATTACH DATABASE ? AS blocked").run(blocked.path);
184
+ blocked.db.exec("BEGIN IMMEDIATE");
185
+ withSqliteTransformPass(() => {
186
+ expect(() =>
187
+ main.db.exec("UPDATE free.result SET n=n+1; UPDATE blocked.result SET n=n+1"),
188
+ ).toThrow(SqliteAcquisitionBusyError);
189
+ });
190
+ expect(main.db.prepare("SELECT n FROM free.result").get()).toEqual({ n: 1 });
191
+ expect(main.db.prepare("SELECT n FROM blocked.result").get()).toEqual({ n: 0 });
192
+ } finally {
193
+ blocked.db.exec("ROLLBACK");
194
+ main.close();
195
+ free.close();
196
+ blocked.close();
197
+ }
198
+ });
199
+
200
+ for (const location of ["main", "free"] as const) {
201
+ test(`an ignored AUTOINCREMENT prefix in ${location} is committed only once before a later BUSY`, () => {
202
+ const main = fixture();
203
+ const free = fixture();
204
+ const blocked = fixture();
205
+ try {
206
+ main.db.prepare("ATTACH DATABASE ? AS free").run(free.path);
207
+ main.db.exec(`CREATE TABLE ${location}.numbered(id INTEGER PRIMARY KEY AUTOINCREMENT, value TEXT UNIQUE);
208
+ INSERT INTO ${location}.numbered(value) VALUES ('existing')`);
209
+ main.db.prepare("ATTACH DATABASE ? AS blocked").run(blocked.path);
210
+ blocked.db.exec("BEGIN IMMEDIATE");
211
+ const before = main.db.prepare("SELECT total_changes() AS n").get();
212
+ withSqliteTransformPass(() => {
213
+ guardSqliteTransformPass({ assert() {}, remainingMs: () => 50 });
214
+ expect(() =>
215
+ main.db.exec(
216
+ `INSERT OR IGNORE INTO ${location}.numbered(value) VALUES ('existing'); UPDATE blocked.result SET n=n+1`,
217
+ ),
218
+ ).toThrow(SqliteAcquisitionBusyError);
219
+ });
220
+ expect(main.db.prepare("SELECT total_changes() AS n").get()).toEqual(before);
221
+ expect(
222
+ main.db
223
+ .prepare(`SELECT seq FROM ${location}.sqlite_sequence WHERE name='numbered'`)
224
+ .get(),
225
+ ).toEqual({ seq: 2 });
226
+ expect(main.db.prepare(`SELECT * FROM ${location}.numbered`).all()).toEqual([
227
+ { id: 1, value: "existing" },
228
+ ]);
229
+ } finally {
230
+ blocked.db.exec("ROLLBACK");
231
+ main.close();
232
+ free.close();
233
+ blocked.close();
234
+ }
235
+ });
236
+ }
237
+
238
+ test("a WAL BUSY_SNAPSHOT in an explicit read transaction is not retried", () => {
239
+ const { db, path, close } = fixture();
240
+ db.exec("PRAGMA journal_mode=WAL");
241
+ const other = new Database(path);
242
+ try {
243
+ db.exec("BEGIN; SELECT * FROM result");
244
+ other.exec("UPDATE result SET n=n+1");
245
+ withSqliteTransformPass(() => {
246
+ expect(() => db.prepare("UPDATE result SET n=n+10").run()).toThrow("locked");
247
+ });
248
+ expect(db.inTransaction).toBe(true);
249
+ db.exec("ROLLBACK");
250
+ expect(db.prepare("SELECT n FROM result").get()).toEqual({ n: 1 });
251
+ } finally {
252
+ if (db.inTransaction) db.exec("ROLLBACK");
253
+ other.close();
254
+ close();
255
+ }
256
+ });
257
+
258
+ test("a BUSY from an AFTER trigger writing an attached database rolls back the outer statement", async () => {
259
+ const main = fixture();
260
+ const aux = fixture();
261
+ main.db.prepare("ATTACH DATABASE ? AS aux").run(aux.path);
262
+ // The TEMP trigger resolves an unqualified table in main first; give the
263
+ // attached target its own name so the trigger must write the other file.
264
+ main.db.exec("ALTER TABLE aux.result RENAME TO attached_result");
265
+ main.db.exec(`CREATE TEMP TRIGGER update_aux AFTER UPDATE ON main.result
266
+ BEGIN UPDATE attached_result SET n=n+1 WHERE id=1; END`);
267
+ const statement = main.db.prepare("UPDATE main.result SET n=n+1 RETURNING n");
268
+ const blocker = new Database(aux.path);
269
+ try {
270
+ blocker.exec("BEGIN IMMEDIATE");
271
+ main.db.exec("PRAGMA busy_timeout=0");
272
+ expect(() => statement.all()).toThrow("locked");
273
+ expect(main.db.prepare("SELECT n FROM main.result").get()).toEqual({ n: 0 });
274
+ expect(main.db.prepare("SELECT n FROM aux.attached_result").get()).toEqual({ n: 0 });
275
+ expect(main.db.inTransaction).toBe(false);
276
+ blocker.exec("ROLLBACK");
277
+ const { exited } = await lock(aux.path, "write", 100);
278
+ try {
279
+ await withSqliteTransformPass(() => statement.all());
280
+ } finally {
281
+ expect(await exited).toBe(0);
282
+ }
283
+ expect(main.db.prepare("SELECT n FROM main.result").get()).toEqual({ n: 1 });
284
+ expect(main.db.prepare("SELECT n FROM aux.attached_result").get()).toEqual({ n: 1 });
285
+ } finally {
286
+ if (blocker.inTransaction) blocker.exec("ROLLBACK");
287
+ blocker.close();
288
+ main.close();
289
+ aux.close();
290
+ }
291
+ });