@cortexkit/opencode-magic-context 0.42.6 → 0.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (479) hide show
  1. package/README.md +4 -5
  2. package/dist/agents/dreamer.d.ts +7 -9
  3. package/dist/agents/dreamer.d.ts.map +1 -1
  4. package/dist/agents/hidden-agent-registrations.d.ts.map +1 -1
  5. package/dist/agents/magic-context-prompt.d.ts.map +1 -1
  6. package/dist/config/index.d.ts +1 -1
  7. package/dist/config/index.d.ts.map +1 -1
  8. package/dist/config/live-run-config.d.ts +12 -0
  9. package/dist/config/live-run-config.d.ts.map +1 -0
  10. package/dist/config/live-snapshot.d.ts +32 -0
  11. package/dist/config/live-snapshot.d.ts.map +1 -0
  12. package/dist/config/schema/magic-context.d.ts +12 -2
  13. package/dist/config/schema/magic-context.d.ts.map +1 -1
  14. package/dist/{conflict-warning-hook-aktepwpz.js → conflict-warning-hook-t2vb0wnx.js} +3 -3
  15. package/dist/{derive-budgets-v1fkhjjr.js → derive-budgets-0sg5vp61.js} +5 -2
  16. package/dist/features/builtin-commands/commands.d.ts +0 -4
  17. package/dist/features/builtin-commands/commands.d.ts.map +1 -1
  18. package/dist/features/magic-context/compaction-marker.d.ts +6 -0
  19. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  20. package/dist/features/magic-context/compartment-chunk-embedding.d.ts +4 -1
  21. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  22. package/dist/features/magic-context/compartment-lease.d.ts +8 -0
  23. package/dist/features/magic-context/compartment-lease.d.ts.map +1 -1
  24. package/dist/features/magic-context/compartment-storage.d.ts +21 -0
  25. package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
  26. package/dist/features/magic-context/context-authority.d.ts +9 -2
  27. package/dist/features/magic-context/context-authority.d.ts.map +1 -1
  28. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  29. package/dist/features/magic-context/dreamer/docs-proposals.d.ts +23 -0
  30. package/dist/features/magic-context/dreamer/docs-proposals.d.ts.map +1 -0
  31. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts +5 -1
  32. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  33. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts +48 -0
  34. package/dist/features/magic-context/dreamer/hidden-single-shot.d.ts.map +1 -0
  35. package/dist/features/magic-context/dreamer/manual-summary.d.ts +7 -0
  36. package/dist/features/magic-context/dreamer/manual-summary.d.ts.map +1 -0
  37. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  38. package/dist/features/magic-context/dreamer/promote-primers.d.ts +8 -1
  39. package/dist/features/magic-context/dreamer/promote-primers.d.ts.map +1 -1
  40. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  41. package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts +5 -2
  42. package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts.map +1 -1
  43. package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts +22 -13
  44. package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts.map +1 -1
  45. package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts +9 -0
  46. package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts.map +1 -1
  47. package/dist/features/magic-context/dreamer/task-config.d.ts.map +1 -1
  48. package/dist/features/magic-context/dreamer/task-executor.d.ts +3 -0
  49. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  50. package/dist/features/magic-context/dreamer/task-prompts.d.ts +7 -4
  51. package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -1
  52. package/dist/features/magic-context/dreamer/task-registry.d.ts +53 -2
  53. package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
  54. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +3 -0
  55. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  56. package/dist/features/magic-context/dreamer/tick-failure.d.ts +38 -0
  57. package/dist/features/magic-context/dreamer/tick-failure.d.ts.map +1 -0
  58. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  59. package/dist/features/magic-context/git-commits/search-git-commits.d.ts +2 -0
  60. package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -1
  61. package/dist/features/magic-context/memory/embedding-identity.d.ts +1 -0
  62. package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -1
  63. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  64. package/dist/features/magic-context/memory/memory-diagnostics.d.ts +6 -0
  65. package/dist/features/magic-context/memory/memory-diagnostics.d.ts.map +1 -0
  66. package/dist/features/magic-context/memory/memory-selection.d.ts +12 -0
  67. package/dist/features/magic-context/memory/memory-selection.d.ts.map +1 -0
  68. package/dist/features/magic-context/memory/memory-visibility.d.ts +46 -0
  69. package/dist/features/magic-context/memory/memory-visibility.d.ts.map +1 -0
  70. package/dist/features/magic-context/memory/mirror-reembed.d.ts +22 -0
  71. package/dist/features/magic-context/memory/mirror-reembed.d.ts.map +1 -0
  72. package/dist/features/magic-context/memory/project-identity.d.ts +9 -0
  73. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  74. package/dist/features/magic-context/memory/storage-memory-fts.d.ts +6 -2
  75. package/dist/features/magic-context/memory/storage-memory-fts.d.ts.map +1 -1
  76. package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
  77. package/dist/features/magic-context/memory/transformers-remote-host.d.ts +6 -0
  78. package/dist/features/magic-context/memory/transformers-remote-host.d.ts.map +1 -0
  79. package/dist/features/magic-context/memory/transformers-web-entry.d.ts.map +1 -1
  80. package/dist/features/magic-context/message-fts-rowid-map.d.ts +3 -1
  81. package/dist/features/magic-context/message-fts-rowid-map.d.ts.map +1 -1
  82. package/dist/features/magic-context/message-index-async.d.ts +8 -3
  83. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  84. package/dist/features/magic-context/message-index.d.ts +7 -1
  85. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  86. package/dist/features/magic-context/message-time-backfill.d.ts +19 -0
  87. package/dist/features/magic-context/message-time-backfill.d.ts.map +1 -0
  88. package/dist/features/magic-context/migrations.d.ts +10 -6
  89. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  90. package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
  91. package/dist/features/magic-context/mural/storage-mural.d.ts +5 -0
  92. package/dist/features/magic-context/mural/storage-mural.d.ts.map +1 -1
  93. package/dist/features/magic-context/opencode2-relabel.d.ts +132 -0
  94. package/dist/features/magic-context/opencode2-relabel.d.ts.map +1 -0
  95. package/dist/features/magic-context/overflow-detection.d.ts +3 -0
  96. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  97. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  98. package/dist/features/magic-context/protection-window.d.ts +1 -1
  99. package/dist/features/magic-context/protection-window.d.ts.map +1 -1
  100. package/dist/features/magic-context/search.d.ts +6 -0
  101. package/dist/features/magic-context/search.d.ts.map +1 -1
  102. package/dist/features/magic-context/session-decision-calibration.d.ts +31 -0
  103. package/dist/features/magic-context/session-decision-calibration.d.ts.map +1 -0
  104. package/dist/features/magic-context/shadow-backfill-state.d.ts +1 -1
  105. package/dist/features/magic-context/shadow-backfill-state.d.ts.map +1 -1
  106. package/dist/features/magic-context/smart-notes/compiler.d.ts +5 -1
  107. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
  108. package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
  109. package/dist/features/magic-context/storage-db.d.ts +1 -1
  110. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  111. package/dist/features/magic-context/storage-historian-runs.d.ts +4 -2
  112. package/dist/features/magic-context/storage-historian-runs.d.ts.map +1 -1
  113. package/dist/features/magic-context/storage-meta-persisted.d.ts +16 -2
  114. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  115. package/dist/features/magic-context/storage-meta-shared.d.ts +1 -1
  116. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  117. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  118. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  119. package/dist/features/magic-context/storage-notes.d.ts +1 -0
  120. package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
  121. package/dist/features/magic-context/storage-replay-document.d.ts +2 -0
  122. package/dist/features/magic-context/storage-replay-document.d.ts.map +1 -1
  123. package/dist/features/magic-context/storage-subagent-invocations.d.ts +1 -1
  124. package/dist/features/magic-context/storage-subagent-invocations.d.ts.map +1 -1
  125. package/dist/features/magic-context/storage-tags.d.ts +42 -4
  126. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  127. package/dist/features/magic-context/storage.d.ts +2 -2
  128. package/dist/features/magic-context/storage.d.ts.map +1 -1
  129. package/dist/features/magic-context/store-generation-rebase.d.ts +95 -0
  130. package/dist/features/magic-context/store-generation-rebase.d.ts.map +1 -0
  131. package/dist/features/magic-context/subagent-token-capture.d.ts +1 -0
  132. package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -1
  133. package/dist/features/magic-context/tagger.d.ts +2 -0
  134. package/dist/features/magic-context/tagger.d.ts.map +1 -1
  135. package/dist/features/magic-context/tool-definition-tokens.d.ts +1 -0
  136. package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
  137. package/dist/features/magic-context/tool-owner-backfill.d.ts.map +1 -1
  138. package/dist/features/magic-context/user-memory/review-user-memories.d.ts +5 -1
  139. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
  140. package/dist/hooks/magic-context/apply-operations.d.ts +10 -1
  141. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  142. package/dist/hooks/magic-context/cache-busting-signals.d.ts +19 -3
  143. package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
  144. package/dist/hooks/magic-context/command-handler.d.ts +5 -4
  145. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  146. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  147. package/dist/hooks/magic-context/compaction-off-transition.d.ts +1 -0
  148. package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -1
  149. package/dist/hooks/magic-context/compartment-prompt.d.ts +1 -1
  150. package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
  151. package/dist/hooks/magic-context/compartment-render-epoch.d.ts +3 -1
  152. package/dist/hooks/magic-context/compartment-render-epoch.d.ts.map +1 -1
  153. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts +1 -1
  154. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts.map +1 -1
  155. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +1 -0
  156. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  157. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +8 -1
  158. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  159. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  160. package/dist/hooks/magic-context/compartment-runner-types.d.ts +19 -11
  161. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  162. package/dist/hooks/magic-context/compartment-runner-validation.d.ts +4 -1
  163. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  164. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
  165. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  166. package/dist/hooks/magic-context/decay-render.d.ts +1 -0
  167. package/dist/hooks/magic-context/decay-render.d.ts.map +1 -1
  168. package/dist/hooks/magic-context/decision-calibration.d.ts +24 -0
  169. package/dist/hooks/magic-context/decision-calibration.d.ts.map +1 -0
  170. package/dist/hooks/magic-context/derive-budgets.d.ts +2 -0
  171. package/dist/hooks/magic-context/derive-budgets.d.ts.map +1 -1
  172. package/dist/hooks/magic-context/dropped-input-guard.d.ts +50 -4
  173. package/dist/hooks/magic-context/dropped-input-guard.d.ts.map +1 -1
  174. package/dist/hooks/magic-context/embed-history-runner.d.ts +30 -0
  175. package/dist/hooks/magic-context/embed-history-runner.d.ts.map +1 -0
  176. package/dist/hooks/magic-context/emergency-drop.d.ts +13 -8
  177. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  178. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  179. package/dist/hooks/magic-context/event-payloads.d.ts +2 -1
  180. package/dist/hooks/magic-context/event-payloads.d.ts.map +1 -1
  181. package/dist/hooks/magic-context/execute-status.d.ts +2 -1
  182. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
  183. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +12 -4
  184. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  185. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  186. package/dist/hooks/magic-context/historian-no-fire-cause.d.ts +5 -0
  187. package/dist/hooks/magic-context/historian-no-fire-cause.d.ts.map +1 -0
  188. package/dist/hooks/magic-context/historian-publish-stage-logger.d.ts +3 -0
  189. package/dist/hooks/magic-context/historian-publish-stage-logger.d.ts.map +1 -0
  190. package/dist/hooks/magic-context/hook-handlers.d.ts +0 -3
  191. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  192. package/dist/hooks/magic-context/hook.d.ts +4 -4
  193. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  194. package/dist/hooks/magic-context/host-served-rows.d.ts +58 -0
  195. package/dist/hooks/magic-context/host-served-rows.d.ts.map +1 -0
  196. package/dist/hooks/magic-context/inject-compartments.d.ts +38 -0
  197. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  198. package/dist/hooks/magic-context/legacy-compartments.d.ts +20 -0
  199. package/dist/hooks/magic-context/legacy-compartments.d.ts.map +1 -0
  200. package/dist/hooks/magic-context/live-session-state.d.ts +7 -7
  201. package/dist/hooks/magic-context/m0-token-breakdown.d.ts +6 -0
  202. package/dist/hooks/magic-context/m0-token-breakdown.d.ts.map +1 -1
  203. package/dist/hooks/magic-context/maintenance-authority.d.ts +0 -1
  204. package/dist/hooks/magic-context/maintenance-authority.d.ts.map +1 -1
  205. package/dist/hooks/magic-context/module-state-sync.d.ts +1 -1
  206. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  207. package/dist/hooks/magic-context/module-transport.d.ts +1 -1
  208. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  209. package/dist/hooks/magic-context/module-wire.d.ts +42 -0
  210. package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
  211. package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
  212. package/dist/hooks/magic-context/postprocess-read-cache.d.ts +8 -0
  213. package/dist/hooks/magic-context/postprocess-read-cache.d.ts.map +1 -0
  214. package/dist/hooks/magic-context/producer-window-guard.d.ts +16 -0
  215. package/dist/hooks/magic-context/producer-window-guard.d.ts.map +1 -1
  216. package/dist/hooks/magic-context/producer-window-test-support.d.ts +14 -0
  217. package/dist/hooks/magic-context/producer-window-test-support.d.ts.map +1 -0
  218. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +2 -0
  219. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  220. package/dist/hooks/magic-context/read-session-chunk.d.ts +45 -10
  221. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  222. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  223. package/dist/hooks/magic-context/read-session-raw.d.ts +4 -0
  224. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  225. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts +6 -0
  226. package/dist/hooks/magic-context/read-session-true-raw-tokens.d.ts.map +1 -1
  227. package/dist/hooks/magic-context/recomp-orchestrator.d.ts +17 -39
  228. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  229. package/dist/hooks/magic-context/rust-mode-transform.d.ts +24 -3
  230. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  231. package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
  232. package/dist/hooks/magic-context/system-prompt-hash.d.ts +6 -7
  233. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  234. package/dist/hooks/magic-context/tag-messages.d.ts +21 -1
  235. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  236. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +63 -0
  237. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  238. package/dist/hooks/magic-context/tokenizer-calibration.d.ts +19 -12
  239. package/dist/hooks/magic-context/tokenizer-calibration.d.ts.map +1 -1
  240. package/dist/hooks/magic-context/tool-drop-target.d.ts +52 -1
  241. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  242. package/dist/hooks/magic-context/tool-sweep-policy.d.ts +50 -0
  243. package/dist/hooks/magic-context/tool-sweep-policy.d.ts.map +1 -0
  244. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +20 -1
  245. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  246. package/dist/hooks/magic-context/transform-context-state.d.ts +9 -0
  247. package/dist/hooks/magic-context/transform-context-state.d.ts.map +1 -1
  248. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +5 -3
  249. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  250. package/dist/hooks/magic-context/transform.d.ts +37 -4
  251. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  252. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  253. package/dist/{index-f9gem5cr.js → index-8w1skpnm.js} +85 -5
  254. package/dist/index-99sfbrrf.js +170 -0
  255. package/dist/index-9skq8m9y.js +16 -0
  256. package/dist/{index-djp6rwz6.js → index-d0dh7v0f.js} +28130 -30282
  257. package/dist/{index-s61hh7gv.js → index-rpz2me0v.js} +94 -72
  258. package/dist/{index-ngjmj6xx.js → index-rvwvdq59.js} +1 -1
  259. package/dist/index-w2ety11c.js +393 -0
  260. package/dist/index-y5145x8k.js +619 -0
  261. package/dist/index-ygwdyntq.js +5407 -0
  262. package/dist/{index-a9ssj59b.js → index-ykg9sdzz.js} +55 -15
  263. package/dist/index.d.ts.map +1 -1
  264. package/dist/index.js +5749 -3006
  265. package/dist/message-time-backfill-gzjer78y.js +108 -0
  266. package/dist/plugin/dream-timer.d.ts +13 -0
  267. package/dist/plugin/dream-timer.d.ts.map +1 -1
  268. package/dist/plugin/hooks/create-session-hooks.d.ts +5 -2
  269. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  270. package/dist/plugin/memory-id-translation.d.ts +86 -0
  271. package/dist/plugin/memory-id-translation.d.ts.map +1 -1
  272. package/dist/plugin/messages-transform.d.ts.map +1 -1
  273. package/dist/plugin/rpc-handlers.d.ts +10 -0
  274. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  275. package/dist/plugin/rust-note-backend.d.ts +84 -0
  276. package/dist/plugin/rust-note-backend.d.ts.map +1 -0
  277. package/dist/plugin/tool-registry.d.ts +1 -0
  278. package/dist/plugin/tool-registry.d.ts.map +1 -1
  279. package/dist/read-session-chunk-ec3jkvhg.js +61 -0
  280. package/dist/{recomp-orchestrator-0xx1364v.js → recomp-orchestrator-6akjp11f.js} +8 -8
  281. package/dist/{send-session-notification-jbxknvar.js → send-session-notification-f6gwkesy.js} +2 -2
  282. package/dist/shared/assistant-message-extractor.d.ts +6 -0
  283. package/dist/shared/assistant-message-extractor.d.ts.map +1 -1
  284. package/dist/shared/conflict-detector.d.ts +9 -4
  285. package/dist/shared/conflict-detector.d.ts.map +1 -1
  286. package/dist/shared/hidden-variant-warnings.d.ts +5 -0
  287. package/dist/shared/hidden-variant-warnings.d.ts.map +1 -0
  288. package/dist/shared/host-limitations.d.ts +14 -0
  289. package/dist/shared/host-limitations.d.ts.map +1 -0
  290. package/dist/shared/keep-subagents.d.ts +1 -1
  291. package/dist/shared/keep-subagents.d.ts.map +1 -1
  292. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  293. package/dist/shared/models-dev-cache.d.ts +1 -0
  294. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  295. package/dist/shared/opencode-config-dir.d.ts +52 -0
  296. package/dist/shared/opencode-config-dir.d.ts.map +1 -1
  297. package/dist/shared/opencode-db-path.d.ts +15 -0
  298. package/dist/shared/opencode-db-path.d.ts.map +1 -1
  299. package/dist/shared/prompt-surface-runtime.d.ts +5 -5
  300. package/dist/shared/rpc-server.d.ts +10 -0
  301. package/dist/shared/rpc-server.d.ts.map +1 -1
  302. package/dist/shared/rpc-types.d.ts +64 -5
  303. package/dist/shared/rpc-types.d.ts.map +1 -1
  304. package/dist/shared/status-detail-text.d.ts +1 -3
  305. package/dist/shared/status-detail-text.d.ts.map +1 -1
  306. package/dist/shared/status-summary.d.ts +7 -0
  307. package/dist/shared/status-summary.d.ts.map +1 -1
  308. package/dist/shared/status-view.d.ts +229 -0
  309. package/dist/shared/status-view.d.ts.map +1 -0
  310. package/dist/shared/tag-transcript.d.ts.map +1 -1
  311. package/dist/shared/tail-hygiene-status.d.ts +8 -0
  312. package/dist/shared/tail-hygiene-status.d.ts.map +1 -1
  313. package/dist/shared/user-facing-codes.d.ts +32 -7
  314. package/dist/shared/user-facing-codes.d.ts.map +1 -1
  315. package/dist/shared/window-geometry.d.ts +3 -0
  316. package/dist/shared/window-geometry.d.ts.map +1 -1
  317. package/dist/{task-config-cv8k9y8r.js → task-config-ex4nt0q0.js} +1 -1
  318. package/dist/tools/ctx-expand/constants.d.ts +1 -1
  319. package/dist/tools/ctx-expand/constants.d.ts.map +1 -1
  320. package/dist/tools/ctx-expand/render.d.ts.map +1 -1
  321. package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
  322. package/dist/tools/ctx-memory/constants.d.ts +3 -1
  323. package/dist/tools/ctx-memory/constants.d.ts.map +1 -1
  324. package/dist/tools/ctx-memory/tools.d.ts +1 -0
  325. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  326. package/dist/tools/ctx-memory/types.d.ts +2 -2
  327. package/dist/tools/ctx-note/constants.d.ts +1 -1
  328. package/dist/tools/ctx-note/constants.d.ts.map +1 -1
  329. package/dist/tools/ctx-note/render.d.ts +88 -0
  330. package/dist/tools/ctx-note/render.d.ts.map +1 -0
  331. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  332. package/dist/tools/ctx-reduce/constants.d.ts +1 -1
  333. package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
  334. package/dist/tools/ctx-search/constants.d.ts +1 -1
  335. package/dist/tools/ctx-search/constants.d.ts.map +1 -1
  336. package/dist/tools/ctx-search/date-range.d.ts +9 -0
  337. package/dist/tools/ctx-search/date-range.d.ts.map +1 -0
  338. package/dist/tools/ctx-search/tools.d.ts.map +1 -1
  339. package/dist/tools/ctx-search/types.d.ts +2 -0
  340. package/dist/tools/ctx-search/types.d.ts.map +1 -1
  341. package/dist/tools/light-descriptions.d.ts +5 -5
  342. package/dist/tools/light-descriptions.d.ts.map +1 -1
  343. package/dist/tools/parameter-descriptions.d.ts +75 -0
  344. package/dist/tools/parameter-descriptions.d.ts.map +1 -0
  345. package/dist/transformers-node-wasm.js +1918 -826
  346. package/dist/transformers-web.js +1736 -636
  347. package/dist/{transformers.node-dpmf3wpx.js → transformers.node-3zqr6k1w.js} +4087 -2898
  348. package/dist/tui/data/context-db.d.ts +19 -7
  349. package/dist/tui/data/context-db.d.ts.map +1 -1
  350. package/dist/tui-compiled/data/context-db.d.ts +19 -7
  351. package/dist/tui-compiled/data/context-db.d.ts.map +1 -1
  352. package/dist/v2/fold/host-media.d.ts +36 -0
  353. package/dist/v2/fold/host-media.d.ts.map +1 -0
  354. package/dist/v2/fold/restore.d.ts +21 -1
  355. package/dist/v2/fold/restore.d.ts.map +1 -1
  356. package/dist/v2/hidden-completion.d.ts +45 -1
  357. package/dist/v2/hidden-completion.d.ts.map +1 -1
  358. package/dist/v2/hooks/commands.d.ts +29 -0
  359. package/dist/v2/hooks/commands.d.ts.map +1 -0
  360. package/dist/v2/hooks/context.d.ts +46 -2
  361. package/dist/v2/hooks/context.d.ts.map +1 -1
  362. package/dist/v2/hooks/deleted-session-tombstones.d.ts +10 -0
  363. package/dist/v2/hooks/deleted-session-tombstones.d.ts.map +1 -0
  364. package/dist/v2/hooks/dream-manual.d.ts +43 -0
  365. package/dist/v2/hooks/dream-manual.d.ts.map +1 -0
  366. package/dist/v2/hooks/dream-trigger.d.ts +7 -0
  367. package/dist/v2/hooks/dream-trigger.d.ts.map +1 -1
  368. package/dist/v2/hooks/hidden-child.d.ts +1 -0
  369. package/dist/v2/hooks/hidden-child.d.ts.map +1 -1
  370. package/dist/v2/hooks/model-limit-cache.d.ts +19 -0
  371. package/dist/v2/hooks/model-limit-cache.d.ts.map +1 -0
  372. package/dist/v2/hooks/payload.d.ts.map +1 -1
  373. package/dist/v2/hooks/provider-admission.d.ts +22 -0
  374. package/dist/v2/hooks/provider-admission.d.ts.map +1 -0
  375. package/dist/v2/hooks/rpc-live-state.d.ts +9 -0
  376. package/dist/v2/hooks/rpc-live-state.d.ts.map +1 -0
  377. package/dist/v2/hooks/store.d.ts +38 -2
  378. package/dist/v2/hooks/store.d.ts.map +1 -1
  379. package/dist/v2/hooks/tools.d.ts +8 -0
  380. package/dist/v2/hooks/tools.d.ts.map +1 -0
  381. package/dist/v2/hooks/types.d.ts +58 -0
  382. package/dist/v2/hooks/types.d.ts.map +1 -1
  383. package/dist/v2/hooks/usage-reading.d.ts +42 -0
  384. package/dist/v2/hooks/usage-reading.d.ts.map +1 -0
  385. package/dist/v2/host-service.d.ts +65 -0
  386. package/dist/v2/host-service.d.ts.map +1 -0
  387. package/dist/v2/server.js +141678 -111890
  388. package/dist/v2/store-reader.d.ts +67 -1
  389. package/dist/v2/store-reader.d.ts.map +1 -1
  390. package/dist/v2/tui/events.d.ts +7 -0
  391. package/dist/v2/tui/events.d.ts.map +1 -0
  392. package/dist/v2/tui/index.d.ts +23 -0
  393. package/dist/v2/tui/index.d.ts.map +1 -1
  394. package/dist/v2/tui/sidebar-mount.d.ts +40 -0
  395. package/dist/v2/tui/sidebar-mount.d.ts.map +1 -0
  396. package/dist/v2/tui/status-dialog-mount.d.ts +29 -0
  397. package/dist/v2/tui/status-dialog-mount.d.ts.map +1 -0
  398. package/dist/v2/tui/types.d.ts +74 -6
  399. package/dist/v2/tui/types.d.ts.map +1 -1
  400. package/dist/wrapup-orchestrator-5akc87gr.js +16 -0
  401. package/package.json +8 -7
  402. package/src/agents/dreamer.ts +7 -16
  403. package/src/agents/hidden-agent-registrations.ts +10 -22
  404. package/src/agents/magic-context-prompt.test.ts +29 -39
  405. package/src/agents/magic-context-prompt.ts +99 -122
  406. package/src/agents/permissions.test.ts +17 -21
  407. package/src/config/index.ts +8 -3
  408. package/src/config/live-run-config.test.ts +237 -0
  409. package/src/config/live-run-config.ts +80 -0
  410. package/src/config/live-schema-drift.test.ts +67 -0
  411. package/src/config/live-snapshot.test.ts +85 -0
  412. package/src/config/live-snapshot.ts +191 -0
  413. package/src/config/raw-loader.test.ts +1 -0
  414. package/src/config/schema/magic-context.test.ts +13 -5
  415. package/src/config/schema/magic-context.ts +101 -10
  416. package/src/features/magic-context/dreamer/task-registry.ts +137 -13
  417. package/src/shared/assistant-message-extractor.test.ts +21 -0
  418. package/src/shared/assistant-message-extractor.ts +43 -8
  419. package/src/shared/child-session-teardown.test.ts +38 -3
  420. package/src/shared/child-session-teardown.ts +3 -3
  421. package/src/shared/conflict-detector.test.ts +224 -7
  422. package/src/shared/conflict-detector.ts +161 -89
  423. package/src/shared/hidden-variant-warnings.ts +21 -0
  424. package/src/shared/host-limitations.ts +43 -0
  425. package/src/shared/keep-subagents.ts +6 -6
  426. package/src/shared/model-suggestion-retry.test.ts +43 -0
  427. package/src/shared/model-suggestion-retry.ts +12 -0
  428. package/src/shared/models-dev-cache.ts +5 -0
  429. package/src/shared/opencode-config-dir.ts +80 -7
  430. package/src/shared/opencode-db-path.test.ts +78 -0
  431. package/src/shared/opencode-db-path.ts +49 -2
  432. package/src/shared/opencode-host-generation.test.ts +29 -0
  433. package/src/shared/prompt-surface-a1-golden.md +142 -211
  434. package/src/shared/rpc-server.ts +18 -0
  435. package/src/shared/rpc-types.ts +63 -4
  436. package/src/shared/status-detail-text.test.ts +52 -18
  437. package/src/shared/status-detail-text.ts +1 -90
  438. package/src/shared/status-summary.ts +37 -2
  439. package/src/shared/status-view.test.ts +441 -0
  440. package/src/shared/status-view.ts +707 -0
  441. package/src/shared/tag-transcript.ts +115 -16
  442. package/src/shared/tail-hygiene-status.ts +9 -1
  443. package/src/shared/user-facing-codes.test.ts +3 -4
  444. package/src/shared/user-facing-codes.ts +33 -8
  445. package/src/shared/window-geometry.test.ts +23 -5
  446. package/src/shared/window-geometry.ts +13 -3
  447. package/src/tui/data/context-db.ts +50 -15
  448. package/src/tui/dialogs/status-dialog-colors.test.ts +58 -0
  449. package/src/tui/dialogs/status-dialog.tsx +288 -0
  450. package/src/tui/index.tsx +7 -464
  451. package/src/tui/slots/sidebar-content.tsx +21 -5
  452. package/src/tui-compiled/data/context-db.ts +50 -15
  453. package/src/tui-compiled/dialogs/status-dialog.tsx +552 -0
  454. package/src/tui-compiled/index.tsx +43 -1025
  455. package/src/tui-compiled/slots/sidebar-content.tsx +173 -152
  456. package/src/v2/tui/__fixtures__/ga-host-theme.json +160 -0
  457. package/src/v2/tui/events.ts +23 -0
  458. package/src/v2/tui/host-contract.test.ts +57 -8
  459. package/src/v2/tui/index.ts +315 -59
  460. package/src/v2/tui/load-compiled-sidebar.d.mts +59 -0
  461. package/src/v2/tui/load-compiled-sidebar.mjs +24 -0
  462. package/src/v2/tui/load-compiled-status-dialog.d.mts +17 -0
  463. package/src/v2/tui/load-compiled-status-dialog.mjs +16 -0
  464. package/src/v2/tui/sidebar-fallback.test.ts +100 -0
  465. package/src/v2/tui/sidebar-mount.ts +164 -0
  466. package/src/v2/tui/sidebar-text.test.ts +70 -0
  467. package/src/v2/tui/status-dialog-fallback.test.ts +97 -0
  468. package/src/v2/tui/status-dialog-mount.ts +76 -0
  469. package/src/v2/tui/theme-mapping.test.ts +57 -0
  470. package/src/v2/tui/types.ts +69 -4
  471. package/tui.js +1 -0
  472. package/dist/features/magic-context/memory/memory-migration.d.ts +0 -129
  473. package/dist/features/magic-context/memory/memory-migration.d.ts.map +0 -1
  474. package/dist/hooks/magic-context/upgrade-reminder.d.ts +0 -76
  475. package/dist/hooks/magic-context/upgrade-reminder.d.ts.map +0 -1
  476. package/dist/index-4wwr6cz0.js +0 -112
  477. package/dist/index-avwt563y.js +0 -62
  478. package/dist/index-znraa0kv.js +0 -637
  479. package/dist/storage-meta-session-z818pn1e.js +0 -20
