rovecode 0.3.3 → 0.4.0-beta.3

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 (495) hide show
  1. package/CHANGELOG.md +527 -0
  2. package/README.md +46 -48
  3. package/bin/rovecode.js +24 -0
  4. package/dist/cli/app-j6gn14w3.js +2 -0
  5. package/dist/cli/ask-user-cwstt8fz.js +2 -0
  6. package/dist/cli/auth-login-9bbp9915.js +2 -0
  7. package/dist/cli/auth-m8p9grty.js +2 -0
  8. package/dist/cli/bench-16zqdms5.js +9 -0
  9. package/dist/cli/catalog-1xchffa4.js +2 -0
  10. package/dist/cli/cli-1n1zb64f.js +2 -0
  11. package/dist/cli/client-2t9gjkck.js +2 -0
  12. package/dist/cli/commands-exafvm2b.js +2 -0
  13. package/dist/cli/connect-6zde0kn3.js +2 -0
  14. package/dist/cli/context-cmd-5t43wgqt.js +2 -0
  15. package/dist/cli/context-report-kt01pw8y.js +2 -0
  16. package/dist/cli/count-remote-ap7x3vh6.js +2 -0
  17. package/dist/cli/design-ne5zszyh.js +2 -0
  18. package/dist/cli/dispatch-2r5myxye.js +2 -0
  19. package/dist/cli/doctor-ws4fh4tn.js +3 -0
  20. package/dist/cli/executor-bdrjn634.js +2 -0
  21. package/dist/cli/export-1mxb9g5p.js +2 -0
  22. package/dist/cli/files-g104xghh.js +2 -0
  23. package/dist/cli/gauntlet-07xrjpj7.js +2 -0
  24. package/dist/cli/gauntlet-runner-xvy64436.js +10 -0
  25. package/dist/cli/gauntlet-wave3-jm91yt5w.js +5 -0
  26. package/dist/cli/gauntlet-wave4-r13py7p1.js +14 -0
  27. package/dist/cli/hashline-znvrat11.js +2 -0
  28. package/dist/cli/http-xafw6fsh.js +143 -0
  29. package/dist/cli/index-1sgjm25y.js +2 -0
  30. package/dist/cli/init-g2m0tn4m.js +51 -0
  31. package/dist/cli/install-avaqjjqq.js +2 -0
  32. package/dist/cli/loop-mmpfft01.js +2 -0
  33. package/dist/cli/main-0904f6ps.js +5 -0
  34. package/dist/cli/main-0ab9fc26.js +9 -0
  35. package/dist/cli/main-0jys2ccn.js +3 -0
  36. package/dist/cli/main-0mtcdbs7.js +3 -0
  37. package/dist/cli/main-0z1w2zsg.js +3 -0
  38. package/dist/cli/main-1dchs7xv.js +18 -0
  39. package/dist/cli/main-1ereejm1.js +3 -0
  40. package/dist/cli/main-1k1kw6b5.js +3 -0
  41. package/dist/cli/main-27y4sm2k.js +38 -0
  42. package/dist/cli/main-2wwjex5j.js +58 -0
  43. package/dist/cli/main-2yeveeve.js +6 -0
  44. package/dist/cli/main-2yfck9b5.js +3 -0
  45. package/dist/cli/main-2zmzgkwh.js +3 -0
  46. package/dist/cli/main-351pz3z7.js +7 -0
  47. package/dist/cli/main-3gjqfh7a.js +6 -0
  48. package/dist/cli/main-3nf3kgve.js +3 -0
  49. package/dist/cli/main-3pjrb2hd.js +3 -0
  50. package/dist/cli/main-3rxcvgna.js +19 -0
  51. package/dist/cli/main-4b3jgy66.js +19 -0
  52. package/dist/cli/main-4wndhjdc.js +7 -0
  53. package/dist/cli/main-4xcmvxnk.js +3 -0
  54. package/dist/cli/main-5tbz0wbz.js +4 -0
  55. package/dist/cli/main-5ywnwthm.js +3 -0
  56. package/dist/cli/main-6b62vkz0.js +14 -0
  57. package/dist/cli/main-6dnk69vp.js +3 -0
  58. package/dist/cli/main-6genrmhs.js +136 -0
  59. package/dist/cli/main-73g7eff4.js +15 -0
  60. package/dist/cli/main-7c5thhjd.js +5 -0
  61. package/dist/cli/main-7rn6bqje.js +3 -0
  62. package/dist/cli/main-80haw7qk.js +4 -0
  63. package/dist/cli/main-875s60s2.js +4 -0
  64. package/dist/cli/main-8kjxbpw4.js +8 -0
  65. package/dist/cli/main-90ds1z4e.js +10 -0
  66. package/dist/cli/main-9etavkew.js +3 -0
  67. package/dist/cli/main-a9njrkk1.js +3 -0
  68. package/dist/cli/main-aecrjq2d.js +12 -0
  69. package/dist/cli/main-ck9asesq.js +9 -0
  70. package/dist/cli/main-cta9racd.js +4 -0
  71. package/dist/cli/main-ddv7j2ag.js +3 -0
  72. package/dist/cli/main-dfreez27.js +10 -0
  73. package/dist/cli/main-f7rw7des.js +3 -0
  74. package/dist/cli/main-ggcn7rd7.js +5 -0
  75. package/dist/cli/main-gzkmycnv.js +3 -0
  76. package/dist/cli/main-hq51jg8v.js +18 -0
  77. package/dist/cli/main-jft389w9.js +8 -0
  78. package/dist/cli/main-k1eqkg83.js +3 -0
  79. package/dist/cli/main-k2y8a2aw.js +9 -0
  80. package/dist/cli/main-kcpbykxz.js +4 -0
  81. package/dist/cli/main-kd488vje.js +22 -0
  82. package/dist/cli/main-kh32yvgk.js +5 -0
  83. package/dist/cli/main-kqxnqjnv.js +25 -0
  84. package/dist/cli/main-kyn0xnsg.js +3 -0
  85. package/dist/cli/main-m1kk6fp5.js +21 -0
  86. package/dist/cli/main-mv40pcr2.js +4 -0
  87. package/dist/cli/main-n0t3973w.js +3 -0
  88. package/dist/cli/main-nqveez48.js +4 -0
  89. package/dist/cli/main-pknhvrmj.js +3 -0
  90. package/dist/cli/main-pn1w7a7j.js +3 -0
  91. package/dist/cli/main-prxxs70n.js +4 -0
  92. package/dist/cli/main-q3vsesf9.js +3 -0
  93. package/dist/cli/main-qsevpgsv.js +3 -0
  94. package/dist/cli/main-rdgdw24b.js +25 -0
  95. package/dist/cli/main-rfth4tbm.js +16 -0
  96. package/dist/cli/main-rg0wn0xf.js +5 -0
  97. package/dist/cli/main-sdmxhtv8.js +4 -0
  98. package/dist/cli/main-skbp13js.js +18 -0
  99. package/dist/cli/main-t4xnd213.js +7 -0
  100. package/dist/cli/main-vqak588n.js +4 -0
  101. package/dist/cli/main-w2n1303f.js +9 -0
  102. package/dist/cli/main-wbrdspr2.js +5 -0
  103. package/dist/cli/main-wsrg79c1.js +7 -0
  104. package/dist/cli/main-x4r0fne4.js +5 -0
  105. package/dist/cli/main-xea2f3tn.js +6 -0
  106. package/dist/cli/main-xg704a3c.js +3 -0
  107. package/dist/cli/main-xvnrabfp.js +16 -0
  108. package/dist/cli/main-xy53xf0r.js +4 -0
  109. package/dist/cli/main-y1fqy60y.js +3 -0
  110. package/dist/cli/main-yn8cd281.js +34 -0
  111. package/dist/cli/main-yr0ksc0h.js +4 -0
  112. package/dist/cli/main-z2ex2vyf.js +4 -0
  113. package/dist/cli/main-z3aayzvq.js +3 -0
  114. package/dist/cli/main-zaqh35jg.js +3 -0
  115. package/dist/cli/main-zc2e8e46.js +4 -0
  116. package/dist/cli/main-zzrfw6cf.js +13 -0
  117. package/dist/cli/main.js +280 -0
  118. package/dist/cli/market-cmd-e14kmx9n.js +5 -0
  119. package/dist/cli/mcp-login-wq7ktdek.js +2 -0
  120. package/dist/cli/mcp-market-cmd-9mg3jecy.js +2 -0
  121. package/dist/cli/notify-b7qc0cjb.js +2 -0
  122. package/dist/cli/oauth-z8whcgfx.js +2 -0
  123. package/dist/cli/output-b3ewj3ps.js +16 -0
  124. package/dist/cli/profiles-6mr5he5e.js +2 -0
  125. package/dist/cli/provider-config-g7j42q8x.js +2 -0
  126. package/dist/cli/provider-jr1y8vvm.js +2 -0
  127. package/dist/cli/registry-s8yk86g0.js +2 -0
  128. package/dist/cli/registry-t6p8d4mn.js +2 -0
  129. package/dist/cli/repl-bajwe1mh.js +11 -0
  130. package/dist/cli/resume-rwn9nz7y.js +2 -0
  131. package/dist/cli/run-flags-nah7ndpt.js +2 -0
  132. package/dist/cli/runtime-n7gafzhb.js +2 -0
  133. package/dist/cli/sandbox-config-emdy18x4.js +2 -0
  134. package/dist/cli/server-b0nvs2bn.js +5 -0
  135. package/dist/cli/session-arg-y75wd4kj.js +2 -0
  136. package/dist/cli/session-j62evmjq.js +2 -0
  137. package/dist/cli/sessions-cmd-tsnwz0ns.js +7 -0
  138. package/dist/cli/settings-df10wfez.js +2 -0
  139. package/dist/cli/setup-jzvv72fg.js +2 -0
  140. package/dist/cli/sextant-smoke-37m81ke6.js +5 -0
  141. package/dist/cli/skills-cmd-gjxnxnhx.js +2 -0
  142. package/dist/cli/smoke-p7748apt.js +8 -0
  143. package/dist/cli/start-chat-s4st3mm0.js +12 -0
  144. package/dist/cli/stream-gmeyewds.js +2 -0
  145. package/dist/cli/task-gh0kkp3n.js +2 -0
  146. package/dist/cli/tasks-z1kfpe8e.js +2 -0
  147. package/dist/cli/thinking-0eqkrz6t.js +2 -0
  148. package/dist/cli/todo-5brcrt9m.js +2 -0
  149. package/dist/cli/tools-7pzm0vj9.js +2 -0
  150. package/dist/cli/tools-s635p6s8.js +2 -0
  151. package/dist/cli/trust-cmd-cjav8zgm.js +2 -0
  152. package/dist/cli/update-check-pt31bm2f.js +2 -0
  153. package/dist/cli/update-cmd-tk131s9t.js +2 -0
  154. package/dist/cli/voice-56nabd8d.js +2 -0
  155. package/dist/cli/webfetch-xd8q596m.js +2 -0
  156. package/dist/cli/websearch-5hkf98k1.js +2 -0
  157. package/dist/cli/workflow-cmd-cy3cvzjp.js +4 -0
  158. package/dist/cli/workspace-q10g5z3e.js +2 -0
  159. package/dist/lib/index.js +62 -0
  160. package/dist/lib/models-index.json +1 -0
  161. package/dist/lib/plugins.js +55 -0
  162. package/dist/lib/providers.js +17 -0
  163. package/dist/lib/public-api.js +20 -0
  164. package/dist/lib/sdk.js +360 -0
  165. package/package.json +84 -72
  166. package/bin/rovecode.ts +0 -21
  167. package/src/acp/server.ts +0 -374
  168. package/src/cli/auth-login.ts +0 -122
  169. package/src/cli/connect.ts +0 -244
  170. package/src/cli/context-cmd.ts +0 -199
  171. package/src/cli/dispatch.ts +0 -82
  172. package/src/cli/doctor.ts +0 -362
  173. package/src/cli/export.ts +0 -276
  174. package/src/cli/help.ts +0 -293
  175. package/src/cli/is-tui-invocation.ts +0 -8
  176. package/src/cli/main.ts +0 -583
  177. package/src/cli/market-cmd.ts +0 -658
  178. package/src/cli/mcp-login.ts +0 -141
  179. package/src/cli/mcp-market-cmd.ts +0 -302
  180. package/src/cli/output.ts +0 -382
  181. package/src/cli/repl.ts +0 -250
  182. package/src/cli/repomap-root.ts +0 -14
  183. package/src/cli/resume.ts +0 -57
  184. package/src/cli/run-flags.ts +0 -43
  185. package/src/cli/run-limits.ts +0 -78
  186. package/src/cli/runtime.ts +0 -931
  187. package/src/cli/session-arg.ts +0 -30
  188. package/src/cli/sessions-cmd.ts +0 -145
  189. package/src/cli/setup.ts +0 -153
  190. package/src/cli/skills-cmd.ts +0 -194
  191. package/src/cli/start-chat.ts +0 -65
  192. package/src/cli/trust-cmd.ts +0 -52
  193. package/src/coding/bash.ts +0 -148
  194. package/src/coding/checkpoints.ts +0 -327
  195. package/src/coding/diff.ts +0 -138
  196. package/src/coding/files.ts +0 -341
  197. package/src/coding/hashline.ts +0 -274
  198. package/src/coding/lsp-gate.ts +0 -254
  199. package/src/coding/lsp-servers.ts +0 -147
  200. package/src/coding/lsp.ts +0 -283
  201. package/src/coding/repomap-cache.ts +0 -99
  202. package/src/coding/repomap-files.ts +0 -192
  203. package/src/coding/repomap.ts +0 -481
  204. package/src/core/agents.ts +0 -255
  205. package/src/core/compaction.ts +0 -259
  206. package/src/core/config.ts +0 -289
  207. package/src/core/context-report.ts +0 -228
  208. package/src/core/context.ts +0 -60
  209. package/src/core/count-remote.ts +0 -107
  210. package/src/core/execpolicy-rules.ts +0 -196
  211. package/src/core/execpolicy.ts +0 -385
  212. package/src/core/executor.ts +0 -454
  213. package/src/core/guardrails.ts +0 -400
  214. package/src/core/hooks.ts +0 -411
  215. package/src/core/images.ts +0 -230
  216. package/src/core/intro.ts +0 -266
  217. package/src/core/loop.ts +0 -567
  218. package/src/core/modes.ts +0 -372
  219. package/src/core/orchestrator.ts +0 -245
  220. package/src/core/proc-group.ts +0 -48
  221. package/src/core/project-trust.ts +0 -98
  222. package/src/core/reflection.ts +0 -165
  223. package/src/core/sandbox-config.ts +0 -186
  224. package/src/core/session-id.ts +0 -24
  225. package/src/core/session-images.ts +0 -73
  226. package/src/core/session-ops.ts +0 -183
  227. package/src/core/session-text.ts +0 -29
  228. package/src/core/session.ts +0 -469
  229. package/src/core/settings.ts +0 -170
  230. package/src/core/tasks.ts +0 -646
  231. package/src/core/token-scale.ts +0 -108
  232. package/src/core/tools.ts +0 -309
  233. package/src/core/trust.ts +0 -104
  234. package/src/core/types.ts +0 -330
  235. package/src/core/update-check.ts +0 -171
  236. package/src/core/usage.ts +0 -204
  237. package/src/core/validate.ts +0 -121
  238. package/src/core/verify-gate.ts +0 -159
  239. package/src/core/verify.ts +0 -236
  240. package/src/core/voice.ts +0 -158
  241. package/src/core/win-job.ts +0 -183
  242. package/src/core/workspace.ts +0 -184
  243. package/src/design/audit.ts +0 -797
  244. package/src/design/direction.ts +0 -190
  245. package/src/design/rules.ts +0 -157
  246. package/src/eval/bench.ts +0 -150
  247. package/src/eval/gauntlet-runner.ts +0 -215
  248. package/src/eval/gauntlet-support.ts +0 -84
  249. package/src/eval/gauntlet-wave3.ts +0 -269
  250. package/src/eval/gauntlet-wave4.ts +0 -217
  251. package/src/eval/gauntlet.ts +0 -253
  252. package/src/index.ts +0 -17
  253. package/src/lanes/agy.ts +0 -95
  254. package/src/lanes/approval.ts +0 -24
  255. package/src/lanes/claude.ts +0 -129
  256. package/src/lanes/codex.ts +0 -127
  257. package/src/lanes/events.ts +0 -130
  258. package/src/lanes/job.ts +0 -142
  259. package/src/lanes/opencode.ts +0 -122
  260. package/src/lanes/process.ts +0 -184
  261. package/src/lanes/progress.ts +0 -183
  262. package/src/lanes/registry.ts +0 -178
  263. package/src/lanes/runner.ts +0 -124
  264. package/src/lanes/types.ts +0 -112
  265. package/src/market/catalogs/mcp-docs.json +0 -111
  266. package/src/market/catalogs/plugins.json +0 -111
  267. package/src/market/catalogs/skills.json +0 -478
  268. package/src/market/clone.ts +0 -72
  269. package/src/market/context-cost.ts +0 -121
  270. package/src/market/digest.ts +0 -106
  271. package/src/market/index.ts +0 -22
  272. package/src/market/install.ts +0 -578
  273. package/src/market/manifest.ts +0 -187
  274. package/src/market/prereq.ts +0 -145
  275. package/src/market/registry.ts +0 -363
  276. package/src/market/resolve.ts +0 -111
  277. package/src/market/types.ts +0 -236
  278. package/src/market/validate.ts +0 -227
  279. package/src/mcp/client.ts +0 -449
  280. package/src/mcp/config.ts +0 -252
  281. package/src/mcp/local-package.ts +0 -211
  282. package/src/mcp/market-catalog.ts +0 -84
  283. package/src/mcp/market-install.ts +0 -289
  284. package/src/mcp/market.ts +0 -362
  285. package/src/mcp/oauth.ts +0 -251
  286. package/src/mcp/prompts-resources.ts +0 -249
  287. package/src/mcp/shared.ts +0 -149
  288. package/src/mcp/status.ts +0 -67
  289. package/src/mcp/tools.ts +0 -275
  290. package/src/mcp/transport.ts +0 -122
  291. package/src/mcp/trust.ts +0 -25
  292. package/src/memory/blocks.ts +0 -278
  293. package/src/memory/recall.ts +0 -355
  294. package/src/memory/scope.ts +0 -182
  295. package/src/memory/store.ts +0 -105
  296. package/src/memory/tools.ts +0 -99
  297. package/src/plugins/cli.ts +0 -119
  298. package/src/plugins/discover.ts +0 -108
  299. package/src/plugins/index.ts +0 -50
  300. package/src/plugins/install.ts +0 -184
  301. package/src/plugins/load.ts +0 -124
  302. package/src/plugins/manifest.ts +0 -92
  303. package/src/plugins/state.ts +0 -83
  304. package/src/providers/auth.ts +0 -408
  305. package/src/providers/cache.ts +0 -223
  306. package/src/providers/catalog-local.ts +0 -160
  307. package/src/providers/catalog.ts +0 -421
  308. package/src/providers/middleware-context.ts +0 -86
  309. package/src/providers/middleware.ts +0 -373
  310. package/src/providers/model-list.ts +0 -23
  311. package/src/providers/oauth/common.ts +0 -105
  312. package/src/providers/oauth/device-code.ts +0 -107
  313. package/src/providers/oauth/github-copilot.ts +0 -146
  314. package/src/providers/oauth/loopback.ts +0 -158
  315. package/src/providers/oauth/openai.ts +0 -163
  316. package/src/providers/oauth/openrouter.ts +0 -89
  317. package/src/providers/oauth/pkce.ts +0 -45
  318. package/src/providers/oauth/registry.ts +0 -39
  319. package/src/providers/oauth/seam.ts +0 -89
  320. package/src/providers/profile-glm53.ts +0 -111
  321. package/src/providers/profile-sonnet5-persona.ts +0 -65
  322. package/src/providers/profile-sonnet5-voice.ts +0 -23
  323. package/src/providers/profiles.ts +0 -156
  324. package/src/providers/provider-config.ts +0 -311
  325. package/src/providers/registry.ts +0 -333
  326. package/src/providers/responses.ts +0 -209
  327. package/src/providers/retry.ts +0 -234
  328. package/src/providers/router.ts +0 -294
  329. package/src/providers/sse.ts +0 -26
  330. package/src/providers/stream-errors.ts +0 -117
  331. package/src/providers/stream.ts +0 -566
  332. package/src/providers/thinking.ts +0 -189
  333. package/src/providers/wire-messages.ts +0 -129
  334. package/src/providers/wire-responses.ts +0 -79
  335. package/src/providers/wire-select.ts +0 -53
  336. package/src/server/http.ts +0 -291
  337. package/src/server/openapi.ts +0 -246
  338. package/src/sextant/card-hits.ts +0 -102
  339. package/src/sextant/card-keys.ts +0 -55
  340. package/src/sextant/context-source.ts +0 -157
  341. package/src/sextant/crew-cards.ts +0 -350
  342. package/src/sextant/draw-agents.ts +0 -273
  343. package/src/sextant/draw-code.ts +0 -388
  344. package/src/sextant/draw-context.ts +0 -222
  345. package/src/sextant/draw-frame.ts +0 -164
  346. package/src/sextant/draw-market.ts +0 -573
  347. package/src/sextant/draw-messages.ts +0 -386
  348. package/src/sextant/draw-pet.ts +0 -230
  349. package/src/sextant/draw-plan.ts +0 -187
  350. package/src/sextant/draw-tabs.ts +0 -85
  351. package/src/sextant/draw-util.ts +0 -65
  352. package/src/sextant/draw-wizard.ts +0 -378
  353. package/src/sextant/engine.ts +0 -230
  354. package/src/sextant/frame-hits.ts +0 -25
  355. package/src/sextant/frame.ts +0 -101
  356. package/src/sextant/git-status.ts +0 -197
  357. package/src/sextant/grid.ts +0 -59
  358. package/src/sextant/input.ts +0 -119
  359. package/src/sextant/keys.ts +0 -521
  360. package/src/sextant/layout.ts +0 -86
  361. package/src/sextant/local-commands.ts +0 -169
  362. package/src/sextant/market-source.ts +0 -287
  363. package/src/sextant/mentions.ts +0 -200
  364. package/src/sextant/message-hits.ts +0 -26
  365. package/src/sextant/model.ts +0 -387
  366. package/src/sextant/overlays.ts +0 -456
  367. package/src/sextant/panel-hits.ts +0 -38
  368. package/src/sextant/pet.ts +0 -399
  369. package/src/sextant/screen.ts +0 -324
  370. package/src/sextant/scroll-hits.ts +0 -66
  371. package/src/sextant/scrollbar.ts +0 -82
  372. package/src/sextant/sextant-bridge.ts +0 -174
  373. package/src/sextant/sextant-cards.ts +0 -142
  374. package/src/sextant/sextant-diff-base.ts +0 -63
  375. package/src/sextant/sextant-files.ts +0 -154
  376. package/src/sextant/sextant-frame-loop.ts +0 -335
  377. package/src/sextant/sextant-renderer.ts +0 -574
  378. package/src/sextant/sextant-repo.ts +0 -140
  379. package/src/sextant/theme.ts +0 -66
  380. package/src/sextant/tool-rows.ts +0 -189
  381. package/src/sextant/types.ts +0 -493
  382. package/src/skills/index.ts +0 -387
  383. package/src/skills/pack.ts +0 -220
  384. package/src/skills/spec.ts +0 -162
  385. package/src/skills/tools.ts +0 -69
  386. package/src/skills/versioned.ts +0 -227
  387. package/src/telemetry/otel-export.ts +0 -122
  388. package/src/telemetry/otel-lanes.ts +0 -89
  389. package/src/telemetry/otel-logs.ts +0 -131
  390. package/src/telemetry/otel-metrics.ts +0 -136
  391. package/src/telemetry/otel.ts +0 -397
  392. package/src/telemetry/otlp.ts +0 -76
  393. package/src/tools/ask-user.ts +0 -156
  394. package/src/tools/bash-bg.ts +0 -94
  395. package/src/tools/bash-jobs.ts +0 -237
  396. package/src/tools/design.ts +0 -151
  397. package/src/tools/evalcell.ts +0 -338
  398. package/src/tools/html-text.ts +0 -139
  399. package/src/tools/provider.ts +0 -149
  400. package/src/tools/task.ts +0 -250
  401. package/src/tools/todo.ts +0 -320
  402. package/src/tools/webfetch.ts +0 -332
  403. package/src/tools/websearch.ts +0 -359
  404. package/src/tui/agents-cmd.ts +0 -41
  405. package/src/tui/app.ts +0 -749
  406. package/src/tui/attach.ts +0 -127
  407. package/src/tui/boot-notes.ts +0 -41
  408. package/src/tui/builtin-prompts.ts +0 -59
  409. package/src/tui/checkpoints-cmd.ts +0 -70
  410. package/src/tui/clipboard-image.ts +0 -81
  411. package/src/tui/clipboard.ts +0 -78
  412. package/src/tui/commands.ts +0 -283
  413. package/src/tui/config-view.ts +0 -53
  414. package/src/tui/context-cmds.ts +0 -282
  415. package/src/tui/cost.ts +0 -108
  416. package/src/tui/crash-guard.ts +0 -173
  417. package/src/tui/focus-terminal.ts +0 -34
  418. package/src/tui/git-cmds.ts +0 -273
  419. package/src/tui/git-plain.ts +0 -58
  420. package/src/tui/info-cmd.ts +0 -150
  421. package/src/tui/input-plain.ts +0 -76
  422. package/src/tui/mcp-cmd.ts +0 -128
  423. package/src/tui/memory-note.ts +0 -77
  424. package/src/tui/modes-cmd.ts +0 -45
  425. package/src/tui/notify-seq.ts +0 -100
  426. package/src/tui/notify.ts +0 -318
  427. package/src/tui/overlays.ts +0 -97
  428. package/src/tui/pi-renderer.ts +0 -428
  429. package/src/tui/providers-cmd.ts +0 -377
  430. package/src/tui/reasoning-view.ts +0 -56
  431. package/src/tui/renderer.ts +0 -128
  432. package/src/tui/replay-marker.ts +0 -29
  433. package/src/tui/session-cmd.ts +0 -148
  434. package/src/tui/session-manage.ts +0 -95
  435. package/src/tui/sextant-attach.ts +0 -102
  436. package/src/tui/sextant-io.ts +0 -202
  437. package/src/tui/sextant-smoke.ts +0 -110
  438. package/src/tui/shell-cmd.ts +0 -158
  439. package/src/tui/smoke.ts +0 -72
  440. package/src/tui/staged-terminal.ts +0 -50
  441. package/src/tui/startup.ts +0 -12
  442. package/src/tui/theme.ts +0 -59
  443. package/src/tui/todo-label.ts +0 -7
  444. package/src/tui/trust-card.ts +0 -107
  445. package/src/tui/tui-commands.ts +0 -87
  446. package/tsconfig.json +0 -30
  447. package/vendor/pi-tui/LICENSE +0 -21
  448. package/vendor/pi-tui/PATCHES.md +0 -12
  449. package/vendor/pi-tui/PROVENANCE.md +0 -12
  450. package/vendor/pi-tui/README.upstream.md +0 -854
  451. package/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  452. package/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  453. package/vendor/pi-tui/src/alt-screen-search.ts +0 -158
  454. package/vendor/pi-tui/src/autocomplete.ts +0 -827
  455. package/vendor/pi-tui/src/components/alt-screen-flash.ts +0 -52
  456. package/vendor/pi-tui/src/components/box.ts +0 -138
  457. package/vendor/pi-tui/src/components/cancellable-loader.ts +0 -41
  458. package/vendor/pi-tui/src/components/editor.ts +0 -2364
  459. package/vendor/pi-tui/src/components/h-stack.ts +0 -45
  460. package/vendor/pi-tui/src/components/image.ts +0 -128
  461. package/vendor/pi-tui/src/components/input.ts +0 -448
  462. package/vendor/pi-tui/src/components/loader.ts +0 -93
  463. package/vendor/pi-tui/src/components/markdown.ts +0 -1016
  464. package/vendor/pi-tui/src/components/scroll-view.ts +0 -217
  465. package/vendor/pi-tui/src/components/select-list.ts +0 -230
  466. package/vendor/pi-tui/src/components/settings-list.ts +0 -277
  467. package/vendor/pi-tui/src/components/spacer.ts +0 -29
  468. package/vendor/pi-tui/src/components/stack.ts +0 -155
  469. package/vendor/pi-tui/src/components/text.ts +0 -108
  470. package/vendor/pi-tui/src/components/truncated-text.ts +0 -66
  471. package/vendor/pi-tui/src/components/v-stack.ts +0 -34
  472. package/vendor/pi-tui/src/editor-component.ts +0 -75
  473. package/vendor/pi-tui/src/fuzzy.ts +0 -138
  474. package/vendor/pi-tui/src/index.ts +0 -149
  475. package/vendor/pi-tui/src/keybindings.ts +0 -321
  476. package/vendor/pi-tui/src/keys.ts +0 -1402
  477. package/vendor/pi-tui/src/kill-ring.ts +0 -47
  478. package/vendor/pi-tui/src/latex.ts +0 -1381
  479. package/vendor/pi-tui/src/layout-node.ts +0 -52
  480. package/vendor/pi-tui/src/layout.ts +0 -411
  481. package/vendor/pi-tui/src/native-modifiers.ts +0 -60
  482. package/vendor/pi-tui/src/native-module-path.ts +0 -32
  483. package/vendor/pi-tui/src/stdin-buffer.ts +0 -445
  484. package/vendor/pi-tui/src/terminal-colors.ts +0 -74
  485. package/vendor/pi-tui/src/terminal-image.ts +0 -701
  486. package/vendor/pi-tui/src/terminal.ts +0 -554
  487. package/vendor/pi-tui/src/tui-alt-screen.ts +0 -1379
  488. package/vendor/pi-tui/src/tui-main-screen.ts +0 -655
  489. package/vendor/pi-tui/src/tui.ts +0 -1264
  490. package/vendor/pi-tui/src/undo-stack.ts +0 -29
  491. package/vendor/pi-tui/src/utils.ts +0 -1327
  492. package/vendor/pi-tui/src/word-navigation.ts +0 -118
  493. package/vendor/pi-tui/test/test-themes.ts +0 -39
  494. package/vendor/pi-tui/test/virtual-terminal.ts +0 -219
  495. /package/{src/providers → dist/cli}/models-index.json +0 -0
