@cortexkit/opencode-magic-context 0.41.4 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. package/README.md +21 -3
  2. package/dist/agents/hidden-agent-registrations.d.ts +1 -3
  3. package/dist/agents/hidden-agent-registrations.d.ts.map +1 -1
  4. package/dist/agents/magic-context-prompt.d.ts +1 -1
  5. package/dist/agents/magic-context-prompt.d.ts.map +1 -1
  6. package/dist/agents/permissions.d.ts +1 -22
  7. package/dist/agents/permissions.d.ts.map +1 -1
  8. package/dist/config/agent-disable.d.ts +0 -5
  9. package/dist/config/agent-disable.d.ts.map +1 -1
  10. package/dist/config/index.d.ts +5 -0
  11. package/dist/config/index.d.ts.map +1 -1
  12. package/dist/config/migrate-config-location.d.ts.map +1 -1
  13. package/dist/config/project-security.d.ts +17 -0
  14. package/dist/config/project-security.d.ts.map +1 -1
  15. package/dist/config/removed-agent-config.d.ts +8 -0
  16. package/dist/config/removed-agent-config.d.ts.map +1 -0
  17. package/dist/config/schema/magic-context.d.ts +23 -201
  18. package/dist/config/schema/magic-context.d.ts.map +1 -1
  19. package/dist/{conflict-warning-hook-ejkc9sjn.js → conflict-warning-hook-6p3xqeac.js} +3 -3
  20. package/dist/{derive-budgets-bc366cz8.js → derive-budgets-s2pgnnm4.js} +1 -1
  21. package/dist/features/builtin-commands/commands.d.ts +0 -4
  22. package/dist/features/builtin-commands/commands.d.ts.map +1 -1
  23. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  24. package/dist/features/magic-context/compartment-chunk-embedding.d.ts +7 -0
  25. package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
  26. package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
  27. package/dist/features/magic-context/context-authority.d.ts +31 -4
  28. package/dist/features/magic-context/context-authority.d.ts.map +1 -1
  29. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  30. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  31. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  32. package/dist/features/magic-context/dreamer/open-opencode-db.d.ts.map +1 -1
  33. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  34. package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts +19 -9
  35. package/dist/features/magic-context/dreamer/retrospective-orphan-sweep.d.ts.map +1 -1
  36. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  37. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +4 -0
  38. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  39. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  40. package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
  41. package/dist/features/magic-context/git-commits/sweep-coordinator.d.ts.map +1 -1
  42. package/dist/features/magic-context/index.d.ts +0 -1
  43. package/dist/features/magic-context/index.d.ts.map +1 -1
  44. package/dist/features/magic-context/memory/embedding-local.d.ts +13 -0
  45. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  46. package/dist/features/magic-context/memory/embedding-synapse.d.ts +43 -10
  47. package/dist/features/magic-context/memory/embedding-synapse.d.ts.map +1 -1
  48. package/dist/features/magic-context/memory/embedding.d.ts +1 -1
  49. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
  50. package/dist/features/magic-context/memory/memory-migration.d.ts.map +1 -1
  51. package/dist/features/magic-context/memory/project-identity.d.ts +1 -0
  52. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  53. package/dist/features/magic-context/memory/promotion.d.ts +7 -1
  54. package/dist/features/magic-context/memory/promotion.d.ts.map +1 -1
  55. package/dist/features/magic-context/merged-reasoning-decisions.d.ts +6 -0
  56. package/dist/features/magic-context/merged-reasoning-decisions.d.ts.map +1 -0
  57. package/dist/features/magic-context/message-fts-rowid-map.d.ts.map +1 -1
  58. package/dist/features/magic-context/message-index-async.d.ts +12 -0
  59. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  60. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  61. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  62. package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
  63. package/dist/features/magic-context/mural/render-trigger.d.ts +6 -0
  64. package/dist/features/magic-context/mural/render-trigger.d.ts.map +1 -1
  65. package/dist/features/magic-context/no-content-compartment.d.ts +12 -0
  66. package/dist/features/magic-context/no-content-compartment.d.ts.map +1 -0
  67. package/dist/features/magic-context/pi-content-decisions.d.ts +9 -0
  68. package/dist/features/magic-context/pi-content-decisions.d.ts.map +1 -0
  69. package/dist/features/magic-context/project-docs-hash.d.ts +4 -0
  70. package/dist/features/magic-context/project-docs-hash.d.ts.map +1 -1
  71. package/dist/features/magic-context/project-embedding-registry.d.ts +13 -4
  72. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  73. package/dist/features/magic-context/protection-window.d.ts +79 -0
  74. package/dist/features/magic-context/protection-window.d.ts.map +1 -0
  75. package/dist/features/magic-context/search.d.ts.map +1 -1
  76. package/dist/features/magic-context/session-project-backfill.d.ts.map +1 -1
  77. package/dist/features/magic-context/shadow-backfill-state.d.ts +26 -0
  78. package/dist/features/magic-context/shadow-backfill-state.d.ts.map +1 -0
  79. package/dist/features/magic-context/smart-notes/compiler.d.ts.map +1 -1
  80. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts +4 -0
  81. package/dist/features/magic-context/smart-notes/sandbox-runner.d.ts.map +1 -1
  82. package/dist/features/magic-context/smart-notes/storage.d.ts.map +1 -1
  83. package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
  84. package/dist/features/magic-context/storage-db.d.ts +1 -1
  85. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  86. package/dist/features/magic-context/storage-embedding-measurements.d.ts +2 -2
  87. package/dist/features/magic-context/storage-embedding-measurements.d.ts.map +1 -1
  88. package/dist/features/magic-context/storage-historian-runs.d.ts +4 -0
  89. package/dist/features/magic-context/storage-historian-runs.d.ts.map +1 -1
  90. package/dist/features/magic-context/storage-memory-mutation-log.d.ts +1 -0
  91. package/dist/features/magic-context/storage-memory-mutation-log.d.ts.map +1 -1
  92. package/dist/features/magic-context/storage-meta-persisted.d.ts +79 -13
  93. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  94. package/dist/features/magic-context/storage-meta.d.ts +1 -1
  95. package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
  96. package/dist/features/magic-context/storage-native-replay.d.ts +29 -0
  97. package/dist/features/magic-context/storage-native-replay.d.ts.map +1 -0
  98. package/dist/features/magic-context/storage-notes.d.ts +6 -0
  99. package/dist/features/magic-context/storage-notes.d.ts.map +1 -1
  100. package/dist/features/magic-context/storage-replay-document.d.ts +33 -0
  101. package/dist/features/magic-context/storage-replay-document.d.ts.map +1 -0
  102. package/dist/features/magic-context/storage-subagent-invocations.d.ts +1 -1
  103. package/dist/features/magic-context/storage-subagent-invocations.d.ts.map +1 -1
  104. package/dist/features/magic-context/storage-tags.d.ts +19 -11
  105. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  106. package/dist/features/magic-context/storage.d.ts +3 -3
  107. package/dist/features/magic-context/storage.d.ts.map +1 -1
  108. package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -1
  109. package/dist/features/magic-context/tagger.d.ts +13 -0
  110. package/dist/features/magic-context/tagger.d.ts.map +1 -1
  111. package/dist/features/magic-context/tool-owner-backfill.d.ts.map +1 -1
  112. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
  113. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
  114. package/dist/features/magic-context/workspaces.d.ts.map +1 -1
  115. package/dist/hooks/magic-context/apply-operations.d.ts +11 -5
  116. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  117. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  118. package/dist/hooks/magic-context/cache-busting-signals.d.ts +9 -1
  119. package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -1
  120. package/dist/hooks/magic-context/caveman-cleanup.d.ts +1 -1
  121. package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -1
  122. package/dist/hooks/magic-context/channel2-delivery.d.ts.map +1 -1
  123. package/dist/hooks/magic-context/child-session-spawn.d.ts +3 -3
  124. package/dist/hooks/magic-context/child-session-spawn.d.ts.map +1 -1
  125. package/dist/hooks/magic-context/command-handler.d.ts +1 -10
  126. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  127. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  128. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts +10 -21
  129. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts.map +1 -1
  130. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  131. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  132. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +26 -2
  133. package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
  134. package/dist/hooks/magic-context/decay-render.d.ts.map +1 -1
  135. package/dist/hooks/magic-context/dropped-input-guard.d.ts +9 -0
  136. package/dist/hooks/magic-context/dropped-input-guard.d.ts.map +1 -0
  137. package/dist/hooks/magic-context/emergency-drop.d.ts +6 -1
  138. package/dist/hooks/magic-context/emergency-drop.d.ts.map +1 -1
  139. package/dist/hooks/magic-context/event-handler.d.ts +0 -1
  140. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  141. package/dist/hooks/magic-context/event-payloads.d.ts +7 -6
  142. package/dist/hooks/magic-context/event-payloads.d.ts.map +1 -1
  143. package/dist/hooks/magic-context/event-resolvers.d.ts +1 -1
  144. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
  145. package/dist/hooks/magic-context/execute-status.d.ts +1 -1
  146. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
  147. package/dist/hooks/magic-context/format-embed-status.d.ts.map +1 -1
  148. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +7 -1
  149. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  150. package/dist/hooks/magic-context/hook-handlers.d.ts +3 -1
  151. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  152. package/dist/hooks/magic-context/hook.d.ts +13 -4
  153. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  154. package/dist/hooks/magic-context/inject-compartments.d.ts +14 -1
  155. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  156. package/dist/hooks/magic-context/live-session-state.d.ts +1 -1
  157. package/dist/hooks/magic-context/lkg-slot.d.ts +34 -0
  158. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  159. package/dist/hooks/magic-context/module-state-sync-timing.d.ts +21 -0
  160. package/dist/hooks/magic-context/module-state-sync-timing.d.ts.map +1 -0
  161. package/dist/hooks/magic-context/module-state-sync.d.ts +21 -7
  162. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  163. package/dist/hooks/magic-context/module-transport.d.ts +12 -0
  164. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  165. package/dist/hooks/magic-context/module-wire.d.ts +8 -0
  166. package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
  167. package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
  168. package/dist/hooks/magic-context/persist-filtered-noise.d.ts +5 -0
  169. package/dist/hooks/magic-context/persist-filtered-noise.d.ts.map +1 -0
  170. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +6 -0
  171. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  172. package/dist/hooks/magic-context/read-session-chunk.d.ts +18 -18
  173. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  174. package/dist/hooks/magic-context/read-session-db.d.ts +22 -12
  175. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  176. package/dist/hooks/magic-context/read-session-formatting.d.ts +8 -0
  177. package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
  178. package/dist/hooks/magic-context/read-session-raw.d.ts +10 -1
  179. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
  180. package/dist/hooks/magic-context/reference-retrieval.d.ts.map +1 -1
  181. package/dist/hooks/magic-context/rust-mode-transform.d.ts +74 -9
  182. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  183. package/dist/hooks/magic-context/send-session-notification.d.ts +11 -10
  184. package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
  185. package/dist/hooks/magic-context/strip-content.d.ts +7 -0
  186. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  187. package/dist/hooks/magic-context/supersession-reclaim.d.ts +13 -0
  188. package/dist/hooks/magic-context/supersession-reclaim.d.ts.map +1 -1
  189. package/dist/hooks/magic-context/system-prompt-hash.d.ts +2 -3
  190. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  191. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts +8 -3
  192. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  193. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -1
  194. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  195. package/dist/hooks/magic-context/transform-context-state.d.ts +7 -1
  196. package/dist/hooks/magic-context/transform-context-state.d.ts.map +1 -1
  197. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +11 -4
  198. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  199. package/dist/hooks/magic-context/transform.d.ts +7 -2
  200. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  201. package/dist/hooks/magic-context/upgrade-reminder.d.ts +7 -9
  202. package/dist/hooks/magic-context/upgrade-reminder.d.ts.map +1 -1
  203. package/dist/hooks/magic-context/wrapup-orchestrator.d.ts.map +1 -1
  204. package/dist/index-1974jvn3.js +783 -0
  205. package/dist/{index-4avmwfp5.js → index-36wd1d6k.js} +6 -29
  206. package/dist/{index-0y2mcg5y.js → index-c9hamh36.js} +18332 -16226
  207. package/dist/{index-fz104x1j.js → index-jmtjh2d3.js} +3 -3
  208. package/dist/{index-q264erdp.js → index-nqgjwfzn.js} +70 -38
  209. package/dist/{index-mjv9je4e.js → index-xdtge3y2.js} +45 -7
  210. package/dist/index.d.ts.map +1 -1
  211. package/dist/index.js +6199 -5088
  212. package/dist/plugin/conflict-warning-hook.d.ts +5 -6
  213. package/dist/plugin/conflict-warning-hook.d.ts.map +1 -1
  214. package/dist/plugin/dream-timer.d.ts +1 -0
  215. package/dist/plugin/dream-timer.d.ts.map +1 -1
  216. package/dist/plugin/embedding-routing.d.ts +4 -1
  217. package/dist/plugin/embedding-routing.d.ts.map +1 -1
  218. package/dist/plugin/hooks/create-session-hooks.d.ts +16 -2
  219. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  220. package/dist/plugin/rpc-handlers.d.ts +31 -1
  221. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  222. package/dist/plugin/rust-tool-backends.d.ts +1 -0
  223. package/dist/plugin/rust-tool-backends.d.ts.map +1 -1
  224. package/dist/plugin/tool-registry.d.ts.map +1 -1
  225. package/dist/{recomp-orchestrator-q98r6rga.js → recomp-orchestrator-3atsasjy.js} +5 -5
  226. package/dist/{send-session-notification-hdh02wy9.js → send-session-notification-1qeqkswb.js} +6 -4
  227. package/dist/shared/child-session-teardown.d.ts +34 -0
  228. package/dist/shared/child-session-teardown.d.ts.map +1 -0
  229. package/dist/shared/keep-subagents.d.ts +1 -1
  230. package/dist/shared/keep-subagents.d.ts.map +1 -1
  231. package/dist/shared/model-suggestion-retry.d.ts +1 -1
  232. package/dist/shared/opencode-db-path.d.ts +24 -0
  233. package/dist/shared/opencode-db-path.d.ts.map +1 -0
  234. package/dist/shared/prompt-surface-runtime.d.ts +10 -5
  235. package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
  236. package/dist/shared/resolve-fallbacks.d.ts +1 -1
  237. package/dist/shared/rpc-types.d.ts +111 -0
  238. package/dist/shared/rpc-types.d.ts.map +1 -1
  239. package/dist/shared/sqlite.d.ts +42 -0
  240. package/dist/shared/sqlite.d.ts.map +1 -1
  241. package/dist/shared/status-detail-text.d.ts.map +1 -1
  242. package/dist/shared/subagent-runner.d.ts +17 -10
  243. package/dist/shared/subagent-runner.d.ts.map +1 -1
  244. package/dist/shared/tag-transcript.d.ts.map +1 -1
  245. package/dist/shared/transcript.d.ts +6 -0
  246. package/dist/shared/transcript.d.ts.map +1 -1
  247. package/dist/shared/window-geometry.d.ts +23 -0
  248. package/dist/shared/window-geometry.d.ts.map +1 -1
  249. package/dist/shared/write-transaction-timing.d.ts +1 -1
  250. package/dist/shared/write-transaction-timing.d.ts.map +1 -1
  251. package/dist/{storage-meta-session-dvwfw778.js → storage-meta-session-e6g0mmec.js} +2 -2
  252. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  253. package/dist/tools/ctx-memory/verification-recording.d.ts.map +1 -1
  254. package/dist/tools/ctx-note/constants.d.ts +1 -1
  255. package/dist/tools/ctx-note/constants.d.ts.map +1 -1
  256. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  257. package/dist/tools/ctx-note/types.d.ts +1 -0
  258. package/dist/tools/ctx-note/types.d.ts.map +1 -1
  259. package/dist/tools/ctx-reduce/tools.d.ts +10 -1
  260. package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
  261. package/dist/tools/ctx-search/constants.d.ts +1 -1
  262. package/dist/tools/ctx-search/constants.d.ts.map +1 -1
  263. package/dist/tools/light-descriptions.d.ts +2 -2
  264. package/dist/tools/light-descriptions.d.ts.map +1 -1
  265. package/package.json +2 -3
  266. package/src/agents/hidden-agent-registrations.ts +3 -15
  267. package/src/agents/magic-context-prompt.test.ts +7 -5
  268. package/src/agents/magic-context-prompt.ts +22 -30
  269. package/src/agents/permissions.test.ts +1 -42
  270. package/src/agents/permissions.ts +1 -24
  271. package/src/config/agent-disable.ts +5 -22
  272. package/src/config/index.test.ts +126 -15
  273. package/src/config/index.ts +41 -6
  274. package/src/config/latch-permanence-guard.test.ts +4 -0
  275. package/src/config/migrate-config-location.test.ts +39 -6
  276. package/src/config/migrate-config-location.ts +18 -31
  277. package/src/config/profiles.ts +1 -1
  278. package/src/config/project-security.hostile-matrix.test.ts +0 -8
  279. package/src/config/project-security.test.ts +11 -22
  280. package/src/config/project-security.ts +103 -9
  281. package/src/config/protected-tokens.test.ts +235 -0
  282. package/src/config/removed-agent-config.ts +45 -0
  283. package/src/config/removed-agent-source-fence.test.ts +56 -0
  284. package/src/config/schema/magic-context.test.ts +21 -42
  285. package/src/config/schema/magic-context.ts +46 -37
  286. package/src/shared/child-session-teardown.test.ts +218 -0
  287. package/src/shared/child-session-teardown.ts +66 -0
  288. package/src/shared/keep-subagents.ts +9 -14
  289. package/src/shared/model-suggestion-retry.ts +1 -1
  290. package/src/shared/opencode-db-path.test.ts +196 -0
  291. package/src/shared/opencode-db-path.ts +215 -0
  292. package/src/shared/prompt-surface-a1-golden.md +50 -35
  293. package/src/shared/prompt-surface-runtime.test.ts +28 -0
  294. package/src/shared/prompt-surface-runtime.ts +22 -5
  295. package/src/shared/resolve-fallbacks.ts +1 -1
  296. package/src/shared/rpc-types.ts +118 -0
  297. package/src/shared/session-messages-bounded.test.ts +1 -1
  298. package/src/shared/sqlite-import-fence.test.ts +19 -0
  299. package/src/shared/sqlite.test.ts +27 -1
  300. package/src/shared/sqlite.ts +204 -1
  301. package/src/shared/status-detail-text.test.ts +6 -3
  302. package/src/shared/status-detail-text.ts +15 -0
  303. package/src/shared/subagent-runner.ts +17 -10
  304. package/src/shared/tag-transcript.ts +33 -21
  305. package/src/shared/transcript.ts +7 -0
  306. package/src/shared/window-geometry.test.ts +44 -0
  307. package/src/shared/window-geometry.ts +89 -11
  308. package/src/shared/write-transaction-attribution.test.ts +241 -0
  309. package/src/shared/write-transaction-timing.ts +2 -1
  310. package/src/tui/index.tsx +3 -3
  311. package/src/tui/slots/sidebar-content.tsx +12 -7
  312. package/src/tui-compiled/index.tsx +3 -3
  313. package/src/tui-compiled/slots/sidebar-content.tsx +301 -305
  314. package/dist/agents/sidekick.d.ts +0 -2
  315. package/dist/agents/sidekick.d.ts.map +0 -1
  316. package/dist/features/magic-context/defaults.d.ts +0 -2
  317. package/dist/features/magic-context/defaults.d.ts.map +0 -1
  318. package/dist/features/magic-context/sidekick/agent.d.ts +0 -14
  319. package/dist/features/magic-context/sidekick/agent.d.ts.map +0 -1
  320. package/dist/features/magic-context/sidekick/core.d.ts +0 -38
  321. package/dist/features/magic-context/sidekick/core.d.ts.map +0 -1
  322. package/dist/features/magic-context/sidekick/index.d.ts +0 -3
  323. package/dist/features/magic-context/sidekick/index.d.ts.map +0 -1
  324. package/dist/hooks/magic-context/boundary-execution.d.ts +0 -27
  325. package/dist/hooks/magic-context/boundary-execution.d.ts.map +0 -1
  326. package/dist/index-raatkvw5.js +0 -360
  327. package/src/agents/sidekick.ts +0 -1
  328. package/src/features/magic-context/defaults.ts +0 -1
