rovecode 0.4.0-beta.3 → 0.4.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 (432) hide show
  1. package/README.md +57 -72
  2. package/THIRD_PARTY_NOTICES.md +0 -44
  3. package/bin/rovecode.ts +21 -0
  4. package/package.json +16 -38
  5. package/src/account/keys.ts +97 -0
  6. package/src/account/login.ts +158 -0
  7. package/src/account/provision.ts +47 -0
  8. package/src/account/store.ts +63 -0
  9. package/src/acp/server.ts +373 -0
  10. package/src/cli/account-cmd.ts +116 -0
  11. package/src/cli/connect.ts +244 -0
  12. package/src/cli/context-cmd.ts +199 -0
  13. package/src/cli/dispatch.ts +109 -0
  14. package/src/cli/doctor.ts +324 -0
  15. package/src/cli/export.ts +278 -0
  16. package/src/cli/help.ts +240 -0
  17. package/src/cli/is-tui-invocation.ts +8 -0
  18. package/src/cli/main.ts +599 -0
  19. package/src/cli/market-cmd.ts +658 -0
  20. package/src/cli/mcp-market-cmd.ts +299 -0
  21. package/src/cli/output.ts +382 -0
  22. package/src/cli/repl.ts +172 -0
  23. package/src/cli/resume.ts +32 -0
  24. package/src/cli/run-limits.ts +78 -0
  25. package/src/cli/runtime.ts +792 -0
  26. package/src/cli/setup.ts +187 -0
  27. package/src/cli/update-cmd.ts +78 -0
  28. package/src/cli/workflow-cmd.ts +100 -0
  29. package/src/coding/checkpoints.ts +270 -0
  30. package/src/coding/diff.ts +136 -0
  31. package/src/coding/files.ts +339 -0
  32. package/src/coding/hashline.ts +319 -0
  33. package/src/coding/lsp.ts +406 -0
  34. package/src/coding/repomap-cache.ts +99 -0
  35. package/src/coding/repomap-files.ts +110 -0
  36. package/src/coding/repomap.ts +392 -0
  37. package/src/core/compaction.ts +399 -0
  38. package/src/core/config.ts +289 -0
  39. package/src/core/context-report.ts +228 -0
  40. package/src/core/context.ts +60 -0
  41. package/src/core/count-remote.ts +107 -0
  42. package/src/core/execpolicy-rules.ts +196 -0
  43. package/src/core/execpolicy.ts +385 -0
  44. package/src/core/executor.ts +397 -0
  45. package/src/core/guardrails.ts +400 -0
  46. package/src/core/hooks.ts +398 -0
  47. package/src/core/images.ts +230 -0
  48. package/src/core/intro.ts +236 -0
  49. package/src/core/loop.ts +621 -0
  50. package/src/core/modes.ts +372 -0
  51. package/src/core/orchestrator.ts +207 -0
  52. package/src/core/reflection.ts +165 -0
  53. package/src/core/sandbox-config.ts +167 -0
  54. package/src/core/session-images.ts +73 -0
  55. package/src/core/session.ts +398 -0
  56. package/src/core/settings.ts +98 -0
  57. package/src/core/stuck-detector.ts +273 -0
  58. package/src/core/tasks.ts +374 -0
  59. package/src/core/token-scale.ts +108 -0
  60. package/src/core/tool-output-budget.ts +166 -0
  61. package/src/core/tools.ts +288 -0
  62. package/src/core/types.ts +330 -0
  63. package/src/core/update-check.ts +171 -0
  64. package/src/core/update.ts +158 -0
  65. package/src/core/usage.ts +204 -0
  66. package/src/core/validate.ts +121 -0
  67. package/src/core/verify-gate.ts +159 -0
  68. package/src/core/verify.ts +237 -0
  69. package/src/core/voice.ts +158 -0
  70. package/src/core/win-job.ts +183 -0
  71. package/src/design/audit.ts +797 -0
  72. package/src/design/direction.ts +190 -0
  73. package/src/design/rules.ts +157 -0
  74. package/src/eval/bench.ts +150 -0
  75. package/src/eval/gauntlet-runner.ts +218 -0
  76. package/src/eval/gauntlet.ts +226 -0
  77. package/src/eval/grader.ts +186 -0
  78. package/src/eval/record.ts +202 -0
  79. package/src/eval/redact.ts +141 -0
  80. package/src/eval/replay.ts +147 -0
  81. package/src/eval/trajectory.ts +373 -0
  82. package/src/index.ts +17 -0
  83. package/src/market/catalogs/mcp-docs.json +111 -0
  84. package/src/market/catalogs/plugins.json +111 -0
  85. package/src/market/catalogs/skills.json +478 -0
  86. package/src/market/clone.ts +72 -0
  87. package/src/market/context-cost.ts +121 -0
  88. package/src/market/digest.ts +106 -0
  89. package/src/market/index.ts +22 -0
  90. package/src/market/install.ts +578 -0
  91. package/src/market/manifest.ts +187 -0
  92. package/src/market/prereq.ts +145 -0
  93. package/src/market/registry.ts +363 -0
  94. package/src/market/resolve.ts +111 -0
  95. package/src/market/types.ts +236 -0
  96. package/src/market/validate.ts +227 -0
  97. package/src/mcp/client.ts +431 -0
  98. package/src/mcp/config.ts +239 -0
  99. package/src/mcp/local-package.ts +211 -0
  100. package/src/mcp/market-catalog.ts +84 -0
  101. package/src/mcp/market-install.ts +289 -0
  102. package/src/mcp/market.ts +0 -0
  103. package/src/mcp/tools.ts +131 -0
  104. package/src/mcp/trust.ts +49 -0
  105. package/src/memory/blocks.ts +175 -0
  106. package/src/memory/recall.ts +355 -0
  107. package/src/memory/store.ts +105 -0
  108. package/src/memory/tools.ts +99 -0
  109. package/src/plugins/cli.ts +123 -0
  110. package/src/plugins/discover.ts +108 -0
  111. package/src/plugins/index.ts +50 -0
  112. package/src/plugins/init.ts +140 -0
  113. package/src/plugins/install.ts +184 -0
  114. package/src/plugins/load.ts +149 -0
  115. package/src/plugins/manifest.ts +106 -0
  116. package/src/plugins/state.ts +83 -0
  117. package/src/providers/auth.ts +293 -0
  118. package/src/providers/cache.ts +223 -0
  119. package/src/providers/catalog-local.ts +160 -0
  120. package/src/providers/catalog.ts +408 -0
  121. package/src/providers/middleware-context.ts +86 -0
  122. package/src/providers/middleware.ts +373 -0
  123. package/src/providers/profile-glm53.ts +111 -0
  124. package/src/providers/profile-sonnet5-persona.ts +65 -0
  125. package/src/providers/profile-sonnet5-voice.ts +23 -0
  126. package/src/providers/profiles.ts +156 -0
  127. package/src/providers/provider-config.ts +311 -0
  128. package/src/providers/registry.ts +302 -0
  129. package/src/providers/response-validation.ts +80 -0
  130. package/src/providers/retry.ts +234 -0
  131. package/src/providers/router.ts +294 -0
  132. package/src/providers/sse.ts +26 -0
  133. package/src/providers/stream-errors.ts +117 -0
  134. package/src/providers/stream.ts +569 -0
  135. package/src/providers/thinking.ts +189 -0
  136. package/src/providers/wire-messages.ts +129 -0
  137. package/src/sdk/client.ts +225 -0
  138. package/src/sdk/index.ts +3 -0
  139. package/src/server/dashboard.ts +144 -0
  140. package/src/server/http.ts +343 -0
  141. package/src/server/openapi.ts +246 -0
  142. package/src/sextant/card-hits.ts +102 -0
  143. package/src/sextant/card-keys.ts +55 -0
  144. package/src/sextant/context-source.ts +157 -0
  145. package/src/sextant/draw-agents.ts +273 -0
  146. package/src/sextant/draw-code.ts +388 -0
  147. package/src/sextant/draw-context.ts +222 -0
  148. package/src/sextant/draw-frame.ts +164 -0
  149. package/src/sextant/draw-market.ts +573 -0
  150. package/src/sextant/draw-messages.ts +386 -0
  151. package/src/sextant/draw-pet.ts +230 -0
  152. package/src/sextant/draw-plan.ts +159 -0
  153. package/src/sextant/draw-tabs.ts +85 -0
  154. package/src/sextant/draw-util.ts +65 -0
  155. package/src/sextant/engine.ts +230 -0
  156. package/src/sextant/frame-hits.ts +25 -0
  157. package/src/sextant/frame.ts +101 -0
  158. package/src/sextant/git-status.ts +197 -0
  159. package/src/sextant/grid.ts +59 -0
  160. package/src/sextant/input.ts +119 -0
  161. package/src/sextant/keys.ts +488 -0
  162. package/src/sextant/layout.ts +86 -0
  163. package/src/sextant/local-commands.ts +156 -0
  164. package/src/sextant/market-source.ts +287 -0
  165. package/src/sextant/mentions.ts +141 -0
  166. package/src/sextant/message-hits.ts +26 -0
  167. package/src/sextant/model.ts +387 -0
  168. package/src/sextant/overlays.ts +451 -0
  169. package/src/sextant/panel-hits.ts +38 -0
  170. package/src/sextant/pet.ts +399 -0
  171. package/src/sextant/screen.ts +324 -0
  172. package/src/sextant/scroll-hits.ts +66 -0
  173. package/src/sextant/scrollbar.ts +82 -0
  174. package/src/sextant/selection.ts +123 -0
  175. package/src/sextant/sextant-bridge.ts +174 -0
  176. package/src/sextant/sextant-cards.ts +142 -0
  177. package/src/sextant/sextant-diff-base.ts +63 -0
  178. package/src/sextant/sextant-files.ts +154 -0
  179. package/src/sextant/sextant-frame-loop.ts +314 -0
  180. package/src/sextant/sextant-renderer.ts +478 -0
  181. package/src/sextant/sextant-repo.ts +131 -0
  182. package/src/sextant/theme.ts +66 -0
  183. package/src/sextant/tool-rows.ts +189 -0
  184. package/src/sextant/types.ts +473 -0
  185. package/src/skills/index.ts +306 -0
  186. package/src/skills/tools.ts +69 -0
  187. package/src/skills/versioned.ts +227 -0
  188. package/src/telemetry/otel.ts +353 -0
  189. package/src/telemetry/otlp.ts +68 -0
  190. package/src/tools/ask-user.ts +156 -0
  191. package/src/tools/design.ts +151 -0
  192. package/src/tools/evalcell.ts +338 -0
  193. package/src/tools/html-text.ts +139 -0
  194. package/src/tools/provider.ts +149 -0
  195. package/src/tools/task.ts +216 -0
  196. package/src/tools/todo.ts +320 -0
  197. package/src/tools/webfetch.ts +331 -0
  198. package/src/tui/app.ts +608 -0
  199. package/src/tui/attach.ts +127 -0
  200. package/src/tui/checkpoints-cmd.ts +70 -0
  201. package/src/tui/clipboard-image.ts +81 -0
  202. package/src/tui/commands.ts +277 -0
  203. package/src/tui/cost.ts +108 -0
  204. package/src/tui/info-cmd.ts +144 -0
  205. package/src/tui/mcp-cmd.ts +128 -0
  206. package/src/tui/modes-cmd.ts +45 -0
  207. package/src/tui/overlays.ts +97 -0
  208. package/src/tui/pi-renderer.ts +424 -0
  209. package/src/tui/providers-cmd.ts +366 -0
  210. package/src/tui/renderer.ts +101 -0
  211. package/src/tui/replay-marker.ts +29 -0
  212. package/src/tui/session-cmd.ts +146 -0
  213. package/src/tui/sextant-attach.ts +68 -0
  214. package/src/tui/sextant-io.ts +184 -0
  215. package/src/tui/sextant-smoke.ts +110 -0
  216. package/src/tui/smoke.ts +72 -0
  217. package/src/tui/theme.ts +59 -0
  218. package/src/tui/todo-label.ts +7 -0
  219. package/src/workflow/engine.ts +266 -0
  220. package/tsconfig.json +30 -0
  221. package/vendor/pi-tui/LICENSE +21 -0
  222. package/vendor/pi-tui/PATCHES.md +12 -0
  223. package/vendor/pi-tui/PROVENANCE.md +12 -0
  224. package/vendor/pi-tui/README.upstream.md +854 -0
  225. package/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  226. package/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  227. package/vendor/pi-tui/src/alt-screen-search.ts +158 -0
  228. package/vendor/pi-tui/src/autocomplete.ts +827 -0
  229. package/vendor/pi-tui/src/components/alt-screen-flash.ts +52 -0
  230. package/vendor/pi-tui/src/components/box.ts +138 -0
  231. package/vendor/pi-tui/src/components/cancellable-loader.ts +41 -0
  232. package/vendor/pi-tui/src/components/editor.ts +2364 -0
  233. package/vendor/pi-tui/src/components/h-stack.ts +45 -0
  234. package/vendor/pi-tui/src/components/image.ts +128 -0
  235. package/vendor/pi-tui/src/components/input.ts +448 -0
  236. package/vendor/pi-tui/src/components/loader.ts +93 -0
  237. package/vendor/pi-tui/src/components/markdown.ts +1016 -0
  238. package/vendor/pi-tui/src/components/scroll-view.ts +217 -0
  239. package/vendor/pi-tui/src/components/select-list.ts +230 -0
  240. package/vendor/pi-tui/src/components/settings-list.ts +277 -0
  241. package/vendor/pi-tui/src/components/spacer.ts +29 -0
  242. package/vendor/pi-tui/src/components/stack.ts +155 -0
  243. package/vendor/pi-tui/src/components/text.ts +108 -0
  244. package/vendor/pi-tui/src/components/truncated-text.ts +66 -0
  245. package/vendor/pi-tui/src/components/v-stack.ts +34 -0
  246. package/vendor/pi-tui/src/editor-component.ts +75 -0
  247. package/vendor/pi-tui/src/fuzzy.ts +138 -0
  248. package/vendor/pi-tui/src/index.ts +149 -0
  249. package/vendor/pi-tui/src/keybindings.ts +321 -0
  250. package/vendor/pi-tui/src/keys.ts +1402 -0
  251. package/vendor/pi-tui/src/kill-ring.ts +47 -0
  252. package/vendor/pi-tui/src/latex.ts +1381 -0
  253. package/vendor/pi-tui/src/layout-node.ts +52 -0
  254. package/vendor/pi-tui/src/layout.ts +411 -0
  255. package/vendor/pi-tui/src/native-modifiers.ts +60 -0
  256. package/vendor/pi-tui/src/native-module-path.ts +32 -0
  257. package/vendor/pi-tui/src/stdin-buffer.ts +445 -0
  258. package/vendor/pi-tui/src/terminal-colors.ts +74 -0
  259. package/vendor/pi-tui/src/terminal-image.ts +701 -0
  260. package/vendor/pi-tui/src/terminal.ts +554 -0
  261. package/vendor/pi-tui/src/tui-alt-screen.ts +1379 -0
  262. package/vendor/pi-tui/src/tui-main-screen.ts +655 -0
  263. package/vendor/pi-tui/src/tui.ts +1264 -0
  264. package/vendor/pi-tui/src/undo-stack.ts +29 -0
  265. package/vendor/pi-tui/src/utils.ts +1327 -0
  266. package/vendor/pi-tui/src/word-navigation.ts +118 -0
  267. package/vendor/pi-tui/test/test-themes.ts +39 -0
  268. package/vendor/pi-tui/test/virtual-terminal.ts +219 -0
  269. package/CHANGELOG.md +0 -527
  270. package/bin/rovecode.js +0 -24
  271. package/dist/cli/app-j6gn14w3.js +0 -2
  272. package/dist/cli/ask-user-cwstt8fz.js +0 -2
  273. package/dist/cli/auth-login-9bbp9915.js +0 -2
  274. package/dist/cli/auth-m8p9grty.js +0 -2
  275. package/dist/cli/bench-16zqdms5.js +0 -9
  276. package/dist/cli/catalog-1xchffa4.js +0 -2
  277. package/dist/cli/cli-1n1zb64f.js +0 -2
  278. package/dist/cli/client-2t9gjkck.js +0 -2
  279. package/dist/cli/commands-exafvm2b.js +0 -2
  280. package/dist/cli/connect-6zde0kn3.js +0 -2
  281. package/dist/cli/context-cmd-5t43wgqt.js +0 -2
  282. package/dist/cli/context-report-kt01pw8y.js +0 -2
  283. package/dist/cli/count-remote-ap7x3vh6.js +0 -2
  284. package/dist/cli/design-ne5zszyh.js +0 -2
  285. package/dist/cli/dispatch-2r5myxye.js +0 -2
  286. package/dist/cli/doctor-ws4fh4tn.js +0 -3
  287. package/dist/cli/executor-bdrjn634.js +0 -2
  288. package/dist/cli/export-1mxb9g5p.js +0 -2
  289. package/dist/cli/files-g104xghh.js +0 -2
  290. package/dist/cli/gauntlet-07xrjpj7.js +0 -2
  291. package/dist/cli/gauntlet-runner-xvy64436.js +0 -10
  292. package/dist/cli/gauntlet-wave3-jm91yt5w.js +0 -5
  293. package/dist/cli/gauntlet-wave4-r13py7p1.js +0 -14
  294. package/dist/cli/hashline-znvrat11.js +0 -2
  295. package/dist/cli/http-xafw6fsh.js +0 -143
  296. package/dist/cli/index-1sgjm25y.js +0 -2
  297. package/dist/cli/init-g2m0tn4m.js +0 -51
  298. package/dist/cli/install-avaqjjqq.js +0 -2
  299. package/dist/cli/loop-mmpfft01.js +0 -2
  300. package/dist/cli/main-0904f6ps.js +0 -5
  301. package/dist/cli/main-0ab9fc26.js +0 -9
  302. package/dist/cli/main-0jys2ccn.js +0 -3
  303. package/dist/cli/main-0mtcdbs7.js +0 -3
  304. package/dist/cli/main-0z1w2zsg.js +0 -3
  305. package/dist/cli/main-1dchs7xv.js +0 -18
  306. package/dist/cli/main-1ereejm1.js +0 -3
  307. package/dist/cli/main-1k1kw6b5.js +0 -3
  308. package/dist/cli/main-27y4sm2k.js +0 -38
  309. package/dist/cli/main-2wwjex5j.js +0 -58
  310. package/dist/cli/main-2yeveeve.js +0 -6
  311. package/dist/cli/main-2yfck9b5.js +0 -3
  312. package/dist/cli/main-2zmzgkwh.js +0 -3
  313. package/dist/cli/main-351pz3z7.js +0 -7
  314. package/dist/cli/main-3gjqfh7a.js +0 -6
  315. package/dist/cli/main-3nf3kgve.js +0 -3
  316. package/dist/cli/main-3pjrb2hd.js +0 -3
  317. package/dist/cli/main-3rxcvgna.js +0 -19
  318. package/dist/cli/main-4b3jgy66.js +0 -19
  319. package/dist/cli/main-4wndhjdc.js +0 -7
  320. package/dist/cli/main-4xcmvxnk.js +0 -3
  321. package/dist/cli/main-5tbz0wbz.js +0 -4
  322. package/dist/cli/main-5ywnwthm.js +0 -3
  323. package/dist/cli/main-6b62vkz0.js +0 -14
  324. package/dist/cli/main-6dnk69vp.js +0 -3
  325. package/dist/cli/main-6genrmhs.js +0 -136
  326. package/dist/cli/main-73g7eff4.js +0 -15
  327. package/dist/cli/main-7c5thhjd.js +0 -5
  328. package/dist/cli/main-7rn6bqje.js +0 -3
  329. package/dist/cli/main-80haw7qk.js +0 -4
  330. package/dist/cli/main-875s60s2.js +0 -4
  331. package/dist/cli/main-8kjxbpw4.js +0 -8
  332. package/dist/cli/main-90ds1z4e.js +0 -10
  333. package/dist/cli/main-9etavkew.js +0 -3
  334. package/dist/cli/main-a9njrkk1.js +0 -3
  335. package/dist/cli/main-aecrjq2d.js +0 -12
  336. package/dist/cli/main-ck9asesq.js +0 -9
  337. package/dist/cli/main-cta9racd.js +0 -4
  338. package/dist/cli/main-ddv7j2ag.js +0 -3
  339. package/dist/cli/main-dfreez27.js +0 -10
  340. package/dist/cli/main-f7rw7des.js +0 -3
  341. package/dist/cli/main-ggcn7rd7.js +0 -5
  342. package/dist/cli/main-gzkmycnv.js +0 -3
  343. package/dist/cli/main-hq51jg8v.js +0 -18
  344. package/dist/cli/main-jft389w9.js +0 -8
  345. package/dist/cli/main-k1eqkg83.js +0 -3
  346. package/dist/cli/main-k2y8a2aw.js +0 -9
  347. package/dist/cli/main-kcpbykxz.js +0 -4
  348. package/dist/cli/main-kd488vje.js +0 -22
  349. package/dist/cli/main-kh32yvgk.js +0 -5
  350. package/dist/cli/main-kqxnqjnv.js +0 -25
  351. package/dist/cli/main-kyn0xnsg.js +0 -3
  352. package/dist/cli/main-m1kk6fp5.js +0 -21
  353. package/dist/cli/main-mv40pcr2.js +0 -4
  354. package/dist/cli/main-n0t3973w.js +0 -3
  355. package/dist/cli/main-nqveez48.js +0 -4
  356. package/dist/cli/main-pknhvrmj.js +0 -3
  357. package/dist/cli/main-pn1w7a7j.js +0 -3
  358. package/dist/cli/main-prxxs70n.js +0 -4
  359. package/dist/cli/main-q3vsesf9.js +0 -3
  360. package/dist/cli/main-qsevpgsv.js +0 -3
  361. package/dist/cli/main-rdgdw24b.js +0 -25
  362. package/dist/cli/main-rfth4tbm.js +0 -16
  363. package/dist/cli/main-rg0wn0xf.js +0 -5
  364. package/dist/cli/main-sdmxhtv8.js +0 -4
  365. package/dist/cli/main-skbp13js.js +0 -18
  366. package/dist/cli/main-t4xnd213.js +0 -7
  367. package/dist/cli/main-vqak588n.js +0 -4
  368. package/dist/cli/main-w2n1303f.js +0 -9
  369. package/dist/cli/main-wbrdspr2.js +0 -5
  370. package/dist/cli/main-wsrg79c1.js +0 -7
  371. package/dist/cli/main-x4r0fne4.js +0 -5
  372. package/dist/cli/main-xea2f3tn.js +0 -6
  373. package/dist/cli/main-xg704a3c.js +0 -3
  374. package/dist/cli/main-xvnrabfp.js +0 -16
  375. package/dist/cli/main-xy53xf0r.js +0 -4
  376. package/dist/cli/main-y1fqy60y.js +0 -3
  377. package/dist/cli/main-yn8cd281.js +0 -34
  378. package/dist/cli/main-yr0ksc0h.js +0 -4
  379. package/dist/cli/main-z2ex2vyf.js +0 -4
  380. package/dist/cli/main-z3aayzvq.js +0 -3
  381. package/dist/cli/main-zaqh35jg.js +0 -3
  382. package/dist/cli/main-zc2e8e46.js +0 -4
  383. package/dist/cli/main-zzrfw6cf.js +0 -13
  384. package/dist/cli/main.js +0 -280
  385. package/dist/cli/market-cmd-e14kmx9n.js +0 -5
  386. package/dist/cli/mcp-login-wq7ktdek.js +0 -2
  387. package/dist/cli/mcp-market-cmd-9mg3jecy.js +0 -2
  388. package/dist/cli/notify-b7qc0cjb.js +0 -2
  389. package/dist/cli/oauth-z8whcgfx.js +0 -2
  390. package/dist/cli/output-b3ewj3ps.js +0 -16
  391. package/dist/cli/profiles-6mr5he5e.js +0 -2
  392. package/dist/cli/provider-config-g7j42q8x.js +0 -2
  393. package/dist/cli/provider-jr1y8vvm.js +0 -2
  394. package/dist/cli/registry-s8yk86g0.js +0 -2
  395. package/dist/cli/registry-t6p8d4mn.js +0 -2
  396. package/dist/cli/repl-bajwe1mh.js +0 -11
  397. package/dist/cli/resume-rwn9nz7y.js +0 -2
  398. package/dist/cli/run-flags-nah7ndpt.js +0 -2
  399. package/dist/cli/runtime-n7gafzhb.js +0 -2
  400. package/dist/cli/sandbox-config-emdy18x4.js +0 -2
  401. package/dist/cli/server-b0nvs2bn.js +0 -5
  402. package/dist/cli/session-arg-y75wd4kj.js +0 -2
  403. package/dist/cli/session-j62evmjq.js +0 -2
  404. package/dist/cli/sessions-cmd-tsnwz0ns.js +0 -7
  405. package/dist/cli/settings-df10wfez.js +0 -2
  406. package/dist/cli/setup-jzvv72fg.js +0 -2
  407. package/dist/cli/sextant-smoke-37m81ke6.js +0 -5
  408. package/dist/cli/skills-cmd-gjxnxnhx.js +0 -2
  409. package/dist/cli/smoke-p7748apt.js +0 -8
  410. package/dist/cli/start-chat-s4st3mm0.js +0 -12
  411. package/dist/cli/stream-gmeyewds.js +0 -2
  412. package/dist/cli/task-gh0kkp3n.js +0 -2
  413. package/dist/cli/tasks-z1kfpe8e.js +0 -2
  414. package/dist/cli/thinking-0eqkrz6t.js +0 -2
  415. package/dist/cli/todo-5brcrt9m.js +0 -2
  416. package/dist/cli/tools-7pzm0vj9.js +0 -2
  417. package/dist/cli/tools-s635p6s8.js +0 -2
  418. package/dist/cli/trust-cmd-cjav8zgm.js +0 -2
  419. package/dist/cli/update-check-pt31bm2f.js +0 -2
  420. package/dist/cli/update-cmd-tk131s9t.js +0 -2
  421. package/dist/cli/voice-56nabd8d.js +0 -2
  422. package/dist/cli/webfetch-xd8q596m.js +0 -2
  423. package/dist/cli/websearch-5hkf98k1.js +0 -2
  424. package/dist/cli/workflow-cmd-cy3cvzjp.js +0 -4
  425. package/dist/cli/workspace-q10g5z3e.js +0 -2
  426. package/dist/lib/index.js +0 -62
  427. package/dist/lib/models-index.json +0 -1
  428. package/dist/lib/plugins.js +0 -55
  429. package/dist/lib/providers.js +0 -17
  430. package/dist/lib/public-api.js +0 -20
  431. package/dist/lib/sdk.js +0 -360
  432. /package/{dist/cli → src/providers}/models-index.json +0 -0