@@ -1,377 +0,0 @@
1
- /** /model · /models · /provider — the TUI's provider surface over the runtime's LIVE registry
2
- * (providers/registry.ts). Nothing here rebuilds the runtime: the registry's dispatching stream
3
- * resolves model.provider per call, so a provider added or a key stored in this session serves the
4
- * very next prompt. Kept out of app.ts (ADR-002 cap) like info-cmd.ts / session-cmd.ts.
5
- *
6
- * Secrets: `/provider key <id> <secret>` stores through auth.ts saveCredential and echoes only the
7
- * redacted prefix; slash commands never reach the agent or the session store, so the key is not in
8
- * the transcript. Prefer `--key-env NAME` or `rovecode auth set <id>` (masked prompt) when possible. */
9
-
10
- import type { Runtime } from "../cli/runtime.ts";
11
- import type { ModeManager } from "../core/modes.ts";
12
- import type { ModelRef } from "../core/types.ts";
13
- import type { Renderer } from "./renderer.ts";
14
- import { redactSecret, saveCredential } from "../providers/auth.ts";
15
- import { isConfigured } from "../providers/provider-config.ts";
16
- import { ADD_USAGE, formatProviderList, parseAddArgs } from "../providers/registry.ts";
17
- import { PROVIDER_ID_RE } from "../providers/provider-config.ts";
18
- import type { PickItem } from "./renderer.ts";
19
- import { SETUP_PICKS } from "../cli/setup.ts";
20
- import { CONNECT_WAITING, parseConnectArgs, runConnect } from "../cli/connect.ts";
21
- import { next } from "../core/voice.ts";
22
- import { ModelCatalog } from "../providers/catalog.ts"; // port #60: enrich existing picker rows
23
- import { describeModel } from "../providers/model-list.ts"; // port #60
24
-
25
- export interface ProviderCmdCtx {
26
- rt: Runtime;
27
- modes: ModeManager;
28
- state: { provider: string; model: string };
29
- renderer: Renderer;
30
- pushStatus: () => void;
31
- catalog?: Pick<ModelCatalog, "lookup">; // port #60: reuse the app's /cost catalog (offline fallback for other callers)
32
- }
33
-
34
- type NoteLevel = Parameters<Renderer["addSystemNote"]>[1];
35
-
36
- export const MODEL_COMMAND = { name: "model", description: "Switch the model I use: /model <provider/model | model> [--save]", group: "model & provider" };
37
-
38
- /** every `provider/model` id the configured providers list — the `/model` suggestions in the sextant. A
39
- * provider that errors or lists nothing drops out silently here; `/models` is where the reasons show. */
40
- export async function listModelIds(reg: Pick<Runtime["providers"], "list" | "models">): Promise<string[]> {
41
- const ids = reg.list().filter(isConfigured).map((p) => p.id);
42
- const results = await Promise.all(ids.map(async (id) => ({ id, r: await reg.models(id) })));
43
- return results.flatMap(({ id, r }) => (r.ok ? r.models.map((m) => `${id}/${m}`) : []));
44
- }
45
- export const SETUP_COMMAND = { name: "setup", description: "Connect a model step by step: provider, model, key, one test call", group: "start here" };
46
- export const CONNECT_COMMAND = { name: "connect", description: "Connect a model: /connect (guided, same as /setup) · /connect <id> [<url>] [--model <id>] [--key-env NAME] [--no-key] [--project] [--no-test]", group: "start here" };
47
- export const PROVIDER_COMMANDS = [
48
- { name: "models", description: "Pick a model from a list: /models [provider] [--save]", group: "model & provider" },
49
- { name: "provider", description: "Endpoints I can talk to: /provider list · add <id> <url> [--protocol …] [--key-env …] [--model …] [--no-key] [--project] · remove <id> · use <provider/model> · test <id> [model] · key <id> <secret>", group: "model & provider" },
50
- ];
51
- /** the last line of a finished /setup */
52
- export const SETUP_DONE_TUI = "Done. Tell me what you want done — try: explain this repo";
53
-
54
- /** `/model …` / `/provider use` write the default themselves and report it — the watcher must not
55
- * announce the same change a second time. Set around the write; refresh() fires synchronously. */
56
- let localWrite = false;
57
-
58
- const note = (ctx: ProviderCmdCtx, text: string, level?: NoteLevel): void => { ctx.renderer.addSystemNote(text, level); };
59
-
60
- /** the session's model = the current mode's slot (port #20; mirrored to both when planActSeparateModels is off) */
61
- function applyRef(ctx: ProviderCmdCtx, ref: ModelRef): void {
62
- ctx.modes.setModel({ provider: ref.provider, model: ref.model });
63
- const cur = ctx.modes.modelFor();
64
- ctx.state.model = cur.model;
65
- ctx.state.provider = cur.provider;
66
- ctx.pushStatus();
67
- }
68
-
69
- /** /model <provider/model | model> [--save] — switch this session; --save also persists it as the default. */
70
- export function cmdModel(ctx: ProviderCmdCtx, arg: string): void | Promise<void> {
71
- const words = arg.split(/\s+/).filter((w) => w.length > 0);
72
- const save = words.includes("--save");
73
- const sel = words.filter((w) => w !== "--save").join(" ");
74
- if (sel.length === 0) return cmdModels(ctx, save ? "--save" : ""); // port #60: bare /model uses the existing picker
75
- const ref = ctx.rt.providers.resolveSelector(sel, ctx.state.provider);
76
- if ("error" in ref) { note(ctx, `${ref.error} — add one with /provider add <id> <baseUrl>`, "warn"); return; }
77
- const switchedProvider = ref.provider !== ctx.state.provider;
78
- applyRef(ctx, ref);
79
- let saved = "";
80
- if (save) {
81
- localWrite = true;
82
- try {
83
- const r = ctx.rt.providers.setDefault(`${ref.provider}/${ref.model}`);
84
- saved = "error" in r ? ` (not saved: ${r.error})` : " (saved as default)";
85
- } finally { localWrite = false; }
86
- }
87
- const p = ctx.rt.providers.get(ref.provider);
88
- const keyNote = p !== undefined && !isConfigured(p) ? `\n${ctx.rt.providers.keyHint(p)}` : "";
89
- // same provider → the bare model id (the historical `/model <id>` note); a provider switch names both
90
- note(ctx, `model → ${switchedProvider ? `${ref.provider}/` : ""}${ref.model}${saved}${ctx.modes.separate ? ` (${ctx.modes.mode} mode)` : ""}${keyNote}`, keyNote.length > 0 ? "warn" : undefined);
91
- }
92
-
93
- /** /models [provider] — ids from providers.json `models` or the endpoint's /models. */
94
- /** /models [provider] [--all] [--save] — PICK a model, do not read a wall of ids.
95
- *
96
- * It used to print up to 60 rows as a note and leave you to retype one into `/model <id>`. The ids
97
- * are long and often differ by a date suffix, so retyping is where the mistakes were. Now the same
98
- * list opens in the picker the setup flow already uses: arrow, Enter, done — and Enter applies it
99
- * to this session immediately.
100
- *
101
- * Bare, it lists every CONFIGURED provider's models, so switching vendor is the same gesture as
102
- * switching model; naming a provider narrows it to that one (and reaches an unconfigured one, which
103
- * is how you look before you commit). `--save` also persists the pick as the default.
104
- *
105
- * Fetching is per provider and concurrent — a provider whose endpoint is down or keyless reports
106
- * itself as one row instead of failing the whole list. */
107
- export async function cmdModels(ctx: ProviderCmdCtx, arg: string): Promise<void> {
108
- const words = arg.split(/\s+/).filter((w) => w.length > 0);
109
- const save = words.includes("--save");
110
- const named = words.filter((w) => !w.startsWith("-"))[0];
111
- const reg = ctx.rt.providers;
112
-
113
- const ids = named !== undefined ? [named] : reg.list().filter(isConfigured).map((p) => p.id);
114
- if (ids.length === 0) { note(ctx, `no provider is configured yet. ${next("/connect")}`, "warn"); return; }
115
-
116
- note(ctx, ids.length === 1 ? `fetching ${ids[0]} models…` : `fetching models from ${ids.length} providers…`);
117
- const results = await Promise.all(ids.map(async (id) => ({ id, r: await reg.models(id) })));
118
-
119
- const items: PickItem[] = [];
120
- const problems: string[] = [];
121
- const catalog = ctx.catalog ?? new ModelCatalog(); // port #60: lookup only, never refresh/fetch metadata
122
- const itemFor = (id: string, model: string): PickItem => {
123
- const current = ctx.state.provider === id && ctx.state.model === model;
124
- const description = [current ? "current" : "", describeModel(catalog.lookup(id, model))].filter(Boolean).join(" · ");
125
- return { value: `${id}/${model}`, label: `${current ? "* " : " "}${id}/${model}`, ...(description ? { description } : {}) };
126
- }; // port #60
127
- for (const { id, r } of results) {
128
- if (!r.ok) { problems.push(`${id}: ${r.error}`); continue; }
129
- if (r.models.length === 0) { problems.push(`${id}: the endpoint listed no models (no /models route?) — /model ${id}/<model> still works`); continue; }
130
- for (const m of r.models) {
131
- items.push(itemFor(id, m)); // port #60: same live ids, optional context/pricing/capabilities
132
- }
133
- }
134
- for (const p of problems) note(ctx, p, "warn");
135
- // port #60: never hide the running model just because a provider's list does not know it.
136
- const currentRef = `${ctx.state.provider}/${ctx.state.model}`;
137
- if (ctx.state.model && ids.includes(ctx.state.provider) && !items.some((item) => item.value === currentRef)) items.unshift(itemFor(ctx.state.provider, ctx.state.model));
138
- if (items.length === 0) return;
139
-
140
- // the current model first: the list is long and the answer to "what am I on?" should not need scrolling
141
- items.sort((a, b) => Number(b.label.startsWith("*")) - Number(a.label.startsWith("*")));
142
- // short on purpose: the box clips its title, and it already draws an `esc` affordance of its own
143
- const picked = await ctx.renderer.pickOne(items, `pick a model · ${items.length} from ${ids.length} provider${ids.length === 1 ? "" : "s"}`);
144
- if (picked === null || (!save && picked === `${ctx.state.provider}/${ctx.state.model}`)) return; // port #60: cancel/re-pick changes no slot; --save still persists
145
- cmdModel(ctx, save ? `${picked} --save` : picked); // ONE path for applying a model, flags and all
146
- }
147
-
148
- /** /provider list|add|remove|use|test|key */
149
- export async function cmdProvider(ctx: ProviderCmdCtx, arg: string): Promise<void> {
150
- const words = arg.split(/\s+/).filter((w) => w.length > 0);
151
- const [action, ...rest] = words;
152
- const reg = ctx.rt.providers;
153
- switch (action) {
154
- case undefined:
155
- case "list":
156
- note(ctx, formatProviderList(reg, { all: rest.includes("--all") }));
157
- return;
158
- case "add": {
159
- const parsed = parseAddArgs(rest);
160
- if ("error" in parsed) { note(ctx, parsed.error, "warn"); return; }
161
- const r = reg.add(parsed.spec, parsed.scope);
162
- if ("error" in r) { note(ctx, r.error, "warn"); return; }
163
- const key = isConfigured(r) ? "" : `\nkey: /provider key ${r.id} <secret> · or set ${r.keyEnv} (live, no restart)`;
164
- note(ctx, `added ${r.id} (${r.protocol}, ${r.baseUrl}) [${parsed.scope}]${key}\nuse it: /model ${r.id}/${r.defaultModel ?? "<model>"}`);
165
- return;
166
- }
167
- case "remove": {
168
- if (rest[0] === undefined) break;
169
- const r = reg.remove(rest[0]);
170
- if ("error" in r) { note(ctx, r.error, "warn"); return; }
171
- note(ctx, r.removed.length > 0 ? `removed ${rest[0]} (${r.removed.join(", ")} providers.json)` : `${rest[0]} was not in any providers.json`);
172
- return;
173
- }
174
- case "use": {
175
- if (rest[0] === undefined) break;
176
- localWrite = true;
177
- let r: ReturnType<typeof reg.setDefault>;
178
- try { r = reg.setDefault(rest[0]); } finally { localWrite = false; }
179
- if ("error" in r) { note(ctx, r.error, "warn"); return; }
180
- applyRef(ctx, r);
181
- const p = reg.get(r.provider);
182
- const keyNote = p !== undefined && !isConfigured(p) ? `\n${reg.keyHint(p)}` : "";
183
- note(ctx, `default → ${r.provider}/${r.model} (saved; this session switched)${keyNote}`, keyNote.length > 0 ? "warn" : undefined);
184
- return;
185
- }
186
- case "test": {
187
- if (rest[0] === undefined) break;
188
- note(ctx, `testing ${rest[0]}${rest[1] !== undefined ? `/${rest[1]}` : ""}…`);
189
- const r = await reg.probe(rest[0], rest[1]);
190
- note(ctx, `${rest[0]}/${r.model}: ${r.detail}`, r.ok ? undefined : "warn");
191
- return;
192
- }
193
- case "key": {
194
- const [id, secret] = rest;
195
- if (id === undefined || secret === undefined) break;
196
- const p = reg.get(id);
197
- if (p === undefined) { note(ctx, `unknown provider "${id}" — /provider add ${id} <baseUrl> first`, "warn"); return; }
198
- saveCredential(id, secret, p.keyEnv);
199
- reg.refresh();
200
- note(ctx, `stored ${p.keyEnv} for ${id} (${redactSecret(secret)}) — live now`);
201
- return;
202
- }
203
- default:
204
- break;
205
- }
206
- note(ctx, `usage: /provider list [--all] · /provider ${ADD_USAGE} · remove <id> · use <provider/model> · test <id> [model] · key <id> <secret>`, "warn");
207
- }
208
-
209
- // ---------- /setup ----------
210
-
211
- /** the watcher + poll an unfinished /setup left armed (one at a time; a new /setup replaces it) */
212
- let pendingSetup: (() => void) | null = null;
213
-
214
- /** /setup — the TUI's guided connect: provider from the picker, model from a question card, then the
215
- * key. The cards have no masked input, so the key is a HAND-OFF: `rovecode auth set <id>` in another
216
- * terminal (masked) or `/provider key` here. The live registry notices the key landing (a 1 s poll keeps
217
- * its mtime check warm while a setup is pending) and this finishes the job — one test call, default,
218
- * session switch — without another command. Wording: core/voice.ts. */
219
- export async function cmdSetup(ctx: ProviderCmdCtx): Promise<void> {
220
- const reg = ctx.rt.providers;
221
- pendingSetup?.(); pendingSetup = null;
222
- const items = SETUP_PICKS.map((p) => ({ value: p.key, label: p.label }));
223
- const key = await ctx.renderer.pickOne(items, "◆ connect a model — which provider? (Esc = cancel)");
224
- if (key === null) { note(ctx, "setup cancelled — nothing changed. /setup whenever you like"); return; }
225
- const pick = SETUP_PICKS.find((p) => p.key === key);
226
- if (pick === undefined) return;
227
- const askText = async (question: string): Promise<string | null> => {
228
- const a = await ctx.renderer.askQuestion({ question, options: [], allowFreeText: true }).catch(() => null);
229
- return a?.text?.trim() ?? null;
230
- };
231
- let id: string;
232
- if (pick.url !== undefined) {
233
- const idText = ((await askText("Short name for it? (letters, digits, - _ .)")) ?? "").toLowerCase();
234
- if (!PROVIDER_ID_RE.test(idText)) { note(ctx, `setup stopped — "${idText}" won't work as an id. ${next("/setup, and pick a name like myproxy")}`, "warn"); return; }
235
- const baseUrl = (await askText(`Base URL for ${idText}? (e.g. https://host/v1)`)) ?? "";
236
- if (!/^https?:\/\//.test(baseUrl)) { note(ctx, `setup stopped — "${baseUrl}" is not an http(s) URL. ${next("/setup")}`, "warn"); return; }
237
- const keyA = await ctx.renderer.askQuestion({ question: "Does it need an API key?", options: ["yes", "no — it is a local server"], allowFreeText: false }).catch(() => null);
238
- const noKey = keyA?.choice === 1;
239
- const r = reg.add({ id: idText, baseUrl, protocol: pick.url, ...(noKey ? { noKey: true } : {}) }, "user");
240
- if ("error" in r) { note(ctx, `setup stopped — ${r.error}`, "warn"); return; }
241
- id = idText;
242
- note(ctx, `◆ ${id} registered (${pick.url} protocol, ${baseUrl}).`);
243
- } else {
244
- id = pick.id ?? "";
245
- const known = reg.get(id);
246
- if (known === undefined) { note(ctx, `setup stopped — ${id} is missing from the built-in table`, "warn"); return; }
247
- if (pick.local === true && known.noKey !== true) {
248
- // the built-in row expects a key env; a local server needs none — the user entry says so
249
- const r = reg.add({ id, baseUrl: known.baseUrl, protocol: known.protocol, noKey: true, ...(known.defaultModel !== undefined ? { defaultModel: known.defaultModel } : {}) }, "user");
250
- if ("error" in r) { note(ctx, `setup stopped — ${r.error}`, "warn"); return; }
251
- note(ctx, `◆ ${id} marked as a local server (${known.baseUrl}, no key).`);
252
- }
253
- }
254
- const spec = reg.get(id);
255
- if (spec === undefined) return;
256
- // A provider that ships a default model does not need a question: taking it is right nearly always,
257
- // and `/model <id>/<other> --save` changes it in one line afterwards. Only an endpoint with no
258
- // default (a bare proxy, a self-hosted server) still has to be asked — there is nothing to assume.
259
- let model = spec.defaultModel;
260
- if (model === undefined) {
261
- const mA = await ctx.renderer.askQuestion({ question: `Which model id on ${id}?`, options: [], allowFreeText: true }).catch(() => null);
262
- model = mA?.text?.trim() || mA?.label;
263
- if (model === undefined || model.length === 0) { note(ctx, `◆ ${id} is set up but has no model yet. ${next(`/models ${id}, then /model ${id}/<model> --save`)}`); return; }
264
- } else {
265
- note(ctx, `◆ model → ${id}/${model} (change it any time: /model ${id}/<other> --save)`);
266
- }
267
-
268
- const finish = async (): Promise<void> => {
269
- note(ctx, `◆ testing ${id}/${model} …`);
270
- const r = await reg.probe(id, model);
271
- if (r.ok) note(ctx, ` ${r.detail}`);
272
- else note(ctx, ` that didn't work: ${r.detail}\n ${next(`check the key and the URL, then /provider test ${id} ${model}`)}`, "warn");
273
- localWrite = true;
274
- let d: ReturnType<typeof reg.setDefault>;
275
- try { d = reg.setDefault(`${id}/${model}`, "user"); } finally { localWrite = false; }
276
- if ("error" in d) { note(ctx, ` ${d.error}`, "warn"); return; }
277
- applyRef(ctx, d);
278
- note(ctx, `◆ default → ${d.provider}/${d.model} — this session switched too.\n${SETUP_DONE_TUI}`);
279
- };
280
- if (isConfigured(spec)) { await finish(); return; }
281
- note(ctx, [
282
- `◆ I need the key for ${id}. Paste it hidden in another terminal:`,
283
- ` rovecode auth set ${id}`,
284
- ` or here (this line only, redacted in the note): /provider key ${id} <secret>`,
285
- ` or set ${spec.keyEnv} in your environment.`,
286
- " I'll notice as soon as it lands and finish the setup.",
287
- ].join("\n"));
288
- armKeyWatch(reg, id, finish);
289
- }
290
-
291
- /** Park until the key for `id` lands, then run `finish` once. The registry's mtime check only runs on
292
- * access, so a 1 s poll keeps it warm while we wait; one watch at a time — a new /setup or /connect
293
- * replaces the one before it. */
294
- function armKeyWatch(reg: ProviderCmdCtx["rt"]["providers"], id: string, finish: () => Promise<void>): void {
295
- const timer = setInterval(() => { reg.snapshot(); }, 1000);
296
- timer.unref?.();
297
- const off = reg.onChange(() => {
298
- const p = reg.get(id);
299
- if (p === undefined || !isConfigured(p)) return;
300
- stop();
301
- void finish();
302
- });
303
- const stop = (): void => { clearInterval(timer); off(); if (pendingSetup === stop) pendingSetup = null; };
304
- pendingSetup = stop;
305
- }
306
-
307
- /** /connect — the same job as /setup, but with the answers on the line instead of in cards, so it is one
308
- * command to paste. Bare, it IS /setup. It runs cli/connect.ts against this session's LIVE registry and
309
- * applies the new default to the session, like /setup does.
310
- *
311
- * There is no masked input in here, so `--key` and `--key-stdin` are refused rather than quietly
312
- * ignored: a key typed on this line would sit in the transcript. When a key is simply missing,
313
- * `deferKey` hands over the same way /setup does and the watcher finishes the job when it lands. */
314
- export async function cmdConnect(ctx: ProviderCmdCtx, arg: string): Promise<void> {
315
- const words = arg.split(/\s+/).filter((w) => w.length > 0);
316
- if (words.length === 0) { await cmdSetup(ctx); return; }
317
- const parsed = parseConnectArgs(words);
318
- if ("error" in parsed) { note(ctx, `${parsed.error.replace("usage: rovecode connect", "usage: /connect")}`, "warn"); return; }
319
- if (parsed.key === "prompt" || parsed.key === "stdin") {
320
- note(ctx, `there is no hidden prompt in here — a key on this line would sit in the transcript.\n ${next(`rovecode auth set ${parsed.id} in another terminal, or /provider key ${parsed.id} <secret>`)}`, "warn");
321
- return;
322
- }
323
- const reg = ctx.rt.providers;
324
- pendingSetup?.(); pendingSetup = null;
325
-
326
- /** the default is written by the time connect returns (even on a failed test call) — bring the
327
- * session with it, the way /setup does. Also runs on the deferred pass, after the key lands. */
328
- const follow = (code: number): void => {
329
- if (code === CONNECT_WAITING || code === 2) return;
330
- const d = reg.defaultRef();
331
- if (d !== null && d.provider === parsed.id && d.model.length > 0) applyRef(ctx, d);
332
- };
333
-
334
- const run = async (): Promise<number> => {
335
- localWrite = true; // the watcher must not announce a default this command already reported
336
- try {
337
- return await runConnect(parsed, {
338
- registry: reg,
339
- tty: false, // cards, not a terminal: never let runConnect reach for a prompt or for stdin
340
- out: (l) => note(ctx, l),
341
- done: SETUP_DONE_TUI,
342
- where: "tui", // the "→ next:" steps are slash commands in here, not shell lines
343
- deferKey: (spec) => {
344
- note(ctx, [
345
- `◆ I need the key for ${parsed.id}. Paste it hidden in another terminal:`,
346
- ` rovecode auth set ${parsed.id}`,
347
- ` or here (this line only, redacted in the note): /provider key ${parsed.id} <secret>`,
348
- ` or set ${spec.keyEnv} in your environment.`,
349
- " I'll notice as soon as it lands and finish the job.",
350
- ].join("\n"));
351
- armKeyWatch(reg, parsed.id, async () => { follow(await run()); });
352
- },
353
- });
354
- } finally { localWrite = false; }
355
- };
356
-
357
- follow(await run());
358
- }
359
-
360
- /** Boot-time subscription: when the persisted default changes underneath this session (another
361
- * terminal's `rovecode model use`, the agent's provider_edit use) the session follows it; when the
362
- * first provider appears, say so. In-process slash writes report themselves (localWrite). */
363
- export function watchProviders(ctx: ProviderCmdCtx): () => void {
364
- let lastSelector = ctx.rt.providers.defaultSelector();
365
- let hadProvider = ctx.rt.noProviderReason() === null;
366
- return ctx.rt.providers.onChange(() => {
367
- const sel = ctx.rt.providers.defaultSelector();
368
- if (sel !== lastSelector) {
369
- lastSelector = sel;
370
- const d = ctx.rt.providers.defaultRef();
371
- if (d !== null && d.model.length > 0 && !localWrite) { applyRef(ctx, d); note(ctx, `default model changed → ${d.provider}/${d.model}`); }
372
- }
373
- const has = ctx.rt.noProviderReason() === null;
374
- if (has && !hadProvider) note(ctx, "provider configured — ready for the next prompt");
375
- hadProvider = has;
376
- });
377
- }
@@ -1,56 +0,0 @@
1
- /** Reasoning blocks on the interactive surfaces (port #60): the app's per-message bookkeeping between
2
- * `reasoning_update` events and a Renderer — ONE collapsed block per assistant message, opened on the
3
- * turn's first reasoning event, settled when the message's text starts, the turn ends or the run ends.
4
- * A renderer with `beginReasoning` (the classic card) gets the settle; one without gets a single system
5
- * note carrying the collapsed label once the block settles.
6
- *
7
- * THE DELIBERATE DIFFERENCE FROM AION: rovecode's reasoning_update carries `tokens`, never text —
8
- * the loop drops the thinking text on purpose ("only its estimated size leaves the loop", loop.ts:272),
9
- * so there is nothing to append and this module counts tokens instead of characters. The property that
10
- * matters survives the translation: the thinking text is never rendered and never kept here.
11
- * `reasoningLabel` is the ONE wording every surface prints (the classic card, the fallback note).
12
- * Pure: no clock, no timers, no process. */
13
-
14
- import type { RunEvent } from "../core/types.ts";
15
- import type { AssistantView, Renderer } from "./renderer.ts";
16
-
17
- /** `reasoning · 1234 tokens …` while streaming, `reasoning · 1234 tokens · collapsed` once settled */
18
- export function reasoningLabel(tokens: number, streaming: boolean): string {
19
- return `reasoning · ${tokens} tokens${streaming ? " …" : " · collapsed"}`;
20
- }
21
-
22
- /** the `--plain` REPL's one line per block (printed when the message's text starts or the turn ends) */
23
- export function collapsedReasoningLine(tokens: number): string {
24
- return ` ∴ ${reasoningLabel(tokens, false)}`;
25
- }
26
-
27
- interface OpenBlock { id: string; view: AssistantView | null; tokens: number }
28
-
29
- export class ReasoningViews {
30
- private open: OpenBlock | null = null;
31
- constructor(private readonly renderer: Pick<Renderer, "addSystemNote" | "beginReasoning">) {}
32
-
33
- /** feed every RunEvent of the live run (app.ts: right after renderer.onEvent, before the per-event calls).
34
- * `reasoning_update.tokens` is CUMULATIVE for the message (a dropped event costs nothing), so the block
35
- * takes the event's value rather than summing. */
36
- onEvent(ev: RunEvent): void {
37
- if (ev.type === "reasoning_update") {
38
- if (this.open && this.open.id !== ev.messageId) this.settle();
39
- if (!this.open) this.open = { id: ev.messageId, view: this.renderer.beginReasoning?.() ?? null, tokens: 0 };
40
- this.open.tokens = Math.max(this.open.tokens, ev.tokens);
41
- this.open.view?.set?.(`∴ ${reasoningLabel(this.open.tokens, true)}`);
42
- } else if (ev.type === "message_update" || ev.type === "turn_end" || ev.type === "run_end") this.settle();
43
- }
44
-
45
- /** the open block (if any) is done: the card settles, or the fallback note lands */
46
- settle(): void {
47
- const o = this.open;
48
- if (!o) return;
49
- this.open = null;
50
- if (o.view) o.view.done();
51
- else this.renderer.addSystemNote(`∴ ${reasoningLabel(o.tokens, false)}`);
52
- }
53
-
54
- /** tokens of the block still open (tests) */
55
- get openTokens(): number { return this.open?.tokens ?? 0; }
56
- }
@@ -1,128 +0,0 @@
1
- /** The Renderer seam (BLUEPRINT port #1): the TUI app talks only to this interface.
2
- * PiTuiRenderer is today's implementation; OpenTUI or others can slot in later
3
- * without touching the app/loop. House code outside src/tui must not import vendor. */
4
-
5
- import type { QuestionAnswer, QuestionPrompt } from "../tools/ask-user.ts";
6
- import type { PermissionLevel, ThinkingEffort, RunEvent } from "../core/types.ts";
7
- import type { SextantAttach } from "../sextant/types.ts";
8
-
9
- export type { QuestionAnswer, QuestionPrompt, SextantAttach };
10
-
11
- /** `all-edits` is offered only on an edit/write card: it answers THIS call and asks the surface to
12
- * drop to accept-edits for the rest of the session (writes inside the workspace stop prompting). */
13
- export type ApprovalAnswer = "once" | "always" | "all-edits" | "deny";
14
-
15
- export interface StatusInfo {
16
- provider: string;
17
- model: string;
18
- yolo: boolean;
19
- /** the full permission tier; `yolo` stays for the surfaces that only know two. Optional so a
20
- * renderer that does not paint it needs no change. */
21
- permission?: PermissionLevel;
22
- /** the thinking dial, painted next to the model when it is on */
23
- effort?: ThinkingEffort;
24
- turns: number;
25
- tokensIn: number;
26
- tokensOut: number;
27
- /** port #20: plan/act mode indicator (optional — plain surfaces omit it) */
28
- mode?: "plan" | "act";
29
- /** port #32: "todos done/total" for the status bar; omitted when the session has no list */
30
- todos?: string;
31
- }
32
-
33
- export interface RendererHooks {
34
- /** user submitted a line from the editor (already trimmed, non-empty) */
35
- onSubmit: (text: string) => void;
36
- /** user asked to interrupt the in-flight run (Escape on the loader) */
37
- onInterrupt: () => void;
38
- /** user asked to leave (Ctrl+C) */
39
- onExit: () => void;
40
- }
41
-
42
- /** A streaming assistant message in the transcript. */
43
- export interface AssistantView {
44
- append(delta: string): void;
45
- /** finalize; no more appends */
46
- done(): void;
47
- /** port #60 (OPTIONAL): replace the view's content — the reasoning card uses it because a reasoning_update
48
- * carries the cumulative TOKEN count, not deltas, so the card repaints one line per event. A view without
49
- * it (plain transcript appends) is left alone; ReasoningViews skips the update instead of appending counts. */
50
- set?(content: string): void;
51
- }
52
-
53
- export interface SlashCommand {
54
- name: string;
55
- description: string;
56
- /** /help topic the command is listed under (info-cmd.ts); the palette ignores it */
57
- group?: string;
58
- /** the argument values (`/effort` levels; `/model` ids): the sextant lists them as suggestions once
59
- * the command is typed and completes the one picked. A function is read at suggestion time, for a
60
- * set that changes while the TUI runs (the models of the providers that have a key). */
61
- choices?: readonly string[] | (() => readonly string[]);
62
- /** what Enter does on a picked choice: "submit" (default — `/effort high` runs) or "complete" — the
63
- * choice is a subcommand that wants more words (`/mcp add ` waits for a name) */
64
- choicesThen?: "submit" | "complete";
65
- }
66
-
67
- export interface PickItem { value: string; label: string; description?: string }
68
-
69
- export interface RendererStartOptions {
70
- /** false after a loading intro: reveal the complete layout, not a second panel animation. */
71
- animate?: boolean;
72
- /** Called once the scene exists but before its first paint, to seed transcript and status. */
73
- beforeFirstRender?: () => void;
74
- /** Keep the prepared frame offscreen while the loading intro completes. Never reads stdin. */
75
- beforeReveal?: () => Promise<void>;
76
- /** Last handoff: the frame is laid out, immediately before terminal takeover/output. */
77
- onReveal?: () => void;
78
- }
79
-
80
- export interface Renderer {
81
- start(hooks: RendererHooks, options?: RendererStartOptions): void | Promise<void>;
82
- stop(): void;
83
- /** Put the terminal back and nothing else — no settling, no child processes, no async. `stop()` is the
84
- * orderly shutdown and calls this as its last act; this is what the CRASH path calls, because there
85
- * the only thing that still matters is that the person gets their shell back. Separated because
86
- * `stop()` does work that can itself throw, and a throw before the restore is how a crash turns into
87
- * "my terminal is broken": the alt screen never closes and mouse reporting keeps typing escape
88
- * sequences at the prompt. Must be idempotent and must never throw. Optional: a renderer that never
89
- * touched the terminal (the test fake) has nothing to restore. */
90
- restoreTerminal?(): void;
91
- /** slash commands offered by editor autocomplete; call before start() */
92
- setCommands(cmds: SlashCommand[]): void;
93
- addUser(text: string): void;
94
- addSystemNote(text: string, tone?: "info" | "warn" | "error"): void;
95
- beginAssistant(): AssistantView;
96
- /** port #60 (OPTIONAL): a collapsed reasoning block for the assistant message being streamed — its view
97
- * settles on done(); surfaces render a SIZE (tokens), never the text. A renderer without it gets one
98
- * system note per block from tui/reasoning-view.ts instead. */
99
- beginReasoning?(): AssistantView;
100
- toolStart(callId: string, tool: string, argsPreview: string): void;
101
- toolUpdate(callId: string, note: string): void;
102
- toolEnd(callId: string, ok: boolean, outputPreview: string, durationMs: number): void;
103
- /** modal approval; resolves deny on cancel/escape. `detail` (port #24): pre-rendered
104
- * unified diff of a pending edit/write, shown inside the overlay above the verdicts */
105
- askApproval(tool: string, argsPreview: string, detail?: string): Promise<ApprovalAnswer>;
106
- /** modal picker (session/turn navigators); resolves null on cancel/escape/stop */
107
- pickOne(items: PickItem[], title?: string): Promise<string | null>;
108
- /** modal question for the ask_user tool (port #33): options + a free-text entry when allowed.
109
- * Resolves the pick/typed text; null when the user declines, `signal` aborts (the run's
110
- * controller — the card must dismiss, never leak), or the UI stops. Implementations may
111
- * reject a SECOND concurrent ask with a clear error (the tool turns it into a failed result). */
112
- askQuestion(q: QuestionPrompt, signal?: AbortSignal): Promise<QuestionAnswer | null>;
113
- /** remove all transcript items (history replay after rewind/resume) */
114
- clearTranscript(): void;
115
- /** place text in the editor for edit-and-resubmit (pi sessions.md:106-116) */
116
- prefillEditor(text: string): void;
117
- setBusy(busy: boolean, label?: string): void;
118
- setStatus(info: StatusInfo): void;
119
- /** port #44 (OPTIONAL — FakeRenderer/PiTuiRenderer omit it): every RunEvent of the live run, delivered
120
- * as the FIRST statement of the app's event loop, BEFORE the toolStart/beginAssistant/addSystemNote
121
- * calls the same event triggers. A renderer that implements it (sextant) treats the event stream as
122
- * its source of truth for transcript rows and ignores the duplicate per-event calls while busy. */
123
- onEvent?(ev: RunEvent): void;
124
- /** port #44 (OPTIONAL): the runtime handles the sextant panels read — cwd, sessions dir, the ACTIVE
125
- * store, tasks, model + context window, usage math. Called exactly once by runTui, after runtime
126
- * construction and before start(). */
127
- attach?(ctx: SextantAttach): void;
128
- }
@@ -1,29 +0,0 @@
1
- /** Persisted RunEvent annotations → transcript lines (port #25 LOW-4). The loop persists a
2
- * compaction as a `kind: "event"` entry (SessionStore.appendEvent) right where it happened, and
3
- * the live TUI shows it as a system note; a resumed session (--resume, /resume, /sessions)
4
- * replays the SAME line at the same place, so "was this context compacted?" has one answer on
5
- * both paths. ONE wording, built here, used by app.ts (live) and session-cmd.ts replayTranscript
6
- * (replay) — never two strings to keep in step. Any other persisted event type renders nothing:
7
- * the live TUI shows nothing for a bare event either, and replay must never add a line the run
8
- * did not (context-drop compactions are yielded but not persisted — loop.ts:191 — so a resumed
9
- * session cannot show them; nothing to render). */
10
-
11
- import type { Entry } from "../core/session.ts";
12
- import type { Message, RunEvent } from "../core/types.ts";
13
-
14
- export type CompactionEvent = Extract<RunEvent, { type: "compaction" }>;
15
- /** SessionStore.appendEvent's entry shape — the non-message half of Entry */
16
- export type EventEntry = Exclude<Entry, Message>;
17
-
18
- /** the TUI's system note for a compaction — live (app.ts startRun) and replayed alike */
19
- export function compactionNote(ev: CompactionEvent): string {
20
- return `compacted (${ev.strategy}): ${ev.tokensBefore} → ${ev.tokensAfter} tokens`;
21
- }
22
-
23
- /** the transcript line for a persisted event entry, or null when the live TUI shows nothing for
24
- * it. Tolerant of a foreign/corrupt entry (session.ts never throws on shape; neither does replay). */
25
- export function replayMarkerLine(entry: EventEntry): string | null {
26
- const ev = entry.event as RunEvent | undefined;
27
- if (!ev || typeof ev !== "object") return null;
28
- return ev.type === "compaction" ? compactionNote(ev) : null;
29
- }