@cortexkit/opencode-magic-context 0.45.0 → 0.46.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 (396) hide show
  1. package/README.md +26 -0
  2. package/dist/{announcement-f75t58v9.js → announcement-y35wzg2r.js} +1 -1
  3. package/dist/config/index.d.ts.map +1 -1
  4. package/dist/config/live-run-config.d.ts.map +1 -1
  5. package/dist/config/migrate-config-location.d.ts.map +1 -1
  6. package/dist/config/schema/magic-context.d.ts +13 -7
  7. package/dist/config/schema/magic-context.d.ts.map +1 -1
  8. package/dist/{conflict-warning-hook-5yrz2r24.js → conflict-warning-hook-7fj2b9jw.js} +6 -5
  9. package/dist/context-sh2m2vde.js +4525 -0
  10. package/dist/{derive-budgets-a63zsm5c.js → derive-budgets-7nj7r1rv.js} +2 -2
  11. package/dist/embedding-worker.js +4 -4
  12. package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts +45 -0
  13. package/dist/features/magic-context/checkout-claim-fake-subc.test-support.d.ts.map +1 -0
  14. package/dist/features/magic-context/checkout-claim.d.ts +155 -0
  15. package/dist/features/magic-context/checkout-claim.d.ts.map +1 -0
  16. package/dist/features/magic-context/compaction-marker.d.ts +20 -3
  17. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  18. package/dist/features/magic-context/compartment-storage.d.ts +23 -2
  19. package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  21. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/provider-output-failure.d.ts +6 -2
  23. package/dist/features/magic-context/dreamer/provider-output-failure.d.ts.map +1 -1
  24. package/dist/features/magic-context/dreamer/provider-output-failure.test-support.d.ts +30 -0
  25. package/dist/features/magic-context/dreamer/provider-output-failure.test-support.d.ts.map +1 -0
  26. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  27. package/dist/features/magic-context/dreamer/task-executor.d.ts +9 -0
  28. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  29. package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -1
  30. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  31. package/dist/features/magic-context/dreamer/verify-diff.d.ts.map +1 -1
  32. package/dist/features/magic-context/dreamer/verify-gate.d.ts.map +1 -1
  33. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  34. package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -1
  35. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  36. package/dist/features/magic-context/memory/project-identity-cache.d.ts.map +1 -1
  37. package/dist/features/magic-context/memory/storage-memory-verifications.d.ts.map +1 -1
  38. package/dist/features/magic-context/memory/storage-memory.d.ts +3 -0
  39. package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
  40. package/dist/features/magic-context/memory/verification-paths.d.ts +2 -2
  41. package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -1
  42. package/dist/features/magic-context/merged-reasoning-decisions.d.ts.map +1 -1
  43. package/dist/features/magic-context/message-index-async.d.ts +3 -3
  44. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  45. package/dist/features/magic-context/message-index.d.ts +2 -0
  46. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  47. package/dist/features/magic-context/migration-v95-perf-indexes.d.ts +12 -0
  48. package/dist/features/magic-context/migration-v95-perf-indexes.d.ts.map +1 -0
  49. package/dist/features/magic-context/migration-worker-client.d.ts +4 -4
  50. package/dist/features/magic-context/migration-worker-client.d.ts.map +1 -1
  51. package/dist/features/magic-context/migrations.d.ts +1 -0
  52. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  53. package/dist/features/magic-context/mural/render-trigger.d.ts.map +1 -1
  54. package/dist/features/magic-context/mural/resolve-mural.d.ts +15 -4
  55. package/dist/features/magic-context/mural/resolve-mural.d.ts.map +1 -1
  56. package/dist/features/magic-context/mural/source-revision.d.ts +7 -0
  57. package/dist/features/magic-context/mural/source-revision.d.ts.map +1 -0
  58. package/dist/features/magic-context/mural/storage-mural-cues.d.ts.map +1 -1
  59. package/dist/features/magic-context/reclaim-protection.d.ts +15 -10
  60. package/dist/features/magic-context/reclaim-protection.d.ts.map +1 -1
  61. package/dist/features/magic-context/session-cache-ttl.d.ts +4 -2
  62. package/dist/features/magic-context/session-cache-ttl.d.ts.map +1 -1
  63. package/dist/features/magic-context/smart-notes/capabilities.d.ts +3 -0
  64. package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -1
  65. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
  66. package/dist/features/magic-context/smart-notes/github-token.d.ts +5 -0
  67. package/dist/features/magic-context/smart-notes/github-token.d.ts.map +1 -0
  68. package/dist/features/magic-context/smart-notes/runner.d.ts +1 -0
  69. package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -1
  70. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts +12 -0
  71. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
  72. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts +6 -0
  73. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts.map +1 -1
  74. package/dist/features/magic-context/smart-notes/storage.d.ts.map +1 -1
  75. package/dist/features/magic-context/smart-notes/types.d.ts +2 -0
  76. package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -1
  77. package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
  78. package/dist/features/magic-context/storage-db.d.ts +6 -9
  79. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  80. package/dist/features/magic-context/storage-meta-shared.d.ts +1 -1
  81. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  82. package/dist/features/magic-context/storage-ops.d.ts +8 -1
  83. package/dist/features/magic-context/storage-ops.d.ts.map +1 -1
  84. package/dist/features/magic-context/storage-replay-document.d.ts +7 -0
  85. package/dist/features/magic-context/storage-replay-document.d.ts.map +1 -1
  86. package/dist/features/magic-context/storage-schema-helpers.d.ts +2 -0
  87. package/dist/features/magic-context/storage-schema-helpers.d.ts.map +1 -1
  88. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  89. package/dist/features/magic-context/storage-source.d.ts.map +1 -1
  90. package/dist/features/magic-context/storage-tags.d.ts +11 -3
  91. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  92. package/dist/features/magic-context/storage.d.ts +2 -2
  93. package/dist/features/magic-context/storage.d.ts.map +1 -1
  94. package/dist/features/magic-context/temporal-decisions.d.ts +10 -0
  95. package/dist/features/magic-context/temporal-decisions.d.ts.map +1 -0
  96. package/dist/features/magic-context/tool-definition-tokens.d.ts +2 -0
  97. package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
  98. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  99. package/dist/features/magic-context/types.d.ts +7 -6
  100. package/dist/features/magic-context/types.d.ts.map +1 -1
  101. package/dist/features/magic-context/window-report-ledger.d.ts.map +1 -1
  102. package/dist/hooks/auto-update-checker/index.d.ts.map +1 -1
  103. package/dist/hooks/magic-context/apply-operations.d.ts +8 -0
  104. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  105. package/dist/hooks/magic-context/cache-busting-signals.d.ts +6 -3
  106. package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
  107. package/dist/hooks/magic-context/channel2-cycle.d.ts +2 -0
  108. package/dist/hooks/magic-context/channel2-cycle.d.ts.map +1 -1
  109. package/dist/hooks/magic-context/compaction-marker-manager.d.ts +7 -0
  110. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  111. package/dist/hooks/magic-context/compartment-prompt.d.ts +2 -2
  112. package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
  113. package/dist/hooks/magic-context/compartment-render-epoch.d.ts +8 -0
  114. package/dist/hooks/magic-context/compartment-render-epoch.d.ts.map +1 -1
  115. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts +18 -4
  116. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts.map +1 -1
  117. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  118. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  119. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  120. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +12 -0
  121. package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -1
  122. package/dist/hooks/magic-context/decision-calibration.d.ts +3 -0
  123. package/dist/hooks/magic-context/decision-calibration.d.ts.map +1 -1
  124. package/dist/hooks/magic-context/default-protection-pressure.test-support.d.ts +37 -0
  125. package/dist/hooks/magic-context/default-protection-pressure.test-support.d.ts.map +1 -0
  126. package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts +4 -0
  127. package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts.map +1 -1
  128. package/dist/hooks/magic-context/edit-marker.d.ts.map +1 -1
  129. package/dist/hooks/magic-context/emergency-drop.d.ts +2 -0
  130. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  131. package/dist/hooks/magic-context/emergency-fail-closed.d.ts +21 -1
  132. package/dist/hooks/magic-context/emergency-fail-closed.d.ts.map +1 -1
  133. package/dist/hooks/magic-context/event-handler.d.ts +5 -0
  134. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  135. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +30 -1
  136. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  137. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +2 -0
  138. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  139. package/dist/hooks/magic-context/historian-prompt-fit.d.ts +4 -2
  140. package/dist/hooks/magic-context/historian-prompt-fit.d.ts.map +1 -1
  141. package/dist/hooks/magic-context/hook.d.ts +2 -1
  142. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  143. package/dist/hooks/magic-context/inject-compartments.d.ts +9 -10
  144. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  145. package/dist/hooks/magic-context/lkg-measured-request.d.ts +69 -0
  146. package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -0
  147. package/dist/hooks/magic-context/lkg-persist.d.ts +2 -0
  148. package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
  149. package/dist/hooks/magic-context/lkg-replay-fit.d.ts +14 -0
  150. package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -1
  151. package/dist/hooks/magic-context/lkg-replay.d.ts +10 -1
  152. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  153. package/dist/hooks/magic-context/lkg-slot.d.ts +4 -0
  154. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  155. package/dist/hooks/magic-context/module-state-sync.d.ts +2 -0
  156. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  157. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  158. package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
  159. package/dist/hooks/magic-context/note-nudger.d.ts +17 -5
  160. package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
  161. package/dist/hooks/magic-context/read-session-chunk.d.ts +1 -1
  162. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  163. package/dist/hooks/magic-context/read-session-db.d.ts +1 -0
  164. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  165. package/dist/hooks/magic-context/read-session-formatting.d.ts +7 -0
  166. package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
  167. package/dist/hooks/magic-context/read-session-raw.d.ts +4 -0
  168. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  169. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  170. package/dist/hooks/magic-context/recomp-orchestrator.d.ts +2 -0
  171. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  172. package/dist/hooks/magic-context/reference-retrieval.d.ts +27 -17
  173. package/dist/hooks/magic-context/reference-retrieval.d.ts.map +1 -1
  174. package/dist/hooks/magic-context/request-hook-order.d.ts +56 -0
  175. package/dist/hooks/magic-context/request-hook-order.d.ts.map +1 -0
  176. package/dist/hooks/magic-context/rust-mode-transform.d.ts +22 -3
  177. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  178. package/dist/hooks/magic-context/strip-content.d.ts +4 -2
  179. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  180. package/dist/hooks/magic-context/supersession-reclaim.d.ts +4 -0
  181. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
  182. package/dist/hooks/magic-context/system-prompt-hash.d.ts +7 -0
  183. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  184. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +12 -3
  185. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  186. package/dist/hooks/magic-context/temporal-awareness.d.ts +6 -3
  187. package/dist/hooks/magic-context/temporal-awareness.d.ts.map +1 -1
  188. package/dist/hooks/magic-context/temporal-served-projection.d.ts +4 -0
  189. package/dist/hooks/magic-context/temporal-served-projection.d.ts.map +1 -0
  190. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  191. package/dist/hooks/magic-context/tool-reclaim.d.ts +2 -0
  192. package/dist/hooks/magic-context/tool-reclaim.d.ts.map +1 -1
  193. package/dist/hooks/magic-context/transform-message-helpers.d.ts +5 -0
  194. package/dist/hooks/magic-context/transform-message-helpers.d.ts.map +1 -1
  195. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +41 -17
  196. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  197. package/dist/hooks/magic-context/transform.d.ts +12 -0
  198. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  199. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  200. package/dist/{index-vvtfyw1z.js → index-0d3g3461.js} +5 -13
  201. package/dist/index-1bc61ans.js +154 -0
  202. package/dist/{index-n96ag4rk.js → index-1zx87sdm.js} +5 -1
  203. package/dist/{index-4krbw8z9.js → index-3h0ybwah.js} +608 -102
  204. package/dist/{index-gd5qx1j9.js → index-5eqk6z3s.js} +62 -1
  205. package/dist/index-5gq3b2ya.js +494 -0
  206. package/dist/{index-8fgkmxmy.js → index-5p8jdswx.js} +4 -3
  207. package/dist/{index-75zjgwga.js → index-7qw742ev.js} +1 -1
  208. package/dist/{index-f85teqck.js → index-8da2zjhz.js} +3 -256
  209. package/dist/{index-q7yesyk9.js → index-8x2v7gg9.js} +25 -24
  210. package/dist/{index-w9jwmntv.js → index-b35pxds2.js} +9 -1
  211. package/dist/{v2/server-a4m2b1yv.js → index-fg34g6a5.js} +55 -1
  212. package/dist/index-hpecdzec.js +28506 -0
  213. package/dist/{index-2ntg5sd4.js → index-k5bdx1bx.js} +9 -5
  214. package/dist/{index-bmzf7zxv.js → index-majxda46.js} +23 -5
  215. package/dist/{index-2aq21j41.js → index-pkbcrdqs.js} +418 -127
  216. package/dist/{index-remp7e2g.js → index-q4yp4b52.js} +16 -1
  217. package/dist/{index-fr2z4qy8.js → index-r5hmbx3t.js} +132 -169
  218. package/dist/index-sfnj6h8h.js +259 -0
  219. package/dist/{index-xgt9k6c6.js → index-sgthv3f7.js} +2 -1
  220. package/dist/index-sj29b3z2.js +30 -0
  221. package/dist/{index-16ny736w.js → index-sjthx78w.js} +20526 -19817
  222. package/dist/index.d.ts.map +1 -1
  223. package/dist/index.js +1983 -33118
  224. package/dist/{message-time-backfill-an311pmk.js → message-time-backfill-68gj6t3e.js} +2 -2
  225. package/dist/migration-worker.js +12 -7
  226. package/dist/plugin/dream-timer.d.ts +25 -1
  227. package/dist/plugin/dream-timer.d.ts.map +1 -1
  228. package/dist/plugin/hooks/create-session-hooks.d.ts +2 -1
  229. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  230. package/dist/plugin/messages-transform.d.ts +13 -0
  231. package/dist/plugin/messages-transform.d.ts.map +1 -1
  232. package/dist/plugin/rpc-handlers.d.ts +4 -0
  233. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  234. package/dist/plugin/subagent-tool-policy.d.ts +14 -0
  235. package/dist/plugin/subagent-tool-policy.d.ts.map +1 -0
  236. package/dist/plugin/tool-registry.d.ts +1 -0
  237. package/dist/plugin/tool-registry.d.ts.map +1 -1
  238. package/dist/{read-session-chunk-8rxs0tc9.js → read-session-chunk-egz7r68d.js} +8 -8
  239. package/dist/{recomp-orchestrator-nzamtw29.js → recomp-orchestrator-y15j0rb9.js} +15 -15
  240. package/dist/{send-session-notification-nqpv7cne.js → send-session-notification-dyw42dtr.js} +4 -4
  241. package/dist/shared/announcement.d.ts.map +1 -1
  242. package/dist/shared/cache-ttl-display.d.ts +6 -4
  243. package/dist/shared/cache-ttl-display.d.ts.map +1 -1
  244. package/dist/shared/model-cache-ttl.d.ts +1 -1
  245. package/dist/shared/model-cache-ttl.d.ts.map +1 -1
  246. package/dist/shared/model-suggestion-retry.d.ts +2 -0
  247. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  248. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  249. package/dist/shared/protected-tools-policy.d.ts +6 -0
  250. package/dist/shared/protected-tools-policy.d.ts.map +1 -0
  251. package/dist/shared/quota-diagnostic.d.ts +4 -0
  252. package/dist/shared/quota-diagnostic.d.ts.map +1 -0
  253. package/dist/shared/rpc-server.d.ts.map +1 -1
  254. package/dist/shared/sqlite-context-pragmas.d.ts +12 -0
  255. package/dist/shared/sqlite-context-pragmas.d.ts.map +1 -0
  256. package/dist/shared/sqlite-helpers.d.ts +9 -0
  257. package/dist/shared/sqlite-helpers.d.ts.map +1 -1
  258. package/dist/shared/sqlite.d.ts +10 -0
  259. package/dist/shared/sqlite.d.ts.map +1 -1
  260. package/dist/shared/status-summary.d.ts +1 -0
  261. package/dist/shared/status-summary.d.ts.map +1 -1
  262. package/dist/shared/status-view-check.d.ts.map +1 -1
  263. package/dist/shared/status-view.d.ts +4 -0
  264. package/dist/shared/status-view.d.ts.map +1 -1
  265. package/dist/shared/storage-permissions.d.ts +24 -0
  266. package/dist/shared/storage-permissions.d.ts.map +1 -1
  267. package/dist/shared/temporal-upgrade-fixture.d.ts +19 -0
  268. package/dist/shared/temporal-upgrade-fixture.d.ts.map +1 -0
  269. package/dist/shared/user-facing-codes.d.ts +5 -0
  270. package/dist/shared/user-facing-codes.d.ts.map +1 -1
  271. package/dist/shared/write-transaction-timing.d.ts +8 -1
  272. package/dist/shared/write-transaction-timing.d.ts.map +1 -1
  273. package/dist/tools/ctx-expand/render.d.ts.map +1 -1
  274. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  275. package/dist/tools/ctx-reduce/constants.d.ts +2 -0
  276. package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
  277. package/dist/tools/ctx-reduce/tools.d.ts +4 -4
  278. package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
  279. package/dist/{transform-postprocess-phase-414phndq.js → transform-postprocess-phase-bqhz6vdr.js} +15 -15
  280. package/dist/v2/context-zecmzk5s.js +52209 -0
  281. package/dist/v2/{derive-budgets-v0krf3t7.js → derive-budgets-kdgp4s3r.js} +4 -3
  282. package/dist/v2/embedding-worker.js +6 -5
  283. package/dist/v2/fold/boundary.d.ts +2 -0
  284. package/dist/v2/fold/boundary.d.ts.map +1 -1
  285. package/dist/v2/fold/owner.d.ts.map +1 -1
  286. package/dist/v2/hidden-child-native.d.ts +7 -0
  287. package/dist/v2/hidden-child-native.d.ts.map +1 -1
  288. package/dist/v2/hidden-child-record.d.ts +8 -0
  289. package/dist/v2/hidden-child-record.d.ts.map +1 -1
  290. package/dist/v2/hidden-completion.d.ts.map +1 -1
  291. package/dist/v2/hooks/channel2.d.ts +2 -0
  292. package/dist/v2/hooks/channel2.d.ts.map +1 -1
  293. package/dist/v2/hooks/context.d.ts +2 -2
  294. package/dist/v2/hooks/context.d.ts.map +1 -1
  295. package/dist/v2/hooks/dream-timer.d.ts +39 -0
  296. package/dist/v2/hooks/dream-timer.d.ts.map +1 -0
  297. package/dist/v2/hooks/dream-trigger.d.ts +15 -1
  298. package/dist/v2/hooks/dream-trigger.d.ts.map +1 -1
  299. package/dist/v2/hooks/hidden-child.d.ts +54 -3
  300. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  301. package/dist/v2/hooks/payload.d.ts.map +1 -1
  302. package/dist/v2/hooks/store.d.ts.map +1 -1
  303. package/dist/v2/hooks/tools.d.ts +1 -1
  304. package/dist/v2/hooks/tools.d.ts.map +1 -1
  305. package/dist/v2/hooks/types.d.ts +12 -1
  306. package/dist/v2/hooks/types.d.ts.map +1 -1
  307. package/dist/v2/hooks/update-check.d.ts.map +1 -1
  308. package/dist/v2/{message-time-backfill-0n93vrd7.js → message-time-backfill-r6qkem1x.js} +3 -3
  309. package/dist/v2/migration-worker.js +13 -8
  310. package/dist/v2/{read-session-chunk-hjza38hr.js → read-session-chunk-8vjp6581.js} +9 -9
  311. package/dist/v2/recomp-orchestrator-8ejxvrzz.js +39 -0
  312. package/dist/v2/{safe-notification-target-wtj0bbc2.js → safe-notification-target-eb1n1vfb.js} +2 -2
  313. package/dist/v2/{send-session-notification-mq9frrtm.js → send-session-notification-qs0j78v6.js} +6 -6
  314. package/dist/v2/server-14vq4kpm.js +30 -0
  315. package/dist/v2/server-1bc61ans.js +154 -0
  316. package/dist/v2/{server-n96ag4rk.js → server-1zx87sdm.js} +5 -1
  317. package/dist/v2/server-3n4q9xme.js +79 -0
  318. package/dist/v2/{server-rhdgxp1t.js → server-51dv1pr5.js} +63 -2
  319. package/dist/v2/{server-5317ykaf.js → server-6r257mf5.js} +1 -1
  320. package/dist/v2/server-84w6rvvf.js +14 -0
  321. package/dist/v2/{server-qpg6wf72.js → server-ajzeteqw.js} +9 -1
  322. package/dist/v2/server-c5gz8wph.js +3892 -0
  323. package/dist/v2/{server-v5xgft5v.js → server-e29d7p7c.js} +188 -3533
  324. package/dist/{index-a4m2b1yv.js → v2/server-fg34g6a5.js} +55 -1
  325. package/dist/v2/{server-e36nf2p1.js → server-frbm99q5.js} +1595 -1599
  326. package/dist/v2/{server-remp7e2g.js → server-g0fjrkta.js} +16 -1
  327. package/dist/v2/{server-c4g2y1z8.js → server-jc7y02q0.js} +2816 -5392
  328. package/dist/v2/{server-z19x7eqz.js → server-mcfawjgc.js} +4 -4
  329. package/dist/v2/{server-hfjfbg59.js → server-qp5hx1ad.js} +608 -105
  330. package/dist/v2/server-vs5gpnd4.js +493 -0
  331. package/dist/v2/{server-w99cyt6a.js → server-wvjvfhck.js} +14 -6
  332. package/dist/v2/server-xa4xe3rv.js +3351 -0
  333. package/dist/v2/{server-0jqw05sa.js → server-y8maxeft.js} +6 -84
  334. package/dist/v2/server.d.ts.map +1 -1
  335. package/dist/v2/server.js +104 -49288
  336. package/dist/v2/store-reader.d.ts +39 -1
  337. package/dist/v2/store-reader.d.ts.map +1 -1
  338. package/dist/v2/tool-result.d.ts +8 -0
  339. package/dist/v2/tool-result.d.ts.map +1 -0
  340. package/dist/v2/tui/index.d.ts.map +1 -1
  341. package/dist/v2/{wrapup-orchestrator-tbyx78dz.js → wrapup-orchestrator-0snhvwcv.js} +20 -16
  342. package/dist/wrapup-orchestrator-39amhv9s.js +26 -0
  343. package/package.json +26 -10
  344. package/src/config/index.ts +21 -4
  345. package/src/config/latch-permanence-guard.test.ts +6 -1
  346. package/src/config/live-run-config.ts +1 -0
  347. package/src/config/migrate-config-location.test.ts +31 -1
  348. package/src/config/migrate-config-location.ts +8 -41
  349. package/src/config/protected-tools.test.ts +70 -0
  350. package/src/config/raw-loader.test.ts +15 -0
  351. package/src/config/raw-loader.ts +1 -1
  352. package/src/config/removed-agent-source-fence.test.ts +10 -1
  353. package/src/config/schema/magic-context.test.ts +20 -1
  354. package/src/config/schema/magic-context.ts +26 -7
  355. package/src/shared/announcement.ts +6 -5
  356. package/src/shared/cache-ttl-display.test.ts +1 -1
  357. package/src/shared/cache-ttl-display.ts +17 -16
  358. package/src/shared/fold-render-lock-fence.test.ts +84 -0
  359. package/src/shared/fold-render-lock-fixtures.test.ts +276 -0
  360. package/src/shared/model-cache-ttl.test.ts +2 -2
  361. package/src/shared/model-cache-ttl.ts +8 -4
  362. package/src/shared/model-suggestion-retry.test.ts +104 -1
  363. package/src/shared/model-suggestion-retry.ts +63 -6
  364. package/src/shared/models-dev-cache.ts +3 -11
  365. package/src/shared/protected-tools-policy.ts +23 -0
  366. package/src/shared/quota-diagnostic.ts +9 -0
  367. package/src/shared/rpc-server.ts +6 -54
  368. package/src/shared/sqlite-context-pragmas.test.ts +105 -0
  369. package/src/shared/sqlite-context-pragmas.ts +24 -0
  370. package/src/shared/sqlite-helpers.ts +17 -0
  371. package/src/shared/sqlite.ts +75 -0
  372. package/src/shared/status-detail-text.test.ts +18 -1
  373. package/src/shared/status-summary.ts +11 -0
  374. package/src/shared/status-view-check.ts +5 -0
  375. package/src/shared/status-view.test.ts +11 -2
  376. package/src/shared/status-view.ts +12 -1
  377. package/src/shared/storage-permissions.test.ts +204 -0
  378. package/src/shared/storage-permissions.ts +192 -0
  379. package/src/shared/temporal-upgrade-fixture.ts +50 -0
  380. package/src/shared/user-facing-codes.ts +6 -0
  381. package/src/shared/write-transaction-timing.test.ts +39 -0
  382. package/src/shared/write-transaction-timing.ts +25 -1
  383. package/src/tui/dialogs/status-dialog-render.test.ts +1 -1
  384. package/src/tui/index.tsx +3 -1
  385. package/src/tui/startup-order.test.ts +16 -0
  386. package/src/tui-compiled/index.tsx +3 -1
  387. package/src/v2/tui/index.ts +9 -2
  388. package/dist/index-anq4nn6f.js +0 -131
  389. package/dist/index-e44zzy84.js +0 -10
  390. package/dist/index-x23gah8c.js +0 -16
  391. package/dist/v2/recomp-orchestrator-1aq7h44c.js +0 -36
  392. package/dist/v2/server-e44zzy84.js +0 -10
  393. package/dist/v2/server-fgmxwrgy.js +0 -16
  394. package/dist/v2/server-r7cmye3k.js +0 -131
  395. package/dist/wrapup-orchestrator-h28bqsy6.js +0 -26
  396. package/dist/v2/{server-ckpc8pxy.js → server-1qbnzc80.js} +8 -8
