@cortexkit/opencode-magic-context 0.26.0 → 0.27.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 (285) hide show
  1. package/README.md +14 -12
  2. package/dist/agents/dreamer.d.ts +19 -0
  3. package/dist/agents/dreamer.d.ts.map +1 -1
  4. package/dist/agents/hidden-agent-registrations.d.ts +67 -0
  5. package/dist/agents/hidden-agent-registrations.d.ts.map +1 -0
  6. package/dist/agents/historian.d.ts +1 -0
  7. package/dist/agents/historian.d.ts.map +1 -1
  8. package/dist/agents/permissions.d.ts +15 -44
  9. package/dist/agents/permissions.d.ts.map +1 -1
  10. package/dist/agents/smart-note-compiler.d.ts +2 -0
  11. package/dist/agents/smart-note-compiler.d.ts.map +1 -0
  12. package/dist/config/index.d.ts +1 -1
  13. package/dist/config/index.d.ts.map +1 -1
  14. package/dist/config/migrate-config-location.d.ts +89 -0
  15. package/dist/config/migrate-config-location.d.ts.map +1 -0
  16. package/dist/config/migrate-dreamer-v2.d.ts +37 -0
  17. package/dist/config/migrate-dreamer-v2.d.ts.map +1 -0
  18. package/dist/config/migrate-experimental.d.ts.map +1 -1
  19. package/dist/config/project-security.d.ts +3 -0
  20. package/dist/config/project-security.d.ts.map +1 -1
  21. package/dist/config/prune-config-leaf.d.ts.map +1 -1
  22. package/dist/config/schema/magic-context.d.ts +584 -60
  23. package/dist/config/schema/magic-context.d.ts.map +1 -1
  24. package/dist/features/magic-context/compaction-marker.d.ts +9 -3
  25. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  26. package/dist/features/magic-context/compartment-chunk-embedding.d.ts +1 -1
  27. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  28. package/dist/features/magic-context/dreamer/classify-prompt.d.ts +50 -0
  29. package/dist/features/magic-context/dreamer/classify-prompt.d.ts.map +1 -0
  30. package/dist/features/magic-context/dreamer/classify.d.ts +22 -0
  31. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -0
  32. package/dist/features/magic-context/dreamer/cron.d.ts +72 -0
  33. package/dist/features/magic-context/dreamer/cron.d.ts.map +1 -0
  34. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts +30 -0
  35. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -0
  36. package/dist/features/magic-context/dreamer/index.d.ts +1 -3
  37. package/dist/features/magic-context/dreamer/index.d.ts.map +1 -1
  38. package/dist/features/magic-context/dreamer/lease.d.ts +44 -6
  39. package/dist/features/magic-context/dreamer/lease.d.ts.map +1 -1
  40. package/dist/features/magic-context/dreamer/maintain-docs-protected-enforcement.d.ts +13 -0
  41. package/dist/features/magic-context/dreamer/maintain-docs-protected-enforcement.d.ts.map +1 -0
  42. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts +36 -0
  43. package/dist/features/magic-context/dreamer/map-memories-prompt.d.ts.map +1 -0
  44. package/dist/features/magic-context/dreamer/map-memories.d.ts +22 -0
  45. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -0
  46. package/dist/features/magic-context/dreamer/open-opencode-db.d.ts +7 -0
  47. package/dist/features/magic-context/dreamer/open-opencode-db.d.ts.map +1 -0
  48. package/dist/features/magic-context/dreamer/primer-seed.d.ts +25 -0
  49. package/dist/features/magic-context/dreamer/primer-seed.d.ts.map +1 -0
  50. package/dist/features/magic-context/dreamer/promote-primers.d.ts +21 -0
  51. package/dist/features/magic-context/dreamer/promote-primers.d.ts.map +1 -0
  52. package/dist/features/magic-context/dreamer/protected-regions.d.ts +19 -0
  53. package/dist/features/magic-context/dreamer/protected-regions.d.ts.map +1 -0
  54. package/dist/features/magic-context/dreamer/refresh-primers.d.ts +30 -0
  55. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -0
  56. package/dist/features/magic-context/dreamer/retrospective-learnings.d.ts +47 -0
  57. package/dist/features/magic-context/dreamer/retrospective-learnings.d.ts.map +1 -0
  58. package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts +48 -0
  59. package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts.map +1 -0
  60. package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts +81 -0
  61. package/dist/features/magic-context/dreamer/retrospective-raw-provider.d.ts.map +1 -0
  62. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +8 -0
  63. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  64. package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts +82 -0
  65. package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts.map +1 -0
  66. package/dist/features/magic-context/dreamer/task-config.d.ts +28 -0
  67. package/dist/features/magic-context/dreamer/task-config.d.ts.map +1 -0
  68. package/dist/features/magic-context/dreamer/task-executor.d.ts +49 -0
  69. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -0
  70. package/dist/features/magic-context/dreamer/task-gates.d.ts +29 -0
  71. package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -0
  72. package/dist/features/magic-context/dreamer/task-prompts.d.ts +37 -6
  73. package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -1
  74. package/dist/features/magic-context/dreamer/task-registry.d.ts +48 -0
  75. package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -0
  76. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +88 -0
  77. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -0
  78. package/dist/features/magic-context/dreamer/verify-gate.d.ts +43 -0
  79. package/dist/features/magic-context/dreamer/verify-gate.d.ts.map +1 -0
  80. package/dist/features/magic-context/dreamer/verify-prompt.d.ts +41 -0
  81. package/dist/features/magic-context/dreamer/verify-prompt.d.ts.map +1 -0
  82. package/dist/features/magic-context/dreamer/verify.d.ts +43 -0
  83. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -0
  84. package/dist/features/magic-context/git-commits/search-git-commits.d.ts +2 -0
  85. package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -1
  86. package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts +4 -4
  87. package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -1
  88. package/dist/features/magic-context/index.d.ts +1 -0
  89. package/dist/features/magic-context/index.d.ts.map +1 -1
  90. package/dist/features/magic-context/memory/embedding-cache.d.ts +2 -2
  91. package/dist/features/magic-context/memory/embedding-cache.d.ts.map +1 -1
  92. package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -1
  93. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  94. package/dist/features/magic-context/memory/embedding-openai.d.ts +12 -5
  95. package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
  96. package/dist/features/magic-context/memory/embedding.d.ts +2 -2
  97. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
  98. package/dist/features/magic-context/memory/index.d.ts +4 -1
  99. package/dist/features/magic-context/memory/index.d.ts.map +1 -1
  100. package/dist/features/magic-context/memory/memory-migration.d.ts +1 -0
  101. package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
  102. package/dist/features/magic-context/memory/promotion.d.ts +16 -4
  103. package/dist/features/magic-context/memory/promotion.d.ts.map +1 -1
  104. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +2 -2
  105. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
  106. package/dist/features/magic-context/memory/storage-memory-verifications.d.ts +31 -0
  107. package/dist/features/magic-context/memory/storage-memory-verifications.d.ts.map +1 -0
  108. package/dist/features/magic-context/memory/storage-memory.d.ts +12 -1
  109. package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
  110. package/dist/features/magic-context/memory/types.d.ts +4 -0
  111. package/dist/features/magic-context/memory/types.d.ts.map +1 -1
  112. package/dist/features/magic-context/memory/verification-paths.d.ts +32 -0
  113. package/dist/features/magic-context/memory/verification-paths.d.ts.map +1 -0
  114. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  115. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  116. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  117. package/dist/features/magic-context/primer-clustering.d.ts +29 -0
  118. package/dist/features/magic-context/primer-clustering.d.ts.map +1 -0
  119. package/dist/features/magic-context/project-embedding-registry.d.ts +25 -1
  120. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  121. package/dist/features/magic-context/search.d.ts +12 -2
  122. package/dist/features/magic-context/search.d.ts.map +1 -1
  123. package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -1
  124. package/dist/features/magic-context/smart-notes/capabilities.d.ts +31 -0
  125. package/dist/features/magic-context/smart-notes/capabilities.d.ts.map +1 -0
  126. package/dist/features/magic-context/smart-notes/compiler-prompt.d.ts +2 -0
  127. package/dist/features/magic-context/smart-notes/compiler-prompt.d.ts.map +1 -0
  128. package/dist/features/magic-context/smart-notes/compiler.d.ts +52 -0
  129. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -0
  130. package/dist/features/magic-context/smart-notes/index.d.ts +10 -0
  131. package/dist/features/magic-context/smart-notes/index.d.ts.map +1 -0
  132. package/dist/features/magic-context/smart-notes/runner.d.ts +18 -0
  133. package/dist/features/magic-context/smart-notes/runner.d.ts.map +1 -0
  134. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts +22 -0
  135. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -0
  136. package/dist/features/magic-context/smart-notes/schedule.d.ts +9 -0
  137. package/dist/features/magic-context/smart-notes/schedule.d.ts.map +1 -0
  138. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts +49 -0
  139. package/dist/features/magic-context/smart-notes/ssrf-guard.d.ts.map +1 -0
  140. package/dist/features/magic-context/smart-notes/storage.d.ts +27 -0
  141. package/dist/features/magic-context/smart-notes/storage.d.ts.map +1 -0
  142. package/dist/features/magic-context/smart-notes/types.d.ts +63 -0
  143. package/dist/features/magic-context/smart-notes/types.d.ts.map +1 -0
  144. package/dist/features/magic-context/storage-db.d.ts +5 -1
  145. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  146. package/dist/features/magic-context/storage-meta-persisted.d.ts +8 -4
  147. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  148. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  149. package/dist/features/magic-context/storage-meta-shared.d.ts +3 -1
  150. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
  151. package/dist/features/magic-context/storage-notes.d.ts +15 -0
  152. package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
  153. package/dist/features/magic-context/storage-primers.d.ts +85 -0
  154. package/dist/features/magic-context/storage-primers.d.ts.map +1 -0
  155. package/dist/features/magic-context/storage-tags.d.ts +20 -0
  156. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  157. package/dist/features/magic-context/storage.d.ts +2 -1
  158. package/dist/features/magic-context/storage.d.ts.map +1 -1
  159. package/dist/features/magic-context/tagger.d.ts +6 -0
  160. package/dist/features/magic-context/tagger.d.ts.map +1 -1
  161. package/dist/features/magic-context/tool-owner-backfill.d.ts.map +1 -1
  162. package/dist/features/magic-context/transform-decision-log.d.ts +10 -0
  163. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  164. package/dist/features/magic-context/types.d.ts +2 -0
  165. package/dist/features/magic-context/types.d.ts.map +1 -1
  166. package/dist/features/magic-context/user-memory/review-user-memories.d.ts +5 -0
  167. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
  168. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +18 -0
  169. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
  170. package/dist/features/magic-context/v22-deferred-backfill.d.ts.map +1 -1
  171. package/dist/hooks/auto-update-checker/semver.d.ts +9 -0
  172. package/dist/hooks/auto-update-checker/semver.d.ts.map +1 -1
  173. package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
  174. package/dist/hooks/magic-context/command-handler.d.ts +8 -15
  175. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  176. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  177. package/dist/hooks/magic-context/compartment-parser.d.ts +9 -0
  178. package/dist/hooks/magic-context/compartment-parser.d.ts.map +1 -1
  179. package/dist/hooks/magic-context/compartment-prompt.d.ts +4 -1
  180. package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -1
  181. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +1 -0
  182. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  183. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  184. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  185. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  186. package/dist/hooks/magic-context/compartment-runner-types.d.ts +8 -0
  187. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  188. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -1
  189. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
  190. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  191. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  192. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  193. package/dist/hooks/magic-context/historian-prompt.generated.d.ts +1 -1
  194. package/dist/hooks/magic-context/historian-prompt.generated.d.ts.map +1 -1
  195. package/dist/hooks/magic-context/historian-state-file.d.ts.map +1 -1
  196. package/dist/hooks/magic-context/hook-handlers.d.ts +2 -1
  197. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  198. package/dist/hooks/magic-context/hook.d.ts +1 -0
  199. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  200. package/dist/hooks/magic-context/inject-compartments.d.ts +0 -3
  201. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  202. package/dist/hooks/magic-context/send-session-notification.d.ts +2 -0
  203. package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
  204. package/dist/hooks/magic-context/system-prompt-hash.d.ts +17 -0
  205. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  206. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +8 -5
  207. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  208. package/dist/hooks/magic-context/transform.d.ts +0 -2
  209. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  210. package/dist/index.d.ts +2 -2
  211. package/dist/index.d.ts.map +1 -1
  212. package/dist/index.js +17034 -4059
  213. package/dist/plugin/dream-timer.d.ts +17 -9
  214. package/dist/plugin/dream-timer.d.ts.map +1 -1
  215. package/dist/plugin/embedding-bootstrap-helpers.d.ts +1 -1
  216. package/dist/plugin/embedding-bootstrap-helpers.d.ts.map +1 -1
  217. package/dist/plugin/embedding-bootstrap.d.ts.map +1 -1
  218. package/dist/plugin/hooks/create-session-hooks.d.ts +211 -0
  219. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  220. package/dist/plugin/instance-disposal.d.ts +2 -0
  221. package/dist/plugin/instance-disposal.d.ts.map +1 -0
  222. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  223. package/dist/shared/announcement.d.ts +1 -1
  224. package/dist/shared/announcement.d.ts.map +1 -1
  225. package/dist/shared/data-path.d.ts +26 -7
  226. package/dist/shared/data-path.d.ts.map +1 -1
  227. package/dist/shared/model-suggestion-retry.d.ts +48 -2
  228. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  229. package/dist/shared/redaction.d.ts +7 -0
  230. package/dist/shared/redaction.d.ts.map +1 -0
  231. package/dist/shared/resolve-fallbacks.d.ts +12 -0
  232. package/dist/shared/resolve-fallbacks.d.ts.map +1 -1
  233. package/dist/shared/rpc-server.d.ts.map +1 -1
  234. package/dist/shared/rpc-types.d.ts +2 -0
  235. package/dist/shared/rpc-types.d.ts.map +1 -1
  236. package/dist/shared/subagent-runner.d.ts +12 -3
  237. package/dist/shared/subagent-runner.d.ts.map +1 -1
  238. package/dist/shared/tui-config.d.ts.map +1 -1
  239. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  240. package/dist/tools/ctx-memory/types.d.ts.map +1 -1
  241. package/dist/tools/ctx-memory/verification-recording.d.ts +8 -0
  242. package/dist/tools/ctx-memory/verification-recording.d.ts.map +1 -0
  243. package/dist/tools/ctx-search/tools.d.ts.map +1 -1
  244. package/dist/tools/ctx-search/types.d.ts +1 -1
  245. package/dist/tools/ctx-search/types.d.ts.map +1 -1
  246. package/dist/tui/data/context-db.d.ts +2 -0
  247. package/dist/tui/data/context-db.d.ts.map +1 -1
  248. package/package.json +3 -1
  249. package/src/shared/announcement.test.ts +20 -0
  250. package/src/shared/announcement.ts +19 -7
  251. package/src/shared/data-path.test.ts +70 -6
  252. package/src/shared/data-path.ts +50 -8
  253. package/src/shared/model-suggestion-retry.test.ts +79 -2
  254. package/src/shared/model-suggestion-retry.ts +181 -3
  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 +63 -0
  262. package/src/shared/tui-config.ts +67 -39
  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/hooks/magic-context/key-files-block.d.ts +0 -27
  285. package/dist/hooks/magic-context/key-files-block.d.ts.map +0 -1