@@ -0,0 +1,223 @@
1
+ /** Anthropic prompt-cache boundary placement — pure transform for the /messages request body.
2
+ *
3
+ * Prompt caching is a PREFIX match: the API render order is tools → system → messages, and a
4
+ * `cache_control: {type:"ephemeral"}` marker on a content block caches everything from the start
5
+ * of the request up to and including that block. Any byte change before a marker invalidates it.
6
+ * Therefore boundaries only pay off on STABLE prefixes — a boundary after content that changes
7
+ * every turn is a wasted breakpoint (Anthropic allows at most 4 per request).
8
+ *
9
+ * Pattern reference (hermes-agent snapshot, research/source_snapshots/hermes-agent):
10
+ * - agent/prompt_caching.py:1-8 — "The default layout uses 4 cache_control breakpoints: the static
11
+ * system prefix, the end of the system prompt, and the last 2 non-system messages."
12
+ * - agent/prompt_caching.py:157-162 (_build_marker) — the marker is `{"type": "ephemeral"}`.
13
+ * - agent/prompt_caching.py:113-121 (_apply_cache_marker) — string content is converted to a
14
+ * single text block carrying the marker; list content gets the marker on its LAST block.
15
+ * - agent/prompt_caching.py:99-103, 331-333 — volatile tails ride UNMARKED ("a changed ticket ID
16
+ * or timestamp no longer invalidates the whole skill body"), and empty text blocks are never
17
+ * emitted (HTTP 400 on native Anthropic).
18
+ * - agent/prompt_caching.py:567-573 (apply_anthropic_cache_control) — idempotence contract:
19
+ * re-application "can never accumulate past 4 markers".
20
+ * - agent/system_prompt.py:911-924 and agent/turn_context.py:214-217 — the stability principle:
21
+ * volatile per-turn facts are kept OUT of / AFTER the cached band so the prefix stays
22
+ * byte-stable turn-over-turn.
23
+ *
24
+ * Placement policy implemented here (deliberately simpler than Hermes' 4-marker layout):
25
+ * (1) SYSTEM boundary — `system: string` is converted to
26
+ * `[{type:"text", text, cache_control:{type:"ephemeral"}}]` when it is ≥ minChunkChars.
27
+ * A system-block array already provided by the caller gets the marker on its last block
28
+ * (unless any block is already marked). Because caching is prefix-based, this single marker
29
+ * also covers the `tools` array rendered before `system` — no separate tools marker needed.
30
+ * (2) CONVERSATION-PREFIX boundary — the marker goes on the LAST content block of the most
31
+ * recent message that has ≥ 2 messages after it (index length-3): an agent turn appends
32
+ * the trailing exchange (assistant tool_use + tool_result, or user + assistant), so the
33
+ * tail churns every turn while the prefix up to there is CANONICALLY stable — not
34
+ * byte-identical. Two rewrites make consecutive requests differ in raw bytes: the marker
35
+ * moves forward each turn (dropped from the old anchor, added at the new one), and the
36
+ * marked message's string content is rewritten to [{type:"text",...}] by
37
+ * withMarkerOnLastBlock below. Anthropic's cache key normalizes exactly those two
38
+ * (cache_control is placement metadata, and string content is equivalent to a single
39
+ * text block), so the previous request's prefix still cache-hits. Pinned by the
40
+ * consecutive-turn stability test in test/unit/cache.test.ts.
41
+ * If the anchor message cannot carry a marker (empty content — cf. Hermes _can_carry_marker,
42
+ * prompt_caching.py:127-140, "so the breakpoints land on messages that count"), the
43
+ * boundary reallocates to the nearest earlier eligible message. String content is
44
+ * converted to a one-block array, preserving the text byte-for-byte.
45
+ * (3) BUDGET — never exceed maxBreakpoints total, counting markers already present in
46
+ * system/messages/tools before placing new ones. System wins over conversation prefix.
47
+ * (4) IDEMPOTENT — a position that already carries a marker is left untouched, existing markers
48
+ * count toward the budget, and untouched inputs are returned by reference, so
49
+ * apply(apply(body)) deep-equals apply(body).
50
+ * (5) Bodies without messages/system pass through untouched (same reference), as does anything
51
+ * whose shapes don't match — this is a best-effort decorator, never a validator.
52
+ *
53
+ * minChunkChars default: 4096 chars ≈ 1024 tokens (~4 chars/token) — the documented minimum
54
+ * cacheable prefix for Sonnet/Opus-class models (model-dependent, 512–4096 tokens per the API
55
+ * docs). Prefixes below the model minimum are silently NOT cached, so spending a breakpoint on
56
+ * them is pure waste. For the message boundary the gate compares the CUMULATIVE prefix
57
+ * (system + messages[0..anchor]) against minChunkChars, since that whole span is what the
58
+ * marker would cache (tools text is not counted — a conservative undercount).
59
+ *
60
+ * Pure: the input body is never mutated; modified paths are copied copy-on-write.
61
+ */
62
+
63
+ export interface CacheOptions {
64
+ /** Maximum cache_control markers allowed in the request. Anthropic's limit — and the default — is 4. */
65
+ maxBreakpoints?: number;
66
+ /** Don't spend a breakpoint on a prefix shorter than this many characters. Default 4096 (≈1024 tokens). */
67
+ minChunkChars?: number;
68
+ }
69
+
70
+ export interface CacheControl { type: "ephemeral" }
71
+
72
+ /** Loose ("-ish") view of the body anthropicStream builds (src/providers/stream.ts:152-160):
73
+ * `{ model, max_tokens, system?: string, messages: [...], tools?: [...] }`. Every field is
74
+ * unknown-typed so the adapter's `Record<string, unknown>` is directly assignable; this module
75
+ * narrows at runtime and passes through anything it does not recognize. */
76
+ export interface AnthropicishBody {
77
+ system?: unknown;
78
+ messages?: unknown;
79
+ tools?: unknown;
80
+ [key: string]: unknown;
81
+ }
82
+
83
+ export const DEFAULT_MAX_BREAKPOINTS = 4;
84
+ export const DEFAULT_MIN_CHUNK_CHARS = 4096;
85
+
86
+ const EPHEMERAL: CacheControl = { type: "ephemeral" };
87
+
88
+ type Rec = Record<string, unknown>;
89
+
90
+ function isRec(v: unknown): v is Rec {
91
+ return typeof v === "object" && v !== null && !Array.isArray(v);
92
+ }
93
+
94
+ /** Marker presence on a content block / tool entry (block-level only — the shapes this module emits). */
95
+ function hasMarker(block: unknown): boolean {
96
+ return isRec(block) && block["cache_control"] !== undefined;
97
+ }
98
+
99
+ function blockText(block: unknown): string {
100
+ if (!isRec(block)) return "";
101
+ return typeof block["text"] === "string" ? block["text"] : "";
102
+ }
103
+
104
+ function systemChars(system: unknown): number {
105
+ if (typeof system === "string") return system.length;
106
+ if (Array.isArray(system)) return system.reduce((n: number, b) => n + blockText(b).length, 0);
107
+ return 0;
108
+ }
109
+
110
+ function contentChars(content: unknown): number {
111
+ if (typeof content === "string") return content.length;
112
+ if (!Array.isArray(content)) return 0;
113
+ let n = 0;
114
+ for (const b of content) {
115
+ n += blockText(b).length;
116
+ // tool_result blocks carry their payload under "content" (string form only; arrays undercount)
117
+ if (isRec(b) && typeof b["content"] === "string") n += b["content"].length;
118
+ }
119
+ return n;
120
+ }
121
+
122
+ function messageMarkerCount(msg: unknown): number {
123
+ if (!isRec(msg)) return 0;
124
+ const content = msg["content"];
125
+ return Array.isArray(content) ? content.filter(hasMarker).length : 0;
126
+ }
127
+
128
+ function countExistingMarkers(system: unknown, messages: readonly unknown[] | null, tools: unknown): number {
129
+ let n = 0;
130
+ if (Array.isArray(system)) n += system.filter(hasMarker).length;
131
+ for (const m of messages ?? []) n += messageMarkerCount(m);
132
+ if (Array.isArray(tools)) n += tools.filter(hasMarker).length;
133
+ return n;
134
+ }
135
+
136
+ /** A marker on this message would actually land on the wire: non-empty string content (an empty
137
+ * string would convert to an empty text block — HTTP 400), or a non-empty block array whose last
138
+ * element is an object. Mirrors Hermes _can_carry_marker (prompt_caching.py:127-154). */
139
+ function canCarryMarker(msg: unknown): boolean {
140
+ if (!isRec(msg)) return false;
141
+ const content = msg["content"];
142
+ if (typeof content === "string") return content.length > 0;
143
+ if (Array.isArray(content) && content.length > 0) return isRec(content[content.length - 1]);
144
+ return false;
145
+ }
146
+
147
+ /** Copy of `msg` with the ephemeral marker on its last content block; string content becomes a
148
+ * one-block array with the text preserved byte-for-byte (Hermes prompt_caching.py:113-121). */
149
+ function withMarkerOnLastBlock(msg: Rec): Rec {
150
+ const content = msg["content"];
151
+ if (typeof content === "string") {
152
+ return { ...msg, content: [{ type: "text", text: content, cache_control: EPHEMERAL }] };
153
+ }
154
+ if (Array.isArray(content) && content.length > 0) {
155
+ const last = content[content.length - 1];
156
+ if (isRec(last)) {
157
+ const blocks = content.slice();
158
+ blocks[blocks.length - 1] = { ...last, cache_control: EPHEMERAL };
159
+ return { ...msg, content: blocks };
160
+ }
161
+ }
162
+ return msg; // callers gate on canCarryMarker(); unreachable in practice
163
+ }
164
+
165
+ export function applyAnthropicCacheBoundaries(body: AnthropicishBody, opts?: CacheOptions): AnthropicishBody {
166
+ const maxBreakpoints = opts?.maxBreakpoints ?? DEFAULT_MAX_BREAKPOINTS;
167
+ const minChunkChars = opts?.minChunkChars ?? DEFAULT_MIN_CHUNK_CHARS;
168
+
169
+ const system = body.system;
170
+ const messages: readonly unknown[] | null = Array.isArray(body.messages) ? body.messages : null;
171
+
172
+ const hasSystem = (typeof system === "string" && system.length > 0) || (Array.isArray(system) && system.length > 0);
173
+ const hasMessages = messages !== null && messages.length > 0;
174
+ if (!hasSystem && !hasMessages) return body; // policy (5): pass through untouched
175
+
176
+ let used = countExistingMarkers(system, messages, body.tools);
177
+ let out = body;
178
+ const copyOnWrite = (): AnthropicishBody => (out === body ? (out = { ...body }) : out);
179
+
180
+ // ---- policy (1): system boundary ------------------------------------------------------------
181
+ if (used < maxBreakpoints && hasSystem) {
182
+ if (typeof system === "string") {
183
+ if (system.length >= minChunkChars) {
184
+ copyOnWrite().system = [{ type: "text", text: system, cache_control: EPHEMERAL }];
185
+ used += 1;
186
+ }
187
+ } else if (Array.isArray(system) && !system.some(hasMarker)) {
188
+ const last = system[system.length - 1];
189
+ if (isRec(last) && systemChars(system) >= minChunkChars) {
190
+ const blocks = system.slice();
191
+ blocks[blocks.length - 1] = { ...last, cache_control: EPHEMERAL };
192
+ copyOnWrite().system = blocks;
193
+ used += 1;
194
+ }
195
+ }
196
+ }
197
+
198
+ // ---- policy (2): conversation-prefix boundary ------------------------------------------------
199
+ // Anchor = most recent message with ≥2 messages after it (index length-3); the trailing two
200
+ // messages are this turn's churn. Reallocate backwards past marker-incapable messages.
201
+ if (used < maxBreakpoints && messages !== null && messages.length >= 3) {
202
+ let anchor = -1;
203
+ for (let i = messages.length - 3; i >= 0; i -= 1) {
204
+ if (canCarryMarker(messages[i])) { anchor = i; break; }
205
+ }
206
+ const msg = anchor >= 0 ? messages[anchor] : undefined;
207
+ if (isRec(msg) && messageMarkerCount(msg) === 0) {
208
+ let prefixChars = systemChars(system);
209
+ for (let i = 0; i <= anchor; i += 1) {
210
+ const m = messages[i];
211
+ if (isRec(m)) prefixChars += contentChars(m["content"]);
212
+ }
213
+ if (prefixChars >= minChunkChars) {
214
+ const next = messages.slice();
215
+ next[anchor] = withMarkerOnLastBlock(msg);
216
+ copyOnWrite().messages = next;
217
+ used += 1;
218
+ }
219
+ }
220
+ }
221
+
222
+ return out;
223
+ }
@@ -0,0 +1,160 @@
1
+ /** rovecode's own price table for models the models.dev snapshot does not carry — the API ALIASES a
2
+ * vendor sells under (DeepSeek's `deepseek-chat` / `deepseek-reasoner` are aliases of a release; the
3
+ * snapshot lists release ids), and xAI's retired grok-4 slugs, which still resolve but are served and
4
+ * billed as grok-4.3. Without these a real run on those ids is "unpriced" in /cost and `rovecode model show`.
5
+ *
6
+ * Rules: an entry here applies ONLY when neither the live models.dev layer nor the snapshot has the model
7
+ * (catalog.ts findIn) — a later snapshot entry wins by construction. Every entry names the vendor page the
8
+ * numbers were read from and the day; "fetched" means the page was read on that day, "unverified" means the
9
+ * page no longer documents the id and the row is the last known value. `rovecode model show` prints
10
+ * "priced from rovecode's own table" so nobody mistakes them for models.dev's. Prices are USD per million
11
+ * tokens. Output limits are given only where the vendor publishes one (the runtime caps at MAX_OUTPUT_CAP). */
12
+
13
+ export interface LocalModel {
14
+ context: number;
15
+ output?: number;
16
+ /** has a reasoning mode (thinking.ts sends the dial only when this is not false) */
17
+ reasoning: boolean;
18
+ toolCall: boolean;
19
+ image?: boolean;
20
+ cost: { input: number; output: number; cacheRead?: number; cacheWrite?: number };
21
+ /** where the numbers were read — the reader's warrant */
22
+ source: string;
23
+ /** when, and how: "YYYY-MM-DD (fetched)" or "YYYY-MM-DD (unverified: …)" */
24
+ checked: string;
25
+ /** Take precedence over a models.dev entry for this model. Off by default and deliberately rare: the
26
+ * overlay exists to fill gaps, and a snapshot that gains a model should normally win. Set it ONLY when
27
+ * the vendor's own page was read and disagrees with the snapshot, and say so in `source` — a reader has
28
+ * to be able to see which number rovecode chose and why. */
29
+ override?: true;
30
+ }
31
+
32
+ /** A vendor whose price CHANGES WITH PROMPT SIZE. models.dev has no field for this, so it lives beside the
33
+ * overlay and augments a row whatever its source — the snapshot keeps owning the base prices.
34
+ *
35
+ * `mode` is the part that is easy to get wrong and expensive to get wrong:
36
+ * - "per-request": crossing the threshold reprices THE WHOLE REQUEST, every token, at the upper rate
37
+ * (xAI). A 201k-token prompt costs 201k × the high rate, not 200k low + 1k high.
38
+ * - "marginal": only the tokens past the threshold take the upper rate. NO vendor row uses this today —
39
+ * it exists because the two shapes are not interchangeable and a cost function must branch on which one
40
+ * it has, rather than assume. Do not classify a vendor as marginal without wording that says so. */
41
+ export interface PriceTier {
42
+ thresholdTokens: number;
43
+ mode: "per-request" | "marginal";
44
+ above: { input: number; output: number; cacheRead?: number; cacheWrite?: number };
45
+ source: string;
46
+ checked: string;
47
+ }
48
+
49
+ /** xAI, docs.x.ai/developers/migration/may-15-retirement (fetched 2026-09-04): grok-4-0709, grok-4-fast-reasoning,
50
+ * grok-4-fast-non-reasoning, grok-4-1-fast-* and grok-3 were retired on 2026-05-15; the slugs still resolve and
51
+ * are SERVED BY grok-4.3 — reasoning slugs at low effort, non-reasoning ones at none — and BILLED at grok-4.3
52
+ * rates ($1.25 in / $2.50 out / $0.20 cached per 1M under 200k context; docs.x.ai/docs/models/grok-4.3, fetched
53
+ * the same day: 1M context, configurable reasoning none|low|medium|high). So a request to `grok-4` costs this. */
54
+ const GROK_43_REDIRECT = { context: 1_000_000, toolCall: true, image: true, cost: { input: 1.25, output: 2.5, cacheRead: 0.2 },
55
+ source: "docs.x.ai May-15-2026 retirement: served by grok-4.3, billed at grok-4.3 rates (under 200k context)", checked: "2026-09-04 (fetched)" } as const;
56
+
57
+ /** Tiered pricing, by provider and model id. Verified 2026-09-05 against the vendors' own pricing pages.
58
+ * Nothing here changes a base price — `catalog.ts` attaches the tier to whatever row it resolved, so a
59
+ * models.dev entry keeps its numbers and gains the threshold it has no field for. */
60
+ export const PRICE_TIERS: Readonly<Record<string, Readonly<Record<string, PriceTier>>>> = {
61
+ // xAI: "requests over 200,000 prompt tokens are billed at the higher rate FOR THE ENTIRE REQUEST"
62
+ xai: {
63
+ "grok-4.6": { thresholdTokens: 200_000, mode: "per-request", above: { input: 4, output: 12, cacheRead: 1 },
64
+ source: "docs.x.ai/developers/pricing — over 200k prompt tokens the whole request bills at the high rate", checked: "2026-09-05 (fetched)" },
65
+ "grok-4.3": { thresholdTokens: 200_000, mode: "per-request", above: { input: 2.5, output: 5, cacheRead: 0.4 },
66
+ source: "docs.x.ai/developers/pricing — over 200k prompt tokens the whole request bills at the high rate", checked: "2026-09-05 (fetched)" },
67
+ },
68
+ // OpenAI, developers.openai.com/api/docs/models/gpt-5.4 and /gpt-5.5: "Prompts with >272K input tokens
69
+ // are priced at 2x input and 1.5x output for the full session." The multipliers are ASYMMETRIC — input
70
+ // doubles, output goes up by half — so these are written out rather than derived from one rate.
71
+ // The -pro tiers are NOT given this: their own pages do not carry the sentence, and inventing a
72
+ // threshold for a $30/1M model is the expensive kind of guess.
73
+ openai: {
74
+ "gpt-5.4": { thresholdTokens: 272_000, mode: "per-request", above: { input: 5, output: 22.5, cacheRead: 0.5 },
75
+ source: "developers.openai.com/api/docs/models/gpt-5.4 — >272K input tokens: 2x input, 1.5x output for the full session", checked: "2026-09-05 (fetched)" },
76
+ "gpt-5.5": { thresholdTokens: 272_000, mode: "per-request", above: { input: 10, output: 45, cacheRead: 1 },
77
+ source: "developers.openai.com/api/docs/models/gpt-5.5 — >272K input tokens: 2x input, 1.5x output for the full session", checked: "2026-09-05 (fetched)" },
78
+ },
79
+ // Google prices by PROMPT SIZE, not by overflow: the page's own columns read "prompts <= 200k tokens"
80
+ // and "prompts > 200k tokens" for BOTH input and output, so a 201k prompt bills every token — and that
81
+ // request's output — at the upper rate. Same shape as xAI, which is why neither is "marginal".
82
+ google: {
83
+ "gemini-3.1-pro-preview": { thresholdTokens: 200_000, mode: "per-request", above: { input: 4, output: 18 },
84
+ source: "ai.google.dev/gemini-api/docs/pricing — \"$4.00, prompts > 200k tokens\" / \"$18.00, prompts > 200k\"", checked: "2026-09-05 (fetched)" },
85
+ "gemini-2.5-pro": { thresholdTokens: 200_000, mode: "per-request", above: { input: 2.5, output: 15 },
86
+ source: "ai.google.dev/gemini-api/docs/pricing — \"$2.50, prompts > 200k tokens\" / \"$15.00, prompts > 200k\"", checked: "2026-09-05 (fetched)" },
87
+ },
88
+ } as const;
89
+
90
+ /** A price that is scheduled to change, or a condition the number depends on. Not a tier and not an
91
+ * override — just the sentence a reader needs so today's number is not mistaken for a permanent one.
92
+ * Attached to a row whatever its source. */
93
+ export const PRICE_NOTES: Readonly<Record<string, Readonly<Record<string, string>>>> = {
94
+ google: {
95
+ "gemini-3.8-flash": "promotional pricing through 2026-12-31: ai.google.dev/gemini-api/docs/pricing says it doubles to $1.50 in / $7.50 out starting 2027-01-01 (checked 2026-09-05)",
96
+ },
97
+ mistral: {
98
+ // Checked against mistral.ai/pricing/api on 2026-09-05: the table publishes ONLY `-latest` aliases
99
+ // (mistral-medium-latest $1.5/$7.5, mistral-small-latest $0.15/$0.6, mistral-large-latest $0.5/$1.5).
100
+ // No dated id appears — not the snapshot's `mistral-medium-2604`, and not `mistral-medium-3-5` or
101
+ // `ministral-8b-2512` either. The prices match, the ids are unverifiable, so nothing is renamed here.
102
+ "mistral-medium-latest": "mistral.ai/pricing/api publishes only `-latest` aliases and NO maximum output for any model — the catalog's maxOutput equalling the context window is filler, not a vendor figure (checked 2026-09-05)",
103
+ "mistral-medium-2604": "this dated id is not on mistral.ai/pricing/api, which lists only `-latest` aliases; the price matches mistral-medium-latest but the id itself is unverified (checked 2026-09-05)",
104
+ },
105
+ groq: {
106
+ // Not "unverified" — UNPUBLISHED. Groq's docs table says "Contact Sales" for the Llama models and
107
+ // console.groq.com/pricing is a 404, so any number here came from a third party, not from Groq.
108
+ "llama-3.3-70b-versatile": "Groq does not publish a price for this model — its docs table says \"Contact Sales\" and there is no public pricing page; the catalog's figure is models.dev's, not the vendor's (checked 2026-09-05)",
109
+ },
110
+ anthropic: {
111
+ // true of every Anthropic row; recorded on the one most runs use
112
+ "claude-mythos-5-1": "invite-only access (platform.claude.com/docs/en/models/mythos-5-1/overview); outside the Batches 300k beta, which covers Opus 5/4.8/4.7/4.6 and Sonnet 5/4.6 only (checked 2026-09-05)",
113
+ "claude-fable-5-1": "outside the Batches 300k beta, which covers Opus 5/4.8/4.7/4.6 and Sonnet 5/4.6 only (checked 2026-09-05)",
114
+ "claude-opus-5": "thinking tokens bill as OUTPUT and count inside max_tokens; from Opus 4.5 / Sonnet 4.6 / Fable 5.x earlier thinking blocks are preserved and bill as INPUT on the next turn (platform.claude.com/docs, checked 2026-09-05)",
115
+ },
116
+ } as const;
117
+
118
+ export const LOCAL_MODELS: Readonly<Record<string, Readonly<Record<string, LocalModel>>>> = {
119
+ deepseek: {
120
+ // api-docs.deepseek.com/quick_start/pricing, fetched 2026-09-05. These three rows OVERRIDE models.dev,
121
+ // which carries roughly a third of the vendor's own peak numbers for the same ids (flash 0.14/0.28 vs
122
+ // 0.44/1.32). The page is the seller; the snapshot is a mirror that has drifted, so the page wins here
123
+ // and says so. Peak rates are used: the page's own off-peak wording is self-contradictory (it labels
124
+ // "peak" 01:00-04:00 and 06:00-10:00 UTC, which are its cheap hours elsewhere), so rovecode quotes the
125
+ // HIGHER of the two — an estimate that surprises nobody with a bigger bill. Do not build discount logic
126
+ // on that wording until the page is unambiguous.
127
+ "deepseek-v4-flash": { context: 1_000_000, output: 384_000, reasoning: true, toolCall: true, override: true,
128
+ cost: { input: 0.44, output: 1.32, cacheRead: 0.014 },
129
+ source: "api-docs.deepseek.com/quick_start/pricing (peak rate — off-peak is half, we do not model time-of-day; models.dev carries ~1/3 of these)", checked: "2026-09-05 (fetched)" },
130
+ "deepseek-v4-pro": { context: 1_000_000, output: 384_000, reasoning: true, toolCall: true, override: true,
131
+ cost: { input: 1.32, output: 3.96, cacheRead: 0.044 },
132
+ source: "api-docs.deepseek.com/quick_start/pricing (peak rate — off-peak is half, we do not model time-of-day; models.dev carries ~1/3 of these)", checked: "2026-09-05 (fetched)" },
133
+ "deepseek-v4-flash-vision-exp": { context: 1_000_000, output: 384_000, reasoning: true, toolCall: true, image: true, override: true,
134
+ cost: { input: 0.44, output: 1.32, cacheRead: 0.014 },
135
+ source: "api-docs.deepseek.com/quick_start/pricing (peak rate — off-peak is half, we do not model time-of-day; models.dev carries ~1/3 of these)", checked: "2026-09-05 (fetched)" },
136
+ // The two API aliases. The pricing page lists only the v4-* ids, so nothing here is verified: the
137
+ // numbers are the last ones DeepSeek published for them and are marked as such rather than being
138
+ // quietly refreshed to a v4 price they may not be billed at.
139
+ "deepseek-chat": { context: 128_000, output: 8_000, reasoning: true, toolCall: true, cost: { input: 0.28, output: 0.42, cacheRead: 0.028 }, source: "api-docs.deepseek.com pricing (V3.2 era)", checked: "2026-09-05 (unverified: the alias is not on the pricing page, which lists deepseek-v4-* only)" },
140
+ "deepseek-reasoner": { context: 128_000, output: 64_000, reasoning: true, toolCall: true, cost: { input: 0.28, output: 0.42, cacheRead: 0.028 }, source: "api-docs.deepseek.com pricing (V3.2 era)", checked: "2026-09-05 (unverified: not on the pricing page; DeepSeek now exposes thinking as a MODE of the v4 models, not a separate id)" },
141
+ },
142
+ openai: {
143
+ // developers.openai.com/api/docs/pricing, fetched 2026-09-05. Not in the snapshot at all, so this is a
144
+ // gap fill, not an override.
145
+ "gpt-6-astra": { context: 1_050_000, output: 128_000, reasoning: true, toolCall: true, image: true,
146
+ cost: { input: 10, output: 50, cacheRead: 1 },
147
+ source: "developers.openai.com/api/docs/pricing", checked: "2026-09-05 (fetched)" },
148
+ },
149
+ xai: {
150
+ "grok-4": { ...GROK_43_REDIRECT, reasoning: true },
151
+ "grok-4-0709": { ...GROK_43_REDIRECT, reasoning: true },
152
+ "grok-4-fast": { ...GROK_43_REDIRECT, reasoning: true },
153
+ "grok-4-fast-reasoning": { ...GROK_43_REDIRECT, reasoning: true },
154
+ "grok-4-fast-non-reasoning": { ...GROK_43_REDIRECT, reasoning: false },
155
+ "grok-4-1-fast-reasoning": { ...GROK_43_REDIRECT, reasoning: true },
156
+ "grok-4-1-fast-non-reasoning": { ...GROK_43_REDIRECT, reasoning: false },
157
+ "grok-3": { ...GROK_43_REDIRECT, reasoning: false },
158
+ // grok-3-mini: neither on docs.x.ai/docs/models nor in the retirement list on 2026-09-04 — no row, stays unpriced
159
+ },
160
+ };