@@ -1,4 +1,5 @@
1
1
  import { formatCacheTtlDisplay } from "./cache-ttl-display";
2
+ import { primaryQuotaDiagnostic } from "./quota-diagnostic";
2
3
  import type { RunnerStatus, StatusDetail } from "./rpc-types";
3
4
  import { renderUserFacingFailure, type UserFacingFailureKey } from "./user-facing-codes";
4
5
 
@@ -37,6 +38,7 @@ export interface UserStatusSummary {
37
38
  warnings: UserFacingFailureKey[];
38
39
  hiddenVariantWarnings?: string[];
39
40
  dreamerSkipped?: readonly string[];
41
+ dreamerQuotas?: readonly string[];
40
42
  }
41
43
 
42
44
  /**
@@ -129,6 +131,14 @@ export function statusSummaryFromDetail(detail: StatusDetail): UserStatusSummary
129
131
  warnings: statusWarningsFromDetail(detail),
130
132
  hiddenVariantWarnings: detail.hiddenVariantWarnings ?? [],
131
133
  dreamerSkipped: detail.dreamerSkipped,
134
+ dreamerQuotas: [
135
+ ...new Set(
136
+ (detail.dreamerFailures ?? []).flatMap((failure) => {
137
+ const quota = primaryQuotaDiagnostic(failure.error);
138
+ return quota ? [quota] : [];
139
+ }),
140
+ ),
141
+ ],
132
142
  };
133
143
  }
134
144
 
@@ -221,6 +231,7 @@ export function renderUserStatusSummary(
221
231
  values.push(["Dreamer runner", runnerText(summary.dreamerRunner)]);
222
232
  }
223
233
  for (const skipped of summary.dreamerSkipped ?? []) values.push(["Dreamer skipped", skipped]);
234
+ for (const quota of summary.dreamerQuotas ?? []) values.push(["Dreamer quota", quota]);
224
235
  if (summary.historianRefusal) {
225
236
  values.push([
226
237
  "Historian refusal",
@@ -312,6 +312,11 @@ export function checkStatusViewSource(candidate: unknown):
312
312
  lastDreamerRunAt: optional.read("lastDreamerRunAt", isNullableNumber),
313
313
  dreamerUnsupportedTasks: optional.readArray("dreamerUnsupportedTasks", isString),
314
314
  dreamerSkipped: optional.readArray("dreamerSkipped", isString),
315
+ dreamerFailures: optional.readArray(
316
+ "dreamerFailures",
317
+ (value): value is { task: string; error: string } =>
318
+ isRecord(value) && isString(value.task) && isString(value.error),
319
+ ),
315
320
  dreamerTickFailure: optional.read(
316
321
  "dreamerTickFailure",
317
322
  (value): value is NonNullable<StatusViewSource["dreamerTickFailure"]> | null =>
@@ -264,7 +264,7 @@ describe("status view model", () => {
264
264
  * gap fit; otherwise the caller draws one column.
265
265
  */
