@wolfx/opencode-magic-context 0.21.8-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 (544) hide show
  1. package/dist/agents/dreamer.d.ts +2 -0
  2. package/dist/agents/dreamer.d.ts.map +1 -0
  3. package/dist/agents/historian.d.ts +3 -0
  4. package/dist/agents/historian.d.ts.map +1 -0
  5. package/dist/agents/magic-context-prompt.d.ts +3 -0
  6. package/dist/agents/magic-context-prompt.d.ts.map +1 -0
  7. package/dist/agents/permissions.d.ts +142 -0
  8. package/dist/agents/permissions.d.ts.map +1 -0
  9. package/dist/agents/sidekick.d.ts +2 -0
  10. package/dist/agents/sidekick.d.ts.map +1 -0
  11. package/dist/config/agent-disable.d.ts +26 -0
  12. package/dist/config/agent-disable.d.ts.map +1 -0
  13. package/dist/config/index.d.ts +33 -0
  14. package/dist/config/index.d.ts.map +1 -0
  15. package/dist/config/schema/agent-overrides.d.ts +55 -0
  16. package/dist/config/schema/agent-overrides.d.ts.map +1 -0
  17. package/dist/config/schema/magic-context.d.ts +841 -0
  18. package/dist/config/schema/magic-context.d.ts.map +1 -0
  19. package/dist/config/schema.d.ts +3 -0
  20. package/dist/config/schema.d.ts.map +1 -0
  21. package/dist/config/variable.d.ts +48 -0
  22. package/dist/config/variable.d.ts.map +1 -0
  23. package/dist/features/builtin-commands/commands.d.ts +3 -0
  24. package/dist/features/builtin-commands/commands.d.ts.map +1 -0
  25. package/dist/features/builtin-commands/types.d.ts +5 -0
  26. package/dist/features/builtin-commands/types.d.ts.map +1 -0
  27. package/dist/features/magic-context/compaction-marker.d.ts +91 -0
  28. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -0
  29. package/dist/features/magic-context/compaction.d.ts +7 -0
  30. package/dist/features/magic-context/compaction.d.ts.map +1 -0
  31. package/dist/features/magic-context/compartment-lease.d.ts +14 -0
  32. package/dist/features/magic-context/compartment-lease.d.ts.map +1 -0
  33. package/dist/features/magic-context/compartment-storage.d.ts +130 -0
  34. package/dist/features/magic-context/compartment-storage.d.ts.map +1 -0
  35. package/dist/features/magic-context/compression-depth-storage.d.ts +14 -0
  36. package/dist/features/magic-context/compression-depth-storage.d.ts.map +1 -0
  37. package/dist/features/magic-context/defaults.d.ts +2 -0
  38. package/dist/features/magic-context/defaults.d.ts.map +1 -0
  39. package/dist/features/magic-context/dreamer/index.d.ts +8 -0
  40. package/dist/features/magic-context/dreamer/index.d.ts.map +1 -0
  41. package/dist/features/magic-context/dreamer/lease.d.ts +8 -0
  42. package/dist/features/magic-context/dreamer/lease.d.ts.map +1 -0
  43. package/dist/features/magic-context/dreamer/queue.d.ts +44 -0
  44. package/dist/features/magic-context/dreamer/queue.d.ts.map +1 -0
  45. package/dist/features/magic-context/dreamer/runner.d.ts +81 -0
  46. package/dist/features/magic-context/dreamer/runner.d.ts.map +1 -0
  47. package/dist/features/magic-context/dreamer/scheduler.d.ts +33 -0
  48. package/dist/features/magic-context/dreamer/scheduler.d.ts.map +1 -0
  49. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +41 -0
  50. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -0
  51. package/dist/features/magic-context/dreamer/storage-dream-state.d.ts +5 -0
  52. package/dist/features/magic-context/dreamer/storage-dream-state.d.ts.map +1 -0
  53. package/dist/features/magic-context/dreamer/task-prompts.d.ts +26 -0
  54. package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -0
  55. package/dist/features/magic-context/git-commits/git-log-reader.d.ts +57 -0
  56. package/dist/features/magic-context/git-commits/git-log-reader.d.ts.map +1 -0
  57. package/dist/features/magic-context/git-commits/index.d.ts +7 -0
  58. package/dist/features/magic-context/git-commits/index.d.ts.map +1 -0
  59. package/dist/features/magic-context/git-commits/indexer.d.ts +43 -0
  60. package/dist/features/magic-context/git-commits/indexer.d.ts.map +1 -0
  61. package/dist/features/magic-context/git-commits/search-git-commits.d.ts +32 -0
  62. package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -0
  63. package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts +19 -0
  64. package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -0
  65. package/dist/features/magic-context/git-commits/storage-git-commits.d.ts +47 -0
  66. package/dist/features/magic-context/git-commits/storage-git-commits.d.ts.map +1 -0
  67. package/dist/features/magic-context/index.d.ts +12 -0
  68. package/dist/features/magic-context/index.d.ts.map +1 -0
  69. package/dist/features/magic-context/key-files/aft-availability.d.ts +11 -0
  70. package/dist/features/magic-context/key-files/aft-availability.d.ts.map +1 -0
  71. package/dist/features/magic-context/key-files/identify-key-files.d.ts +84 -0
  72. package/dist/features/magic-context/key-files/identify-key-files.d.ts.map +1 -0
  73. package/dist/features/magic-context/key-files/project-key-files.d.ts +42 -0
  74. package/dist/features/magic-context/key-files/project-key-files.d.ts.map +1 -0
  75. package/dist/features/magic-context/key-files/read-history.d.ts +26 -0
  76. package/dist/features/magic-context/key-files/read-history.d.ts.map +1 -0
  77. package/dist/features/magic-context/key-files/read-stats.d.ts +20 -0
  78. package/dist/features/magic-context/key-files/read-stats.d.ts.map +1 -0
  79. package/dist/features/magic-context/key-files/storage-key-files.d.ts +25 -0
  80. package/dist/features/magic-context/key-files/storage-key-files.d.ts.map +1 -0
  81. package/dist/features/magic-context/memory/constants.d.ts +5 -0
  82. package/dist/features/magic-context/memory/constants.d.ts.map +1 -0
  83. package/dist/features/magic-context/memory/cosine-similarity.d.ts +2 -0
  84. package/dist/features/magic-context/memory/cosine-similarity.d.ts.map +1 -0
  85. package/dist/features/magic-context/memory/embedding-backfill.d.ts +9 -0
  86. package/dist/features/magic-context/memory/embedding-backfill.d.ts.map +1 -0
  87. package/dist/features/magic-context/memory/embedding-cache.d.ts +8 -0
  88. package/dist/features/magic-context/memory/embedding-cache.d.ts.map +1 -0
  89. package/dist/features/magic-context/memory/embedding-identity.d.ts +11 -0
  90. package/dist/features/magic-context/memory/embedding-identity.d.ts.map +1 -0
  91. package/dist/features/magic-context/memory/embedding-local.d.ts +20 -0
  92. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -0
  93. package/dist/features/magic-context/memory/embedding-openai.d.ts +44 -0
  94. package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -0
  95. package/dist/features/magic-context/memory/embedding-probe.d.ts +69 -0
  96. package/dist/features/magic-context/memory/embedding-probe.d.ts.map +1 -0
  97. package/dist/features/magic-context/memory/embedding-provider.d.ts +15 -0
  98. package/dist/features/magic-context/memory/embedding-provider.d.ts.map +1 -0
  99. package/dist/features/magic-context/memory/embedding.d.ts +39 -0
  100. package/dist/features/magic-context/memory/embedding.d.ts.map +1 -0
  101. package/dist/features/magic-context/memory/index.d.ts +12 -0
  102. package/dist/features/magic-context/memory/index.d.ts.map +1 -0
  103. package/dist/features/magic-context/memory/normalize-hash.d.ts +3 -0
  104. package/dist/features/magic-context/memory/normalize-hash.d.ts.map +1 -0
  105. package/dist/features/magic-context/memory/project-identity.d.ts +23 -0
  106. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -0
  107. package/dist/features/magic-context/memory/promotion.d.ts +13 -0
  108. package/dist/features/magic-context/memory/promotion.d.ts.map +1 -0
  109. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +8 -0
  110. package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -0
  111. package/dist/features/magic-context/memory/storage-memory-fts.d.ts +12 -0
  112. package/dist/features/magic-context/memory/storage-memory-fts.d.ts.map +1 -0
  113. package/dist/features/magic-context/memory/storage-memory.d.ts +31 -0
  114. package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -0
  115. package/dist/features/magic-context/memory/types.d.ts +37 -0
  116. package/dist/features/magic-context/memory/types.d.ts.map +1 -0
  117. package/dist/features/magic-context/message-index-async.d.ts +12 -0
  118. package/dist/features/magic-context/message-index-async.d.ts.map +1 -0
  119. package/dist/features/magic-context/message-index.d.ts +10 -0
  120. package/dist/features/magic-context/message-index.d.ts.map +1 -0
  121. package/dist/features/magic-context/migrations.d.ts +33 -0
  122. package/dist/features/magic-context/migrations.d.ts.map +1 -0
  123. package/dist/features/magic-context/mock-database.d.ts +3 -0
  124. package/dist/features/magic-context/mock-database.d.ts.map +1 -0
  125. package/dist/features/magic-context/overflow-detection.d.ts +51 -0
  126. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -0
  127. package/dist/features/magic-context/plugin-messages.d.ts +75 -0
  128. package/dist/features/magic-context/plugin-messages.d.ts.map +1 -0
  129. package/dist/features/magic-context/project-embedding-registry.d.ts +44 -0
  130. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -0
  131. package/dist/features/magic-context/range-parser.d.ts +13 -0
  132. package/dist/features/magic-context/range-parser.d.ts.map +1 -0
  133. package/dist/features/magic-context/resolve-subagent-fallback.d.ts +40 -0
  134. package/dist/features/magic-context/resolve-subagent-fallback.d.ts.map +1 -0
  135. package/dist/features/magic-context/scheduler.d.ts +18 -0
  136. package/dist/features/magic-context/scheduler.d.ts.map +1 -0
  137. package/dist/features/magic-context/search.d.ts +69 -0
  138. package/dist/features/magic-context/search.d.ts.map +1 -0
  139. package/dist/features/magic-context/sidekick/agent.d.ts +13 -0
  140. package/dist/features/magic-context/sidekick/agent.d.ts.map +1 -0
  141. package/dist/features/magic-context/sidekick/core.d.ts +38 -0
  142. package/dist/features/magic-context/sidekick/core.d.ts.map +1 -0
  143. package/dist/features/magic-context/sidekick/index.d.ts +3 -0
  144. package/dist/features/magic-context/sidekick/index.d.ts.map +1 -0
  145. package/dist/features/magic-context/storage-db.d.ts +48 -0
  146. package/dist/features/magic-context/storage-db.d.ts.map +1 -0
  147. package/dist/features/magic-context/storage-meta-persisted.d.ts +246 -0
  148. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -0
  149. package/dist/features/magic-context/storage-meta-session.d.ts +6 -0
  150. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -0
  151. package/dist/features/magic-context/storage-meta-shared.d.ts +31 -0
  152. package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -0
  153. package/dist/features/magic-context/storage-meta.d.ts +3 -0
  154. package/dist/features/magic-context/storage-meta.d.ts.map +1 -0
  155. package/dist/features/magic-context/storage-notes.d.ts +62 -0
  156. package/dist/features/magic-context/storage-notes.d.ts.map +1 -0
  157. package/dist/features/magic-context/storage-ops.d.ts +7 -0
  158. package/dist/features/magic-context/storage-ops.d.ts.map +1 -0
  159. package/dist/features/magic-context/storage-source.d.ts +5 -0
  160. package/dist/features/magic-context/storage-source.d.ts.map +1 -0
  161. package/dist/features/magic-context/storage-subagent-invocations.d.ts +52 -0
  162. package/dist/features/magic-context/storage-subagent-invocations.d.ts.map +1 -0
  163. package/dist/features/magic-context/storage-tags.d.ts +206 -0
  164. package/dist/features/magic-context/storage-tags.d.ts.map +1 -0
  165. package/dist/features/magic-context/storage.d.ts +11 -0
  166. package/dist/features/magic-context/storage.d.ts.map +1 -0
  167. package/dist/features/magic-context/subagent-token-capture.d.ts +33 -0
  168. package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -0
  169. package/dist/features/magic-context/tagger.d.ts +64 -0
  170. package/dist/features/magic-context/tagger.d.ts.map +1 -0
  171. package/dist/features/magic-context/tool-definition-tokens.d.ts +79 -0
  172. package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -0
  173. package/dist/features/magic-context/tool-owner-backfill.d.ts +90 -0
  174. package/dist/features/magic-context/tool-owner-backfill.d.ts.map +1 -0
  175. package/dist/features/magic-context/types.d.ts +72 -0
  176. package/dist/features/magic-context/types.d.ts.map +1 -0
  177. package/dist/features/magic-context/user-memory/review-user-memories.d.ts +22 -0
  178. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -0
  179. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +33 -0
  180. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -0
  181. package/dist/features/magic-context/work-metrics.d.ts +13 -0
  182. package/dist/features/magic-context/work-metrics.d.ts.map +1 -0
  183. package/dist/hooks/auto-update-checker/cache.d.ts +23 -0
  184. package/dist/hooks/auto-update-checker/cache.d.ts.map +1 -0
  185. package/dist/hooks/auto-update-checker/checker.d.ts +13 -0
  186. package/dist/hooks/auto-update-checker/checker.d.ts.map +1 -0
  187. package/dist/hooks/auto-update-checker/constants.d.ts +10 -0
  188. package/dist/hooks/auto-update-checker/constants.d.ts.map +1 -0
  189. package/dist/hooks/auto-update-checker/index.d.ts +40 -0
  190. package/dist/hooks/auto-update-checker/index.d.ts.map +1 -0
  191. package/dist/hooks/auto-update-checker/types.d.ts +50 -0
  192. package/dist/hooks/auto-update-checker/types.d.ts.map +1 -0
  193. package/dist/hooks/is-anthropic-provider.d.ts +2 -0
  194. package/dist/hooks/is-anthropic-provider.d.ts.map +1 -0
  195. package/dist/hooks/magic-context/apply-context-nudge.d.ts +5 -0
  196. package/dist/hooks/magic-context/apply-context-nudge.d.ts.map +1 -0
  197. package/dist/hooks/magic-context/apply-operations.d.ts +7 -0
  198. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -0
  199. package/dist/hooks/magic-context/auto-search-hint.d.ts +34 -0
  200. package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -0
  201. package/dist/hooks/magic-context/auto-search-runner.d.ts +53 -0
  202. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -0
  203. package/dist/hooks/magic-context/boundary-execution.d.ts +24 -0
  204. package/dist/hooks/magic-context/boundary-execution.d.ts.map +1 -0
  205. package/dist/hooks/magic-context/cache-busting-signals.d.ts +10 -0
  206. package/dist/hooks/magic-context/cache-busting-signals.d.ts.map +1 -0
  207. package/dist/hooks/magic-context/caveman-cleanup.d.ts +86 -0
  208. package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -0
  209. package/dist/hooks/magic-context/caveman.d.ts +35 -0
  210. package/dist/hooks/magic-context/caveman.d.ts.map +1 -0
  211. package/dist/hooks/magic-context/command-handler.d.ts +89 -0
  212. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -0
  213. package/dist/hooks/magic-context/compaction-marker-manager.d.ts +106 -0
  214. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -0
  215. package/dist/hooks/magic-context/compartment-parser.d.ts +18 -0
  216. package/dist/hooks/magic-context/compartment-parser.d.ts.map +1 -0
  217. package/dist/hooks/magic-context/compartment-prompt.d.ts +19 -0
  218. package/dist/hooks/magic-context/compartment-prompt.d.ts.map +1 -0
  219. package/dist/hooks/magic-context/compartment-runner-compressor.d.ts +87 -0
  220. package/dist/hooks/magic-context/compartment-runner-compressor.d.ts.map +1 -0
  221. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts +26 -0
  222. package/dist/hooks/magic-context/compartment-runner-drop-queue.d.ts.map +1 -0
  223. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +42 -0
  224. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -0
  225. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +6 -0
  226. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -0
  227. package/dist/hooks/magic-context/compartment-runner-mapping.d.ts +33 -0
  228. package/dist/hooks/magic-context/compartment-runner-mapping.d.ts.map +1 -0
  229. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts +29 -0
  230. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -0
  231. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts +3 -0
  232. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -0
  233. package/dist/hooks/magic-context/compartment-runner-state-xml.d.ts +21 -0
  234. package/dist/hooks/magic-context/compartment-runner-state-xml.d.ts.map +1 -0
  235. package/dist/hooks/magic-context/compartment-runner-types.d.ts +102 -0
  236. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -0
  237. package/dist/hooks/magic-context/compartment-runner-validation.d.ts +28 -0
  238. package/dist/hooks/magic-context/compartment-runner-validation.d.ts.map +1 -0
  239. package/dist/hooks/magic-context/compartment-runner.d.ts +54 -0
  240. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -0
  241. package/dist/hooks/magic-context/compartment-trigger.d.ts +17 -0
  242. package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -0
  243. package/dist/hooks/magic-context/derive-budgets.d.ts +57 -0
  244. package/dist/hooks/magic-context/derive-budgets.d.ts.map +1 -0
  245. package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts +4 -0
  246. package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts.map +1 -0
  247. package/dist/hooks/magic-context/event-handler.d.ts +49 -0
  248. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -0
  249. package/dist/hooks/magic-context/event-payloads.d.ts +62 -0
  250. package/dist/hooks/magic-context/event-payloads.d.ts.map +1 -0
  251. package/dist/hooks/magic-context/event-resolvers.d.ts +72 -0
  252. package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -0
  253. package/dist/hooks/magic-context/execute-flush.d.ts +3 -0
  254. package/dist/hooks/magic-context/execute-flush.d.ts.map +1 -0
  255. package/dist/hooks/magic-context/execute-status.d.ts +12 -0
  256. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -0
  257. package/dist/hooks/magic-context/format-bytes.d.ts +2 -0
  258. package/dist/hooks/magic-context/format-bytes.d.ts.map +1 -0
  259. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +22 -0
  260. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -0
  261. package/dist/hooks/magic-context/historian-state-file.d.ts +43 -0
  262. package/dist/hooks/magic-context/historian-state-file.d.ts.map +1 -0
  263. package/dist/hooks/magic-context/hook-handlers.d.ts +165 -0
  264. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -0
  265. package/dist/hooks/magic-context/hook.d.ts +118 -0
  266. package/dist/hooks/magic-context/hook.d.ts.map +1 -0
  267. package/dist/hooks/magic-context/image-token-estimate.d.ts +6 -0
  268. package/dist/hooks/magic-context/image-token-estimate.d.ts.map +1 -0
  269. package/dist/hooks/magic-context/index.d.ts +3 -0
  270. package/dist/hooks/magic-context/index.d.ts.map +1 -0
  271. package/dist/hooks/magic-context/inject-compartments.d.ts +52 -0
  272. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -0
  273. package/dist/hooks/magic-context/key-files-block.d.ts +27 -0
  274. package/dist/hooks/magic-context/key-files-block.d.ts.map +1 -0
  275. package/dist/hooks/magic-context/live-session-state.d.ts +42 -0
  276. package/dist/hooks/magic-context/live-session-state.d.ts.map +1 -0
  277. package/dist/hooks/magic-context/note-nudger.d.ts +71 -0
  278. package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -0
  279. package/dist/hooks/magic-context/note-visibility.d.ts +43 -0
  280. package/dist/hooks/magic-context/note-visibility.d.ts.map +1 -0
  281. package/dist/hooks/magic-context/nudge-bands.d.ts +6 -0
  282. package/dist/hooks/magic-context/nudge-bands.d.ts.map +1 -0
  283. package/dist/hooks/magic-context/nudge-injection.d.ts +7 -0
  284. package/dist/hooks/magic-context/nudge-injection.d.ts.map +1 -0
  285. package/dist/hooks/magic-context/nudge-placement-store.d.ts +15 -0
  286. package/dist/hooks/magic-context/nudge-placement-store.d.ts.map +1 -0
  287. package/dist/hooks/magic-context/nudger.d.ts +21 -0
  288. package/dist/hooks/magic-context/nudger.d.ts.map +1 -0
  289. package/dist/hooks/magic-context/read-session-chunk.d.ts +99 -0
  290. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -0
  291. package/dist/hooks/magic-context/read-session-db.d.ts +21 -0
  292. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -0
  293. package/dist/hooks/magic-context/read-session-formatting.d.ts +35 -0
  294. package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -0
  295. package/dist/hooks/magic-context/read-session-raw.d.ts +10 -0
  296. package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -0
  297. package/dist/hooks/magic-context/send-session-notification.d.ts +13 -0
  298. package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -0
  299. package/dist/hooks/magic-context/sentinel.d.ts +102 -0
  300. package/dist/hooks/magic-context/sentinel.d.ts.map +1 -0
  301. package/dist/hooks/magic-context/strip-content.d.ts +140 -0
  302. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -0
  303. package/dist/hooks/magic-context/strip-structural-noise.d.ts +17 -0
  304. package/dist/hooks/magic-context/strip-structural-noise.d.ts.map +1 -0
  305. package/dist/hooks/magic-context/system-injection-stripper.d.ts +2 -0
  306. package/dist/hooks/magic-context/system-injection-stripper.d.ts.map +1 -0
  307. package/dist/hooks/magic-context/system-prompt-hash.d.ts +85 -0
  308. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -0
  309. package/dist/hooks/magic-context/tag-content-primitives.d.ts +6 -0
  310. package/dist/hooks/magic-context/tag-content-primitives.d.ts.map +1 -0
  311. package/dist/hooks/magic-context/tag-id-fallback.d.ts +9 -0
  312. package/dist/hooks/magic-context/tag-id-fallback.d.ts.map +1 -0
  313. package/dist/hooks/magic-context/tag-messages.d.ts +48 -0
  314. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -0
  315. package/dist/hooks/magic-context/tag-part-guards.d.ts +23 -0
  316. package/dist/hooks/magic-context/tag-part-guards.d.ts.map +1 -0
  317. package/dist/hooks/magic-context/temporal-awareness.d.ts +73 -0
  318. package/dist/hooks/magic-context/temporal-awareness.d.ts.map +1 -0
  319. package/dist/hooks/magic-context/text-complete.d.ts +8 -0
  320. package/dist/hooks/magic-context/text-complete.d.ts.map +1 -0
  321. package/dist/hooks/magic-context/todo-view.d.ts +102 -0
  322. package/dist/hooks/magic-context/todo-view.d.ts.map +1 -0
  323. package/dist/hooks/magic-context/tokenizer-calibration.d.ts +85 -0
  324. package/dist/hooks/magic-context/tokenizer-calibration.d.ts.map +1 -0
  325. package/dist/hooks/magic-context/tool-drop-target.d.ts +48 -0
  326. package/dist/hooks/magic-context/tool-drop-target.d.ts.map +1 -0
  327. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +66 -0
  328. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -0
  329. package/dist/hooks/magic-context/transform-context-state.d.ts +12 -0
  330. package/dist/hooks/magic-context/transform-context-state.d.ts.map +1 -0
  331. package/dist/hooks/magic-context/transform-message-helpers.d.ts +29 -0
  332. package/dist/hooks/magic-context/transform-message-helpers.d.ts.map +1 -0
  333. package/dist/hooks/magic-context/transform-operations.d.ts +5 -0
  334. package/dist/hooks/magic-context/transform-operations.d.ts.map +1 -0
  335. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +100 -0
  336. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -0
  337. package/dist/hooks/magic-context/transform-stage-logger.d.ts +2 -0
  338. package/dist/hooks/magic-context/transform-stage-logger.d.ts.map +1 -0
  339. package/dist/hooks/magic-context/transform.d.ts +145 -0
  340. package/dist/hooks/magic-context/transform.d.ts.map +1 -0
  341. package/dist/index.d.ts +4 -0
  342. package/dist/index.d.ts.map +1 -0
  343. package/dist/index.js +179800 -0
  344. package/dist/plugin/conflict-warning-hook.d.ts +34 -0
  345. package/dist/plugin/conflict-warning-hook.d.ts.map +1 -0
  346. package/dist/plugin/dream-timer.d.ts +44 -0
  347. package/dist/plugin/dream-timer.d.ts.map +1 -0
  348. package/dist/plugin/embedding-bootstrap-helpers.d.ts +35 -0
  349. package/dist/plugin/embedding-bootstrap-helpers.d.ts.map +1 -0
  350. package/dist/plugin/embedding-bootstrap.d.ts +3 -0
  351. package/dist/plugin/embedding-bootstrap.d.ts.map +1 -0
  352. package/dist/plugin/event.d.ts +13 -0
  353. package/dist/plugin/event.d.ts.map +1 -0
  354. package/dist/plugin/hooks/create-session-hooks.d.ts +44 -0
  355. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -0
  356. package/dist/plugin/messages-transform.d.ts +46 -0
  357. package/dist/plugin/messages-transform.d.ts.map +1 -0
  358. package/dist/plugin/normalize-tool-arg-schemas.d.ts +7 -0
  359. package/dist/plugin/normalize-tool-arg-schemas.d.ts.map +1 -0
  360. package/dist/plugin/rpc-handlers.d.ts +21 -0
  361. package/dist/plugin/rpc-handlers.d.ts.map +1 -0
  362. package/dist/plugin/sidebar-snapshot-cache.d.ts +19 -0
  363. package/dist/plugin/sidebar-snapshot-cache.d.ts.map +1 -0
  364. package/dist/plugin/tool-registry.d.ts +8 -0
  365. package/dist/plugin/tool-registry.d.ts.map +1 -0
  366. package/dist/plugin/types.d.ts +3 -0
  367. package/dist/plugin/types.d.ts.map +1 -0
  368. package/dist/shared/announcement.d.ts +55 -0
  369. package/dist/shared/announcement.d.ts.map +1 -0
  370. package/dist/shared/assistant-message-extractor.d.ts +2 -0
  371. package/dist/shared/assistant-message-extractor.d.ts.map +1 -0
  372. package/dist/shared/bounded-session-map.d.ts +45 -0
  373. package/dist/shared/bounded-session-map.d.ts.map +1 -0
  374. package/dist/shared/conflict-detector.d.ts +74 -0
  375. package/dist/shared/conflict-detector.d.ts.map +1 -0
  376. package/dist/shared/conflict-fixer.d.ts +3 -0
  377. package/dist/shared/conflict-fixer.d.ts.map +1 -0
  378. package/dist/shared/data-path.d.ts +121 -0
  379. package/dist/shared/data-path.d.ts.map +1 -0
  380. package/dist/shared/error-message.d.ts +32 -0
  381. package/dist/shared/error-message.d.ts.map +1 -0
  382. package/dist/shared/format-bytes.d.ts +2 -0
  383. package/dist/shared/format-bytes.d.ts.map +1 -0
  384. package/dist/shared/format-threshold.d.ts +24 -0
  385. package/dist/shared/format-threshold.d.ts.map +1 -0
  386. package/dist/shared/harness.d.ts +43 -0
  387. package/dist/shared/harness.d.ts.map +1 -0
  388. package/dist/shared/index.d.ts +6 -0
  389. package/dist/shared/index.d.ts.map +1 -0
  390. package/dist/shared/internal-initiator-marker.d.ts +2 -0
  391. package/dist/shared/internal-initiator-marker.d.ts.map +1 -0
  392. package/dist/shared/jsonc-parser.d.ts +8 -0
  393. package/dist/shared/jsonc-parser.d.ts.map +1 -0
  394. package/dist/shared/logger.d.ts +10 -0
  395. package/dist/shared/logger.d.ts.map +1 -0
  396. package/dist/shared/model-requirements.d.ts +26 -0
  397. package/dist/shared/model-requirements.d.ts.map +1 -0
  398. package/dist/shared/model-suggestion-retry.d.ts +68 -0
  399. package/dist/shared/model-suggestion-retry.d.ts.map +1 -0
  400. package/dist/shared/models-dev-cache.d.ts +65 -0
  401. package/dist/shared/models-dev-cache.d.ts.map +1 -0
  402. package/dist/shared/native-binding.d.ts +87 -0
  403. package/dist/shared/native-binding.d.ts.map +1 -0
  404. package/dist/shared/normalize-sdk-response.d.ts +5 -0
  405. package/dist/shared/normalize-sdk-response.d.ts.map +1 -0
  406. package/dist/shared/opencode-compaction-detector.d.ts +2 -0
  407. package/dist/shared/opencode-compaction-detector.d.ts.map +1 -0
  408. package/dist/shared/opencode-config-dir-types.d.ts +14 -0
  409. package/dist/shared/opencode-config-dir-types.d.ts.map +1 -0
  410. package/dist/shared/opencode-config-dir.d.ts +5 -0
  411. package/dist/shared/opencode-config-dir.d.ts.map +1 -0
  412. package/dist/shared/record-type-guard.d.ts +2 -0
  413. package/dist/shared/record-type-guard.d.ts.map +1 -0
  414. package/dist/shared/resolve-fallbacks.d.ts +32 -0
  415. package/dist/shared/resolve-fallbacks.d.ts.map +1 -0
  416. package/dist/shared/rpc-client.d.ts +17 -0
  417. package/dist/shared/rpc-client.d.ts.map +1 -0
  418. package/dist/shared/rpc-notifications.d.ts +24 -0
  419. package/dist/shared/rpc-notifications.d.ts.map +1 -0
  420. package/dist/shared/rpc-server.d.ts +20 -0
  421. package/dist/shared/rpc-server.d.ts.map +1 -0
  422. package/dist/shared/rpc-types.d.ts +105 -0
  423. package/dist/shared/rpc-types.d.ts.map +1 -0
  424. package/dist/shared/rpc-utils.d.ts +19 -0
  425. package/dist/shared/rpc-utils.d.ts.map +1 -0
  426. package/dist/shared/sqlite-helpers.d.ts +16 -0
  427. package/dist/shared/sqlite-helpers.d.ts.map +1 -0
  428. package/dist/shared/sqlite.d.ts +43 -0
  429. package/dist/shared/sqlite.d.ts.map +1 -0
  430. package/dist/shared/stable-json.d.ts +21 -0
  431. package/dist/shared/stable-json.d.ts.map +1 -0
  432. package/dist/shared/subagent-runner.d.ts +208 -0
  433. package/dist/shared/subagent-runner.d.ts.map +1 -0
  434. package/dist/shared/system-directive.d.ts +3 -0
  435. package/dist/shared/system-directive.d.ts.map +1 -0
  436. package/dist/shared/tag-transcript.d.ts +66 -0
  437. package/dist/shared/tag-transcript.d.ts.map +1 -0
  438. package/dist/shared/transcript-opencode.d.ts +71 -0
  439. package/dist/shared/transcript-opencode.d.ts.map +1 -0
  440. package/dist/shared/transcript.d.ts +212 -0
  441. package/dist/shared/transcript.d.ts.map +1 -0
  442. package/dist/shared/tui-config.d.ts +10 -0
  443. package/dist/shared/tui-config.d.ts.map +1 -0
  444. package/dist/tools/ctx-expand/constants.d.ts +3 -0
  445. package/dist/tools/ctx-expand/constants.d.ts.map +1 -0
  446. package/dist/tools/ctx-expand/index.d.ts +2 -0
  447. package/dist/tools/ctx-expand/index.d.ts.map +1 -0
  448. package/dist/tools/ctx-expand/tools.d.ts +3 -0
  449. package/dist/tools/ctx-expand/tools.d.ts.map +1 -0
  450. package/dist/tools/ctx-expand/types.d.ts +5 -0
  451. package/dist/tools/ctx-expand/types.d.ts.map +1 -0
  452. package/dist/tools/ctx-memory/constants.d.ts +4 -0
  453. package/dist/tools/ctx-memory/constants.d.ts.map +1 -0
  454. package/dist/tools/ctx-memory/index.d.ts +4 -0
  455. package/dist/tools/ctx-memory/index.d.ts.map +1 -0
  456. package/dist/tools/ctx-memory/tools.d.ts +4 -0
  457. package/dist/tools/ctx-memory/tools.d.ts.map +1 -0
  458. package/dist/tools/ctx-memory/types.d.ts +35 -0
  459. package/dist/tools/ctx-memory/types.d.ts.map +1 -0
  460. package/dist/tools/ctx-note/constants.d.ts +2 -0
  461. package/dist/tools/ctx-note/constants.d.ts.map +1 -0
  462. package/dist/tools/ctx-note/index.d.ts +4 -0
  463. package/dist/tools/ctx-note/index.d.ts.map +1 -0
  464. package/dist/tools/ctx-note/tools.d.ts +15 -0
  465. package/dist/tools/ctx-note/tools.d.ts.map +1 -0
  466. package/dist/tools/ctx-note/types.d.ts +9 -0
  467. package/dist/tools/ctx-note/types.d.ts.map +1 -0
  468. package/dist/tools/ctx-reduce/constants.d.ts +2 -0
  469. package/dist/tools/ctx-reduce/constants.d.ts.map +1 -0
  470. package/dist/tools/ctx-reduce/index.d.ts +4 -0
  471. package/dist/tools/ctx-reduce/index.d.ts.map +1 -0
  472. package/dist/tools/ctx-reduce/tools.d.ts +9 -0
  473. package/dist/tools/ctx-reduce/tools.d.ts.map +1 -0
  474. package/dist/tools/ctx-reduce/types.d.ts +4 -0
  475. package/dist/tools/ctx-reduce/types.d.ts.map +1 -0
  476. package/dist/tools/ctx-search/constants.d.ts +4 -0
  477. package/dist/tools/ctx-search/constants.d.ts.map +1 -0
  478. package/dist/tools/ctx-search/index.d.ts +4 -0
  479. package/dist/tools/ctx-search/index.d.ts.map +1 -0
  480. package/dist/tools/ctx-search/tools.d.ts +4 -0
  481. package/dist/tools/ctx-search/tools.d.ts.map +1 -0
  482. package/dist/tools/ctx-search/types.d.ts +34 -0
  483. package/dist/tools/ctx-search/types.d.ts.map +1 -0
  484. package/dist/tools/index.d.ts +6 -0
  485. package/dist/tools/index.d.ts.map +1 -0
  486. package/dist/tui/data/context-db.d.ts +36 -0
  487. package/dist/tui/data/context-db.d.ts.map +1 -0
  488. package/package.json +80 -0
  489. package/src/shared/announcement.test.ts +143 -0
  490. package/src/shared/announcement.ts +97 -0
  491. package/src/shared/assistant-message-extractor.ts +74 -0
  492. package/src/shared/bounded-session-map.test.ts +97 -0
  493. package/src/shared/bounded-session-map.ts +84 -0
  494. package/src/shared/conflict-detector.test.ts +232 -0
  495. package/src/shared/conflict-detector.ts +371 -0
  496. package/src/shared/conflict-fixer.test.ts +124 -0
  497. package/src/shared/conflict-fixer.ts +222 -0
  498. package/src/shared/data-path.test.ts +159 -0
  499. package/src/shared/data-path.ts +155 -0
  500. package/src/shared/error-message.test.ts +94 -0
  501. package/src/shared/error-message.ts +115 -0
  502. package/src/shared/format-bytes.ts +5 -0
  503. package/src/shared/format-threshold.ts +28 -0
  504. package/src/shared/harness.ts +61 -0
  505. package/src/shared/index.ts +5 -0
  506. package/src/shared/internal-initiator-marker.ts +1 -0
  507. package/src/shared/jsonc-parser.ts +138 -0
  508. package/src/shared/logger.ts +94 -0
  509. package/src/shared/model-requirements.ts +86 -0
  510. package/src/shared/model-suggestion-retry.test.ts +251 -0
  511. package/src/shared/model-suggestion-retry.ts +348 -0
  512. package/src/shared/models-dev-cache.test.ts +394 -0
  513. package/src/shared/models-dev-cache.ts +337 -0
  514. package/src/shared/native-binding.ts +311 -0
  515. package/src/shared/normalize-sdk-response.ts +40 -0
  516. package/src/shared/opencode-compaction-detector.test.ts +222 -0
  517. package/src/shared/opencode-compaction-detector.ts +81 -0
  518. package/src/shared/opencode-config-dir-types.ts +15 -0
  519. package/src/shared/opencode-config-dir.ts +38 -0
  520. package/src/shared/record-type-guard.ts +3 -0
  521. package/src/shared/resolve-fallbacks.test.ts +136 -0
  522. package/src/shared/resolve-fallbacks.ts +76 -0
  523. package/src/shared/rpc-client.test.ts +161 -0
  524. package/src/shared/rpc-client.ts +183 -0
  525. package/src/shared/rpc-notifications.test.ts +20 -0
  526. package/src/shared/rpc-notifications.ts +53 -0
  527. package/src/shared/rpc-server.ts +174 -0
  528. package/src/shared/rpc-types.ts +104 -0
  529. package/src/shared/rpc-utils.ts +72 -0
  530. package/src/shared/session-messages-bounded.test.ts +112 -0
  531. package/src/shared/sqlite-helpers.ts +27 -0
  532. package/src/shared/sqlite.ts +134 -0
  533. package/src/shared/stable-json.test.ts +87 -0
  534. package/src/shared/stable-json.ts +37 -0
  535. package/src/shared/subagent-runner.ts +222 -0
  536. package/src/shared/system-directive.ts +9 -0
  537. package/src/shared/tag-transcript.ts +553 -0
  538. package/src/shared/transcript-opencode.ts +259 -0
  539. package/src/shared/transcript.ts +226 -0
  540. package/src/shared/tui-config.ts +99 -0
  541. package/src/tui/data/context-db.ts +303 -0
  542. package/src/tui/index.tsx +692 -0
  543. package/src/tui/slots/sidebar-content.tsx +482 -0
  544. package/src/tui/types/opencode-plugin-tui.d.ts +232 -0
