@wolfx/opencode-magic-context 0.26.0 → 0.27.2-patch.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 (287) hide show
  1. package/dist/agents/dreamer.d.ts +19 -0
  2. package/dist/agents/dreamer.d.ts.map +1 -1
  3. package/dist/agents/hidden-agent-registrations.d.ts +67 -0
  4. package/dist/agents/hidden-agent-registrations.d.ts.map +1 -0
  5. package/dist/agents/historian.d.ts +1 -0
  6. package/dist/agents/historian.d.ts.map +1 -1
  7. package/dist/agents/permissions.d.ts +15 -44
  8. package/dist/agents/permissions.d.ts.map +1 -1
  9. package/dist/agents/smart-note-compiler.d.ts +2 -0
  10. package/dist/agents/smart-note-compiler.d.ts.map +1 -0
  11. package/dist/config/index.d.ts +1 -1
  12. package/dist/config/index.d.ts.map +1 -1
  13. package/dist/config/migrate-config-location.d.ts +97 -0
  14. package/dist/config/migrate-config-location.d.ts.map +1 -0
  15. package/dist/config/migrate-dreamer-v2.d.ts +37 -0
  16. package/dist/config/migrate-dreamer-v2.d.ts.map +1 -0
  17. package/dist/config/migrate-experimental.d.ts.map +1 -1
  18. package/dist/config/project-security.d.ts +3 -0
  19. package/dist/config/project-security.d.ts.map +1 -1
  20. package/dist/config/prune-config-leaf.d.ts.map +1 -1
  21. package/dist/config/schema/magic-context.d.ts +586 -77
  22. package/dist/config/schema/magic-context.d.ts.map +1 -1
  23. package/dist/features/magic-context/compaction-marker.d.ts +9 -3
  24. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  25. package/dist/features/magic-context/compartment-chunk-embedding.d.ts +1 -1
  26. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  27. package/dist/features/magic-context/dreamer/classify-prompt.d.ts +50 -0
  28. package/dist/features/magic-context/dreamer/classify-prompt.d.ts.map +1 -0
  29. package/dist/features/magic-context/dreamer/classify.d.ts +22 -0
  30. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -0
  31. package/dist/features/magic-context/dreamer/cron.d.ts +72 -0
  32. package/dist/features/magic-context/dreamer/cron.d.ts.map +1 -0
  33. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts +30 -0
  34. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -0
  35. package/dist/features/magic-context/dreamer/index.d.ts +1 -3
  36. package/dist/features/magic-context/dreamer/index.d.ts.map +1 -1
  37. package/dist/features/magic-context/dreamer/lease.d.ts +44 -6
  38. package/dist/features/magic-context/dreamer/lease.d.ts.map +1 -1
  39. package/dist/features/magic-context/dreamer/maintain-docs-protected-enforcement.d.ts +13 -0
  40. package/dist/features/magic-context/dreamer/maintain-docs-protected-enforcement.d.ts.map +1 -0
  41. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts +36 -0
  42. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts.map +1 -0
  43. package/dist/features/magic-context/dreamer/map-memories.d.ts +22 -0
  44. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -0
  45. package/dist/features/magic-context/dreamer/open-opencode-db.d.ts +7 -0
  46. package/dist/features/magic-context/dreamer/open-opencode-db.d.ts.map +1 -0
  47. package/dist/features/magic-context/dreamer/primer-seed.d.ts +25 -0
  48. package/dist/features/magic-context/dreamer/primer-seed.d.ts.map +1 -0
  49. package/dist/features/magic-context/dreamer/promote-primers.d.ts +21 -0
  50. package/dist/features/magic-context/dreamer/promote-primers.d.ts.map +1 -0
  51. package/dist/features/magic-context/dreamer/protected-regions.d.ts +19 -0
  52. package/dist/features/magic-context/dreamer/protected-regions.d.ts.map +1 -0
  53. package/dist/features/magic-context/dreamer/refresh-primers.d.ts +30 -0
  54. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -0
  55. package/dist/features/magic-context/dreamer/retrospective-learnings.d.ts +47 -0
  56. package/dist/features/magic-context/dreamer/retrospective-learnings.d.ts.map +1 -0
  57. package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts +48 -0
  58. package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts.map +1 -0
  59. package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts +81 -0
  60. package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts.map +1 -0
  61. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +8 -0
  62. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  63. package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts +82 -0
  64. package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts.map +1 -0
  65. package/dist/features/magic-context/dreamer/task-config.d.ts +28 -0
  66. package/dist/features/magic-context/dreamer/task-config.d.ts.map +1 -0
  67. package/dist/features/magic-context/dreamer/task-executor.d.ts +49 -0
  68. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -0
  69. package/dist/features/magic-context/dreamer/task-gates.d.ts +29 -0
  70. package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -0
  71. package/dist/features/magic-context/dreamer/task-prompts.d.ts +37 -6
  72. package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -1
  73. package/dist/features/magic-context/dreamer/task-registry.d.ts +48 -0
  74. package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -0
  75. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +88 -0
  76. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -0
  77. package/dist/features/magic-context/dreamer/verify-gate.d.ts +43 -0
  78. package/dist/features/magic-context/dreamer/verify-gate.d.ts.map +1 -0
  79. package/dist/features/magic-context/dreamer/verify-prompt.d.ts +41 -0
  80. package/dist/features/magic-context/dreamer/verify-prompt.d.ts.map +1 -0
  81. package/dist/features/magic-context/dreamer/verify.d.ts +43 -0
  82. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -0
  83. package/dist/features/magic-context/git-commits/search-git-commits.d.ts +2 -0
  84. package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -1
  85. package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts +4 -4
  86. package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -1
  87. package/dist/features/magic-context/index.d.ts +1 -0
  88. package/dist/features/magic-context/index.d.ts.map +1 -1
  89. package/dist/features/magic-context/memory/embedding-cache.d.ts +2 -2
  90. package/dist/features/magic-context/memory/embedding-cache.d.ts.map +1 -1
  91. package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -1
  92. package/dist/features/magic-context/memory/embedding-openai.d.ts +12 -5
  93. package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
  94. package/dist/features/magic-context/memory/embedding.d.ts +2 -2
  95. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
  96. package/dist/features/magic-context/memory/index.d.ts +4 -1
  97. package/dist/features/magic-context/memory/index.d.ts.map +1 -1
  98. package/dist/features/magic-context/memory/memory-migration.d.ts +1 -0
  99. package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
  100. package/dist/features/magic-context/memory/promotion.d.ts +16 -4
  101. package/dist/features/magic-context/memory/promotion.d.ts.map +1 -1
  102. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +2 -2
  103. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
  104. package/dist/features/magic-context/memory/storage-memory-verifications.d.ts +31 -0
  105. package/dist/features/magic-context/memory/storage-memory-verifications.d.ts.map +1 -0
  106. package/dist/features/magic-context/memory/storage-memory.d.ts +12 -1
  107. package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
  108. package/dist/features/magic-context/memory/types.d.ts +4 -0
  109. package/dist/features/magic-context/memory/types.d.ts.map +1 -1
  110. package/dist/features/magic-context/memory/verification-paths.d.ts +32 -0
  111. package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -0
  112. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  113. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  114. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  115. package/dist/features/magic-context/primer-clustering.d.ts +29 -0
  116. package/dist/features/magic-context/primer-clustering.d.ts.map +1 -0
  117. package/dist/features/magic-context/project-embedding-registry.d.ts +25 -1
  118. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  119. package/dist/features/magic-context/search.d.ts +12 -2
  120. package/dist/features/magic-context/search.d.ts.map +1 -1
  121. package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
  122. package/dist/features/magic-context/smart-notes/capabilities.d.ts +31 -0
  123. package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -0
  124. package/dist/features/magic-context/smart-notes/compiler-prompt.d.ts +2 -0
  125. package/dist/features/magic-context/smart-notes/compiler-prompt.d.ts.map +1 -0
  126. package/dist/features/magic-context/smart-notes/compiler.d.ts +52 -0
  127. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -0
  128. package/dist/features/magic-context/smart-notes/index.d.ts +10 -0
  129. package/dist/features/magic-context/smart-notes/index.d.ts.map +1 -0
  130. package/dist/features/magic-context/smart-notes/runner.d.ts +18 -0
  131. package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -0
  132. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts +22 -0
  133. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -0
  134. package/dist/features/magic-context/smart-notes/schedule.d.ts +9 -0
  135. package/dist/features/magic-context/smart-notes/schedule.d.ts.map +1 -0
  136. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts +49 -0
  137. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts.map +1 -0
  138. package/dist/features/magic-context/smart-notes/storage.d.ts +27 -0
  139. package/dist/features/magic-context/smart-notes/storage.d.ts.map +1 -0
  140. package/dist/features/magic-context/smart-notes/types.d.ts +63 -0
  141. package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -0
  142. package/dist/features/magic-context/storage-db.d.ts +5 -1
  143. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  144. package/dist/features/magic-context/storage-meta-persisted.d.ts +8 -4
  145. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  146. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  147. package/dist/features/magic-context/storage-meta-shared.d.ts +3 -1
  148. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  149. package/dist/features/magic-context/storage-notes.d.ts +15 -0
  150. package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
  151. package/dist/features/magic-context/storage-primers.d.ts +85 -0
  152. package/dist/features/magic-context/storage-primers.d.ts.map +1 -0
  153. package/dist/features/magic-context/storage-tags.d.ts +20 -0
  154. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  155. package/dist/features/magic-context/storage.d.ts +2 -1
  156. package/dist/features/magic-context/storage.d.ts.map +1 -1
  157. package/dist/features/magic-context/tagger.d.ts +6 -0
  158. package/dist/features/magic-context/tagger.d.ts.map +1 -1
  159. package/dist/features/magic-context/tool-owner-backfill.d.ts.map +1 -1
  160. package/dist/features/magic-context/transform-decision-log.d.ts +10 -0
  161. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  162. package/dist/features/magic-context/types.d.ts +2 -0
  163. package/dist/features/magic-context/types.d.ts.map +1 -1
  164. package/dist/features/magic-context/user-memory/review-user-memories.d.ts +5 -0
  165. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
  166. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +18 -0
  167. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
  168. package/dist/features/magic-context/v22-deferred-backfill.d.ts.map +1 -1
  169. package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
  170. package/dist/hooks/magic-context/command-handler.d.ts +8 -15
  171. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  172. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  173. package/dist/hooks/magic-context/compartment-parser.d.ts +9 -0
  174. package/dist/hooks/magic-context/compartment-parser.d.ts.map +1 -1
  175. package/dist/hooks/magic-context/compartment-prompt.d.ts +4 -1
  176. package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
  177. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +1 -0
  178. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  179. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  180. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  181. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  182. package/dist/hooks/magic-context/compartment-runner-types.d.ts +8 -0
  183. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  184. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  185. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  186. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  187. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  188. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  189. package/dist/hooks/magic-context/historian-prompt.generated.d.ts +1 -1
  190. package/dist/hooks/magic-context/historian-prompt.generated.d.ts.map +1 -1
  191. package/dist/hooks/magic-context/historian-state-file.d.ts.map +1 -1
  192. package/dist/hooks/magic-context/hook-handlers.d.ts +2 -1
  193. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  194. package/dist/hooks/magic-context/hook.d.ts +1 -0
  195. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  196. package/dist/hooks/magic-context/inject-compartments.d.ts +0 -3
  197. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  198. package/dist/hooks/magic-context/send-session-notification.d.ts +2 -0
  199. package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
  200. package/dist/hooks/magic-context/system-prompt-hash.d.ts +17 -0
  201. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  202. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +8 -5
  203. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  204. package/dist/hooks/magic-context/transform.d.ts +0 -2
  205. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  206. package/dist/index.d.ts +2 -2
  207. package/dist/index.d.ts.map +1 -1
  208. package/dist/index.js +18059 -13232
  209. package/dist/plugin/dream-timer.d.ts +17 -9
  210. package/dist/plugin/dream-timer.d.ts.map +1 -1
  211. package/dist/plugin/embedding-bootstrap-helpers.d.ts +1 -1
  212. package/dist/plugin/embedding-bootstrap-helpers.d.ts.map +1 -1
  213. package/dist/plugin/embedding-bootstrap.d.ts.map +1 -1
  214. package/dist/plugin/hooks/create-session-hooks.d.ts +211 -0
  215. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  216. package/dist/plugin/instance-disposal.d.ts +2 -0
  217. package/dist/plugin/instance-disposal.d.ts.map +1 -0
  218. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  219. package/dist/shared/announcement.d.ts +1 -1
  220. package/dist/shared/announcement.d.ts.map +1 -1
  221. package/dist/shared/data-path.d.ts +30 -9
  222. package/dist/shared/data-path.d.ts.map +1 -1
  223. package/dist/shared/model-suggestion-retry.d.ts +48 -2
  224. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  225. package/dist/shared/models-dev-cache.d.ts +23 -0
  226. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  227. package/dist/shared/redaction.d.ts +7 -0
  228. package/dist/shared/redaction.d.ts.map +1 -0
  229. package/dist/shared/resolve-fallbacks.d.ts +12 -0
  230. package/dist/shared/resolve-fallbacks.d.ts.map +1 -1
  231. package/dist/shared/rpc-server.d.ts.map +1 -1
  232. package/dist/shared/rpc-types.d.ts +2 -0
  233. package/dist/shared/rpc-types.d.ts.map +1 -1
  234. package/dist/shared/subagent-runner.d.ts +12 -3
  235. package/dist/shared/subagent-runner.d.ts.map +1 -1
  236. package/dist/shared/tui-config.d.ts.map +1 -1
  237. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  238. package/dist/tools/ctx-memory/types.d.ts.map +1 -1
  239. package/dist/tools/ctx-memory/verification-recording.d.ts +8 -0
  240. package/dist/tools/ctx-memory/verification-recording.d.ts.map +1 -0
  241. package/dist/tools/ctx-search/tools.d.ts.map +1 -1
  242. package/dist/tools/ctx-search/types.d.ts +1 -1
  243. package/dist/tools/ctx-search/types.d.ts.map +1 -1
  244. package/dist/tui/data/context-db.d.ts +2 -0
  245. package/dist/tui/data/context-db.d.ts.map +1 -1
  246. package/package.json +7 -3
  247. package/src/shared/announcement.test.ts +20 -0
  248. package/src/shared/announcement.ts +32 -7
  249. package/src/shared/data-path.test.ts +74 -9
  250. package/src/shared/data-path.ts +54 -10
  251. package/src/shared/model-suggestion-retry.test.ts +79 -2
  252. package/src/shared/model-suggestion-retry.ts +181 -3
  253. package/src/shared/models-dev-cache.test.ts +82 -0
  254. package/src/shared/models-dev-cache.ts +35 -0
  255. package/src/shared/redaction.test.ts +84 -0
  256. package/src/shared/redaction.ts +264 -0
  257. package/src/shared/resolve-fallbacks.ts +14 -0
  258. package/src/shared/rpc-server.ts +24 -0
  259. package/src/shared/rpc-types.ts +2 -0
  260. package/src/shared/subagent-runner.ts +12 -3
  261. package/src/shared/tui-config.test.ts +106 -0
  262. package/src/shared/tui-config.ts +75 -40
  263. package/src/tui/data/context-db.ts +12 -0
  264. package/src/tui/index.tsx +87 -17
  265. package/src/tui/slots/sidebar-content.tsx +4 -0
  266. package/dist/features/magic-context/dreamer/queue.d.ts +0 -55
  267. package/dist/features/magic-context/dreamer/queue.d.ts.map +0 -1
  268. package/dist/features/magic-context/dreamer/runner.d.ts +0 -92
  269. package/dist/features/magic-context/dreamer/runner.d.ts.map +0 -1
  270. package/dist/features/magic-context/dreamer/scheduler.d.ts +0 -29
  271. package/dist/features/magic-context/dreamer/scheduler.d.ts.map +0 -1
  272. package/dist/features/magic-context/key-files/aft-availability.d.ts +0 -11
  273. package/dist/features/magic-context/key-files/aft-availability.d.ts.map +0 -1
  274. package/dist/features/magic-context/key-files/identify-key-files.d.ts +0 -84
  275. package/dist/features/magic-context/key-files/identify-key-files.d.ts.map +0 -1
  276. package/dist/features/magic-context/key-files/project-key-files.d.ts +0 -42
  277. package/dist/features/magic-context/key-files/project-key-files.d.ts.map +0 -1
  278. package/dist/features/magic-context/key-files/read-history.d.ts +0 -26
  279. package/dist/features/magic-context/key-files/read-history.d.ts.map +0 -1
  280. package/dist/features/magic-context/key-files/read-stats.d.ts +0 -18
  281. package/dist/features/magic-context/key-files/read-stats.d.ts.map +0 -1
  282. package/dist/features/magic-context/key-files/storage-key-files.d.ts +0 -20
  283. package/dist/features/magic-context/key-files/storage-key-files.d.ts.map +0 -1
  284. package/dist/features/magic-context/memory/embedding-local.d.ts +0 -25
  285. package/dist/features/magic-context/memory/embedding-local.d.ts.map +0 -1
  286. package/dist/hooks/magic-context/key-files-block.d.ts +0 -27
  287. package/dist/hooks/magic-context/key-files-block.d.ts.map +0 -1
