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,246 @@
1
+ /** Hand-authored OpenAPI 3.1 document for the rovecode server surface (port #19).
2
+ * opencode serves its spec at GET /doc — packages/opencode/src/server/routes/
3
+ * instance/httpapi/server.ts:190 (route) + :188 (lazy OpenApi.fromApi(PublicApi))
4
+ * — and generates its client SDK from that spec (packages/sdk/js, @hey-api/openapi-ts).
5
+ * Their spec is derived from Effect httpapi endpoint schemas; ADR-001 rejects Effect
6
+ * idioms, and this surface is five routes, so the object is written by hand — no
7
+ * codegen dependency, the doc IS the source of truth for what the server exposes. */
8
+
9
+ /** Honesty note (bar requirement): served verbatim in the doc so HTTP clients know
10
+ * interactive approvals do not exist in v1. */
11
+ export const APPROVALS_NOTE =
12
+ "v1 approvals are policy-only: the server runs with rule-based permissions and has no " +
13
+ "interactive approver over HTTP. A tool call whose permission rule resolves to effect " +
14
+ "\"prompt\" is NOT paused for approval — it surfaces as a failed tool call " +
15
+ "(tool_call_failed, reason permission_denied, \"approval required but no approver " +
16
+ "connected\") and the run continues. Start the server with --yolo (allow-all rules) " +
17
+ "or provide allow rules to let gated tools run.";
18
+
19
+ /** RunEvent discriminator values (src/core/types.ts RunEvent union). Hand-listed:
20
+ * types are erased at runtime, and the doc is hand-authored by design. */
21
+ export const RUN_EVENT_TYPES = [
22
+ "run_start", "turn_start", "message_update", "reasoning_update",
23
+ "tool_execution_start", "tool_execution_update", "tool_execution_end",
24
+ "tool_call_failed", "compaction", "turn_end", "steer", "run_end",
25
+ ] as const;
26
+
27
+ const errorResponse = (description: string) => ({
28
+ description,
29
+ content: { "application/json": { schema: { $ref: "#/components/schemas/Error" } } },
30
+ });
31
+
32
+ /** Build the OpenAPI 3.1 object. `serverUrl` is the actually-bound base URL. */
33
+ export function buildOpenApiDoc(serverUrl: string): Record<string, unknown> {
34
+ return {
35
+ openapi: "3.1.0",
36
+ info: {
37
+ title: "rovecode server",
38
+ version: "0.1.0",
39
+ description:
40
+ "Headless HTTP surface over the one rovecode agent loop (ADR-003). " +
41
+ "Five routes: create a session, prompt it (SSE stream of typed run events; " +
42
+ "DELETE the same path cancels the in-flight run mid-turn), " +
43
+ "list its background tasks, list sessions, and this document. " + APPROVALS_NOTE,
44
+ },
45
+ servers: [{ url: serverUrl }],
46
+ paths: {
47
+ "/session": {
48
+ post: {
49
+ operationId: "session.create",
50
+ summary: "Create a new session",
51
+ description: "Creates a session backed by the append-only JSONL session store and returns its id.",
52
+ responses: {
53
+ "201": {
54
+ description: "Session created",
55
+ content: {
56
+ "application/json": {
57
+ schema: {
58
+ type: "object",
59
+ required: ["id"],
60
+ properties: { id: { type: "string", description: "Session id (also the session directory name)" } },
61
+ },
62
+ },
63
+ },
64
+ },
65
+ },
66
+ },
67
+ },
68
+ "/session/{id}/prompt": {
69
+ post: {
70
+ operationId: "session.prompt",
71
+ summary: "Run the agent loop on a session and stream its events",
72
+ description:
73
+ "Runs one agent loop over the session with the given text as the goal. " +
74
+ "The response is a Server-Sent Events stream: each event is framed as " +
75
+ "`event: <RunEvent.type>` + `data: <RunEvent JSON>`, and the stream closes " +
76
+ "after the terminal run_end event. " + APPROVALS_NOTE,
77
+ parameters: [
78
+ { name: "id", in: "path", required: true, schema: { type: "string" }, description: "Session id from POST /session" },
79
+ ],
80
+ requestBody: {
81
+ required: true,
82
+ content: {
83
+ "application/json": {
84
+ schema: {
85
+ type: "object",
86
+ required: ["text"],
87
+ properties: {
88
+ text: { type: "string", description: "The user goal for this run" },
89
+ model: {
90
+ type: "object",
91
+ description: "Optional model override; defaults to the server's resolved provider/model",
92
+ required: ["provider", "model"],
93
+ properties: { provider: { type: "string" }, model: { type: "string" } },
94
+ },
95
+ },
96
+ },
97
+ },
98
+ },
99
+ },
100
+ responses: {
101
+ "200": {
102
+ description: "SSE stream of RunEvent frames; closes after run_end",
103
+ content: { "text/event-stream": { schema: { $ref: "#/components/schemas/RunEvent" } } },
104
+ },
105
+ "400": errorResponse("Body is not JSON or lacks a string `text`"),
106
+ "404": errorResponse("Unknown session id"),
107
+ "409": errorResponse("A run is already in progress for this session"),
108
+ "503": errorResponse("No provider configured — run `rovecode setup` (or rovecode provider add + rovecode auth set, or set ROVECODE_BASE_URL/ROVECODE_API_KEY)"),
109
+ },
110
+ },
111
+ delete: {
112
+ operationId: "session.cancel",
113
+ summary: "Cancel the in-flight run on a session",
114
+ description:
115
+ "Aborts the running prompt's AbortController: the in-flight provider fetch and " +
116
+ "tool subprocesses are killed mid-turn, and the run's SSE stream ends with a " +
117
+ "run_end event of status \"stopped\". The session stays busy (409 on new prompts) " +
118
+ "until that stream has actually settled. Idempotent: cancelling an idle session " +
119
+ "returns cancelled: false.",
120
+ parameters: [
121
+ { name: "id", in: "path", required: true, schema: { type: "string" }, description: "Session id from POST /session" },
122
+ ],
123
+ responses: {
124
+ "200": {
125
+ description: "Cancellation signalled (cancelled: true) or nothing was running (cancelled: false)",
126
+ content: {
127
+ "application/json": {
128
+ schema: {
129
+ type: "object",
130
+ required: ["cancelled"],
131
+ properties: { cancelled: { type: "boolean" } },
132
+ },
133
+ },
134
+ },
135
+ },
136
+ "404": errorResponse("Unknown session id"),
137
+ },
138
+ },
139
+ },
140
+ "/session/{id}/tasks": {
141
+ get: {
142
+ operationId: "session.tasks",
143
+ summary: "List the session's background subagent tasks",
144
+ description:
145
+ "Snapshot of the session's background tasks (port #26): child agent sessions started by " +
146
+ "the `task` tool, oldest first, with status queued|running|done|failed|cancelled, timing, " +
147
+ "the child's final text (done) or error (failed). Tasks are process-local and not durable " +
148
+ "across server restarts. Completion notes reach the model as steering on the session's next prompt.",
149
+ parameters: [
150
+ { name: "id", in: "path", required: true, schema: { type: "string" }, description: "Session id from POST /session" },
151
+ ],
152
+ responses: {
153
+ "200": {
154
+ description: "Task snapshots",
155
+ content: {
156
+ "application/json": {
157
+ schema: { type: "array", items: { $ref: "#/components/schemas/TaskInfo" } },
158
+ },
159
+ },
160
+ },
161
+ "404": errorResponse("Unknown session id"),
162
+ },
163
+ },
164
+ },
165
+ "/sessions": {
166
+ get: {
167
+ operationId: "session.list",
168
+ summary: "List sessions",
169
+ description: "Scans the session root and returns summaries, sorted by updatedAt descending. Corrupt or foreign directories are skipped, never errors.",
170
+ responses: {
171
+ "200": {
172
+ description: "Session summaries",
173
+ content: {
174
+ "application/json": {
175
+ schema: { type: "array", items: { $ref: "#/components/schemas/SessionSummary" } },
176
+ },
177
+ },
178
+ },
179
+ },
180
+ },
181
+ },
182
+ "/doc": {
183
+ get: {
184
+ operationId: "doc",
185
+ summary: "This OpenAPI 3.1 document",
186
+ description: "Returns the OpenAPI 3.1 JSON describing exactly this server surface.",
187
+ responses: {
188
+ "200": { description: "OpenAPI 3.1 document", content: { "application/json": { schema: { type: "object" } } } },
189
+ },
190
+ },
191
+ },
192
+ },
193
+ components: {
194
+ schemas: {
195
+ Error: {
196
+ type: "object",
197
+ required: ["error"],
198
+ properties: { error: { type: "string" } },
199
+ },
200
+ SessionSummary: {
201
+ type: "object",
202
+ required: ["id", "createdAt", "updatedAt", "entryCount", "preview"],
203
+ properties: {
204
+ id: { type: "string" },
205
+ createdAt: { type: "number" },
206
+ updatedAt: { type: "number" },
207
+ entryCount: { type: "number" },
208
+ preview: { type: "string", description: "First user-message text, single line, ≤80 chars" },
209
+ },
210
+ },
211
+ RunEvent: {
212
+ type: "object",
213
+ description:
214
+ "Typed agent-loop event (src/core/types.ts RunEvent union), discriminated by `type`. " +
215
+ "The SSE `event:` field always equals this `type` field.",
216
+ required: ["type"],
217
+ properties: {
218
+ type: { type: "string", enum: [...RUN_EVENT_TYPES] },
219
+ },
220
+ additionalProperties: true,
221
+ },
222
+ TaskInfo: {
223
+ type: "object",
224
+ description: "Background subagent task snapshot (src/core/tasks.ts TaskInfo).",
225
+ required: ["id", "label", "agent", "goal", "isolated", "depth", "status", "createdAt"],
226
+ properties: {
227
+ id: { type: "string", description: "Task id (t1, t2, …; scoped to the session)" },
228
+ label: { type: "string" },
229
+ agent: { type: "string", description: "Agent definition the child runs" },
230
+ goal: { type: "string", description: "Bounded preview of the child's goal (≤200 chars)" },
231
+ isolated: { type: "boolean", description: "Ran in a worktree copy; file changes merge back as a patch on success" },
232
+ depth: { type: "number", description: "Child depth (root-started tasks run at 1)" },
233
+ status: { type: "string", enum: ["queued", "running", "done", "failed", "cancelled"] },
234
+ createdAt: { type: "number" },
235
+ startedAt: { type: "number" },
236
+ finishedAt: { type: "number" },
237
+ summary: { type: "string", description: "The child's final text (status done), ≤4000 chars" },
238
+ error: { type: "string", description: "Failure reason (status failed) or \"cancelled\"" },
239
+ usage: { type: "object", properties: { input: { type: "number" }, output: { type: "number" } } },
240
+ patchLines: { type: "number", description: "Isolated children: line count of the merged-back patch" },
241
+ },
242
+ },
243
+ },
244
+ },
245
+ };
246
+ }
@@ -0,0 +1,102 @@
1
+ /** Click zones for the modal card (approval verdicts, question options, free text, skip).
2
+ *
3
+ * Why this exists: the card is the single most frequent interaction in the surface — every gated
4
+ * edit, every shell command, every ask_user question goes through it — and until now it answered
5
+ * only to the arrow keys. Clicking `allow` did nothing at all: keys.ts's onMouse walks the hit zones
6
+ * the drawers registered that frame, and nobody registered any for the card, so the click fell
7
+ * through to the "focus the panel under the pointer" fallback. That is the complaint "most things do
8
+ * not respond to clicks, it only works with the arrow keys", in its most-used place.
9
+ *
10
+ * Geometry, not painting: draw-messages.ts owns how the card looks, this file owns where its targets
11
+ * landed. The two are kept honest by deriving everything from the SAME exported helpers the painter
12
+ * uses (areas, cardShape, cardRows) rather than re-deriving row counts — a second copy of the layout
13
+ * arithmetic would drift the moment the card grew a row.
14
+ *
15
+ * Two subtleties the card forces:
16
+ * - The card is CLIPPED from the top when it does not fit (draw-messages keeps the tail so the
17
+ * buttons stay reachable), so a row's screen y is its index minus the hidden count, and a target
18
+ * scrolled off the top has no zone at all rather than a wrong one.
19
+ * - The approval verdicts share ONE row, laid out horizontally, so they need x ranges; the question
20
+ * card gives every option its own row.
21
+ *
22
+ * `confirm` is false for exactly one target, the free-text row: clicking it means "I want to type
23
+ * here", not "submit an empty answer". Every other target is a labelled button, and a click on a
24
+ * button is the decision — the same as clicking OK in any dialog. */
25
+
26
+ import { areas, cardRows, cardShape, questionRows, SKIP_LABEL, VERDICT_LABEL } from "./draw-messages.ts";
27
+ import { inner } from "./draw-util.ts";
28
+ import { strWidth } from "./screen.ts";
29
+ import type { Rect, SextantState, Theme } from "./types.ts";
30
+
31
+ export interface CardHit {
32
+ rect: Rect;
33
+ /** the value card.selected takes when this target is clicked */
34
+ index: number;
35
+ /** replay Enter after selecting (a button); false leaves the caret on the row (free text) */
36
+ confirm: boolean;
37
+ }
38
+
39
+ /** button() in draw-messages renders a label as ` label `, and the verdict row separates them by two
40
+ * spaces at indent 2. */
41
+ const BUTTON_PAD = 2;
42
+ const BUTTON_GAP = 2;
43
+ const ROW_INDENT = 2;
44
+
45
+ /** The card's clickable targets in screen coordinates, or [] when no card is open, the panel is too
46
+ * small to draw one, or every target is clipped away. `rect` is the messages panel, as passed to
47
+ * drawMessages. */
48
+ export function cardHits(rect: Rect, s: SextantState, theme: Theme): CardHit[] {
49
+ const card = s.card;
50
+ if (card === null || card === undefined) return [];
51
+ if (rect.w < 4 || rect.h < 3) return []; // drawMessages paints nothing at all below this
52
+ const B = inner(rect);
53
+ const { cardH, msgH, maxDetail } = areas(B, s);
54
+ if (cardH <= 0) return [];
55
+
56
+ const all = cardRows(card, B.w, maxDetail, theme);
57
+ // when the card is taller than its slot the painter keeps the TAIL: rows [hidden..] are on screen
58
+ const hidden = all.length - cardH;
59
+ const yOf = (i: number): number | null => {
60
+ const v = i - hidden;
61
+ return v < 0 || v >= cardH ? null : B.y + msgH + v;
62
+ };
63
+ const out: CardHit[] = [];
64
+
65
+ if (card.kind === "approval") {
66
+ // the verdicts are the last row, so they survive clipping — that is why the painter keeps the tail
67
+ const y = yOf(all.length - 1);
68
+ if (y === null) return [];
69
+ let x = B.x + ROW_INDENT;
70
+ for (const [i, v] of card.verdicts.entries()) {
71
+ const w = strWidth(VERDICT_LABEL[v] ?? String(v)) + BUTTON_PAD;
72
+ if (x + w > B.x + B.w) break; // a verdict pushed past the right edge was never drawn
73
+ out.push({ rect: { x, y, w, h: 1 }, index: i, confirm: true });
74
+ x += w + BUTTON_GAP;
75
+ }
76
+ return out;
77
+ }
78
+
79
+ // question card: blank, q question rows, one row per option, [free text, wrapped], skip, hint.
80
+ // The row arithmetic comes from questionRows — the same helper the painter and the caret use — so
81
+ // the three cannot disagree; cardShape is still consulted for the clip.
82
+ const opts = card.prompt.options ?? [];
83
+ const { q, freeRows } = questionRows(card, B.w);
84
+ const shape = cardShape(card, B.w, maxDetail);
85
+ if (shape.total !== 1 + q + opts.length + freeRows + 2) return []; // the painter and the helper disagree: register nothing rather than wrong zones
86
+ const push = (rowIndex: number, index: number, w: number, confirm: boolean, h = 1): void => {
87
+ const y = yOf(rowIndex);
88
+ if (y !== null && w > 0) out.push({ rect: { x: B.x + ROW_INDENT, y, w, h }, index, confirm });
89
+ };
90
+ const full = Math.max(0, B.w - ROW_INDENT);
91
+ for (const [i, o] of opts.entries()) push(1 + q + i, i, Math.min(strWidth(o) + BUTTON_PAD, full), true);
92
+ // the free-text field is one zone across all its wrapped rows: select it, do not answer for the human.
93
+ // Rows clipped off the top shrink the zone from above (the first visible row is where it starts).
94
+ if (freeRows > 0) {
95
+ const first = 1 + q + opts.length;
96
+ const visibleFrom = Math.max(first, hidden);
97
+ const rows = first + freeRows - visibleFrom;
98
+ if (rows > 0) push(visibleFrom, opts.length, full, false, rows);
99
+ }
100
+ push(1 + q + opts.length + freeRows, opts.length + (freeRows > 0 ? 1 : 0), Math.min(strWidth(SKIP_LABEL) + BUTTON_PAD, full), true);
101
+ return out;
102
+ }
@@ -0,0 +1,55 @@
1
+ /** Sextant card keys (port #43): the key route of the ONE modal card — ←→↑↓ (and Tab) move the
2
+ * selection, Enter resolves it (approval: once / always / deny; question: an option, the free-text
3
+ * row or skip), Esc dismisses (deny / null) and the free-text row takes typing and Backspace.
4
+ * Ported from the user's own sextant v0.4.0 prototype app.js:1503-1510 and :1434; split out of
5
+ * keys.ts for the line budget. Pure state mutation, no clock: the card leaves the state before
6
+ * its promise settles, so a re-entrant hook never sees a stale card. */
7
+
8
+ import type { CardState, KeyEvent, SextantState } from "./types.ts";
9
+
10
+ /** false = not a card key: it falls through to the prompt (typing a follow-up while a card waits) */
11
+ export function onCardKey(s: SextantState, c: CardState, ev: KeyEvent): boolean {
12
+ const { name } = ev;
13
+ const n = c.kind === "approval" ? c.verdicts.length // allow · always · [all edits] · deny
14
+ : (c.prompt.options?.length ?? 0) + (c.prompt.allowFreeText !== false ? 1 : 0) + 1; // options · free text · skip
15
+ if (name === "left" || name === "up") return move(c, n, -1);
16
+ if (name === "right" || name === "down" || name === "tab") return move(c, n, 1);
17
+ if (name === "escape") { dismissCard(s); return true; }
18
+ if (c.kind === "approval") {
19
+ if (name !== "enter") return false;
20
+ s.card = null;
21
+ c.resolve(c.verdicts[c.selected] ?? "deny");
22
+ return true;
23
+ }
24
+ const opts = c.prompt.options?.length ?? 0, freeIdx = c.prompt.allowFreeText !== false ? opts : -1;
25
+ if (name === "enter") {
26
+ if (c.selected === n - 1) { dismissCard(s); return true; } // skip
27
+ if (c.selected !== freeIdx) { s.card = null; c.resolve({ kind: "option", index: c.selected }); return true; }
28
+ const t = c.freeText.trim();
29
+ if (t) { s.card = null; c.resolve({ kind: "text", text: t }); }
30
+ return true; // an empty free-text row is not an answer yet
31
+ }
32
+ if (c.selected !== freeIdx) return false;
33
+ if (name === "backspace") { // by code point: 😀 is one glyph, two UTF-16 units
34
+ c.freeText = [...c.freeText].slice(0, -1).join("");
35
+ return true;
36
+ }
37
+ const ch = name === "space" ? " " : ev.ch;
38
+ if (!ch || ev.alt) return false;
39
+ c.freeText += ch;
40
+ return true;
41
+ }
42
+
43
+ /** wrap the selection over the card's n rows */
44
+ function move(c: CardState, n: number, d: -1 | 1): true {
45
+ const v = (c.selected + d + n) % n;
46
+ c.selected = v;
47
+ return true;
48
+ }
49
+
50
+ /** approval → deny, question → null; the card leaves the state before the promise settles */
51
+ export function dismissCard(s: SextantState): void {
52
+ const c = s.card;
53
+ s.card = null;
54
+ if (c?.kind === "approval") c.resolve("deny"); else c?.resolve(null);
55
+ }
@@ -0,0 +1,157 @@
1
+ /** The seam between the context overlay and core/context-report.ts.
2
+ *
3
+ * draw-context.ts is pure over `ContextState` and never counts anything. This file is the only place that
4
+ * knows the report module exists: it lazily imports it (the boot rule — nothing in that dependency tree is
5
+ * loaded until someone opens /context), asks the LIVE runtime for the two rows a transcript cannot know,
6
+ * and maps the report onto the overlay's flat view.
7
+ *
8
+ * The live runtime is the whole reason this overlay is worth having. `rovecode context` on a shell has to
9
+ * BUILD a runtime to learn the system prompt and the tool schemas, and in a fresh session those two are
10
+ * most of the window; here they are already in memory, so the number is complete without constructing
11
+ * anything. What is still missing is MCP tools — their schemas do not exist until a server is connected —
12
+ * and the panel says so on its own line rather than letting a complete-looking total imply otherwise.
13
+ *
14
+ * Two numbers travel, never one. `raw` is what o200k counted; `estimated` is that corrected towards the
15
+ * model's own tokenizer. Presenting only the second would be presenting a corrected figure as a
16
+ * measurement, and someone comparing this panel against a provider's dashboard needs to know which is
17
+ * which. `scale.note` says where the factor came from, including when nobody has measured this model.
18
+ *
19
+ * Nothing here throws. A runtime that cannot answer, a model the catalog does not know, an empty
20
+ * transcript — each is a state the overlay draws, because a panel that reports on the session must not be
21
+ * the thing that ends it. */
22
+
23
+ import type { ContextState } from "./draw-context.ts";
24
+
25
+ /** What the live runtime can tell us that the transcript cannot. Both optional: a session whose runtime
26
+ * is mid-rebuild still opens the panel, and `live: false` makes the total read as a floor. */
27
+ export interface ContextFixed {
28
+ /** the system prompt a real turn would send — buildDef's, not the base alone */
29
+ system?: string;
30
+ /** rovecode's own tool schemas, serialized. MCP tools are deliberately absent. */
31
+ toolSchemas?: string;
32
+ }
33
+
34
+ /** the runtime shape this file needs, structurally — declared here so the overlay never imports the
35
+ * runtime's types and so a test can hand in three lines instead of a process */
36
+ export interface LiveRuntime {
37
+ registry: { list(): { schema: unknown }[] };
38
+ // method syntax, and `unknown` for the prompt: the real AgentDefinition types `systemPrompt` as a string
39
+ // or a function over its own AgentVars, and pinning either shape here would make this file depend on the
40
+ // runtime's types — which is exactly what the overlay must not do. It is narrowed where it is read.
41
+ buildDef(ref: { provider: string; model: string; effort: "auto" }): { systemPrompt: unknown };
42
+ /** optional: the market overlay uses it after installing an MCP server (types.ts SextantAttach) */
43
+ reloadMcp?(): Promise<{ added: string[]; removed: string[]; failed: { name: string; error: string }[]; skipped: string[] }>;
44
+ }
45
+
46
+ /** Pull the two fixed rows out of a runtime that is ALREADY running.
47
+ *
48
+ * Deliberately not `createRuntime`: the CLI builds one because it has none, and paid for that decision
49
+ * with a session directory it had to pass in to avoid creating a stray empty session. Inside the TUI the
50
+ * runtime is the one the next turn will use, so this is a read, not a construction — and it cannot leave
51
+ * anything behind.
52
+ *
53
+ * `buildDef`, not `systemPrompt()`: the prompt a run actually sends is the base plus the model profile,
54
+ * the design section, and — for a model without native tool calling — the tool block. Asking for the base
55
+ * alone under-counts the largest fixed row by everything that makes it large. */
56
+ export function fixedFrom(rt: LiveRuntime | null | undefined, ref: { provider: string; model: string }): ContextFixed {
57
+ if (!rt) return {};
58
+ try {
59
+ const schemas = rt.registry.list().map((t) => t.schema);
60
+ const def = rt.buildDef({ ...ref, effort: "auto" });
61
+ const sp = def.systemPrompt;
62
+ const system = typeof sp === "string" ? sp : typeof sp === "function" ? String((sp as (x: Record<string, unknown>) => unknown)({})) : undefined;
63
+ if (system === undefined) return {};
64
+ return { system, toolSchemas: JSON.stringify(schemas) };
65
+ } catch {
66
+ // a runtime that cannot describe itself is a panel that says so, not a crashed frame
67
+ return {};
68
+ }
69
+ }
70
+
71
+ /** the report module's shape, structurally: this file must compile and be testable without importing it */
72
+ interface Slice { label: string; tokens: number; share: number; note?: string }
73
+ interface Drift { estimated: number; reported: number; delta: number; fraction: number; beyondTolerance: boolean }
74
+ interface Report {
75
+ model: { provider: string; model: string };
76
+ window?: number;
77
+ estimated: number;
78
+ corrected: number;
79
+ scale: { factor: number; measured: boolean; note: string };
80
+ slices: Slice[];
81
+ remaining?: number;
82
+ fraction?: number;
83
+ nearLimit?: boolean;
84
+ drift?: Drift;
85
+ totals: { inputTokens?: number; outputTokens?: number; cacheReadTokens?: number; cacheWriteTokens?: number };
86
+ costUsd?: number;
87
+ unpricedTurns: number;
88
+ images: number;
89
+ }
90
+
91
+ export interface ContextLoadInput {
92
+ messages: readonly unknown[];
93
+ current: { provider: string; model: string };
94
+ /** window + pricing, however the caller has them */
95
+ lookup: (r: { provider: string; model: string }) => unknown;
96
+ fixed: ContextFixed;
97
+ /** the tolerance drift is judged against; printed by the panel, never assumed by a reader */
98
+ tolerance?: number;
99
+ /** tests inject the report function; production lazily imports the real one */
100
+ report?: (input: unknown) => Report;
101
+ }
102
+
103
+ /** the fraction past which drift is called out rather than merely shown. Matches core/context-report.ts;
104
+ * it travels in the state so the panel can print it instead of asserting a number the reader cannot see. */
105
+ const TOLERANCE = 0.05;
106
+
107
+ /** Build the overlay's state. Never throws: every failure becomes something the panel can draw. */
108
+ export async function loadContext(input: ContextLoadInput): Promise<Omit<ContextState, "scroll">> {
109
+ const tolerance = input.tolerance ?? TOLERANCE;
110
+ const model = `${input.current.provider}/${input.current.model}`;
111
+
112
+ let report: Report;
113
+ try {
114
+ const fn = input.report ?? (await import("../core/context-report.ts")).contextReport as unknown as (i: unknown) => Report;
115
+ report = fn({
116
+ messages: input.messages,
117
+ current: input.current,
118
+ lookup: input.lookup,
119
+ ...(input.fixed.system !== undefined ? { system: input.fixed.system } : {}),
120
+ ...(input.fixed.toolSchemas !== undefined ? { toolSchemas: input.fixed.toolSchemas } : {}),
121
+ });
122
+ } catch {
123
+ // the panel opens and says it has nothing, which is more useful than a frame that died counting
124
+ return {
125
+ model, raw: 0, estimated: 0, scale: { factor: 1, measured: false, note: "the context report could not be built" },
126
+ slices: [], images: 0, billed: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
127
+ unpricedTurns: 0, live: false, tolerance,
128
+ };
129
+ }
130
+
131
+ const t = report.totals;
132
+ return {
133
+ model,
134
+ ...(report.window !== undefined ? { window: report.window } : {}),
135
+ // `estimated` on the panel is the CORRECTED number, because that is what the window and the bill are
136
+ // computed from; `raw` carries what o200k counted so the panel can show both
137
+ raw: report.estimated,
138
+ estimated: report.corrected,
139
+ scale: report.scale,
140
+ ...(report.remaining !== undefined ? { remaining: report.remaining } : {}),
141
+ ...(report.fraction !== undefined ? { fraction: report.fraction } : {}),
142
+ ...(report.nearLimit !== undefined ? { nearLimit: report.nearLimit } : {}),
143
+ slices: report.slices.map((s) => ({ label: s.label, tokens: s.tokens, share: s.share, ...(s.note ? { note: s.note } : {}) })),
144
+ images: report.images,
145
+ ...(report.drift ? { drift: { ...report.drift } } : {}),
146
+ billed: {
147
+ input: t.inputTokens ?? 0, output: t.outputTokens ?? 0,
148
+ cacheRead: t.cacheReadTokens ?? 0, cacheWrite: t.cacheWriteTokens ?? 0,
149
+ },
150
+ ...(report.costUsd !== undefined ? { costUsd: report.costUsd } : {}),
151
+ unpricedTurns: report.unpricedTurns,
152
+ // "live" is about the two rows a transcript cannot know. The system prompt is the one that matters:
153
+ // tool schemas can legitimately be an empty list, so their absence proves nothing.
154
+ live: input.fixed.system !== undefined,
155
+ tolerance,
156
+ };
157
+ }