@@ -0,0 +1,251 @@
1
+ import { describe, expect, mock, test } from "bun:test";
2
+
3
+ import { promptSyncWithModelSuggestionRetry } from "./model-suggestion-retry";
4
+
5
+ type PromptCall = {
6
+ body: { model?: { providerID: string; modelID: string } };
7
+ signal?: AbortSignal;
8
+ };
9
+
10
+ function createClient(prompt: ReturnType<typeof mock>) {
11
+ return {
12
+ session: {
13
+ prompt,
14
+ },
15
+ } as never;
16
+ }
17
+
18
+ function createArgs(model?: { providerID: string; modelID: string }) {
19
+ return {
20
+ path: { id: "ses-test" },
21
+ body: model ? { model } : {},
22
+ };
23
+ }
24
+
25
+ describe("promptSyncWithModelSuggestionRetry", () => {
26
+ test("primary succeeds, no fallback iteration", async () => {
27
+ const prompt = mock(async () => ({}));
28
+ const client = createClient(prompt);
29
+
30
+ await promptSyncWithModelSuggestionRetry(client, createArgs(), {
31
+ fallbackModels: ["anthropic/claude-sonnet-4-6"],
32
+ });
33
+
34
+ expect(prompt).toHaveBeenCalledTimes(1);
35
+ });
36
+
37
+ test("primary succeeds with no fallbacks configured", async () => {
38
+ const prompt = mock(async () => ({}));
39
+ const client = createClient(prompt);
40
+
41
+ await promptSyncWithModelSuggestionRetry(client, createArgs());
42
+
43
+ expect(prompt).toHaveBeenCalledTimes(1);
44
+ });
45
+
46
+ test("primary fails, fallback[0] succeeds", async () => {
47
+ const prompt = mock(async () => {
48
+ if (prompt.mock.calls.length === 1) throw new Error("primary failed");
49
+ return {};
50
+ });
51
+ const client = createClient(prompt);
52
+
53
+ await promptSyncWithModelSuggestionRetry(client, createArgs(), {
54
+ fallbackModels: ["anthropic/claude-sonnet-4-6"],
55
+ });
56
+
57
+ expect(prompt).toHaveBeenCalledTimes(2);
58
+ expect((prompt.mock.calls[1]?.[0] as PromptCall).body.model).toEqual({
59
+ providerID: "anthropic",
60
+ modelID: "claude-sonnet-4-6",
61
+ });
62
+ });
63
+
64
+ test("primary fails, fallback[0] fails, fallback[1] succeeds", async () => {
65
+ const prompt = mock(async () => {
66
+ if (prompt.mock.calls.length <= 2)
67
+ throw new Error(`failed ${prompt.mock.calls.length}`);
68
+ return {};
69
+ });
70
+ const client = createClient(prompt);
71
+
72
+ await promptSyncWithModelSuggestionRetry(client, createArgs(), {
73
+ fallbackModels: ["anthropic/claude-sonnet-4-6", "google/gemini-3-flash"],
74
+ });
75
+
76
+ expect(prompt).toHaveBeenCalledTimes(3);
77
+ expect((prompt.mock.calls[2]?.[0] as PromptCall).body.model).toEqual({
78
+ providerID: "google",
79
+ modelID: "gemini-3-flash",
80
+ });
81
+ });
82
+
83
+ test("all attempts fail throws the last fallback error", async () => {
84
+ const primaryError = new Error("primary failed");
85
+ const firstFallbackError = new Error("fallback 0 failed");
86
+ const lastFallbackError = new Error("fallback 1 failed");
87
+ const errors = [primaryError, firstFallbackError, lastFallbackError];
88
+ const prompt = mock(async () => {
89
+ throw errors[prompt.mock.calls.length - 1];
90
+ });
91
+ const client = createClient(prompt);
92
+
93
+ await expect(
94
+ promptSyncWithModelSuggestionRetry(client, createArgs(), {
95
+ fallbackModels: ["anthropic/claude-sonnet-4-6", "google/gemini-3-flash"],
96
+ }),
97
+ ).rejects.toBe(lastFallbackError);
98
+ expect(prompt).toHaveBeenCalledTimes(3);
99
+ });
100
+
101
+ test("abort signal short-circuits", async () => {
102
+ const controller = new AbortController();
103
+ controller.abort();
104
+ const prompt = mock(async () => {
105
+ throw new Error("provider noticed abort");
106
+ });
107
+ const client = createClient(prompt);
108
+
109
+ await expect(
110
+ promptSyncWithModelSuggestionRetry(client, createArgs(), {
111
+ signal: controller.signal,
112
+ fallbackModels: ["anthropic/claude-sonnet-4-6"],
113
+ }),
114
+ ).rejects.toThrow("prompt aborted by external signal");
115
+ // Pre-aborted signal MUST short-circuit before any upstream prompt
116
+ // call — Audit Finding #1 hardening. No round-trip wasted on a
117
+ // request the caller has already cancelled.
118
+ expect(prompt).toHaveBeenCalledTimes(0);
119
+ });
120
+
121
+ test("AbortError name short-circuits", async () => {
122
+ const abortError = new Error("aborted by provider");
123
+ abortError.name = "AbortError";
124
+ const prompt = mock(async () => {
125
+ throw abortError;
126
+ });
127
+ const client = createClient(prompt);
128
+
129
+ await expect(
130
+ promptSyncWithModelSuggestionRetry(client, createArgs(), {
131
+ fallbackModels: ["anthropic/claude-sonnet-4-6"],
132
+ }),
133
+ ).rejects.toBe(abortError);
134
+ expect(prompt).toHaveBeenCalledTimes(1);
135
+ });
136
+
137
+ test("timeout short-circuits", async () => {
138
+ const timeoutError = new Error("prompt timed out after 5000ms");
139
+ const prompt = mock(async () => {
140
+ throw timeoutError;
141
+ });
142
+ const client = createClient(prompt);
143
+
144
+ await expect(
145
+ promptSyncWithModelSuggestionRetry(client, createArgs(), {
146
+ fallbackModels: ["anthropic/claude-sonnet-4-6"],
147
+ }),
148
+ ).rejects.toBe(timeoutError);
149
+ expect(prompt).toHaveBeenCalledTimes(1);
150
+ });
151
+
152
+ test("context overflow short-circuits", async () => {
153
+ const overflowError = new Error("prompt is too long: 50000 tokens > 32000");
154
+ const prompt = mock(async () => {
155
+ throw overflowError;
156
+ });
157
+ const client = createClient(prompt);
158
+
159
+ await expect(
160
+ promptSyncWithModelSuggestionRetry(client, createArgs(), {
161
+ fallbackModels: ["anthropic/claude-sonnet-4-6"],
162
+ }),
163
+ ).rejects.toBe(overflowError);
164
+ expect(prompt).toHaveBeenCalledTimes(1);
165
+ });
166
+
167
+ test("suggestion retry within attempt succeeds", async () => {
168
+ const suggestionError = new Error("model not found");
169
+ suggestionError.name = "ProviderModelNotFoundError";
170
+ Object.assign(suggestionError, {
171
+ data: {
172
+ providerID: "anthropic",
173
+ modelID: "claude-sonnet-4-6",
174
+ suggestions: ["claude-sonnet-4-7"],
175
+ },
176
+ });
177
+ const prompt = mock(async () => {
178
+ if (prompt.mock.calls.length === 1) throw suggestionError;
179
+ return {};
180
+ });
181
+ const client = createClient(prompt);
182
+
183
+ await promptSyncWithModelSuggestionRetry(
184
+ client,
185
+ createArgs({ providerID: "anthropic", modelID: "claude-sonnet-4-6" }),
186
+ { fallbackModels: ["google/gemini-3-flash"] },
187
+ );
188
+
189
+ expect(prompt).toHaveBeenCalledTimes(2);
190
+ expect((prompt.mock.calls[1]?.[0] as PromptCall).body.model).toEqual({
191
+ providerID: "anthropic",
192
+ modelID: "claude-sonnet-4-7",
193
+ });
194
+ });
195
+
196
+ test("invalid fallback specs are skipped", async () => {
197
+ const prompt = mock(async () => {
198
+ if (prompt.mock.calls.length === 1) throw new Error("primary failed");
199
+ return {};
200
+ });
201
+ const client = createClient(prompt);
202
+
203
+ await promptSyncWithModelSuggestionRetry(client, createArgs(), {
204
+ fallbackModels: ["no-slash", "/leading", "valid/model"],
205
+ });
206
+
207
+ expect(prompt).toHaveBeenCalledTimes(2);
208
+ expect((prompt.mock.calls[1]?.[0] as PromptCall).body.model).toEqual({
209
+ providerID: "valid",
210
+ modelID: "model",
211
+ });
212
+ });
213
+
214
+ test("iteration order respected", async () => {
215
+ const prompt = mock(async () => {
216
+ throw new Error(`failed ${prompt.mock.calls.length}`);
217
+ });
218
+ const client = createClient(prompt);
219
+
220
+ await expect(
221
+ promptSyncWithModelSuggestionRetry(client, createArgs(), {
222
+ fallbackModels: [
223
+ "anthropic/claude-sonnet-4-6",
224
+ "google/gemini-3-flash",
225
+ "openrouter/qwen3-coder",
226
+ ],
227
+ }),
228
+ ).rejects.toThrow("failed 4");
229
+
230
+ expect(prompt).toHaveBeenCalledTimes(4);
231
+ expect(prompt.mock.calls.map((call) => (call[0] as PromptCall).body.model)).toEqual([
232
+ undefined,
233
+ { providerID: "anthropic", modelID: "claude-sonnet-4-6" },
234
+ { providerID: "google", modelID: "gemini-3-flash" },
235
+ { providerID: "openrouter", modelID: "qwen3-coder" },
236
+ ]);
237
+ });
238
+
239
+ test("empty fallbackModels = legacy", async () => {
240
+ const originalError = new Error("primary failed without suggestion");
241
+ const prompt = mock(async () => {
242
+ throw originalError;
243
+ });
244
+ const client = createClient(prompt);
245
+
246
+ await expect(
247
+ promptSyncWithModelSuggestionRetry(client, createArgs(), { fallbackModels: [] }),
248
+ ).rejects.toBe(originalError);
249
+ expect(prompt).toHaveBeenCalledTimes(1);
250
+ });
251
+ });
@@ -0,0 +1,348 @@
1
+ import type { createOpencodeClient } from "@opencode-ai/sdk";
2
+
3
+ import { detectOverflow } from "../features/magic-context/overflow-detection";
4
+ import { log } from "./logger";
5
+ import { parseProviderModel } from "./resolve-fallbacks";
6
+
7
+ type Client = ReturnType<typeof createOpencodeClient>;
8
+
9
+ type PromptBody = {
10
+ model?: { providerID: string; modelID: string };
11
+ [key: string]: unknown;
12
+ };
13
+
14
+ type PromptArgs = {
15
+ path: { id: string };
16
+ body: PromptBody;
17
+ signal?: AbortSignal;
18
+ [key: string]: unknown;
19
+ };
20
+
21
+ export interface PromptRetryOptions {
22
+ timeoutMs?: number;
23
+ /** External abort signal — cancels the in-flight LLM prompt immediately when aborted */
24
+ signal?: AbortSignal;
25
+ /**
26
+ * Ordered list of "provider/modelID" alternates to try if the primary call
27
+ * (and its single-suggestion retry) fails. Empty / undefined = no fallback
28
+ * iteration (legacy behavior).
29
+ *
30
+ * Fallback policy:
31
+ * - Each fallback gets the FULL `timeoutMs` budget (per-attempt, not total).
32
+ * - Suggestion-retry runs inside each attempt (so "did you mean X?" errors
33
+ * still self-heal at the primary AND at each fallback).
34
+ * - Iteration stops immediately on abort/timeout/context-overflow errors —
35
+ * fallbacks won't help and the caller's emergency-recovery path needs
36
+ * to handle these.
37
+ * - On all-failed, the LAST error is thrown (matches legacy behavior when
38
+ * `fallbackModels` is empty).
39
+ */
40
+ fallbackModels?: readonly string[];
41
+ /**
42
+ * Identifier for structured logging (e.g. "dreamer:consolidate",
43
+ * "historian", "compressor", "sidekick"). Helps correlate fallback
44
+ * attempts to a specific call site in `magic-context.log`. Defaults to
45
+ * "subagent" if not provided.
46
+ */
47
+ callContext?: string;
48
+ }
49
+
50
+ export interface ModelSuggestionInfo {
51
+ providerID: string;
52
+ modelID: string;
53
+ suggestion: string;
54
+ }
55
+
56
+ function extractMessage(error: unknown): string {
57
+ if (typeof error === "string") return error;
58
+ if (error instanceof Error) return error.message;
59
+ if (typeof error === "object" && error !== null) {
60
+ const obj = error as Record<string, unknown>;
61
+ if (typeof obj.message === "string") return obj.message;
62
+ }
63
+
64
+ try {
65
+ return JSON.stringify(error);
66
+ } catch (_error) {
67
+ return String(error);
68
+ }
69
+ }
70
+
71
+ export function parseModelSuggestion(error: unknown): ModelSuggestionInfo | null {
72
+ if (!error) return null;
73
+
74
+ if (typeof error === "object" && error !== null) {
75
+ const errObj = error as Record<string, unknown>;
76
+
77
+ if (
78
+ errObj.name === "ProviderModelNotFoundError" &&
79
+ typeof errObj.data === "object" &&
80
+ errObj.data !== null
81
+ ) {
82
+ const data = errObj.data as Record<string, unknown>;
83
+ const suggestions = data.suggestions;
84
+ if (Array.isArray(suggestions) && typeof suggestions[0] === "string") {
85
+ return {
86
+ providerID: String(data.providerID ?? ""),
87
+ modelID: String(data.modelID ?? ""),
88
+ suggestion: suggestions[0],
89
+ };
90
+ }
91
+ }
92
+
93
+ for (const key of ["data", "error", "cause"] as const) {
94
+ const nested = errObj[key];
95
+ if (nested && typeof nested === "object") {
96
+ const result = parseModelSuggestion(nested);
97
+ if (result) return result;
98
+ }
99
+ }
100
+ }
101
+
102
+ const message = extractMessage(error);
103
+ const modelMatch = message.match(/model not found:\s*([^/\s]+)\s*\/\s*([^.,\s]+)/i);
104
+ const suggestionMatch = message.match(/did you mean:\s*([^,?]+)/i);
105
+
106
+ if (!modelMatch || !suggestionMatch) {
107
+ return null;
108
+ }
109
+
110
+ return {
111
+ providerID: modelMatch[1].trim(),
112
+ modelID: modelMatch[2].trim(),
113
+ suggestion: suggestionMatch[1].trim(),
114
+ };
115
+ }
116
+
117
+ async function promptWithTimeout(
118
+ client: Client,
119
+ args: PromptArgs,
120
+ timeoutMs: number,
121
+ signal?: AbortSignal,
122
+ ): Promise<void> {
123
+ // Bail immediately if the caller's signal is already aborted (e.g.
124
+ // lease loss before this attempt was scheduled). Per spec
125
+ // `addEventListener('abort', ...)` on an already-aborted signal fires
126
+ // synchronously in modern Node/Bun, but an explicit guard is clearer
127
+ // and avoids one wasted upstream `client.session.prompt` round-trip
128
+ // before `isNonRetryable` catches the cancellation at the chain loop.
129
+ if (signal?.aborted) {
130
+ throw new Error("prompt aborted by external signal");
131
+ }
132
+ const controller = new AbortController();
133
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
134
+
135
+ // Link external signal to internal controller so external abort cancels the fetch
136
+ const onExternalAbort = () => controller.abort();
137
+ signal?.addEventListener("abort", onExternalAbort);
138
+
139
+ try {
140
+ await client.session.prompt({
141
+ ...args,
142
+ signal: controller.signal,
143
+ } as Parameters<typeof client.session.prompt>[0]);
144
+ } catch (error) {
145
+ if (signal?.aborted) {
146
+ throw new Error("prompt aborted by external signal");
147
+ }
148
+ if (controller.signal.aborted) {
149
+ throw new Error(`prompt timed out after ${timeoutMs}ms`);
150
+ }
151
+ throw error;
152
+ } finally {
153
+ clearTimeout(timeout);
154
+ signal?.removeEventListener("abort", onExternalAbort);
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Returns true if the error indicates a NON-RETRYABLE condition where iterating
160
+ * to a fallback model would be pointless or harmful:
161
+ *
162
+ * - External abort (user cancellation, lease loss, etc.) — caller wants to
163
+ * stop, not retry.
164
+ * - Context overflow — same prompt will overflow on any reasonably-sized
165
+ * model. Caller has its own emergency-recovery path for this.
166
+ * - Timeout — same wall-clock budget on the same prompt is unlikely to
167
+ * succeed on another model. Caller decides whether to retry at a higher
168
+ * level (e.g. historian's MAX_HISTORIAN_RETRIES loop).
169
+ *
170
+ * Everything else (auth errors, ProviderModelNotFoundError without suggestion,
171
+ * rate limits, transient network failures, etc.) is considered retryable on a
172
+ * different model.
173
+ */
174
+ function isNonRetryable(error: unknown, externalSignal?: AbortSignal): boolean {
175
+ if (externalSignal?.aborted) return true;
176
+
177
+ if (error instanceof Error) {
178
+ if (error.name === "AbortError") return true;
179
+ // promptWithTimeout wraps both abort cases in plain `Error` with a
180
+ // recognizable message.
181
+ if (error.message === "prompt aborted by external signal") return true;
182
+ if (/^prompt timed out after \d+ms$/.test(error.message)) return true;
183
+ }
184
+
185
+ if (detectOverflow(error).isOverflow) return true;
186
+
187
+ return false;
188
+ }
189
+
190
+ function shortErr(error: unknown): string {
191
+ if (error instanceof Error) {
192
+ return error.name && error.name !== "Error"
193
+ ? `${error.name}: ${error.message}`
194
+ : error.message;
195
+ }
196
+ return extractMessage(error);
197
+ }
198
+
199
+ /**
200
+ * Try a single prompt attempt against the supplied body, with the existing
201
+ * single-suggestion retry layered inside (so "did you mean X?" still self-heals
202
+ * per attempt). Throws on failure; returns on success.
203
+ */
204
+ async function attemptOnce(
205
+ client: Client,
206
+ args: PromptArgs,
207
+ timeoutMs: number,
208
+ signal: AbortSignal | undefined,
209
+ callContext: string,
210
+ label: string,
211
+ ): Promise<void> {
212
+ try {
213
+ await promptWithTimeout(client, args, timeoutMs, signal);
214
+ return;
215
+ } catch (error) {
216
+ // If non-retryable (abort, overflow, timeout), bubble up immediately.
217
+ // Don't even try suggestion retry — caller needs the original error.
218
+ if (isNonRetryable(error, signal)) throw error;
219
+
220
+ const suggestion = parseModelSuggestion(error);
221
+ if (!suggestion || !args.body.model) {
222
+ // No suggestion available — caller's fallback loop will decide
223
+ // whether to try the next chain entry.
224
+ throw error;
225
+ }
226
+
227
+ log(`[${callContext}] ${label}: model not found, retrying with suggestion`, {
228
+ original: `${suggestion.providerID}/${suggestion.modelID}`,
229
+ suggested: suggestion.suggestion,
230
+ });
231
+
232
+ await promptWithTimeout(
233
+ client,
234
+ {
235
+ ...args,
236
+ body: {
237
+ ...args.body,
238
+ model: {
239
+ providerID: suggestion.providerID,
240
+ modelID: suggestion.suggestion,
241
+ },
242
+ },
243
+ },
244
+ timeoutMs,
245
+ signal,
246
+ );
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Run an OpenCode subagent prompt with model fallback support.
252
+ *
253
+ * Attempts the configured primary model first (whatever `args.body.model` or
254
+ * the registered agent default resolves to), then iterates through
255
+ * `options.fallbackModels` if provided. Each attempt internally retries once on
256
+ * the SDK's "model not found, did you mean X?" suggestion. Aborts, timeouts,
257
+ * and context-overflow errors short-circuit the fallback loop because retrying
258
+ * the same prompt against another model won't help.
259
+ *
260
+ * Behavior with `fallbackModels` empty/undefined is identical to the pre-v0.18
261
+ * single-suggestion retry — fully backward-compatible for callers that haven't
262
+ * been updated to thread a chain.
263
+ */
264
+ export async function promptSyncWithModelSuggestionRetry(
265
+ client: Client,
266
+ args: PromptArgs,
267
+ options: PromptRetryOptions = {},
268
+ ): Promise<void> {
269
+ const timeoutMs = options.timeoutMs ?? 300_000;
270
+ const callContext = options.callContext ?? "subagent";
271
+ const fallbacks = options.fallbackModels ?? [];
272
+
273
+ // Attempt 0 = whatever the agent or explicit body.model resolves to.
274
+ // Subsequent attempts override body.model with each fallback in order.
275
+ const explicitPrimaryLabel =
276
+ args.body.model?.providerID && args.body.model.modelID
277
+ ? `${args.body.model.providerID}/${args.body.model.modelID}`
278
+ : "primary";
279
+
280
+ let lastError: unknown = null;
281
+
282
+ try {
283
+ await attemptOnce(
284
+ client,
285
+ args,
286
+ timeoutMs,
287
+ options.signal,
288
+ callContext,
289
+ explicitPrimaryLabel,
290
+ );
291
+ return;
292
+ } catch (error) {
293
+ lastError = error;
294
+ if (isNonRetryable(error, options.signal)) throw error;
295
+
296
+ if (fallbacks.length === 0) {
297
+ // No fallbacks configured — behave exactly like legacy: propagate
298
+ // the original error (which may already have had its suggestion
299
+ // retry attempted inside `attemptOnce`).
300
+ throw error;
301
+ }
302
+
303
+ log(
304
+ `[${callContext}] primary (${explicitPrimaryLabel}) failed: ${shortErr(error)}; trying ${fallbacks.length} fallback(s)`,
305
+ );
306
+ }
307
+
308
+ // Iterate fallbacks.
309
+ for (let i = 0; i < fallbacks.length; i += 1) {
310
+ const parsed = parseProviderModel(fallbacks[i]);
311
+ if (!parsed) {
312
+ log(`[${callContext}] skipping invalid fallback spec: ${fallbacks[i]}`);
313
+ continue;
314
+ }
315
+
316
+ const label = `${parsed.providerID}/${parsed.modelID}`;
317
+ const attemptArgs: PromptArgs = {
318
+ ...args,
319
+ body: { ...args.body, model: parsed },
320
+ };
321
+
322
+ try {
323
+ await attemptOnce(client, attemptArgs, timeoutMs, options.signal, callContext, label);
324
+ log(
325
+ `[${callContext}] fallback succeeded with ${label} (attempt ${i + 2}/${fallbacks.length + 1})`,
326
+ );
327
+ return;
328
+ } catch (error) {
329
+ lastError = error;
330
+ if (isNonRetryable(error, options.signal)) throw error;
331
+
332
+ const remaining = fallbacks.length - i - 1;
333
+ if (remaining > 0) {
334
+ log(
335
+ `[${callContext}] ${label} failed: ${shortErr(error)}; ${remaining} fallback(s) left`,
336
+ );
337
+ }
338
+ }
339
+ }
340
+
341
+ // All exhausted. Log the full chain and throw the last error so the
342
+ // caller's report (e.g. /ctx-dream tasks_json) still surfaces a real
343
+ // diagnostic.
344
+ log(
345
+ `[${callContext}] all models exhausted; tried: ${[explicitPrimaryLabel, ...fallbacks].join(", ")}; last error: ${shortErr(lastError)}`,
346
+ );
347
+ throw lastError ?? new Error("All fallback models failed");
348
+ }