@@ -552,10 +552,14 @@ describe("detectConflicts", () => {
552
552
  }
553
553
  }
554
554
 
555
- it("resolved auto=false + file layer that would default true → NO conflict (#309)", () => {
556
- // No compaction block in any file + no env override → the file-based
557
- // arm would default to auto=true and wrongly disable the plugin.
558
- // The resolved arm says auto=false, which must win.
555
+ it("resolved auto=false outranks a file layer that says auto=true (#309)", () => {
556
+ // The file layer says auto=true, which on its own disables the
557
+ // plugin. The host's resolved config says auto=false, and the host
558
+ // is the authority — it can see layers the file reader cannot.
559
+ writeFileSync(
560
+ join(projectDir, "opencode.json"),
561
+ JSON.stringify({ compaction: { auto: true } }),
562
+ );
559
563
  withoutAutoCompactEnv(() => {
560
564
  const result = detectConflicts(projectDir, {
561
565
  compactionEnabled: true,
@@ -592,8 +596,17 @@ describe("detectConflicts", () => {
592
596
  });
593
597
 
594
598
  it("resolved arm is skipped when resolvedCompaction is absent (file-based fallback unchanged)", () => {
595
- // No resolvedCompaction → the file-based check runs. With no
596
- // compaction block and no env override, it defaults to auto=true.
599
+ // No resolvedCompaction → the file-based check runs and owns the
600
+ // verdict. The written block is what makes the file arm say
601
+ // auto=true; it used to be an absent block relying on the file
602
+ // arm's default-on, which issue #484 removed because an absent
603
+ // block cannot tell "the user wrote nothing" apart from "we read
604
+ // the wrong directory". The claim under test is unchanged: with no
605
+ // resolved value the file arm decides, and its reason is unlabeled.
606
+ writeFileSync(
607
+ join(projectDir, "opencode.json"),
608
+ JSON.stringify({ compaction: { auto: true } }),
609
+ );
597
610
  withoutAutoCompactEnv(() => {
598
611
  const result = detectConflicts(projectDir, { compactionEnabled: true });
599
612
  expect(result.conflicts.compactionAuto).toBe(true);
@@ -635,6 +648,166 @@ describe("detectConflicts", () => {
635
648
  });
636
649
  });
637
650
 
651
+ // --- OPENCODE_CONFIG_DIR is an ADDITION, not a replacement (issue #484) ---
652
+ //
653
+ // A launcher (Orca) exported OPENCODE_CONFIG_DIR to a directory holding
654
+ // only plugin scaffolding. OpenCode kept reading the user's real global
655
+ // config — `opencode debug config` showed compaction.auto=false — but the
656
+ // detector resolved the env directory INSTEAD of the global one, found no
657
+ // file, fell through to its default-on, and disabled the plugin.
658
+ //
659
+ // Verified against the opencode 1.18.30 binary and on a live host:
660
+ // `$XDG_CONFIG_HOME/opencode` is always read; `~/.opencode` is always
661
+ // scanned; `$OPENCODE_CONFIG_DIR` is appended LAST, so it wins ties but
662
+ // never hides the layers below it.
663
+ describe("OPENCODE_CONFIG_DIR is additive, not a replacement (issue #484)", () => {
664
+ let globalDir: string;
665
+ let launcherDir: string;
666
+
667
+ beforeEach(() => {
668
+ // These cases exercise compaction detection itself, so the suite's
669
+ // isolation env var has to go.
670
+ delete process.env.OPENCODE_DISABLE_AUTOCOMPACT;
671
+ // HOME is the temp dir and XDG_CONFIG_HOME is cleared by the suite
672
+ // beforeEach, so this is the same path OpenCode would compute.
673
+ globalDir = join(homeDir, ".config", "opencode");
674
+ mkdirSync(globalDir, { recursive: true });
675
+ // The reporter's launcher directory: plugin scaffolding, no config.
676
+ launcherDir = join(root, "launcher-config-dir");
677
+ mkdirSync(launcherDir, { recursive: true });
678
+ writeFileSync(
679
+ join(launcherDir, "package.json"),
680
+ JSON.stringify({ name: "launcher-scaffold", version: "1.0.0" }),
681
+ );
682
+ process.env.OPENCODE_CONFIG_DIR = launcherDir;
683
+ });
684
+
685
+ afterEach(() => {
686
+ delete process.env.OPENCODE_CONFIG;
687
+ });
688
+
689
+ function writeCompaction(dir: string, file: string, compaction: unknown): void {
690
+ mkdirSync(dir, { recursive: true });
691
+ writeFileSync(join(dir, file), JSON.stringify({ compaction }));
692
+ }
693
+
694
+ it("reporter repro: global auto=false + config-less OPENCODE_CONFIG_DIR → no conflict", () => {
695
+ writeCompaction(globalDir, "opencode.json", { auto: false });
696
+ const result = detectConflicts(projectDir, { compactionEnabled: true });
697
+ expect(result.conflicts.compactionAuto).toBe(false);
698
+ expect(result.hasConflict).toBe(false);
699
+ expect(result.nativeCompaction.auto).toBe(false);
700
+ });
701
+
702
+ it("positive control: global auto=true still reports the conflict", () => {
703
+ writeCompaction(globalDir, "opencode.json", { auto: true });
704
+ const result = detectConflicts(projectDir, { compactionEnabled: true });
705
+ expect(result.conflicts.compactionAuto).toBe(true);
706
+ expect(result.hasConflict).toBe(true);
707
+ expect(result.reasons.join("; ")).toContain("compaction.auto=true");
708
+ });
709
+
710
+ it("an OPENCODE_CONFIG_DIR that DOES carry auto=true outranks a global auto=false", () => {
711
+ writeCompaction(globalDir, "opencode.json", { auto: false });
712
+ writeCompaction(launcherDir, "opencode.json", { auto: true });
713
+ const result = detectConflicts(projectDir, { compactionEnabled: true });
714
+ expect(result.conflicts.compactionAuto).toBe(true);
715
+ expect(result.hasConflict).toBe(true);
716
+ });
717
+
718
+ it("an OPENCODE_CONFIG_DIR auto=false outranks a global auto=true", () => {
719
+ writeCompaction(globalDir, "opencode.json", { auto: true });
720
+ writeCompaction(launcherDir, "opencode.jsonc", { auto: false });
721
+ const result = detectConflicts(projectDir, { compactionEnabled: true });
722
+ expect(result.conflicts.compactionAuto).toBe(false);
723
+ expect(result.hasConflict).toBe(false);
724
+ });
725
+
726
+ it("v1 keeps global supplementary config above the project .opencode overlay", () => {
727
+ writeCompaction(launcherDir, "opencode.json", { auto: false });
728
+ writeCompaction(join(projectDir, ".opencode"), "opencode.json", { auto: true });
729
+ const result = detectConflicts(projectDir, {
730
+ compactionEnabled: true,
731
+ hostGeneration: "v1",
732
+ });
733
+ expect(result.nativeCompaction.auto).toBe(false);
734
+ expect(result.conflicts.compactionAuto).toBe(false);
735
+ });
736
+
737
+ it("v2 ranks the project .opencode overlay above global supplementary config", () => {
738
+ writeCompaction(launcherDir, "opencode.json", { auto: false });
739
+ writeCompaction(join(projectDir, ".opencode"), "opencode.json", { auto: true });
740
+ const result = detectConflicts(projectDir, {
741
+ compactionEnabled: true,
742
+ hostGeneration: "v2",
743
+ });
744
+ expect(result.nativeCompaction.auto).toBe(true);
745
+ expect(result.conflicts.compactionAuto).toBe(false);
746
+ });
747
+
748
+ it("reads the global directory's legacy config.json layer", () => {
749
+ writeCompaction(globalDir, "config.json", { auto: true });
750
+ const result = detectConflicts(projectDir, { compactionEnabled: true });
751
+ expect(result.conflicts.compactionAuto).toBe(true);
752
+ });
753
+
754
+ it("global opencode.jsonc overrides global opencode.json", () => {
755
+ writeCompaction(globalDir, "opencode.json", { auto: true });
756
+ writeCompaction(globalDir, "opencode.jsonc", { auto: false });
757
+ const result = detectConflicts(projectDir, { compactionEnabled: true });
758
+ expect(result.conflicts.compactionAuto).toBe(false);
759
+ expect(result.hasConflict).toBe(false);
760
+ });
761
+
762
+ it("~/.opencode outranks the global config directory", () => {
763
+ writeCompaction(globalDir, "opencode.json", { auto: false });
764
+ writeCompaction(join(homeDir, ".opencode"), "opencode.json", { auto: true });
765
+ const result = detectConflicts(projectDir, { compactionEnabled: true });
766
+ expect(result.conflicts.compactionAuto).toBe(true);
767
+ });
768
+
769
+ it("reads the $OPENCODE_CONFIG single-file override", () => {
770
+ const explicit = join(root, "explicit-opencode.json");
771
+ writeFileSync(explicit, JSON.stringify({ compaction: { auto: true } }));
772
+ process.env.OPENCODE_CONFIG = explicit;
773
+ const result = detectConflicts(projectDir, { compactionEnabled: true });
774
+ expect(result.conflicts.compactionAuto).toBe(true);
775
+ });
776
+
777
+ it("merges keys across layers instead of letting one file erase the other", () => {
778
+ writeCompaction(globalDir, "opencode.json", { auto: false });
779
+ writeCompaction(projectDir, "opencode.json", { prune: true });
780
+ const result = detectConflicts(projectDir, { compactionEnabled: true });
781
+ expect(result.nativeCompaction.auto).toBe(false);
782
+ expect(result.nativeCompaction.prune).toBe(true);
783
+ expect(result.conflicts.compactionAuto).toBe(false);
784
+ expect(result.conflicts.compactionPrune).toBe(true);
785
+ });
786
+
787
+ it("no compaction key in any readable layer is inconclusive, never a disable", () => {
788
+ // Nothing anywhere. OpenCode's own default is auto=true, but we
789
+ // cannot tell "the user wrote nothing" from "the value lives in a
790
+ // layer we cannot read" (managed/enterprise config, an org layer,
791
+ // a file we failed to parse). Guessing the disabling direction
792
+ // leaves NOTHING managing the window — the unrecoverable failure
793
+ // issue #309 established for the resolved arm.
794
+ const result = detectConflicts(projectDir, { compactionEnabled: true });
795
+ expect(result.conflicts.compactionAuto).toBe(false);
796
+ expect(result.conflicts.compactionPrune).toBe(false);
797
+ expect(result.hasConflict).toBe(false);
798
+ expect(result.nativeCompaction.auto).toBe(false);
799
+ });
800
+
801
+ it("still finds a conflicting plugin declared in the global config", () => {
802
+ writeFileSync(
803
+ join(globalDir, "opencode.json"),
804
+ JSON.stringify({ plugin: ["@tarquinen/opencode-dcp"] }),
805
+ );
806
+ const result = detectConflicts(projectDir, { compactionEnabled: true });
807
+ expect(result.conflicts.dcpPlugin).toBe(true);
808
+ });
809
+ });
810
+
638
811
  // --- resolveCompactionForBoot (the resolved-config fetch helper) ---
639
812
  describe("resolveCompactionForBoot", () => {
640
813
  it("returns the resolved compaction block from the client", async () => {
@@ -649,6 +822,40 @@ describe("detectConflicts", () => {
649
822
  expect(result).toEqual({ auto: false, prune: true });
650
823
  });
651
824
 
825
+ it("resolves a host block that carries only compaction.auto (issue #484)", async () => {
826
+ // The shape opencode 1.18.30 actually serves for the ordinary
827
+ // `"compaction": { "auto": false }` config: OpenCode merges only
828
+ // the keys the user wrote and never materialises schema defaults,
829
+ // so `prune` is simply absent. Requiring it here used to reject
830
+ // this block and hand the decision to the file arm.
831
+ const client = {
832
+ config: {
833
+ get: async () => ({ data: { compaction: { auto: false } } }),
834
+ },
835
+ };
836
+ const result = await resolveCompactionForBoot(client);
837
+ expect(result).toEqual({ auto: false, prune: false });
838
+ });
839
+
840
+ it("resolves auto=true without prune and keeps it a conflict", async () => {
841
+ const client = {
842
+ config: {
843
+ get: async () => ({ data: { compaction: { auto: true } } }),
844
+ },
845
+ };
846
+ const resolved = await resolveCompactionForBoot(client);
847
+ expect(resolved).toEqual({ auto: true, prune: false });
848
+ // The suite beforeEach sets OPENCODE_DISABLE_AUTOCOMPACT, which
849
+ // short-circuits both arms; this case is about the verdict.
850
+ delete process.env.OPENCODE_DISABLE_AUTOCOMPACT;
851
+ const result = detectConflicts(projectDir, {
852
+ compactionEnabled: true,
853
+ resolvedCompaction: resolved ?? undefined,
854
+ });
855
+ expect(result.conflicts.compactionAuto).toBe(true);
856
+ expect(result.reasons.join("; ")).toContain("(resolved config)");
857
+ });
858
+
652
859
  it("returns null when the compaction block is absent (file-based fallback, not host defaults)", async () => {
653
860
  // An absent block means the response shape did not carry the resolved
654
861
  // state (server version drift, a fetch racing boot) — NOT that the
@@ -665,7 +872,7 @@ describe("detectConflicts", () => {
665
872
  expect(result).toBeNull();
666
873
  });
667
874
 
668
- it("returns null when compaction values are not explicit booleans", async () => {
875
+ it("returns null when compaction.auto is not an explicit boolean", async () => {
669
876
  const client = {
670
877
  config: {
671
878
  get: async () => ({ data: { compaction: { auto: "true", prune: null } } }),
@@ -675,6 +882,16 @@ describe("detectConflicts", () => {
675
882
  expect(result).toBeNull();
676
883
  });
677
884
 
885
+ it("treats a non-boolean prune as false rather than discarding an explicit auto", async () => {
886
+ const client = {
887
+ config: {
888
+ get: async () => ({ data: { compaction: { auto: true, prune: "yes" } } }),
889
+ },
890
+ };
891
+ const result = await resolveCompactionForBoot(client);
892
+ expect(result).toEqual({ auto: true, prune: false });
893
+ });
894
+
678
895
  it("returns null when the response data is missing entirely", async () => {
679
896
  const client = {
680
897
  config: {
@@ -2,7 +2,7 @@ import { homedir } from "node:os";
2
2
  import { join } from "node:path";
3
3
  import { readJsoncFile } from "./jsonc-parser";
4
4
  import { log } from "./logger";
5
- import { getOpenCodeConfigPaths } from "./opencode-config-dir";
5
+ import { getOpenCodeConfigDirs, getOpenCodeGlobalConfigDir } from "./opencode-config-dir";
6
6
  import type { OpenCodeHostGeneration } from "./opencode-db-path";
7
7
 
8
8
  interface OpenCodeConfig {
@@ -252,12 +252,17 @@ interface ResolvedCompactionBlock {
252
252
  * `compaction` key, and reading that absence as `auto=true` disables the
253
253
  * plugin — the one wrong direction, because a false disable leaves NOTHING
254
254
  * managing the window and every long session overflows (issue #309, second
255
- * arm). Only an explicit boolean from the host resolves this arm; anything
256
- * else returns `null` so the caller falls back to the file-based check,
257
- * which reads the layers the user actually wrote.
255
+ * arm). Only an explicit `compaction.auto` boolean from the host resolves
256
+ * this arm; anything else returns `null` so the caller falls back to the
257
+ * file-based check, which reads the layers the user actually wrote.
258
+ *
259
+ * `compaction.prune` is read when present and treated as `false` when absent.
260
+ * OpenCode serves only the keys the user wrote, so requiring it here rejected
261
+ * the ordinary `{"compaction": {"auto": false}}` config and sent an
262
+ * answerable question to the file arm (issue #484).
258
263
  *
259
264
  * Returns `null` when the fetch fails, times out (bounded to `timeoutMs` so
260
- * boot never hangs), or serves no explicit compaction block.
265
+ * boot never hangs), or serves no explicit `compaction.auto`.
261
266
  */
262
267
  export async function resolveCompactionForBoot(
263
268
  client: OpencodeConfigClientLike,
@@ -312,16 +317,27 @@ export async function resolveCompactionForBoot(
312
317
  ...(buffer === undefined ? {} : { buffer }),
313
318
  };
314
319
  }
315
- // Explicit booleans only. An absent block (or non-boolean values) means
316
- // the response shape did not carry the resolved state — fall back to the
317
- // file arm rather than resolving to the plugin-disabling default.
318
- if (typeof compaction?.auto !== "boolean" || typeof compaction?.prune !== "boolean") {
320
+ // `compaction.auto` is the value the whole conflict decision turns on,
321
+ // so an explicit boolean for it is required: an absent block means the
322
+ // response did not carry the resolved state, and reading that absence
323
+ // as the host default would disable the plugin (issue #309).
324
+ //
325
+ // `compaction.prune` is NOT required. OpenCode merges only the keys a
326
+ // user actually wrote and does not materialise schema defaults into the
327
+ // resolved config, so the ordinary `{"compaction": {"auto": false}}`
328
+ // setup serves a block with no `prune` key at all — verified against
329
+ // opencode 1.18.30 with `opencode debug config`. Demanding both
330
+ // booleans rejected that every-day shape and pushed the decision onto
331
+ // the file arm, which is how issue #484's reporter reached the file
332
+ // arm at all. An absent `prune` takes OpenCode's documented default of
333
+ // `false`, which is also the non-disabling direction.
334
+ if (typeof compaction?.auto !== "boolean") {
319
335
  log(
320
- `[magic-context] conflict-detector: resolved config carried no explicit compaction block (${JSON.stringify(compaction) ?? "absent"}); falling back to file-based detection`,
336
+ `[magic-context] conflict-detector: resolved config carried no explicit compaction.auto (${JSON.stringify(compaction) ?? "absent"}); falling back to file-based detection`,
321
337
  );
322
338
  return null;
323
339
  }
324
- return { auto: compaction.auto, prune: compaction.prune };
340
+ return { auto: compaction.auto, prune: compaction.prune === true };
325
341
  } catch {
326
342
  return null;
327
343
  } finally {
@@ -337,83 +353,130 @@ function checkCompaction(
337
353
  return { auto: false, prune: false };
338
354
  }
339
355
 
340
- // Check project-level config first (higher precedence)
341
- const projectResult = readProjectCompaction(directory, hostGeneration);
342
- if (projectResult.resolved) return projectResult;
343
-
344
- // Fall back to user-level config
345
- const userResult = readUserCompaction(hostGeneration);
346
- if (userResult.resolved) return userResult;
356
+ const merged = readCompactionFromConfigFiles(directory, hostGeneration);
357
+ if (isRelevantCompactionBlock(merged, hostGeneration)) {
358
+ return resolvedCompactionBlock(merged, hostGeneration);
359
+ }
347
360
 
348
- // Default: OpenCode has compaction enabled by default
349
- return { auto: true, prune: false };
361
+ // Nothing in any file OpenCode reads carried an explicit compaction key.
362
+ // That is INCONCLUSIVE, not "the host default applies", and it must never
363
+ // resolve to the plugin-disabling `auto: true`. We cannot tell "the user
364
+ // wrote nothing" apart from "the user's setting lives somewhere this
365
+ // reader cannot see" — a managed/remote config layer, a directory a
366
+ // launcher pointed us away from, a file we failed to parse. Guessing the
367
+ // disabling direction is the one guess with an unrecoverable cost: the
368
+ // plugin switches off and NOTHING manages the context window, so every
369
+ // long session overflows. Guessing the other way at worst leaves both
370
+ // managers running, which is visible and fixable. Issue #309 established
371
+ // this for the resolved-config arm; issue #484 extends it here after a
372
+ // launcher exporting OPENCODE_CONFIG_DIR to a scaffolding-only directory
373
+ // made this default fire against a user whose global config said
374
+ // auto=false.
375
+ log(
376
+ "[magic-context] conflict-detector: no OpenCode config file carried an explicit compaction block; treating native compaction as inconclusive (not disabling the plugin)",
377
+ );
378
+ return { auto: false, prune: false };
350
379
  }
351
380
 
352
- function readProjectCompaction(
381
+ /**
382
+ * Every readable config file OpenCode merges for this project, ordered from
383
+ * LOWEST to HIGHEST precedence.
384
+ *
385
+ * OpenCode 1.18.30 (`Config.loadInstanceState`) uses:
386
+ *
387
+ * 1. `$XDG_CONFIG_HOME/opencode/` — `config.json`, `opencode.json`, `opencode.jsonc`
388
+ * 2. `$OPENCODE_CONFIG` — the explicit single-file override
389
+ * 3. the project's own `opencode.json` / `opencode.jsonc`
390
+ * 4. the project's `.opencode/` directory
391
+ * 5. `~/.opencode/` and `$OPENCODE_CONFIG_DIR` (see getOpenCodeConfigDirs)
392
+ *
393
+ * OpenCode 2.x orders the corresponding groups as well-known, global
394
+ * supplementary, explicit, direct, then project supplementary. See
395
+ * `packages/core/src/config.ts:220-236` at 7e70f7e1ab. Consequently project
396
+ * `.opencode` files outrank global supplementary directories only on v2.
397
+ *
398
+ * Remote, org, managed-enterprise, and content layers are NOT readable from
399
+ * here. That is why an empty result is inconclusive rather than the host
400
+ * default.
401
+ */
402
+ function openCodeConfigFileChain(
353
403
  directory: string,
354
404
  hostGeneration: OpenCodeHostGeneration,
355
- ): ResolvedCompaction & { resolved: boolean } {
356
- // .opencode/ config has higher precedence
357
- const dotOcJsonc = join(directory, ".opencode", "opencode.jsonc");
358
- const dotOcJson = join(directory, ".opencode", "opencode.json");
359
- const dotOcConfig =
360
- readJsoncFile<OpenCodeConfig>(dotOcJsonc) ?? readJsoncFile<OpenCodeConfig>(dotOcJson);
361
-
362
- if (dotOcConfig?.compaction) {
363
- const c = dotOcConfig.compaction;
364
- if (
365
- c.auto !== undefined ||
366
- (hostGeneration === "v1" && c.prune !== undefined) ||
367
- (hostGeneration === "v2" && (c.keep?.tokens !== undefined || c.buffer !== undefined))
368
- ) {
369
- return resolvedCompactionBlock(c, hostGeneration);
370
- }
371
- }
372
-
373
- // Root-level project config
374
- const rootJsonc = join(directory, "opencode.jsonc");
375
- const rootJson = join(directory, "opencode.json");
376
- const rootConfig =
377
- readJsoncFile<OpenCodeConfig>(rootJsonc) ?? readJsoncFile<OpenCodeConfig>(rootJson);
378
-
379
- if (rootConfig?.compaction) {
380
- const c = rootConfig.compaction;
381
- if (
382
- c.auto !== undefined ||
383
- (hostGeneration === "v1" && c.prune !== undefined) ||
384
- (hostGeneration === "v2" && (c.keep?.tokens !== undefined || c.buffer !== undefined))
385
- ) {
386
- return resolvedCompactionBlock(c, hostGeneration);
387
- }
388
- }
405
+ ): string[] {
406
+ const globalDir = getOpenCodeGlobalConfigDir();
407
+ const wellKnown = [
408
+ join(globalDir, "config.json"),
409
+ join(globalDir, "opencode.json"),
410
+ join(globalDir, "opencode.jsonc"),
411
+ ];
412
+ const globalSupplementary = getOpenCodeConfigDirs()
413
+ .filter((dir) => dir !== globalDir)
414
+ .flatMap((dir) => [join(dir, "opencode.json"), join(dir, "opencode.jsonc")]);
415
+ const explicitConfig = process.env.OPENCODE_CONFIG?.trim();
416
+ const explicit = explicitConfig ? [explicitConfig] : [];
417
+ const direct = [join(directory, "opencode.json"), join(directory, "opencode.jsonc")];
418
+ const projectSupplementary = [
419
+ join(directory, ".opencode", "opencode.json"),
420
+ join(directory, ".opencode", "opencode.jsonc"),
421
+ ];
389
422
 
390
- return { auto: false, prune: false, resolved: false };
423
+ const files =
424
+ hostGeneration === "v2"
425
+ ? [
426
+ ...wellKnown,
427
+ ...globalSupplementary,
428
+ ...explicit,
429
+ ...direct,
430
+ ...projectSupplementary,
431
+ ]
432
+ : [
433
+ ...wellKnown,
434
+ ...explicit,
435
+ ...direct,
436
+ ...projectSupplementary,
437
+ ...globalSupplementary,
438
+ ];
439
+ return [...new Set(files)];
391
440
  }
392
441
 
393
- function readUserCompaction(
394
- hostGeneration: OpenCodeHostGeneration,
395
- ): ResolvedCompaction & { resolved: boolean } {
396
- try {
397
- const paths = getOpenCodeConfigPaths({ binary: "opencode" });
398
- const config =
399
- readJsoncFile<OpenCodeConfig>(paths.configJsonc) ??
400
- readJsoncFile<OpenCodeConfig>(paths.configJson);
442
+ type CompactionBlock = NonNullable<OpenCodeConfig["compaction"]>;
401
443
 
402
- if (config?.compaction) {
403
- const c = config.compaction;
404
- if (
405
- c.auto !== undefined ||
406
- (hostGeneration === "v1" && c.prune !== undefined) ||
407
- (hostGeneration === "v2" &&
408
- (c.keep?.tokens !== undefined || c.buffer !== undefined))
409
- ) {
410
- return resolvedCompactionBlock(c, hostGeneration);
411
- }
444
+ /**
445
+ * Merge the `compaction` blocks of every readable config file, in OpenCode's
446
+ * own precedence order. Merging (rather than taking the first file that has a
447
+ * block) is what OpenCode does, so a global `auto: false` and a project-level
448
+ * `prune: true` both survive instead of one silently erasing the other.
449
+ */
450
+ function readCompactionFromConfigFiles(
451
+ directory: string,
452
+ hostGeneration: OpenCodeHostGeneration,
453
+ ): CompactionBlock {
454
+ const merged: CompactionBlock = {};
455
+ for (const filePath of openCodeConfigFileChain(directory, hostGeneration)) {
456
+ let block: CompactionBlock | undefined;
457
+ try {
458
+ block = readJsoncFile<OpenCodeConfig>(filePath)?.compaction;
459
+ } catch {
460
+ // Intentional: each config read is best-effort. An unreadable file
461
+ // leaves the chain inconclusive rather than failing detection.
412
462
  }
413
- } catch {
414
- // Intentional: config read is best-effort
463
+ if (!block || typeof block !== "object") continue;
464
+ if (block.auto !== undefined) merged.auto = block.auto;
465
+ if (block.prune !== undefined) merged.prune = block.prune;
466
+ if (block.buffer !== undefined) merged.buffer = block.buffer;
467
+ if (block.keep !== undefined) merged.keep = { ...merged.keep, ...block.keep };
415
468
  }
416
- return { auto: false, prune: false, resolved: false };
469
+ return merged;
470
+ }
471
+
472
+ /** Whether a merged block carries any key this host generation acts on. */
473
+ function isRelevantCompactionBlock(
474
+ block: CompactionBlock,
475
+ hostGeneration: OpenCodeHostGeneration,
476
+ ): boolean {
477
+ if (block.auto !== undefined) return true;
478
+ if (hostGeneration === "v1") return block.prune !== undefined;
479
+ return block.keep?.tokens !== undefined || block.buffer !== undefined;
417
480
  }
418
481
 
419
482
  function resolvedCompactionBlock(
@@ -523,12 +586,21 @@ function collectPluginEntries(directory: string): string[] {
523
586
  pushFrom(config?.plugin);
524
587
  }
525
588
 
526
- // User-level config
589
+ // User-level config. Every directory OpenCode reads is searched, not just
590
+ // the one we would write to: a launcher that exports OPENCODE_CONFIG_DIR
591
+ // does not stop OpenCode from loading the plugin list in the user's global
592
+ // config, so a conflicting plugin declared there is still installed.
527
593
  try {
528
- const paths = getOpenCodeConfigPaths({ binary: "opencode" });
529
- for (const configPath of [paths.configJsonc, paths.configJson]) {
530
- const config = readJsoncFile<OpenCodeConfig>(configPath);
531
- pushFrom(config?.plugin);
594
+ const globalDir = getOpenCodeGlobalConfigDir();
595
+ for (const dir of getOpenCodeConfigDirs()) {
596
+ const names =
597
+ dir === globalDir
598
+ ? ["config.json", "opencode.json", "opencode.jsonc"]
599
+ : ["opencode.json", "opencode.jsonc"];
600
+ for (const name of names) {
601
+ const config = readJsoncFile<OpenCodeConfig>(join(dir, name));
602
+ pushFrom(config?.plugin);
603
+ }
532
604
  }
533
605
  } catch {
534
606
  // best-effort
@@ -593,13 +665,13 @@ function readOmoDisabledHooks(directory: string): Set<string> {
593
665
  ];
594
666
 
595
667
  try {
596
- const paths = getOpenCodeConfigPaths({ binary: "opencode" });
597
- for (const name of configNames) {
598
- const configPath = join(paths.configDir, name);
599
- const config = readJsoncFile<OmoConfig>(configPath);
600
- if (config?.disabled_hooks) {
601
- for (const hook of config.disabled_hooks) {
602
- disabled.add(hook);
668
+ for (const dir of getOpenCodeConfigDirs()) {
669
+ for (const name of configNames) {
670
+ const config = readJsoncFile<OmoConfig>(join(dir, name));
671
+ if (config?.disabled_hooks) {
672
+ for (const hook of config.disabled_hooks) {
673
+ disabled.add(hook);
674
+ }
603
675
  }
604
676
  }
605
677
  }
@@ -0,0 +1,21 @@
1
+ const warnings = new Map<string, string>();
2
+
3
+ /** Remember a host catalog mismatch until the process exits so status can show it once. */
4
+ export function recordHiddenVariantWarning(
5
+ providerID: string,
6
+ modelID: string,
7
+ variant: string,
8
+ ): string {
9
+ const key = `${providerID}/${modelID}:${variant}`;
10
+ const message = `variant '${variant}' not offered by ${providerID}/${modelID} on this host; running without it`;
11
+ warnings.set(key, message);
12
+ return message;
13
+ }
14
+
15
+ export function listHiddenVariantWarnings(): string[] {
16
+ return [...warnings.values()];
17
+ }
18
+
19
+ export function clearHiddenVariantWarningsForTest(): void {
20
+ warnings.clear();
21
+ }
@@ -0,0 +1,43 @@
1
+ import { USER_FACING_FAILURES, type UserFacingFailureKey } from "./user-facing-codes";
2
+
3
+ /**
4
+ * Named things the host Magic Context is running in cannot do.
5
+ *
6
+ * A limitation is not a failed operation: it is a capability the current host
7
+ * lacks for as long as this process lives, so every status surface keeps
8
+ * printing it instead of showing it once and forgetting. Each one is an
9
+ * existing MC-* user-facing code, so the status dialog, the plain-text status
10
+ * summary and the sidebar all print the same sentence for it.
11
+ *
12
+ * Process-global on purpose. The surfaces that show these (the RPC status and
13
+ * sidebar handlers) are built without a reference to the adapter that
14
+ * discovered the limitation, and a limitation of the host is true for every
15
+ * session in the process rather than for one of them.
16
+ */
17
+ const declared = new Set<UserFacingFailureKey>();
18
+
19
+ /**
20
+ * Record a limitation of this host. Returns true only the first time a given
21
+ * limitation is declared, which is what callers use to log their explanation
22
+ * once instead of on every pass.
23
+ */
24
+ export function declareHostLimitation(key: UserFacingFailureKey): boolean {
25
+ if (declared.has(key)) return false;
26
+ declared.add(key);
27
+ return true;
28
+ }
29
+
30
+ /** Limitations declared so far, in the order they were first declared. */
31
+ export function activeHostLimitations(): UserFacingFailureKey[] {
32
+ return [...declared];
33
+ }
34
+
35
+ /** The MC-* codes for the declared limitations, for logs and reports. */
36
+ export function activeHostLimitationCodes(): string[] {
37
+ return activeHostLimitations().map((key) => USER_FACING_FAILURES[key].code);
38
+ }
39
+
40
+ /** Test helper: forget every declared limitation so suites do not leak them. */
41
+ export function __resetHostLimitations(): void {
42
+ declared.clear();
43
+ }