@@ -0,0 +1,66 @@
1
+ import { shouldKeepSubagents } from "./keep-subagents";
2
+
3
+ interface ChildSessionRequest {
4
+ path: { id: string };
5
+ query?: { directory: string };
6
+ }
7
+
8
+ interface ArchiveChildSessionRequest extends ChildSessionRequest {
9
+ body: { time: { archived: number } };
10
+ }
11
+
12
+ export interface ChildSessionTeardownClient {
13
+ session: {
14
+ delete(request: ChildSessionRequest): Promise<unknown>;
15
+ };
16
+ }
17
+
18
+ export interface TeardownChildSessionArgs {
19
+ client: ChildSessionTeardownClient;
20
+ sessionId: string | null;
21
+ sessionDirectory?: string;
22
+ promptSettled: boolean;
23
+ privacySensitive: boolean;
24
+ context: string;
25
+ log: (message: string) => void;
26
+ }
27
+
28
+ /**
29
+ * Retire a child only after its prompt helper resolves. An unresolved client call
30
+ * can leave OpenCode's server loop writing, so that row is archived for immediate
31
+ * UI hiding and retained until the age-gated sweep can delete it safely.
32
+ *
33
+ * OpenCode's generated v2 SDK models archival as `session.update` with
34
+ * `time.archived`; the plugin's legacy path/body client reaches the same PATCH
35
+ * endpoint, although its generated TypeScript body type does not yet expose time.
36
+ */
37
+ export async function teardownChildSession(args: TeardownChildSessionArgs): Promise<void> {
38
+ const { client, sessionId, sessionDirectory, promptSettled, privacySensitive, context, log } =
39
+ args;
40
+ if (!sessionId) return;
41
+
42
+ const request: ChildSessionRequest = {
43
+ path: { id: sessionId },
44
+ ...(sessionDirectory ? { query: { directory: sessionDirectory } } : {}),
45
+ };
46
+
47
+ if (promptSettled && (privacySensitive || !shouldKeepSubagents())) {
48
+ await client.session.delete(request).catch((error: unknown) => {
49
+ log(`${context}: session cleanup failed: ${String(error)}`);
50
+ });
51
+ return;
52
+ }
53
+
54
+ if (!promptSettled) {
55
+ const archiveSession = client.session as unknown as {
56
+ update?: (request: ArchiveChildSessionRequest) => Promise<unknown>;
57
+ };
58
+ await archiveSession
59
+ .update?.({
60
+ ...request,
61
+ body: { time: { archived: Date.now() } },
62
+ })
63
+ .catch(() => {});
64
+ log(`${context}: prompt unsettled — session ${sessionId} left to the age-gated sweep`);
65
+ }
66
+ }
@@ -1,19 +1,14 @@
1
1
  /**
2
- * Debug / data-collection switch: when enabled, Magic Context does NOT delete
3
- * the child sessions it spawns for its own subagents (historian, dreamer,
4
- * sidekick, memory-migration, key-files, user-memory review, recomp).
2
+ * Debug / data-collection switch for settled ordinary child sessions
3
+ * (historian and memory migration). Privacy-sensitive Dreamer and
4
+ * smart-note children are still deleted after their prompts settle.
5
5
  *
6
- * By default these child sessions are deleted on success (only FAILED ones are
7
- * kept for debugging). With `keep_subagents: true` ALL of them are retained, so
8
- * their full transcript — prompt, tool calls, token usage, model output — stays
9
- * inspectable in OpenCode's session store / the dashboard. Intended for
10
- * short-term data collection (e.g. profiling what the dreamer actually does)
11
- * before the dreamer v2 overhaul, NOT for steady-state use — kept sessions
12
- * accumulate in the host's session DB until manually cleared.
6
+ * Unsettled children are never deleted inline because OpenCode's server loop may
7
+ * still be writing after a client timeout or abort. They remain for the
8
+ * age-gated sweep; privacy-sensitive rows are swept even when this switch is on.
13
9
  *
14
- * Process-global, set once at boot from config (mirrors `harness.ts`). A
15
- * config change requires a restart to take effect. NEVER thread this through
16
- * per-call args — it's a coarse, boot-time debug toggle.
10
+ * Process-global, set once at boot from config (mirrors `harness.ts`). A config
11
+ * change requires a restart to take effect.
17
12
  */