266
266
  test("draws two columns only when both columns' values fit", () => {
267
- const sections = view().sections;
267
+ const sections = view({ cacheTtlSource: "default" }).sections;
268
268
  for (const section of sections) {
269
269
  const longest = Math.max(...section.rows.map((row) => row.value.length));
270
270
  expect(statusSectionWidth(section)).toBe(section.labelWidth + 1 + longest);
@@ -297,7 +297,7 @@ describe("status view model", () => {
297
297
  expect(statusColumnsFor(narrowValues, needed).twoColumn).toBe(true);
298
298
  expect(statusColumnsFor(narrowValues, needed - 1).twoColumn).toBe(false);
299
299
 
300
- // A long value — the model key on the Configured row — pushes the left
300
+ // A long value — the frozen-default source on the Configured row — pushes the left
301
301
  // column past what the dialog has, so the same sections go one column
302
302
  // rather than wrapping that value mid-word.
303
303
  expect(statusColumnsFor(sections, 84).twoColumn).toBe(false);
@@ -398,6 +398,15 @@ describe("status view model", () => {
398
398
  * (issue 496).
399
399
  */
400
400
  describe("blocked background maintenance", () => {
401
+ test("shows a scheduled task's primary quota deadline in the status dialog", () => {
402
+ const error =
403
+ "primary quota exhausted until 2026-10-08T03:40:04.275Z; account=private@example.com";
404
+ const row = view({ dreamerFailures: [{ task: "verify", error }] })
405
+ .sections.find((section) => section.title === "History Compression")
406
+ ?.rows.find((entry) => entry.label === "Dreamer quota");
407
+ expect(row?.value).toBe("primary quota exhausted until 2026-10-08T03:40:04.275Z");
408
+ expect(row?.tone).toBe("warning");
409
+ });
401
410
  const failure = {
402
411
  at: NOW - 2 * 3_600_000,
403
412
  stage: "message-history maintenance",
@@ -17,6 +17,7 @@ import type { DreamerTickFailure } from "../features/magic-context/dreamer/tick-
17
17
  import { formatCacheTtlDisplay } from "./cache-ttl-display";
18
18
  import { type ConfigParseFailure, formatConfigParseStatusLine } from "./config-diagnostics";
19
19
  import { formatThresholdPercent } from "./format-threshold";
20
+ import { primaryQuotaDiagnostic } from "./quota-diagnostic";
20
21
  import type { TailHygieneStatus } from "./rpc-types";
21
22
  import {
22
23
  type StatusCheck,
@@ -153,6 +154,7 @@ export interface StatusViewSource {
153
154
  * its work" are not the same blank space in this view.
154
155
  */
155
156
  readonly dreamerTickFailure?: DreamerTickFailure | null;
157
+ readonly dreamerFailures?: readonly { task: string; error: string }[];
156
158
  readonly memoryCount: number;
157
159
  readonly sessionNoteCount?: number;
158
160
  readonly readySmartNoteCount?: number;
@@ -525,9 +527,18 @@ function dreamerUnsupportedRows(source: StatusViewSource): StatusRow[] {
525
527
 
526
528
  /** One row naming the stage that stopped the last maintenance pass, if one did. */
527
529
  function dreamerTickFailureRows(source: StatusViewSource, now: number): StatusRow[] {
530
+ const quotas = [
531
+ ...new Set(
532
+ (source.dreamerFailures ?? []).flatMap((failure) => {
533
+ const quota = primaryQuotaDiagnostic(failure.error);
534
+ return quota ? [quota] : [];
535
+ }),
536
+ ),
537
+ ].map((value): StatusRow => ({ label: "Dreamer quota", value, tone: "warning" }));
528
538
  const failure = source.dreamerTickFailure;
529
- if (!failure) return [];
539
+ if (!failure) return quotas;
530
540
  return [
541
+ ...quotas,
531
542
  {
532
543
  label: "Dreamer blocked",
533
544
  value: `${failure.stage} failed ${formatRelativeTime(failure.at, now)} (${userFacingFailureCode(
@@ -0,0 +1,204 @@
1
+ import { afterEach, describe, expect, it } from "bun:test";
2
+ import { randomUUID } from "node:crypto";
3
+ import {
4
+ chmodSync,
5
+ lstatSync,
6
+ mkdirSync,
7
+ readdirSync,
8
+ readFileSync,
9
+ readlinkSync,
10
+ rmSync,
11
+ statSync,
12
+ symlinkSync,
13
+ writeFileSync,
14
+ } from "node:fs";
15
+ import { tmpdir } from "node:os";
16
+ import { dirname, join, resolve } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ import { rememberGitIdentity } from "../features/magic-context/memory/project-identity-cache";
19
+ import { markAnnouncementSeen } from "./announcement";
20
+ import { getMagicContextStorageDir } from "./data-path";
21
+ import {
22
+ __resetStoragePrivatePermissionEnforcementForTests,
23
+ copyStorageFileSync,
24
+ copyStorageTreeSync,
25
+ ensureStorageDirectorySync,
26
+ setStoragePrivatePermissionEnforcement,
27
+ tightenStorageTreeSync,
28
+ writeStorageFileAsync,
29
+ writeStorageFileAtomicSync,
30
+ writeStorageFileSync,
31
+ } from "./storage-permissions";
32
+
33
+ const roots: string[] = [];
34
+
35
+ function entriesBelow(path: string): string[] {
36
+ const found = [path];
37
+ const stat = lstatSync(path);
38
+ if (!stat.isDirectory() || stat.isSymbolicLink()) return found;
39
+ for (const entry of readdirSync(path)) found.push(...entriesBelow(join(path, entry)));
40
+ return found;
41
+ }
42
+
43
+ function assertPrivateTree(root: string): void {
44
+ for (const entry of entriesBelow(root)) {
45
+ const mode = statSync(entry).mode & 0o777;
46
+ expect(mode & 0o077, `${entry} mode ${mode.toString(8)}`).toBe(0);
47
+ }
48
+ }
49
+
50
+ afterEach(() => {
51
+ __resetStoragePrivatePermissionEnforcementForTests();
52
+ for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true });
53
+ });
54
+
55
+ describe("owner-only storage permissions", () => {
56
+ it("creates storage directories, ordinary files, and atomic temporaries privately, then tightens old entries", async () => {
57
+ if (process.platform === "win32") return;
58
+ const root = join(
59
+ tmpdir(),
60
+ "magic-context",
61
+ `permissions-ts-${process.pid}-${randomUUID()}`,
62
+ );
63
+ roots.push(root);
64
+ const storage = join(root, "cortexkit", "magic-context");
65
+
66
+ ensureStorageDirectorySync(storage, true);
67
+ writeStorageFileSync(join(storage, "last_announced_version"), "0.45.0", {
68
+ forcePrivate: true,
69
+ });
70
+ writeStorageFileAtomicSync(join(storage, "last-update-check.json"), "{}\n", true);
71
+ const snapshotPath = join(storage, "snapshot.heapsnapshot");
72
+ await writeStorageFileAsync(snapshotPath, "snapshot", true);
73
+ expect(statSync(snapshotPath).mode & 0o077).toBe(0);
74
+ const legacy = join(storage, "project-identities");
75
+ mkdirSync(legacy, { recursive: true });
76
+ writeFileSync(join(legacy, "legacy.json"), "{}\n");
77
+ chmodSync(legacy, 0o755);
78
+ chmodSync(join(legacy, "legacy.json"), 0o644);
79
+
80
+ const result = tightenStorageTreeSync(storage);
81
+
82
+ expect(result.failures).toBe(0);
83
+ expect(result.tightened).toBe(2);
84
+ assertPrivateTree(storage);
85
+
86
+ const copySource = join(root, "copy-source", "context.db");
87
+ mkdirSync(dirname(copySource), { recursive: true });
88
+ writeFileSync(copySource, "database fixture");
89
+ const copyDestination = join(storage, "backup.db");
90
+ copyStorageFileSync(copySource, copyDestination, true);
91
+ expect(statSync(copyDestination).mode & 0o077).toBe(0);
92
+ });
93
+
94
+ it("copies cache symlinks without widening the copied tree", () => {
95
+ if (process.platform === "win32") return;
96
+ const root = join(tmpdir(), "magic-context", `copy-tree-ts-${process.pid}-${randomUUID()}`);
97
+ roots.push(root);
98
+ const source = join(root, "source");
99
+ const destination = join(root, "data", "cortexkit", "magic-context", "models");
100
+ mkdirSync(source, { recursive: true });
101
+ writeFileSync(join(source, "blob"), "weights");
102
+ symlinkSync("blob", join(source, "snapshot"));
103
+
104
+ copyStorageTreeSync(source, destination, true);
105
+
106
+ expect(lstatSync(join(destination, "snapshot")).isSymbolicLink()).toBe(true);
107
+ expect(readlinkSync(join(destination, "snapshot"))).toBe("blob");
108
+ assertPrivateTree(destination);
109
+ });
110
+
111
+ it("creates state and identity files through their public data-directory writers privately", () => {
112
+ if (process.platform === "win32") return;
113
+ const root = join(tmpdir(), "magic-context", `writers-ts-${process.pid}-${randomUUID()}`);
114
+ roots.push(root);
115
+ const previous = {
116
+ testData: process.env.MAGIC_CONTEXT_TEST_DATA_DIR,
117
+ xdgData: process.env.XDG_DATA_HOME,
118
+ storage: process.env.MAGIC_CONTEXT_STORAGE_DIR,
119
+ };
120
+ process.env.MAGIC_CONTEXT_TEST_DATA_DIR = root;
121
+ process.env.XDG_DATA_HOME = root;
122
+ delete process.env.MAGIC_CONTEXT_STORAGE_DIR;
123
+ setStoragePrivatePermissionEnforcement(true);
124
+ try {
125
+ const storage = getMagicContextStorageDir();
126
+ ensureStorageDirectorySync(storage, true);
127
+ rememberGitIdentity(join(root, "project"), "git:0123456789abcdef");
128
+ markAnnouncementSeen("0.45.0");
129
+ assertPrivateTree(storage);
130
+ } finally {
131
+ if (previous.testData === undefined) delete process.env.MAGIC_CONTEXT_TEST_DATA_DIR;
132
+ else process.env.MAGIC_CONTEXT_TEST_DATA_DIR = previous.testData;
133
+ if (previous.xdgData === undefined) delete process.env.XDG_DATA_HOME;
134
+ else process.env.XDG_DATA_HOME = previous.xdgData;
135
+ if (previous.storage === undefined) delete process.env.MAGIC_CONTEXT_STORAGE_DIR;
136
+ else process.env.MAGIC_CONTEXT_STORAGE_DIR = previous.storage;
137
+ }
138
+ });
139
+
140
+ it("keeps storage filesystem creation behind the shared helper", () => {
141
+ const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../../../");
142
+ const scanRoots = [
143
+ "packages/plugin/src",
144
+ "packages/pi-plugin/src",
145
+ "packages/cli/src",
146
+ "packages/dashboard/src",
147
+ ];
148
+ const directCreate =
149
+ /(?:\b(?:fs\.)?(?:mkdirSync|mkdir|writeFileSync|writeFile|appendFileSync|appendFile|createWriteStream|copyFileSync|cpSync)\s*\(|\bBun\.write\s*\()/;
150
+ const directOpenWrite = /\b(?:openSync|open)\s*\([^,]+,\s*["'](?:w|wx|a|ax|as|as\+)/;
151
+ const offenders: string[] = [];
152
+ const visit = (absolute: string): void => {
153
+ for (const entry of readdirSync(absolute, { withFileTypes: true })) {
154
+ const path = join(absolute, entry.name);
155
+ if (entry.isDirectory()) {
156
+ if (entry.name !== "node_modules" && entry.name !== "dist") visit(path);
157
+ continue;
158
+ }
159
+ if (
160
+ !/\.(?:ts|tsx|js|mjs|cjs)$/.test(entry.name) ||
161
+ /(?:\.test|\.spec)\./.test(entry.name)
162
+ )
163
+ continue;
164
+ const source = readFileSync(path, "utf8");
165
+ if (
166
+ !source.includes("getMagicContextStorageDir") ||
167
+ (!directCreate.test(source) && !directOpenWrite.test(source))
168
+ )
169
+ continue;
170
+ const relative = path.slice(repoRoot.length + 1);
171
+ // Project .gitignore maintenance is outside the private data directory;
172
+ // it writes only the shared per-project ignore file.
173
+ if (relative === "packages/plugin/src/shared/data-path.ts") continue;
174
+ // This migration command reads the MC store but writes only harness session files.
175
+ if (relative === "packages/cli/src/commands/migrate.ts") continue;
176
+ offenders.push(relative);
177
+ }
178
+ };
179
+ for (const root of scanRoots) visit(join(repoRoot, root));
180
+ for (const relative of [
181
+ "packages/plugin/scripts/cache-bust-sentinel.ts",
182
+ "packages/plugin/scripts/transform-latency-sentinel.ts",
183
+ "packages/plugin/scripts/subagent-failure-sentinel.ts",
184
+ ]) {
185
+ const source = readFileSync(join(repoRoot, relative), "utf8");
186
+ if (
187
+ source.includes("getMagicContextStorageDir") &&
188
+ (directCreate.test(source) || directOpenWrite.test(source))
189
+ ) {
190
+ offenders.push(relative);
191
+ }
192
+ }
193
+
194
+ expect(offenders, `direct filesystem creators in storage-aware modules`).toEqual([]);
195
+ });
196
+
197
+ it("keeps shell backups and staging private from their first creation", () => {
198
+ const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../../../");
199
+ for (const script of ["scripts/restart-window.sh", "scripts/place-ck-mc.sh"]) {
200
+ const source = readFileSync(join(repoRoot, script), "utf8");
201
+ expect(source, script).toMatch(/^umask 077$/m);
202
+ }
203
+ });
204
+ });
@@ -4,6 +4,28 @@
4
4
  * Storage is shared by OpenCode and Pi, so all writers consult one setting before
5
5
  * applying POSIX modes. The default preserves the historical owner-only policy.
6
6
  */
7
+ import { randomBytes } from "node:crypto";
8
+ import type { WriteStream } from "node:fs";
9
+ import {
10
+ chmodSync,
11
+ closeSync,
12
+ createWriteStream,
13
+ lstatSync,
14
+ mkdirSync,
15
+ openSync,
16
+ readdirSync,
17
+ readlinkSync,
18
+ readSync,
19
+ renameSync,
20
+ rmSync,
21
+ symlinkSync,
22
+ writeFileSync,
23
+ writeSync,
24
+ } from "node:fs";
25
+ import type { FileHandle } from "node:fs/promises";
26
+ import { open as openAsync, writeFile as writeFileAsync } from "node:fs/promises";
27
+ import { dirname, join } from "node:path";
28
+
7
29
  let enforcePrivateStoragePermissions = true;
8
30
 
9
31
  export function setStoragePrivatePermissionEnforcement(enforce: boolean): void {
@@ -18,3 +40,173 @@ export function shouldEnforcePrivateStoragePermissions(): boolean {
18
40
  export function __resetStoragePrivatePermissionEnforcementForTests(): void {
19
41
  enforcePrivateStoragePermissions = true;
20
42
  }
43
+
44
+ /** Create storage directories with owner-only permissions at their creation. */
45
+ export function ensureStorageDirectorySync(
46
+ directory: string,
47
+ forcePrivate = false,
48
+ recursive = true,
49
+ ): void {
50
+ const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
51
+ mkdirSync(directory, {
52
+ recursive,
53
+ ...(privateMode ? { mode: 0o700 } : {}),
54
+ });
55
+ }
56
+
57
+ /** Create or replace a storage file using a private mode from the first byte. */
58
+ export function writeStorageFileSync(
59
+ filePath: string,
60
+ content: string | Uint8Array,
61
+ options: { encoding?: BufferEncoding; flag?: string; forcePrivate?: boolean } = {},
62
+ ): void {
63
+ const { forcePrivate = false, ...writeOptions } = options;
64
+ const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
65
+ writeFileSync(filePath, content, {
66
+ ...writeOptions,
67
+ ...(privateMode ? { mode: 0o600 } : {}),
68
+ });
69
+ }
70
+
71
+ /** Write a private sibling then atomically publish it without a permissive temp window. */
72
+ export function writeStorageFileAtomicSync(
73
+ filePath: string,
74
+ content: string | Uint8Array,
75
+ forcePrivate = false,
76
+ ): void {
77
+ ensureStorageDirectorySync(dirname(filePath), forcePrivate);
78
+ const tempPath = `${filePath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
79
+ try {
80
+ writeStorageFileSync(tempPath, content, { flag: "wx", forcePrivate });
81
+ renameSync(tempPath, filePath);
82
+ } catch (error) {
83
+ rmSync(tempPath, { force: true });
84
+ throw error;
85
+ }
86
+ }
87
+
88
+ export function copyStorageFileSync(
89
+ sourcePath: string,
90
+ destinationPath: string,
91
+ forcePrivate = false,
92
+ ): void {
93
+ ensureStorageDirectorySync(dirname(destinationPath), forcePrivate);
94
+ const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
95
+ const sourceFd = openSync(sourcePath, "r");
96
+ let destinationFd: number | undefined;
97
+ try {
98
+ destinationFd = openSync(destinationPath, "wx", privateMode ? 0o600 : 0o666);
99
+ const buffer = Buffer.allocUnsafe(1024 * 1024);
100
+ for (;;) {
101
+ const bytesRead = readSync(sourceFd, buffer, 0, buffer.length, null);
102
+ if (bytesRead === 0) break;
103
+ let offset = 0;
104
+ while (offset < bytesRead) {
105
+ offset += writeSync(destinationFd, buffer, offset, bytesRead - offset);
106
+ }
107
+ }
108
+ } catch (error) {
109
+ if (destinationFd !== undefined) rmSync(destinationPath, { force: true });
110
+ throw error;
111
+ } finally {
112
+ closeSync(sourceFd);
113
+ if (destinationFd !== undefined) closeSync(destinationFd);
114
+ }
115
+ }
116
+
117
+ export function copyStorageTreeSync(
118
+ sourcePath: string,
119
+ destinationPath: string,
120
+ forcePrivate = false,
121
+ ): void {
122
+ const stat = lstatSync(sourcePath);
123
+ if (stat.isSymbolicLink()) {
124
+ ensureStorageDirectorySync(dirname(destinationPath), forcePrivate);
125
+ symlinkSync(readlinkSync(sourcePath), destinationPath);
126
+ return;
127
+ }
128
+ if (!stat.isDirectory()) {
129
+ copyStorageFileSync(sourcePath, destinationPath, forcePrivate);
130
+ return;
131
+ }
132
+ ensureStorageDirectorySync(destinationPath, forcePrivate);
133
+ for (const entry of readdirSync(sourcePath)) {
134
+ copyStorageTreeSync(join(sourcePath, entry), join(destinationPath, entry), forcePrivate);
135
+ }
136
+ }
137
+
138
+ export function openStorageFileSync(filePath: string, flags: string, forcePrivate = false): number {
139
+ ensureStorageDirectorySync(dirname(filePath), forcePrivate);
140
+ const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
141
+ return openSync(filePath, flags, privateMode ? 0o600 : 0o666);
142
+ }
143
+
144
+ export async function writeStorageFileAsync(
145
+ filePath: string,
146
+ content: string | Uint8Array,
147
+ forcePrivate = false,
148
+ ): Promise<void> {
149
+ const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
150
+ ensureStorageDirectorySync(dirname(filePath), privateMode);
151
+ await writeFileAsync(filePath, content, privateMode ? { mode: 0o600 } : undefined);
152
+ }
153
+
154
+ export async function writeStorageFileHandleAsync(
155
+ handle: FileHandle,
156
+ content: string,
157
+ ): Promise<void> {
158
+ await handle.writeFile(content);
159
+ }
160
+
161
+ export function createStorageWriteStream(filePath: string, forcePrivate = false): WriteStream {
162
+ const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
163
+ return createWriteStream(filePath, privateMode ? { mode: 0o600 } : undefined);
164
+ }
165
+
166
+ export async function createStorageFileHandleAsync(
167
+ filePath: string,
168
+ flags: string,
169
+ forcePrivate = false,
170
+ ) {
171
+ const privateMode = forcePrivate || shouldEnforcePrivateStoragePermissions();
172
+ return openAsync(filePath, flags, privateMode ? 0o600 : undefined);
173
+ }
174
+
175
+ /** Tighten existing entries during storage startup; symlinks are never followed. */
176
+ export function tightenStorageTreeSync(root: string): { tightened: number; failures: number } {
177
+ if (!shouldEnforcePrivateStoragePermissions() || process.platform === "win32") {
178
+ return { tightened: 0, failures: 0 };
179
+ }
180
+ let tightened = 0;
181
+ let failures = 0;
182
+ const visit = (entryPath: string): void => {
183
+ let stat: ReturnType<typeof lstatSync>;
184
+ try {
185
+ stat = lstatSync(entryPath);
186
+ } catch {
187
+ failures++;
188
+ return;
189
+ }
190
+ if (stat.isSymbolicLink()) return;
191
+ const mode = stat.isDirectory() ? 0o700 : 0o600;
192
+ if ((stat.mode & 0o077) !== 0 || (stat.mode & 0o777) !== mode) {
193
+ try {
194
+ chmodSync(entryPath, mode);
195
+ tightened++;
196
+ } catch {
197
+ failures++;
198
+ }
199
+ }
200
+ if (!stat.isDirectory()) return;
201
+ let entries: string[];
202
+ try {
203
+ entries = readdirSync(entryPath);
204
+ } catch {
205
+ failures++;
206
+ return;
207
+ }
208
+ for (const entry of entries) visit(join(entryPath, entry));
209
+ };
210
+ visit(root);
211
+ return { tightened, failures };
212
+ }
@@ -0,0 +1,50 @@
1
+ import fixture from "../../../../testdata/temporal-upgrade-projections.json";
2
+ import type { Database } from "./sqlite";
3
+
4
+ export type TemporalFixtureRuntime = "Pi" | "OpenCode 1" | "OpenCode 2";
5
+ type Value = null | string | number | { base64: string };
6
+ interface CapturedSession {
7
+ sessionId: string;
8
+ cwd?: string;
9
+ input: unknown[];
10
+ entryIds?: string[];
11
+ projection: unknown[];
12
+ projectionJson: string;
13
+ state: Record<string, Array<Record<string, Value>>>;
14
+ }
15
+
16
+ export const temporalUpgradeCases: Record<TemporalFixtureRuntime, CapturedSession> = fixture.cases;
17
+
18
+ /** Restore old served state, never by first rendering it with the current code. */
19
+ export function seedTemporalUpgradeFixture(
20
+ db: Database,
21
+ runtime: TemporalFixtureRuntime,
22
+ ): CapturedSession {
23
+ const captured = temporalUpgradeCases[runtime];
24
+ db.transaction(() => {
25
+ for (const [table, rows] of Object.entries(captured.state)) {
26
+ for (const row of rows) {
27
+ const columns = Object.keys(row);
28
+ const values = Object.values(row).map((value) =>
29
+ value !== null && typeof value === "object"
30
+ ? Buffer.from(value.base64, "base64")
31
+ : value,
32
+ );
33
+ db.prepare(
34
+ `INSERT INTO ${table} (${columns.join(",")}) VALUES (${columns.map(() => "?").join(",")})`,
35
+ ).run(...values);
36
+ }
37
+ }
38
+ // Advance only the cache clock: timestamp-derived marker bytes and
39
+ // the old input/projection are the immutable captured fixture.
40
+ db.prepare("UPDATE session_meta SET last_response_time=? WHERE session_id=?").run(
41
+ Date.now(),
42
+ captured.sessionId,
43
+ );
44
+ db.prepare("UPDATE lkg_slots SET captured_at=? WHERE session_id=?").run(
45
+ Date.now(),
46
+ captured.sessionId,
47
+ );
48
+ }).immediate();
49
+ return captured;
50
+ }
@@ -245,6 +245,12 @@ export const USER_FACING_FAILURES = {
245
245
  sentence: "Magic Context has no context.db.",
246
246
  action: "Run `npx @cortexkit/magic-context doctor store init`, then restart ck-mc.",
247
247
  },
248
+ checkout_claim_held_elsewhere: {
249
+ code: "MC-C16",
250
+ sentence:
251
+ "This request was not sent: this agent is checked out on another machine, so Magic Context will not work on its sessions here.",
252
+ action: "Move the agent back to this machine, then send your message again.",
253
+ },
248
254
  single_store_migration_required: {
249
255
  code: "MC-C14",
250
256
  sentence: "Magic Context's Rust mode needs a one-time migration of its store.",
@@ -0,0 +1,39 @@
1
+ import { expect, spyOn, test } from "bun:test";
2
+ import * as logger from "./logger";
3
+ import { logSlowWriteTransaction } from "./write-transaction-timing";
4
+
5
+ test("slow-write diagnostics distinguish preparation from held rendering and writes", () => {
6
+ const log = spyOn(logger, "log").mockImplementation(() => {});
7
+ try {
8
+ logSlowWriteTransaction("fold", 100, 1000, 1400, {
9
+ pre_metadata: 1,
10
+ pre_onFoldPrepare: 200,
11
+ staleCheck: 5,
12
+ m1Render: 100,
13
+ persistCachedM0: 600,
14
+ sessionMeta: 5,
15
+ onFoldCommit: 10,
16
+ commit: 580,
17
+ });
18
+ expect(log.mock.calls).toEqual([
19
+ [
20
+ "[magic-context] slow write transaction: site=fold held=1300.0ms pre_metadata=1.0ms pre_onFoldPrepare=200.0ms staleCheck=5.0ms m1Render=100.0ms persistCachedM0=600.0ms sessionMeta=5.0ms onFoldCommit=10.0ms commit=580.0ms",
21
+ ],
22
+ ]);
23
+ logSlowWriteTransaction("fast", 100, 1000, 101);
24
+ expect(log).toHaveBeenCalledTimes(1);
25
+ } finally {
26
+ log.mockRestore();
27
+ }
28
+ });
29
+
30
+ test("step diagnostics cannot make a committed write appear to fail", () => {
31
+ const log = spyOn(logger, "log").mockImplementation(() => {
32
+ throw new Error("logging failed");
33
+ });
34
+ try {
35
+ expect(() => logSlowWriteTransaction("fold", 0, 1000, 2000, { commit: 10 })).not.toThrow();
36
+ } finally {
37
+ log.mockRestore();
38
+ }
39
+ });
@@ -15,12 +15,36 @@ export function logSlowWriteTransaction(
15
15
  startedAt: number,
16
16
  thresholdMs = SLOW_WRITE_TRANSACTION_THRESHOLD_MS,
17
17
  completedAtMs = performance.now(),
18
+ steps?: Readonly<Record<string, number>>,
18
19
  ): void {
19
20
  try {
20
21
  const durationMs = completedAtMs - startedAt;
21
22
  if (durationMs < thresholdMs) return;
22
- log(`[magic-context] slow write transaction: site=${site} held=${durationMs.toFixed(1)}ms`);
23
+ const detail = steps
24
+ ? Object.entries(steps)
25
+ .map(([name, ms]) => `${name}=${ms.toFixed(1)}ms`)
26
+ .join(" ")
27
+ : "";
28
+ log(
29
+ `[magic-context] slow write transaction: site=${site} held=${durationMs.toFixed(1)}ms${detail ? ` ${detail}` : ""}`,
30
+ );
23
31
  } catch {
24
32
  // Timing diagnostics must never make a committed write appear to fail.
25
33
  }
26
34
  }
35
+
36
+ /** Step durations include precomputation when named `pre_*`; held time never does. */
37
+ export class WriteTransactionSteps {
38
+ readonly durations: Record<string, number> = {};
39
+ private last = performance.now();
40
+
41
+ mark(name: string): void {
42
+ const now = performance.now();
43
+ this.durations[name] = now - this.last;
44
+ this.last = now;
45
+ }
46
+
47
+ reset(): void {
48
+ this.last = performance.now();
49
+ }
50
+ }
@@ -163,7 +163,7 @@ const LAYOUT_CASES: LayoutCase[] = [
163
163
  status: LONG_VALUE_STATUS,
164
164
  terminalWidth: 80,
165
165
  dialogWidth: 60,
166
- expected: ["Configured", "context-preview)", "Execute threshold", "Esc to close"],
166
+ expected: ["Configured", "your config)", "Execute threshold", "Esc to close"],
167
167
  rows: COMPLETE_ROWS,
168
168
  },
169
169
  ];