@@ -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": "@cortexkit/opencode-magic-context",
3
- "version": "0.26.0",
3
+ "version": "0.27.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",
@@ -41,10 +41,12 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@huggingface/transformers": "^4.1.0",
44
+ "@jitl/quickjs-singlefile-cjs-release-asyncify": "0.32.0",
44
45
  "@opencode-ai/plugin": "^1.15.13",
45
46
  "@opencode-ai/sdk": "^1.15.13",
46
47
  "ai-tokenizer": "^1.0.6",
47
48
  "comment-json": "^4.2.5",
49
+ "quickjs-emscripten": "^0.32.0",
48
50
  "zod": "^4.1.8"
49
51
  },
50
52
  "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,25 @@
17
17
 
18
18
  import * as fs from "node:fs";
19
19
  import * as path from "node:path";
20
+ import { compareSemverCore } from "../hooks/auto-update-checker/semver";
20
21
  import { getMagicContextStorageDir } from "./data-path";
21
22
 
22
23
  /**
23
24
  * Bump only when there are user-visible changes worth a startup dialog.
24
25
  * Does NOT need to match the published package version.
25
26
  */
26
- export const ANNOUNCEMENT_VERSION = "0.26.0";
27
+ export const ANNOUNCEMENT_VERSION = "0.27.0";
27
28
 