18
13
  let keepSubagents = false;
19
14
 
@@ -22,7 +17,7 @@ export function setKeepSubagents(value: boolean): void {
22
17
  keepSubagents = value === true;
23
18
  }
24
19
 
25
- /** True when subagent child sessions should be retained (not deleted). */
20
+ /** True when settled ordinary child sessions should be retained. */
26
21
  export function shouldKeepSubagents(): boolean {
27
22
  return keepSubagents;
28
23
  }
@@ -71,7 +71,7 @@ export interface PromptRetryOptions {
71
71
  fallbackModels?: readonly ModelInput[];
72
72
  /**
73
73
  * Identifier for structured logging (e.g. "dreamer:consolidate",
74
- * "historian", "compressor", "sidekick"). Helps correlate fallback
74
+ * "historian", "compressor", "dreamer"). Helps correlate fallback
75
75
  * attempts to a specific call site in `magic-context.log`. Defaults to
76
76
  * "subagent" if not provided.
77
77
  */
@@ -0,0 +1,196 @@
1
+ /// <reference types="bun-types" />
2
+
3
+ import { afterEach, describe, expect, it } from "bun:test";
4
+ import { mkdirSync, mkdtempSync, rmSync, unlinkSync, utimesSync, writeFileSync } from "node:fs";
5
+ import { tmpdir } from "node:os";
6
+ import { join } from "node:path";
7
+ import {
8
+ formatOpenCodeDbDoctorLine,
9
+ formatOpenCodeDbMissingBanner,
10
+ formatOpenCodeDbMissingStatusLine,
11
+ openCodeDbPathExists,
12
+ resetOpenCodeDbPathStateForTesting,
13
+ resolveOpenCodeDbPath,
14
+ } from "./opencode-db-path";
15
+
16
+ const ORIGINAL_ENV = {
17
+ XDG_DATA_HOME: process.env.XDG_DATA_HOME,
18
+ OPENCODE_DB: process.env.OPENCODE_DB,
19
+ OPENCODE_DISABLE_CHANNEL_DB: process.env.OPENCODE_DISABLE_CHANNEL_DB,
20
+ OPENCODE_CHANNEL: process.env.OPENCODE_CHANNEL,
21
+ };
22
+ const tempDirs: string[] = [];
23
+
24
+ function restore(name: keyof typeof ORIGINAL_ENV): void {
25
+ const value = ORIGINAL_ENV[name];
26
+ if (value === undefined) delete process.env[name];
27
+ else process.env[name] = value;
28
+ }
29
+
30
+ afterEach(() => {
31
+ restore("XDG_DATA_HOME");
32
+ restore("OPENCODE_DB");
33
+ restore("OPENCODE_DISABLE_CHANNEL_DB");
34
+ restore("OPENCODE_CHANNEL");
35
+ resetOpenCodeDbPathStateForTesting();
36
+ for (const directory of tempDirs.splice(0)) rmSync(directory, { recursive: true, force: true });
37
+ });
38
+
39
+ function useDataHome(): { dataHome: string; openCodeDir: string } {
40
+ const dataHome = mkdtempSync(join(tmpdir(), "opencode-db-path-"));
41
+ const openCodeDir = join(dataHome, "opencode");
42
+ mkdirSync(openCodeDir, { recursive: true });
43
+ tempDirs.push(dataHome);
44
+ process.env.XDG_DATA_HOME = dataHome;
45
+ delete process.env.OPENCODE_DB;
46
+ delete process.env.OPENCODE_DISABLE_CHANNEL_DB;
47
+ delete process.env.OPENCODE_CHANNEL;
48
+ resetOpenCodeDbPathStateForTesting();
49
+ return { dataHome, openCodeDir };
50
+ }
51
+
52
+ function createCandidate(openCodeDir: string, name: string, mtimeMs: number): string {
53
+ const path = join(openCodeDir, name);
54
+ writeFileSync(path, "sqlite fixture");
55
+ const time = new Date(mtimeMs);
56
+ utimesSync(path, time, time);
57
+ return path;
58
+ }
59
+
60
+ describe("resolveOpenCodeDbPath", () => {
61
+ it("honors absolute and relative OPENCODE_DB overrides before every other source", () => {
62
+ const { openCodeDir } = useDataHome();
63
+ const absolute = join(openCodeDir, "elsewhere.db");
64
+ process.env.OPENCODE_DB = absolute;
65
+ process.env.OPENCODE_DISABLE_CHANNEL_DB = "true";
66
+ process.env.OPENCODE_CHANNEL = "dev";
67
+ expect(resolveOpenCodeDbPath()).toEqual({
68
+ path: absolute,
69
+ source: "OPENCODE_DB",
70
+ channel: null,
71
+ });
72
+
73
+ process.env.OPENCODE_DB = "relative.db";
74
+ expect(resolveOpenCodeDbPath()).toEqual({
75
+ path: join(openCodeDir, "relative.db"),
76
+ source: "OPENCODE_DB",
77
+ channel: null,
78
+ });
79
+ });
80
+
81
+ it("treats OPENCODE_DB=:memory: as an explicit but absent store", () => {
82
+ useDataHome();
83
+ process.env.OPENCODE_DB = ":memory:";
84
+ const resolution = resolveOpenCodeDbPath();
85
+ expect(resolution).toEqual({ path: ":memory:", source: "OPENCODE_DB", channel: null });
86
+ expect(openCodeDbPathExists(resolution)).toBe(false);
87
+ });
88
+
89
+ it("uses the default DB when channel databases are disabled", () => {
90
+ const { openCodeDir } = useDataHome();
91
+ process.env.OPENCODE_DISABLE_CHANNEL_DB = "1";
92
+ process.env.OPENCODE_CHANNEL = "dev";
93
+ expect(resolveOpenCodeDbPath()).toEqual({
94
+ path: join(openCodeDir, "opencode.db"),
95
+ source: "default",
96
+ channel: null,
97
+ });
98
+ });
99
+
100
+ it("honors an OPENCODE_CHANNEL visible to the plugin", () => {
101
+ const { openCodeDir } = useDataHome();
102
+ process.env.OPENCODE_CHANNEL = "dev";
103
+ expect(resolveOpenCodeDbPath()).toEqual({
104
+ path: join(openCodeDir, "opencode-dev.db"),
105
+ source: "channel",
106
+ channel: "dev",
107
+ });
108
+ });
109
+
110
+ for (const selectedName of [
111
+ "opencode.db",
112
+ "opencode-local.db",
113
+ "opencode-dev.db",
114
+ "opencode-nightly.db",
115
+ ]) {
116
+ it(`discovers ${selectedName} when it is the newest existing candidate`, () => {
117
+ const { openCodeDir } = useDataHome();
118
+ const names = [
119
+ "opencode.db",
120
+ "opencode-local.db",
121
+ "opencode-dev.db",
122
+ "opencode-nightly.db",
123
+ ];
124
+ for (const [index, name] of names.entries()) {
125
+ createCandidate(openCodeDir, name, name === selectedName ? 10_000 : 1_000 + index);
126
+ }
127
+
128
+ expect(resolveOpenCodeDbPath()).toEqual({
129
+ path: join(openCodeDir, selectedName),
130
+ source: "discovered",
131
+ channel:
132
+ selectedName === "opencode.db"
133
+ ? null
134
+ : selectedName.slice("opencode-".length, -".db".length),
135
+ });
136
+ });
137
+ }
138
+
139
+ it("uses candidate order as the deterministic tie-breaker for equal mtimes", () => {
140
+ const { openCodeDir } = useDataHome();
141
+ for (const name of ["opencode-local.db", "opencode-dev.db", "opencode.db"]) {
142
+ createCandidate(openCodeDir, name, 5_000);
143
+ }
144
+ expect(resolveOpenCodeDbPath()).toEqual({
145
+ path: join(openCodeDir, "opencode.db"),
146
+ source: "discovered",
147
+ channel: null,
148
+ });
149
+ });
150
+
151
+ it("returns the default path by value when no candidate exists", () => {
152
+ const { openCodeDir } = useDataHome();
153
+ const resolution = resolveOpenCodeDbPath();
154
+ expect(resolution).toEqual({
155
+ path: join(openCodeDir, "opencode.db"),
156
+ source: "default",
157
+ channel: null,
158
+ });
159
+ expect(openCodeDbPathExists(resolution)).toBe(false);
160
+ });
161
+
162
+ it("re-probes discovery when the memoized chosen file disappears", () => {
163
+ const { openCodeDir } = useDataHome();
164
+ const primary = createCandidate(openCodeDir, "opencode-local.db", 2_000);
165
+ const fallback = createCandidate(openCodeDir, "opencode.db", 1_000);
166
+ expect(resolveOpenCodeDbPath().path).toBe(primary);
167
+
168
+ unlinkSync(primary);
169
+ expect(resolveOpenCodeDbPath()).toEqual({
170
+ path: fallback,
171
+ source: "discovered",
172
+ channel: null,
173
+ });
174
+ });
175
+
176
+ it("formats the missing banner, status, and doctor lines by value", () => {
177
+ const { openCodeDir } = useDataHome();
178
+ const lookedFor = [
179
+ join(openCodeDir, "opencode.db"),
180
+ join(openCodeDir, "opencode-local.db"),
181
+ join(openCodeDir, "opencode-dev.db"),
182
+ join(openCodeDir, "opencode-<channel>.db"),
183
+ ].join(", ");
184
+ const resolution = resolveOpenCodeDbPath();
185
+
186
+ expect(formatOpenCodeDbMissingBanner(resolution)).toBe(
187
+ `Magic Context cannot find OpenCode's session database (looked for ${lookedFor}). History compaction (historian) and the mid-turn valve are disabled until it is found; set OPENCODE_DB if OpenCode stores it elsewhere.`,
188
+ );
189
+ expect(formatOpenCodeDbMissingStatusLine(resolution)).toBe(
190
+ `OpenCode DB: MISSING (looked for ${lookedFor}). History compaction (historian) and the mid-turn valve are disabled; set OPENCODE_DB if OpenCode stores it elsewhere.`,
191
+ );
192
+ expect(formatOpenCodeDbDoctorLine(resolution)).toBe(
193
+ `FAIL OpenCode session database: not found (looked for ${lookedFor}); set OPENCODE_DB if OpenCode stores it elsewhere.`,
194
+ );
195
+ });
196
+ });
@@ -0,0 +1,215 @@
1
+ import { existsSync, readdirSync, statSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { isAbsolute, join } from "node:path";
4
+
5
+ export type OpenCodeDbPathSource = "OPENCODE_DB" | "channel" | "default" | "discovered";
6
+
7
+ export interface OpenCodeDbPathResolution {
8
+ path: string;
9
+ source: OpenCodeDbPathSource;
10
+ channel: string | null;
11
+ }
12
+
13
+ export interface OpenCodeDbReadFailure extends OpenCodeDbPathResolution {
14
+ message: string;
15
+ }
16
+
17
+ interface CachedResolution {
18
+ key: string;
19
+ resolution: OpenCodeDbPathResolution;
20
+ existed: boolean;
21
+ }
22
+
23
+ let cachedResolution: CachedResolution | null = null;
24
+ let lastReadFailure: OpenCodeDbReadFailure | null = null;
25
+ const claimedDiagnostics = new Set<string>();
26
+
27
+ function openCodeDataDir(): string {
28
+ return join(process.env.XDG_DATA_HOME ?? join(homedir(), ".local", "share"), "opencode");
29
+ }
30
+
31
+ function environmentKey(dataDir: string): string {
32
+ return [
33
+ dataDir,
34
+ process.env.OPENCODE_DB ?? "",
35
+ process.env.OPENCODE_DISABLE_CHANNEL_DB ?? "",
36
+ process.env.OPENCODE_CHANNEL ?? "",
37
+ ].join("\0");
38
+ }
39
+
40
+ function channelPath(dataDir: string, channel: string): string {
41
+ return ["latest", "beta", "prod"].includes(channel)
42
+ ? join(dataDir, "opencode.db")
43
+ : join(dataDir, `opencode-${channel}.db`);
44
+ }
45
+
46
+ function discoveredCandidateNames(dataDir: string): string[] {
47
+ const names = ["opencode.db", "opencode-local.db", "opencode-dev.db"];
48
+ try {
49
+ const discovered = readdirSync(dataDir, { withFileTypes: true })
50
+ .filter((entry) => /^opencode-.+\.db$/.test(entry.name) && !names.includes(entry.name))
51
+ .map((entry) => entry.name)
52
+ .sort();
53
+ names.push(...discovered);
54
+ } catch {
55
+ // A missing or unreadable data directory has no discovered candidates.
56
+ }
57
+ return names;
58
+ }
59
+
60
+ function discoverOpenCodeDb(dataDir: string): OpenCodeDbPathResolution {
61
+ const candidates = discoveredCandidateNames(dataDir).map((name, order) => {
62
+ const path = join(dataDir, name);
63
+ try {
64
+ const metadata = statSync(path);
65
+ return metadata.isFile() ? { path, order, mtimeMs: metadata.mtimeMs } : null;
66
+ } catch {
67
+ return null;
68
+ }
69
+ });
70
+ const existing = candidates
71
+ .filter((candidate): candidate is NonNullable<typeof candidate> => candidate !== null)
72
+ .sort((left, right) => right.mtimeMs - left.mtimeMs || left.order - right.order)[0];
73
+
74
+ if (!existing) {
75
+ return { path: join(dataDir, "opencode.db"), source: "default", channel: null };
76
+ }
77
+
78
+ const name = existing.path.slice(dataDir.length + 1);
79
+ const channel =
80
+ name === "opencode.db" ? null : name.slice("opencode-".length, -".db".length) || null;
81
+ return { path: existing.path, source: "discovered", channel };
82
+ }
83
+
84
+ function resolveFresh(dataDir: string): OpenCodeDbPathResolution {
85
+ const explicit = process.env.OPENCODE_DB;
86
+ if (explicit !== undefined && explicit.length > 0) {
87
+ if (explicit === ":memory:") {
88
+ return { path: explicit, source: "OPENCODE_DB", channel: null };
89
+ }
90
+ return {
91
+ path: isAbsolute(explicit) ? explicit : join(dataDir, explicit),
92
+ source: "OPENCODE_DB",
93
+ channel: null,
94
+ };
95
+ }
96
+
97
+ const disableChannelDb = process.env.OPENCODE_DISABLE_CHANNEL_DB;
98
+ if (disableChannelDb === "1" || disableChannelDb === "true") {
99
+ return { path: join(dataDir, "opencode.db"), source: "default", channel: null };
100
+ }
101
+
102
+ const channel = process.env.OPENCODE_CHANNEL;
103
+ if (channel !== undefined && channel.length > 0) {
104
+ return { path: channelPath(dataDir, channel), source: "channel", channel };
105
+ }
106
+
107
+ return discoverOpenCodeDb(dataDir);
108
+ }
109
+
110
+ /** Resolve an explicit DB override first, then channel paths; discover candidates when the compiled channel is unknown. */
111
+ export function resolveOpenCodeDbPath(): OpenCodeDbPathResolution {
112
+ const dataDir = openCodeDataDir();
113
+ const key = environmentKey(dataDir);
114
+ if (
115
+ cachedResolution?.key === key &&
116
+ (!cachedResolution.existed || existsSync(cachedResolution.resolution.path))
117
+ ) {
118
+ if (cachedResolution.existed) return cachedResolution.resolution;
119
+ // An absent result is re-probed so a DB created after plugin boot is detected.
120
+ }
121
+
122
+ const resolution = resolveFresh(dataDir);
123
+ cachedResolution = {
124
+ key,
125
+ resolution,
126
+ existed: resolution.path !== ":memory:" && existsSync(resolution.path),
127
+ };
128
+ return resolution;
129
+ }
130
+
131
+ export function openCodeDbPathExists(
132
+ resolution: OpenCodeDbPathResolution = resolveOpenCodeDbPath(),
133
+ ): boolean {
134
+ return resolution.path !== ":memory:" && existsSync(resolution.path);
135
+ }
136
+
137
+ export function getOpenCodeDbProbeDescriptions(
138
+ resolution: OpenCodeDbPathResolution = resolveOpenCodeDbPath(),
139
+ ): string[] {
140
+ if (resolution.source === "OPENCODE_DB") return [resolution.path];
141
+ if (
142
+ resolution.source === "channel" ||
143
+ process.env.OPENCODE_DISABLE_CHANNEL_DB === "1" ||
144
+ process.env.OPENCODE_DISABLE_CHANNEL_DB === "true"
145
+ ) {
146
+ return [resolution.path];
147
+ }
148
+ const dataDir = openCodeDataDir();
149
+ return [
150
+ join(dataDir, "opencode.db"),
151
+ join(dataDir, "opencode-local.db"),
152
+ join(dataDir, "opencode-dev.db"),
153
+ join(dataDir, "opencode-<channel>.db"),
154
+ ];
155
+ }
156
+
157
+ function lookedForText(resolution: OpenCodeDbPathResolution): string {
158
+ return getOpenCodeDbProbeDescriptions(resolution).join(", ");
159
+ }
160
+
161
+ export function formatOpenCodeDbMissingBanner(
162
+ resolution: OpenCodeDbPathResolution = resolveOpenCodeDbPath(),
163
+ ): string {
164
+ return `Magic Context cannot find OpenCode's session database (looked for ${lookedForText(resolution)}). History compaction (historian) and the mid-turn valve are disabled until it is found; set OPENCODE_DB if OpenCode stores it elsewhere.`;
165
+ }
166
+
167
+ export function formatOpenCodeDbMissingStatusLine(
168
+ resolution: OpenCodeDbPathResolution = resolveOpenCodeDbPath(),
169
+ ): string {
170
+ return `OpenCode DB: MISSING (looked for ${lookedForText(resolution)}). History compaction (historian) and the mid-turn valve are disabled; set OPENCODE_DB if OpenCode stores it elsewhere.`;
171
+ }
172
+
173
+ export function formatOpenCodeDbDoctorLine(
174
+ resolution: OpenCodeDbPathResolution = resolveOpenCodeDbPath(),
175
+ ): string {
176
+ return `FAIL OpenCode session database: not found (looked for ${lookedForText(resolution)}); set OPENCODE_DB if OpenCode stores it elsewhere.`;
177
+ }
178
+
179
+ export function formatOpenCodeDbReadFailureStatusLine(failure: OpenCodeDbReadFailure): string {
180
+ return `OpenCode DB: READ FAILED (path=${failure.path}, source=${failure.source}) — ${failure.message}`;
181
+ }
182
+
183
+ export function recordOpenCodeDbReadFailure(
184
+ resolution: OpenCodeDbPathResolution,
185
+ error: unknown,
186
+ ): OpenCodeDbReadFailure {
187
+ const message = error instanceof Error ? error.message : String(error);
188
+ lastReadFailure = { ...resolution, message };
189
+ return lastReadFailure;
190
+ }
191
+
192
+ export function clearOpenCodeDbReadFailure(path?: string): void {
193
+ if (path === undefined || lastReadFailure?.path === path) lastReadFailure = null;
194
+ }
195
+
196
+ export function getOpenCodeDbReadFailure(): OpenCodeDbReadFailure | null {
197
+ return lastReadFailure;
198
+ }
199
+
200
+ export function claimOpenCodeDbDiagnosticOnce(
201
+ surface: string,
202
+ resolution: OpenCodeDbPathResolution,
203
+ ): boolean {
204
+ const key = `${surface}\0${resolution.path}\0${resolution.source}`;
205
+ if (claimedDiagnostics.has(key)) return false;
206
+ claimedDiagnostics.add(key);
207
+ return true;
208
+ }
209
+
210
+ /** Test-only reset for process memoization and once-only diagnostics. */
211
+ export function resetOpenCodeDbPathStateForTesting(): void {
212
+ cachedResolution = null;
213
+ lastReadFailure = null;
214
+ claimedDiagnostics.clear();
215
+ }