@@ -152,9 +152,9 @@ export type SubagentProgressEvent = {
152
152
  * Fields:
153
153
  * - `ok`: true iff the child produced a final assistant message.
154
154
  * - `assistantText`: concatenated text content from the final assistant
155
- * message, with leading/trailing whitespace trimmed. Empty string if the
156
- * child finished but produced no text (rare usually means the model
157
- * only emitted tool calls and we didn't follow up).
155
+ * message, with leading/trailing whitespace trimmed. Empty assistant text is
156
+ * reported as `ok: false, reason: "no_assistant"` so callers can try fallback
157
+ * models instead of accepting an unusable success.
158
158
  * - `reason`: failure category, one of:
159
159
  * - `"timeout"`: hit `timeoutMs` before the child finished
160
160
  * - `"abort"`: caller's `signal` was triggered
@@ -176,6 +176,15 @@ export type SubagentRunResult = {
176
176
  ok: true;
177
177
  assistantText: string;
178
178
  durationMs: number;
179
+ /**
180
+ * Number of tool invocations the agent made during the run. Pi reports
181
+ * this so callers that gate on "did the agent actually investigate vs
182
+ * just paraphrase" (refresh-primers' grounding gate) work on Pi, whose
183
+ * facade otherwise surfaces only the final assistant text. OpenCode
184
+ * leaves it undefined — its callers read tool-call parts straight off
185
+ * the real session messages.
186
+ */
187
+ toolCallCount?: number;
179
188
  meta?: Record<string, unknown>;
180
189
  } | {
181
190
  ok: false;
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-runner.d.ts","sourceRoot":"","sources":["../../src/shared/subagent-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"subagent-runner.d.ts","sourceRoot":"","sources":["../../src/shared/subagent-runner.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tui-config.d.ts","sourceRoot":"","sources":["../../src/shared/tui-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA4CH;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CA+C9C"}
1
+ {"version":3,"file":"tui-config.d.ts","sourceRoot":"","sources":["../../src/shared/tui-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAyEH;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAqD9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-memory/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AAsChE,OAAO,EAKH,KAAK,iBAAiB,EACzB,MAAM,SAAS,CAAC;AA0oBjB,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAI5F"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-memory/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AA0ChE,OAAO,EAKH,KAAK,iBAAiB,EACzB,MAAM,SAAS,CAAC;AAqqBjB,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAI5F"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-memory/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AASpD,eAAO,MAAM,kBAAkB,kDAAmD,CAAC;AAEnF,eAAO,MAAM,0BAA0B,0DAA2C,CAAC;AAEnF,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,QAAQ,CAAC;IACb,uBAAuB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E;;;;;;;;;;OAUG;IACH,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,eAAe,EAAE,CAAC;IACnC,UAAU,CAAC,EAAE,gBAAgB,CAAC;CACjC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-memory/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAC5E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAWpD,eAAO,MAAM,kBAAkB,kDAAmD,CAAC;AAEnF,eAAO,MAAM,0BAA0B,0DAA2C,CAAC;AAEnF,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,QAAQ,CAAC;IACb,uBAAuB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E;;;;;;;;;;OAUG;IACH,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,eAAe,EAAE,CAAC;IACnC,UAAU,CAAC,EAAE,gBAAgB,CAAC;CACjC"}
@@ -0,0 +1,8 @@
1
+ import type { Database } from "../../shared/sqlite";
2
+ /**
3
+ * Run `fn` inside a `BEGIN IMMEDIATE` transaction, committing on success and
4
+ * rolling back on throw. Used by the in-session ctx_memory mutation actions so
5
+ * a memory write + its mutation-log row commit atomically.
6
+ */
7
+ export declare function runImmediateTransaction<T>(db: Database, fn: () => T): T;
8
+ //# sourceMappingURL=verification-recording.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verification-recording.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-memory/verification-recording.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAUvE"}
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-search/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AAahE,OAAO,KAAK,EAAkC,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAyLjF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAI5F"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-search/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAQ,MAAM,qBAAqB,CAAC;AAahE,OAAO,KAAK,EAAkC,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAqMjF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAI5F"}
@@ -2,7 +2,7 @@ import type { Database } from "../../shared/sqlite";
2
2
  /** Sources the agent can narrow ctx_search to. Facts are intentionally NOT a
3
3
  * source — they're always rendered in <session-history> in message[0], so
4
4
  * searching them returns content already visible in context. */
5
- export type CtxSearchSource = "memory" | "message" | "git_commit";
5
+ export type CtxSearchSource = "memory" | "message" | "git_commit" | "primer";
6
6
  export interface CtxSearchArgs {
7
7
  query: string;
8
8
  limit?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-search/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;iEAEiE;AACjE,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;AAElE,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,QAAQ,CAAC;IACb,uBAAuB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E;;;;;OAKG;IACH,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0EAA0E;IAC1E,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,8EAA8E;IAC9E,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,KAAK,CAAC;QACxC,OAAO,EAAE,MAAM,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,OAAO,EAAE,CAAC;KACpB,CAAC,CAAC;CACN"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tools/ctx-search/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;iEAEiE;AACjE,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;AAE7E,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+DAA+D;IAC/D,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,QAAQ,CAAC;IACb,uBAAuB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E;;;;;OAKG;IACH,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAClD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,0EAA0E;IAC1E,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,8EAA8E;IAC9E,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,KAAK,CAAC;QACxC,OAAO,EAAE,MAAM,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,OAAO,EAAE,CAAC;KACpB,CAAC,CAAC;CACN"}
@@ -22,6 +22,8 @@ export declare function requestUpgrade(sessionId: string): Promise<boolean>;
22
22
  * choice), setting the durable stamp so the FRESH dialog won't re-show. Resume
23
23
  * prompts are staging-driven and unaffected. */
24
24
  export declare function dismissUpgradeReminder(sessionId: string): Promise<boolean>;
25
+ /** Resolve global toast duration from server config via RPC. */
26
+ export declare function loadToastDurationMs(): Promise<number>;
25
27
  export interface TuiMessage {
26
28
  id: number;
27
29
  type: string;
@@ -1 +1 @@
1
- {"version":3,"file":"context-db.d.ts","sourceRoot":"","sources":["../../../src/tui/data/context-db.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACR,WAAW,EAEX,eAAe,EACf,YAAY,EACf,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AAe3D,2DAA2D;AAC3D,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAOrD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,+BAA+B;AAC/B,wBAAgB,QAAQ,IAAI,IAAI,CAO/B;AA4FD,sDAAsD;AACtD,wBAAsB,mBAAmB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CA4B1B;AAED,wDAAwD;AACxD,wBAAsB,gBAAgB,CAClC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC,CAyCvB;AAYD,gEAAgE;AAChE,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAchG;AAED,qCAAqC;AACrC,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ5E;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQvE;AAED;mFACmF;AACnF,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQxE;AAED;;iDAEiD;AACjD,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUhF;AAED,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAkBrE;AAED,wEAAwE;AACxE,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAQtD;AAED,yDAAyD;AACzD,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAyBjF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,CAWtF"}
1
+ {"version":3,"file":"context-db.d.ts","sourceRoot":"","sources":["../../../src/tui/data/context-db.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACR,WAAW,EAEX,eAAe,EACf,YAAY,EACf,MAAM,wBAAwB,CAAC;AAEhC,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;AAe3D,2DAA2D;AAC3D,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAOrD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,+BAA+B;AAC/B,wBAAgB,QAAQ,IAAI,IAAI,CAO/B;AA4FD,sDAAsD;AACtD,wBAAsB,mBAAmB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC,CA4B1B;AAED,wDAAwD;AACxD,wBAAsB,gBAAgB,CAClC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC,CA0CvB;AAYD,gEAAgE;AAChE,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAchG;AAED,qCAAqC;AACrC,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ5E;AAED,6CAA6C;AAC7C,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQvE;AAED;mFACmF;AACnF,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQxE;AAED;;iDAEiD;AACjD,wBAAsB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAUhF;AAED,gEAAgE;AAChE,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAQ3D;AAED,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAkBrE;AAED,wEAAwE;AACxE,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAQtD;AAED,yDAAyD;AACzD,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAyBjF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,CAWtF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wolfx/opencode-magic-context",
3
- "version": "0.26.0",
3
+ "version": "0.27.2-patch.1",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",
@@ -29,7 +29,7 @@
29
29
  "README.md"
30
30
  ],
31
31
  "scripts": {
32
- "build": "bun build src/index.ts --outdir dist --target node --format esm --external @opencode-ai/plugin --external @huggingface/transformers --external onnxruntime-web --external bun:sqlite --external node:sqlite && tsc --emitDeclarationOnly",
32
+ "build": "bun build src/index.ts --outdir dist --target node --format esm --external @opencode-ai/plugin --external bun:sqlite --external node:sqlite && tsc --emitDeclarationOnly",
33
33
  "typecheck": "tsc --noEmit && tsc -p tsconfig.scripts.json",
34
34
  "test": "bun test",
35
35
  "lint": "biome check .",
@@ -40,11 +40,15 @@
40
40
  "prepublishOnly": "bun run build"
41
41
  },
42
42
  "dependencies": {
43
- "@huggingface/transformers": "^4.1.0",
43
+ "@jitl/quickjs-singlefile-cjs-release-asyncify": "0.32.0",
44
44
  "@opencode-ai/plugin": "^1.15.13",
45
45
  "@opencode-ai/sdk": "^1.15.13",
46
+ "@opentui/core": "^0.4.2",
47
+ "@opentui/solid": "^0.4.2",
46
48
  "ai-tokenizer": "^1.0.6",
47
49
  "comment-json": "^4.2.5",
50
+ "quickjs-emscripten": "^0.32.0",
51
+ "solid-js": "1.9.12",
48
52
  "zod": "^4.1.8"
49
53
  },
50
54
  "devDependencies": {
@@ -174,4 +174,24 @@ describe("shouldShowAnnouncement gating", () => {
174
174
  markAnnouncementSeen("0.0.0-pre-historic");
175
175
  expect(shouldShowAnnouncement()).toBe(true);
176
176
  });
177
+
178
+ test("does NOT re-announce on a downgrade (stored version is newer)", async () => {
179
+ const mod = await import(`./announcement?t=${Date.now()}-downgrade`);
180
+ const {
181
+ ANNOUNCEMENT_VERSION,
182
+ ANNOUNCEMENT_FEATURES,
183
+ markAnnouncementSeen,
184
+ shouldShowAnnouncement,
185
+ } = mod;
186
+
187
+ if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0) {
188
+ return;
189
+ }
190
+
191
+ // Stored version is far newer than the running binary (user downgraded).
192
+ // A bare string-inequality gate would re-show the OLD announcement; the
193
+ // semver gate must stay quiet (current is NOT > stored).
194
+ markAnnouncementSeen("999.0.0");
195
+ expect(shouldShowAnnouncement()).toBe(false);
196
+ });
177
197
  });
@@ -17,24 +17,38 @@
17
17
 
18
18
  import * as fs from "node:fs";
19
19
  import * as path from "node:path";
20
+ /**
21
+ * Compare two semver core versions (major.minor.patch). Returns >0 if `a` is
22
+ * newer than `b`, <0 if older, 0 if equal. Pre-release / build metadata is
23
+ * IGNORED. Returns null if either string isn't valid semver.
24
+ */
25
+ function compareSemverCore(a: string, b: string): number | null {
26
+ const isValid = (v: string) => /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(v);
27
+ if (!isValid(a) || !isValid(b)) return null;
28
+ const core = (v: string) =>
29
+ v.split(/[-+]/, 1)[0].split(".").map((n) => Number.parseInt(n, 10));
30
+ const [a0, a1, a2] = core(a);
31
+ const [b0, b1, b2] = core(b);
32
+ return a0 - b0 || a1 - b1 || a2 - b2;
33
+ }
20
34
  import { getMagicContextStorageDir } from "./data-path";
21
35
 
22
36
  /**
23
37
  * Bump only when there are user-visible changes worth a startup dialog.
24
38
  * Does NOT need to match the published package version.
25
39
  */
26
- export const ANNOUNCEMENT_VERSION = "0.26.0";
40
+ export const ANNOUNCEMENT_VERSION = "0.27.0";
27
41
 
28
42
  /**
29
43
  * Short, user-facing bullet strings. Keep each line ~80 chars or shorter so the
30
44
  * TUI dialog renders cleanly without horizontal scroll on a typical terminal.
31
45
  */
32
46
  export const ANNOUNCEMENT_FEATURES: ReadonlyArray<string> = [
33
- "Faster on large sessions: per-message transform overhead is at least 2x lower on typical passes and up to ~10x lower when history summarization fires (no more multi-second pause on big sessions).",
34
- "No more surprise models: the built-in fallback chain is gone. Hidden agents only use the model (and fallback_models) you configure — no confusing 'model not found' for providers you never set up. `doctor` now records every historian run so real failures are visible.",
35
- "Anthropic thinking-block fix: clearing old reasoning no longer risks a stale-signature rejection on Claude / Bedrock / proxied-Claude routes. Plus fewer prompt-cache busts.",
36
- "Community fixes: TUI crash on the upgrade progress panel (#168), historian.disallowed_tools for weak models that loop on tool calls (#166), and a Pi-only config key leak (#167).",
37
- "New: doctor migrate-session re-homes a session (and optionally its memories) to another project, with a dry-run preview.",
47
+ "Dreamer V2: each maintenance task now runs on its own schedule (cron), with its own model. Configure them in setup, the dashboard, or magic-context.jsonc.",
48
+ "New 'classify' task scores each memory's importance so the most relevant stay in context as your work shifts; new 'retrospective' learns from moments you had to correct or re-explain. Both cache-safe, on by default, off anytime.",
49
+ "New Primers: durable answers to the questions that keep coming up about your project, kept current by the dreamer investigating the actual code.",
50
+ "Embedding storage no longer wipes your vectors when you change model or endpoint. Different models now coexist, so switching providers keeps your existing vectors.",
51
+ "Config moved to a shared CortexKit location (~/.config/cortexkit/ and <project>/.cortexkit/). This happens automatically on first run; your old file is preserved.",
38
52
  ];
39
53
 
40
54
  /**
@@ -130,5 +144,16 @@ export function shouldShowAnnouncement(): boolean {
130
144
  // Do not advance the version; a later successful boot can still show it.
131
145
  return false;
132
146
  }
133
- return state.version !== ANNOUNCEMENT_VERSION;
147
+ // Show ONLY on a forward version change (current > stored). A bare string
148
+ // inequality re-announced on a DOWNGRADE (0.27.0 → 0.26.0) or when stored
149
+ // state held an unexpected value. compareSemverCore returns null for
150
+ // non-semver input → treat conservatively (don't announce).
151
+ const ordering = compareSemverCore(ANNOUNCEMENT_VERSION, state.version);
152
+ if (ordering === null) {
153
+ // Stored version isn't parseable as semver but differs from current: only
154
+ // announce when it's genuinely not the current string (avoids re-showing on
155
+ // every boot for a corrupt-but-present value).
156
+ return state.version !== ANNOUNCEMENT_VERSION;
157
+ }
158
+ return ordering > 0;
134
159
  }
@@ -1,7 +1,9 @@
1
1
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
3
  import * as os from "node:os";
3
4
  import * as path from "node:path";
4
5
  import {
6
+ ensureCortexKitArtifactGitignore,
5
7
  getCacheDir,
6
8
  getDataDir,
7
9
  getLegacyOpenCodeMagicContextStorageDir,
@@ -121,19 +123,20 @@ describe("data-path", () => {
121
123
  expect(shared).toContain("cortexkit");
122
124
  });
123
125
 
124
- test("getProjectMagicContextDir composes <project>/.magic-context", () => {
125
- // Project-local artifacts live inside the project so OpenCode's
126
- // external_directory permission system treats them as project-internal.
127
- // Without this, historian's Read tool would trigger a permission prompt
128
- // on every run when artifacts lived under os.tmpdir().
126
+ test("getProjectMagicContextDir composes <project>/.cortexkit/magic-context", () => {
127
+ // Project-local artifacts (historian state file, failure dumps) live
128
+ // inside the project so OpenCode's external_directory permission system
129
+ // treats them as project-internal. Without this, historian's Read tool
130
+ // would trigger a permission prompt on every run when artifacts lived
131
+ // under os.tmpdir(). Moved from .opencode/ to the shared .cortexkit/.
129
132
  expect(getProjectMagicContextDir("/Users/me/Work/proj")).toBe(
130
- path.join("/Users/me/Work/proj", ".magic-context"),
133
+ path.join("/Users/me/Work/proj", ".cortexkit", "magic-context"),
131
134
  );
132
135
  });
133
136
 
134
137
  test("getProjectMagicContextHistorianDir appends historian/", () => {
135
138
  expect(getProjectMagicContextHistorianDir("/Users/me/Work/proj")).toBe(
136
- path.join("/Users/me/Work/proj", ".magic-context", "historian"),
139
+ path.join("/Users/me/Work/proj", ".cortexkit", "magic-context", "historian"),
137
140
  );
138
141
  });
139
142
 
@@ -144,7 +147,7 @@ describe("data-path", () => {
144
147
  // project-local historian dir.
145
148
  process.env.XDG_DATA_HOME = "/tmp/custom-data";
146
149
  expect(getProjectMagicContextDir("/some/project")).toBe(
147
- path.join("/some/project", ".magic-context"),
150
+ path.join("/some/project", ".cortexkit", "magic-context"),
148
151
  );
149
152
  });
150
153
 
@@ -152,7 +155,69 @@ describe("data-path", () => {
152
155
  // path.join normalizes redundant separators so callers don't need to
153
156
  // worry about how the project directory was constructed.
154
157
  expect(getProjectMagicContextDir("/some/project/")).toBe(
155
- path.join("/some/project/", ".magic-context"),
158
+ path.join("/some/project/", ".cortexkit", "magic-context"),
156
159
  );
157
160
  });
158
161
  });
162
+
163
+ describe("ensureCortexKitArtifactGitignore", () => {
164
+ test("creates .cortexkit/.gitignore with a fenced magic-context block", () => {
165
+ const dir = mkdtempSync(path.join(os.tmpdir(), "mc-gi-"));
166
+ try {
167
+ ensureCortexKitArtifactGitignore(dir);
168
+ const gi = readFileSync(path.join(dir, ".cortexkit", ".gitignore"), "utf8");
169
+ expect(gi).toContain("# >>> cortexkit:magic-context");
170
+ expect(gi).toContain("magic-context/");
171
+ expect(gi).toContain("# <<< cortexkit:magic-context");
172
+ } finally {
173
+ rmSync(dir, { recursive: true, force: true });
174
+ }
175
+ });
176
+
177
+ test("is idempotent — a second call does not duplicate the block", () => {
178
+ const dir = mkdtempSync(path.join(os.tmpdir(), "mc-gi-"));
179
+ try {
180
+ ensureCortexKitArtifactGitignore(dir);
181
+ ensureCortexKitArtifactGitignore(dir);
182
+ const gi = readFileSync(path.join(dir, ".cortexkit", ".gitignore"), "utf8");
183
+ const occurrences = gi.split("# >>> cortexkit:magic-context").length - 1;
184
+ expect(occurrences).toBe(1);
185
+ } finally {
186
+ rmSync(dir, { recursive: true, force: true });
187
+ }
188
+ });
189
+
190
+ test("preserves a sibling module's existing entries (appends, never clobbers)", () => {
191
+ const dir = mkdtempSync(path.join(os.tmpdir(), "mc-gi-"));
192
+ try {
193
+ const ckDir = path.join(dir, ".cortexkit");
194
+ mkdirSync(ckDir, { recursive: true });
195
+ // Simulate a sibling (e.g. AFT) already owning a fenced block.
196
+ writeFileSync(
197
+ path.join(ckDir, ".gitignore"),
198
+ "# >>> cortexkit:aft\naft/scratch/\n# <<< cortexkit:aft\n",
199
+ );
200
+ ensureCortexKitArtifactGitignore(dir);
201
+ const gi = readFileSync(path.join(ckDir, ".gitignore"), "utf8");
202
+ expect(gi).toContain("# >>> cortexkit:aft");
203
+ expect(gi).toContain("aft/scratch/");
204
+ expect(gi).toContain("# >>> cortexkit:magic-context");
205
+ expect(gi).toContain("magic-context/");
206
+ } finally {
207
+ rmSync(dir, { recursive: true, force: true });
208
+ }
209
+ });
210
+
211
+ test("does not ignore the project config — only the artifact dir", () => {
212
+ const dir = mkdtempSync(path.join(os.tmpdir(), "mc-gi-"));
213
+ try {
214
+ ensureCortexKitArtifactGitignore(dir);
215
+ const gi = readFileSync(path.join(dir, ".cortexkit", ".gitignore"), "utf8");
216
+ // The config file stays tracked: it must NOT appear as an ignore.
217
+ expect(gi).not.toContain("magic-context.jsonc");
218
+ expect(gi).not.toContain("*.jsonc");
219
+ } finally {
220
+ rmSync(dir, { recursive: true, force: true });
221
+ }
222
+ });
223
+ });
@@ -1,3 +1,4 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
1
2
  import * as os from "node:os";
2
3
  import * as path from "node:path";
3
4
  import { getHarness, type HarnessId } from "./harness";
@@ -62,31 +63,75 @@ export function getMagicContextHistorianDir(harness: HarnessId = getHarness()):
62
63
  /**
63
64
  * Project-local magic-context artifact directory.
64
65
  *
65
- * Layout: `<project-directory>/.magic-context/`
66
+ * Layout: `<project-directory>/.cortexkit/magic-context/`
66
67
  *
67
68
  * Used for artifacts that the historian/recomp pipeline writes during a run
68
69
  * and that the model is asked to read via its native Read tool. OpenCode's
69
70
  * `external_directory` permission system asks the user before reading any
70
71
  * file outside the project directory or its worktree, which interrupts every
71
72
  * historian run when artifacts live under `os.tmpdir()`. Writing under the
72
- * project's own `.magic-context/` subtree falls inside the project boundary
73
- * and never triggers a permission prompt.
73
+ * project's own `.cortexkit/` subtree falls inside the project boundary and
74
+ * never triggers a permission prompt.
74
75
  *
75
- * Using a harness-agnostic name (`/.magic-context/` rather than
76
- * `/.opencode/`) ensures the same path works for both OpenCode and Pi.
76
+ * `.cortexkit/` is the shared CortexKit per-project dir (also holds the
77
+ * project config `magic-context.jsonc`). Because these artifacts are transient
78
+ * debug dumps that shouldn't dirty the user's repo, the first write also drops
79
+ * a fenced-block `.gitignore` entry ignoring this subdir (see
80
+ * ensureCortexKitArtifactGitignore) while leaving `*.jsonc` config tracked.
81
+ *
82
+ * Migration note: artifacts used to live under `.opencode/magic-context/`. We
83
+ * cut the write path forward only — old transient dumps are git-ignored and
84
+ * regenerated, so they are intentionally NOT migrated (left to be cleaned).
77
85
  *
78
86
  * Logger does NOT use this — log files stay in the per-harness tmp subtree
79
87
  * because they are written by the plugin process itself (no model-side Read
80
88
  * tool call, no permission prompt) and span sessions/projects.
81
89
  */
82
90
  export function getProjectMagicContextDir(directory: string): string {
83
- return path.join(directory, ".magic-context");
91
+ return path.join(directory, ".cortexkit", "magic-context");
92
+ }
93
+
94
+ const GITIGNORE_GUARD_OPEN = "# >>> cortexkit:magic-context";
95
+ const GITIGNORE_GUARD_CLOSE = "# <<< cortexkit:magic-context";
96
+
97
+ /**
98
+ * Ensure `<project>/.cortexkit/.gitignore` ignores Magic Context's transient
99
+ * artifact subdir (`magic-context/`) without touching anything else in the
100
+ * shared `.cortexkit/` dir — the project config `magic-context.jsonc` stays
101
+ * tracked, and any sibling module's (e.g. AFT's) entries are preserved.
102
+ *
103
+ * Uses the shared CortexKit fenced-block convention: each module owns exactly
104
+ * its `# >>> cortexkit:<module>` … `# <<< cortexkit:<module>` block and appends
105
+ * it idempotently (no-op when its own guard line is already present). This lets
106
+ * multiple cortexkit modules coexist in one `.gitignore` without clobbering.
107
+ *
108
+ * Best-effort: a write failure never blocks an artifact write (the caller
109
+ * already degrades gracefully on its own write failures).
110
+ */
111
+ export function ensureCortexKitArtifactGitignore(directory: string): void {
112
+ try {
113
+ const cortexKitDir = path.join(directory, ".cortexkit");
114
+ const gitignorePath = path.join(cortexKitDir, ".gitignore");
115
+ let existing = "";
116
+ if (existsSync(gitignorePath)) {
117
+ existing = readFileSync(gitignorePath, "utf8");
118
+ // Already fenced by us — nothing to do.
119
+ if (existing.includes(GITIGNORE_GUARD_OPEN)) return;
120
+ }
121
+ const block = `${GITIGNORE_GUARD_OPEN}\nmagic-context/\n${GITIGNORE_GUARD_CLOSE}\n`;
122
+ const needsLeadingNewline = existing.length > 0 && !existing.endsWith("\n");
123
+ const next = existing + (needsLeadingNewline ? "\n" : "") + block;
124
+ mkdirSync(cortexKitDir, { recursive: true });
125
+ writeFileSync(gitignorePath, next, "utf8");
126
+ } catch {
127
+ // best-effort — never block an artifact write on the gitignore.
128
+ }
84
129
  }
85
130
 
86
131
  /**
87
132
  * Project-local historian artifact directory.
88
133
  *
89
- * Layout: `<project-directory>/.magic-context/historian/`
134
+ * Layout: `<project-directory>/.opencode/magic-context/historian/`
90
135
  *
91
136
  * Used for:
92
137
  * - existing-state offload XMLs that long historian/recomp passes write
@@ -94,9 +139,8 @@ export function getProjectMagicContextDir(directory: string): string {
94
139
  * - validation-failure dump XMLs preserved for debugging
95
140
  *
96
141
  * Callers must `mkdirSync(dir, { recursive: true })` before writing — the
97
- * `.magic-context/` parent may not exist on a fresh project, and write
98
- * failures here must degrade gracefully (e.g. historian falls back to inline
99
- * state).
142
+ * `.opencode/` parent may not exist on a fresh project, and write failures
143
+ * here must degrade gracefully (e.g. historian falls back to inline state).
100
144
  */
101
145
  export function getProjectMagicContextHistorianDir(directory: string): string {
102
146
  return path.join(getProjectMagicContextDir(directory), "historian");
@@ -1,17 +1,25 @@
1
1
  import { describe, expect, mock, test } from "bun:test";
2
2
 
3
- import { promptSyncWithModelSuggestionRetry } from "./model-suggestion-retry";
3
+ import {
4
+ promptSyncWithModelSuggestionRetry,
5
+ promptSyncWithValidatedOutputRetry,
6
+ } from "./model-suggestion-retry";
4
7
 
5
8
  type PromptCall = {
6
9
  body: { model?: { providerID: string; modelID: string } };
7
10
  signal?: AbortSignal;
8
11
  };
9
12
 
10
- function createClient(prompt: ReturnType<typeof mock>, abort?: ReturnType<typeof mock>) {
13
+ function createClient(
14
+ prompt: ReturnType<typeof mock>,
15
+ abort?: ReturnType<typeof mock>,
16
+ messages?: ReturnType<typeof mock>,
17
+ ) {
11
18
  return {
12
19
  session: {
13
20
  prompt,
14
21
  abort: abort ?? mock(async () => ({})),
22
+ messages: messages ?? mock(async () => []),
15
23
  },
16
24
  } as never;
17
25
  }
@@ -309,3 +317,72 @@ describe("promptSyncWithModelSuggestionRetry", () => {
309
317
  expect(prompt).toHaveBeenCalledTimes(1);
310
318
  });
311
319
  });
320
+
321
+ describe("promptSyncWithValidatedOutputRetry", () => {
322
+ test("valid first model returns without trying fallbacks", async () => {
323
+ const prompt = mock(async () => ({}));
324
+ const messages = mock(async () => "primary-output");
325
+ const client = createClient(prompt, undefined, messages);
326
+
327
+ const result = await promptSyncWithValidatedOutputRetry(client, createArgs(), {
328
+ fallbackModels: ["anthropic/claude-sonnet-4-6"],
329
+ fetchOutput: async () => messages(),
330
+ validateOutput: (output: string) => {
331
+ if (output.trim().length === 0) throw new Error("empty output");
332
+ return output.trim();
333
+ },
334
+ });
335
+
336
+ expect(result.validated).toBe("primary-output");
337
+ expect(prompt).toHaveBeenCalledTimes(1);
338
+ expect(messages).toHaveBeenCalledTimes(1);
339
+ });
340
+
341
+ test("empty first model tries the next fallback", async () => {
342
+ const prompt = mock(async () => ({}));
343
+ const messages = mock(async () =>
344
+ messages.mock.calls.length === 1 ? "" : "fallback-output",
345
+ );
346
+ const client = createClient(prompt, undefined, messages);
347
+
348
+ const result = await promptSyncWithValidatedOutputRetry(client, createArgs(), {
349
+ fallbackModels: ["anthropic/claude-sonnet-4-6"],
350
+ fetchOutput: async () => messages(),
351
+ validateOutput: (output: string, attempt) => {
352
+ if (output.trim().length === 0)
353
+ throw new Error(`empty output from ${attempt.label}`);
354
+ return output.trim();
355
+ },
356
+ });
357
+
358
+ expect(result.validated).toBe("fallback-output");
359
+ expect(prompt).toHaveBeenCalledTimes(2);
360
+ expect(messages).toHaveBeenCalledTimes(2);
361
+ expect((prompt.mock.calls[1]?.[0] as PromptCall).body.model).toEqual({
362
+ providerID: "anthropic",
363
+ modelID: "claude-sonnet-4-6",
364
+ });
365
+ });
366
+
367
+ test("all empty outputs surface the original validation failure", async () => {
368
+ const prompt = mock(async () => ({}));
369
+ const messages = mock(async () => "");
370
+ const client = createClient(prompt, undefined, messages);
371
+
372
+ await expect(
373
+ promptSyncWithValidatedOutputRetry(client, createArgs(), {
374
+ fallbackModels: ["anthropic/claude-sonnet-4-6"],
375
+ fetchOutput: async () => messages(),
376
+ validateOutput: (output: string, attempt) => {
377
+ if (output.trim().length === 0) {
378
+ throw new Error(`empty output from ${attempt.label}`);
379
+ }
380
+ return output.trim();
381
+ },
382
+ }),
383
+ ).rejects.toThrow("empty output from primary");
384
+
385
+ expect(prompt).toHaveBeenCalledTimes(2);
386
+ expect(messages).toHaveBeenCalledTimes(2);
387
+ });
388
+ });