28
29
  /**
29
30
  * Short, user-facing bullet strings. Keep each line ~80 chars or shorter so the
30
31
  * TUI dialog renders cleanly without horizontal scroll on a typical terminal.
31
32
  */
32
33
  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.",
34
+ "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.",
35
+ "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.",
36
+ "New Primers: durable answers to the questions that keep coming up about your project, kept current by the dreamer investigating the actual code.",
37
+ "Embedding storage no longer wipes your vectors when you change model or endpoint. Different models now coexist, so switching providers keeps your existing vectors.",
38
+ "Config moved to a shared CortexKit location (~/.config/cortexkit/ and <project>/.cortexkit/). This happens automatically on first run; your old file is preserved.",
38
39
  ];
39
40
 
40
41
  /**
@@ -130,5 +131,16 @@ export function shouldShowAnnouncement(): boolean {
130
131
  // Do not advance the version; a later successful boot can still show it.
131
132
  return false;
132
133
  }
133
- return state.version !== ANNOUNCEMENT_VERSION;
134
+ // Show ONLY on a forward version change (current > stored). A bare string
135
+ // inequality re-announced on a DOWNGRADE (0.27.0 → 0.26.0) or when stored
136
+ // state held an unexpected value. compareSemverCore returns null for
137
+ // non-semver input → treat conservatively (don't announce).
138
+ const ordering = compareSemverCore(ANNOUNCEMENT_VERSION, state.version);
139
+ if (ordering === null) {
140
+ // Stored version isn't parseable as semver but differs from current: only
141
+ // announce when it's genuinely not the current string (avoids re-showing on
142
+ // every boot for a corrupt-but-present value).
143
+ return state.version !== ANNOUNCEMENT_VERSION;
144
+ }
145
+ return ordering > 0;
134
146
  }
@@ -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,20 +123,20 @@ describe("data-path", () => {
121
123
  expect(shared).toContain("cortexkit");
122
124
  });
123
125
 
124
- test("getProjectMagicContextDir composes <project>/.opencode/magic-context", () => {
126
+ test("getProjectMagicContextDir composes <project>/.cortexkit/magic-context", () => {
125
127
  // Project-local artifacts (historian state file, failure dumps) live
126
128
  // inside the project so OpenCode's external_directory permission system
127
129
  // treats them as project-internal. Without this, historian's Read tool
128
130
  // would trigger a permission prompt on every run when artifacts lived
129
- // under os.tmpdir().
131
+ // under os.tmpdir(). Moved from .opencode/ to the shared .cortexkit/.
130
132
  expect(getProjectMagicContextDir("/Users/me/Work/proj")).toBe(
131
- path.join("/Users/me/Work/proj", ".opencode", "magic-context"),
133
+ path.join("/Users/me/Work/proj", ".cortexkit", "magic-context"),
132
134
  );
133
135
  });
134
136
 
135
137
  test("getProjectMagicContextHistorianDir appends historian/", () => {
136
138
  expect(getProjectMagicContextHistorianDir("/Users/me/Work/proj")).toBe(
137
- path.join("/Users/me/Work/proj", ".opencode", "magic-context", "historian"),
139
+ path.join("/Users/me/Work/proj", ".cortexkit", "magic-context", "historian"),
138
140
  );
139
141
  });
140
142
 
@@ -145,7 +147,7 @@ describe("data-path", () => {
145
147
  // project-local historian dir.
146
148
  process.env.XDG_DATA_HOME = "/tmp/custom-data";
147
149
  expect(getProjectMagicContextDir("/some/project")).toBe(
148
- path.join("/some/project", ".opencode", "magic-context"),
150
+ path.join("/some/project", ".cortexkit", "magic-context"),
149
151
  );
150
152
  });
151
153
 
@@ -153,7 +155,69 @@ describe("data-path", () => {
153
155
  // path.join normalizes redundant separators so callers don't need to
154
156
  // worry about how the project directory was constructed.
155
157
  expect(getProjectMagicContextDir("/some/project/")).toBe(
156
- path.join("/some/project/", ".opencode", "magic-context"),
158
+ path.join("/some/project/", ".cortexkit", "magic-context"),
157
159
  );
158
160
  });
159
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,28 +63,69 @@ export function getMagicContextHistorianDir(harness: HarnessId = getHarness()):
62
63
  /**
63
64
  * Project-local magic-context artifact directory.
64
65
  *
65
- * Layout: `<project-directory>/.opencode/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 `.opencode/` subtree falls inside the project boundary and
73
+ * project's own `.cortexkit/` subtree falls inside the project boundary and
73
74
  * never triggers a permission prompt.
74
75
  *
75
- * The `.opencode/` parent dir is OpenCode's own per-project convention (used
76
- * for project-local config, plans, dumps, plugin installs). Anchoring
77
- * magic-context artifacts under `.opencode/magic-context/` keeps them
78
- * co-located with related OpenCode metadata and makes them easy for users to
79
- * locate when debugging.
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).
80
85
  *
81
86
  * Logger does NOT use this — log files stay in the per-harness tmp subtree
82
87
  * because they are written by the plugin process itself (no model-side Read
83
88
  * tool call, no permission prompt) and span sessions/projects.
84
89
  */
85
90
  export function getProjectMagicContextDir(directory: string): string {
86
- return path.join(directory, ".opencode", "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
+ }
87
129
  }
88
130
 
89
131
  /**
@@ -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
+ });