rovecode 0.3.2 → 0.4.0-beta.2

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 (491) hide show
  1. package/CHANGELOG.md +512 -0
  2. package/README.md +33 -45
  3. package/bin/rovecode.js +24 -0
  4. package/dist/cli/app-dybnr56b.js +2 -0
  5. package/dist/cli/ask-user-p8hq4xgj.js +2 -0
  6. package/dist/cli/auth-login-ewpgw5sm.js +2 -0
  7. package/dist/cli/auth-m8p9grty.js +2 -0
  8. package/dist/cli/bench-xv3ypwev.js +9 -0
  9. package/dist/cli/catalog-737wb2s0.js +2 -0
  10. package/dist/cli/cli-arhg40m0.js +2 -0
  11. package/dist/cli/client-cf2pxx8q.js +2 -0
  12. package/dist/cli/commands-3p7e4xxs.js +2 -0
  13. package/dist/cli/connect-3q93d7cb.js +2 -0
  14. package/dist/cli/context-cmd-eqxmxhzq.js +2 -0
  15. package/dist/cli/context-report-hbw9zfes.js +2 -0
  16. package/dist/cli/count-remote-mby98cd0.js +2 -0
  17. package/dist/cli/design-122y0axd.js +2 -0
  18. package/dist/cli/dispatch-b4egzvvh.js +2 -0
  19. package/dist/cli/doctor-x4jkv72e.js +3 -0
  20. package/dist/cli/executor-ftvg6tsy.js +2 -0
  21. package/dist/cli/export-pdgdhkch.js +2 -0
  22. package/dist/cli/files-cez9a96p.js +2 -0
  23. package/dist/cli/gauntlet-r3xxaszc.js +2 -0
  24. package/dist/cli/gauntlet-runner-r515m7kk.js +10 -0
  25. package/dist/cli/gauntlet-wave3-bnkjk2v2.js +5 -0
  26. package/dist/cli/gauntlet-wave4-acs9s60q.js +14 -0
  27. package/dist/cli/hashline-ewg5hbe3.js +2 -0
  28. package/dist/cli/http-n0kehsk8.js +5 -0
  29. package/dist/cli/index-z5qt1s76.js +2 -0
  30. package/dist/cli/install-80mp63kx.js +2 -0
  31. package/dist/cli/loop-12twjcat.js +2 -0
  32. package/dist/cli/main-01pv9206.js +4 -0
  33. package/dist/cli/main-0jys2ccn.js +3 -0
  34. package/dist/cli/main-1ztz6fkj.js +10 -0
  35. package/dist/cli/main-23q7cmww.js +9 -0
  36. package/dist/cli/main-2rzbexn2.js +3 -0
  37. package/dist/cli/main-2wyax8k9.js +9 -0
  38. package/dist/cli/main-2yeveeve.js +6 -0
  39. package/dist/cli/main-2z3dek0b.js +3 -0
  40. package/dist/cli/main-2zgsknth.js +3 -0
  41. package/dist/cli/main-45ejth3a.js +4 -0
  42. package/dist/cli/main-45rn3trk.js +22 -0
  43. package/dist/cli/main-4p4e2w7x.js +4 -0
  44. package/dist/cli/main-4y0tnfpa.js +16 -0
  45. package/dist/cli/main-5py0rkmc.js +4 -0
  46. package/dist/cli/main-6dtqmbt6.js +7 -0
  47. package/dist/cli/main-6h9x282m.js +4 -0
  48. package/dist/cli/main-6vjeds42.js +3 -0
  49. package/dist/cli/main-78gq4bt9.js +6 -0
  50. package/dist/cli/main-7jd5vh3x.js +4 -0
  51. package/dist/cli/main-7kt6r53y.js +4 -0
  52. package/dist/cli/main-8c1tbazx.js +58 -0
  53. package/dist/cli/main-9a9rnh47.js +19 -0
  54. package/dist/cli/main-9ht36z12.js +3 -0
  55. package/dist/cli/main-a2yfvcy9.js +7 -0
  56. package/dist/cli/main-a3f51n0x.js +5 -0
  57. package/dist/cli/main-b8zq261k.js +3 -0
  58. package/dist/cli/main-bxtvnf6d.js +13 -0
  59. package/dist/cli/main-edxc3yzt.js +4 -0
  60. package/dist/cli/main-evgz4mp5.js +21 -0
  61. package/dist/cli/main-f33fc5je.js +9 -0
  62. package/dist/cli/main-fvnpq46y.js +12 -0
  63. package/dist/cli/main-gbbty4d4.js +3 -0
  64. package/dist/cli/main-gth53dnt.js +25 -0
  65. package/dist/cli/main-hqbz10aw.js +9 -0
  66. package/dist/cli/main-hrrvcfan.js +38 -0
  67. package/dist/cli/main-hzwtsb2m.js +5 -0
  68. package/dist/cli/main-j7ttv0sd.js +34 -0
  69. package/dist/cli/main-jak598k9.js +5 -0
  70. package/dist/cli/main-kba6zeyd.js +6 -0
  71. package/dist/cli/main-kwwsz6rq.js +3 -0
  72. package/dist/cli/main-m8vm17zq.js +3 -0
  73. package/dist/cli/main-mg4f96e1.js +3 -0
  74. package/dist/cli/main-mg9b20ac.js +18 -0
  75. package/dist/cli/main-mgb9ccnx.js +3 -0
  76. package/dist/cli/main-mjt2p7aj.js +3 -0
  77. package/dist/cli/main-n6qrdbmy.js +3 -0
  78. package/dist/cli/main-na7wse0x.js +5 -0
  79. package/dist/cli/main-nqveez48.js +4 -0
  80. package/dist/cli/main-ntqef02r.js +10 -0
  81. package/dist/cli/main-nvc3yjay.js +136 -0
  82. package/dist/cli/main-p0cfn6nr.js +16 -0
  83. package/dist/cli/main-qj2djy17.js +19 -0
  84. package/dist/cli/main-qsevpgsv.js +3 -0
  85. package/dist/cli/main-qvarybsp.js +3 -0
  86. package/dist/cli/main-rebtt91r.js +5 -0
  87. package/dist/cli/main-rpg7h8mb.js +3 -0
  88. package/dist/cli/main-rsy72qmw.js +15 -0
  89. package/dist/cli/main-rvetps99.js +18 -0
  90. package/dist/cli/main-s4bb0jav.js +3 -0
  91. package/dist/cli/main-s9v8k74e.js +3 -0
  92. package/dist/cli/main-tjvwmscs.js +3 -0
  93. package/dist/cli/main-tkgarpjj.js +4 -0
  94. package/dist/cli/main-v8y60bb2.js +3 -0
  95. package/dist/cli/main-vhrrq337.js +3 -0
  96. package/dist/cli/main-vp2dfb7s.js +4 -0
  97. package/dist/cli/main-vqbr22sz.js +8 -0
  98. package/dist/cli/main-vxnwe5xx.js +18 -0
  99. package/dist/cli/main-wgph00xf.js +5 -0
  100. package/dist/cli/main-wk2csfnj.js +5 -0
  101. package/dist/cli/main-wm997zjx.js +3 -0
  102. package/dist/cli/main-wpkyraxh.js +3 -0
  103. package/dist/cli/main-wqt32p5x.js +4 -0
  104. package/dist/cli/main-x9ct6y1a.js +3 -0
  105. package/dist/cli/main-xfekqh9m.js +7 -0
  106. package/dist/cli/main-xt9zc3n6.js +7 -0
  107. package/dist/cli/main-xx2z3zh5.js +4 -0
  108. package/dist/cli/main-y5c82rxr.js +3 -0
  109. package/dist/cli/main-yrjt2sqt.js +14 -0
  110. package/dist/cli/main-ys6zj3yr.js +3 -0
  111. package/dist/cli/main-ywbxshqc.js +8 -0
  112. package/dist/cli/main-z13755t8.js +25 -0
  113. package/dist/cli/main-zc7pyrbj.js +4 -0
  114. package/dist/cli/main.js +279 -0
  115. package/dist/cli/market-cmd-bm5xvn9f.js +5 -0
  116. package/dist/cli/mcp-login-bthtfpt7.js +2 -0
  117. package/dist/cli/mcp-market-cmd-mbeshfyd.js +2 -0
  118. package/dist/cli/notify-54v5z9dz.js +2 -0
  119. package/dist/cli/oauth-g5gme95c.js +2 -0
  120. package/dist/cli/output-satndjap.js +16 -0
  121. package/dist/cli/profiles-sfhpbq3m.js +2 -0
  122. package/dist/cli/provider-config-hv3xtdt4.js +2 -0
  123. package/dist/cli/provider-kwzq6g84.js +2 -0
  124. package/dist/cli/registry-fh0hdnyn.js +2 -0
  125. package/dist/cli/registry-y1y8e94r.js +2 -0
  126. package/dist/cli/repl-t4z03mqq.js +11 -0
  127. package/dist/cli/resume-fqt4chg8.js +2 -0
  128. package/dist/cli/run-flags-rysbag9t.js +2 -0
  129. package/dist/cli/runtime-j19fjbsa.js +2 -0
  130. package/dist/cli/sandbox-config-g4qxd7y5.js +2 -0
  131. package/dist/cli/server-r0b6bksk.js +5 -0
  132. package/dist/cli/session-arg-txmn5g4x.js +2 -0
  133. package/dist/cli/session-ed250d9j.js +2 -0
  134. package/dist/cli/sessions-cmd-adw7svfn.js +7 -0
  135. package/dist/cli/settings-y9rzcqx8.js +2 -0
  136. package/dist/cli/setup-jmbr11j0.js +2 -0
  137. package/dist/cli/sextant-smoke-tcth0vea.js +5 -0
  138. package/dist/cli/skills-cmd-zbdy99v6.js +2 -0
  139. package/dist/cli/smoke-1bg937kx.js +8 -0
  140. package/dist/cli/start-chat-p01cdks3.js +12 -0
  141. package/dist/cli/stream-4wmyaypz.js +2 -0
  142. package/dist/cli/task-eg4s093s.js +2 -0
  143. package/dist/cli/tasks-12v9rr9k.js +2 -0
  144. package/dist/cli/thinking-a5ngvqyh.js +2 -0
  145. package/dist/cli/todo-1wxpcecx.js +2 -0
  146. package/dist/cli/tools-2ftsya7w.js +2 -0
  147. package/dist/cli/tools-x1tj4fxm.js +2 -0
  148. package/dist/cli/trust-cmd-hccxehzb.js +2 -0
  149. package/dist/cli/update-check-ygt3vd7m.js +2 -0
  150. package/dist/cli/update-cmd-v23qhr8c.js +2 -0
  151. package/dist/cli/voice-g1gtck92.js +2 -0
  152. package/dist/cli/webfetch-0nnrjgb5.js +2 -0
  153. package/dist/cli/websearch-f0vr2p7d.js +2 -0
  154. package/dist/cli/workspace-9rq1w4ta.js +2 -0
  155. package/dist/lib/index.js +62 -0
  156. package/dist/lib/models-index.json +1 -0
  157. package/dist/lib/plugins.js +6 -0
  158. package/dist/lib/providers.js +17 -0
  159. package/dist/lib/public-api.js +20 -0
  160. package/dist/rovecode.exe +4 -0
  161. package/package.json +38 -11
  162. package/bin/rovecode.ts +0 -21
  163. package/src/acp/server.ts +0 -374
  164. package/src/cli/auth-login.ts +0 -122
  165. package/src/cli/connect.ts +0 -244
  166. package/src/cli/context-cmd.ts +0 -199
  167. package/src/cli/dispatch.ts +0 -82
  168. package/src/cli/doctor.ts +0 -362
  169. package/src/cli/export.ts +0 -276
  170. package/src/cli/help.ts +0 -293
  171. package/src/cli/is-tui-invocation.ts +0 -8
  172. package/src/cli/main.ts +0 -583
  173. package/src/cli/market-cmd.ts +0 -658
  174. package/src/cli/mcp-login.ts +0 -141
  175. package/src/cli/mcp-market-cmd.ts +0 -302
  176. package/src/cli/output.ts +0 -382
  177. package/src/cli/repl.ts +0 -250
  178. package/src/cli/repomap-root.ts +0 -14
  179. package/src/cli/resume.ts +0 -57
  180. package/src/cli/run-flags.ts +0 -43
  181. package/src/cli/run-limits.ts +0 -78
  182. package/src/cli/runtime.ts +0 -931
  183. package/src/cli/session-arg.ts +0 -30
  184. package/src/cli/sessions-cmd.ts +0 -145
  185. package/src/cli/setup.ts +0 -153
  186. package/src/cli/skills-cmd.ts +0 -194
  187. package/src/cli/start-chat.ts +0 -65
  188. package/src/cli/trust-cmd.ts +0 -52
  189. package/src/coding/bash.ts +0 -148
  190. package/src/coding/checkpoints.ts +0 -327
  191. package/src/coding/diff.ts +0 -138
  192. package/src/coding/files.ts +0 -341
  193. package/src/coding/hashline.ts +0 -274
  194. package/src/coding/lsp-gate.ts +0 -254
  195. package/src/coding/lsp-servers.ts +0 -147
  196. package/src/coding/lsp.ts +0 -283
  197. package/src/coding/repomap-cache.ts +0 -99
  198. package/src/coding/repomap-files.ts +0 -192
  199. package/src/coding/repomap.ts +0 -481
  200. package/src/core/agents.ts +0 -255
  201. package/src/core/compaction.ts +0 -259
  202. package/src/core/config.ts +0 -289
  203. package/src/core/context-report.ts +0 -228
  204. package/src/core/context.ts +0 -60
  205. package/src/core/count-remote.ts +0 -107
  206. package/src/core/execpolicy-rules.ts +0 -196
  207. package/src/core/execpolicy.ts +0 -385
  208. package/src/core/executor.ts +0 -454
  209. package/src/core/guardrails.ts +0 -400
  210. package/src/core/hooks.ts +0 -411
  211. package/src/core/images.ts +0 -230
  212. package/src/core/intro.ts +0 -266
  213. package/src/core/loop.ts +0 -567
  214. package/src/core/modes.ts +0 -372
  215. package/src/core/orchestrator.ts +0 -245
  216. package/src/core/proc-group.ts +0 -48
  217. package/src/core/project-trust.ts +0 -98
  218. package/src/core/reflection.ts +0 -165
  219. package/src/core/sandbox-config.ts +0 -186
  220. package/src/core/session-id.ts +0 -24
  221. package/src/core/session-images.ts +0 -73
  222. package/src/core/session-ops.ts +0 -183
  223. package/src/core/session-text.ts +0 -29
  224. package/src/core/session.ts +0 -469
  225. package/src/core/settings.ts +0 -170
  226. package/src/core/tasks.ts +0 -646
  227. package/src/core/token-scale.ts +0 -108
  228. package/src/core/tools.ts +0 -309
  229. package/src/core/trust.ts +0 -104
  230. package/src/core/types.ts +0 -330
  231. package/src/core/update-check.ts +0 -171
  232. package/src/core/usage.ts +0 -204
  233. package/src/core/validate.ts +0 -121
  234. package/src/core/verify-gate.ts +0 -159
  235. package/src/core/verify.ts +0 -236
  236. package/src/core/voice.ts +0 -158
  237. package/src/core/win-job.ts +0 -183
  238. package/src/core/workspace.ts +0 -184
  239. package/src/design/audit.ts +0 -797
  240. package/src/design/direction.ts +0 -190
  241. package/src/design/rules.ts +0 -157
  242. package/src/eval/bench.ts +0 -150
  243. package/src/eval/gauntlet-runner.ts +0 -215
  244. package/src/eval/gauntlet-support.ts +0 -84
  245. package/src/eval/gauntlet-wave3.ts +0 -269
  246. package/src/eval/gauntlet-wave4.ts +0 -217
  247. package/src/eval/gauntlet.ts +0 -253
  248. package/src/index.ts +0 -17
  249. package/src/lanes/agy.ts +0 -95
  250. package/src/lanes/approval.ts +0 -24
  251. package/src/lanes/claude.ts +0 -129
  252. package/src/lanes/codex.ts +0 -127
  253. package/src/lanes/events.ts +0 -130
  254. package/src/lanes/job.ts +0 -142
  255. package/src/lanes/opencode.ts +0 -122
  256. package/src/lanes/process.ts +0 -184
  257. package/src/lanes/progress.ts +0 -183
  258. package/src/lanes/registry.ts +0 -178
  259. package/src/lanes/runner.ts +0 -124
  260. package/src/lanes/types.ts +0 -112
  261. package/src/market/catalogs/mcp-docs.json +0 -111
  262. package/src/market/catalogs/plugins.json +0 -111
  263. package/src/market/catalogs/skills.json +0 -478
  264. package/src/market/clone.ts +0 -72
  265. package/src/market/context-cost.ts +0 -121
  266. package/src/market/digest.ts +0 -106
  267. package/src/market/index.ts +0 -22
  268. package/src/market/install.ts +0 -578
  269. package/src/market/manifest.ts +0 -187
  270. package/src/market/prereq.ts +0 -145
  271. package/src/market/registry.ts +0 -363
  272. package/src/market/resolve.ts +0 -111
  273. package/src/market/types.ts +0 -236
  274. package/src/market/validate.ts +0 -227
  275. package/src/mcp/client.ts +0 -449
  276. package/src/mcp/config.ts +0 -252
  277. package/src/mcp/local-package.ts +0 -211
  278. package/src/mcp/market-catalog.ts +0 -84
  279. package/src/mcp/market-install.ts +0 -289
  280. package/src/mcp/market.ts +0 -362
  281. package/src/mcp/oauth.ts +0 -251
  282. package/src/mcp/prompts-resources.ts +0 -249
  283. package/src/mcp/shared.ts +0 -149
  284. package/src/mcp/status.ts +0 -67
  285. package/src/mcp/tools.ts +0 -275
  286. package/src/mcp/transport.ts +0 -122
  287. package/src/mcp/trust.ts +0 -25
  288. package/src/memory/blocks.ts +0 -278
  289. package/src/memory/recall.ts +0 -355
  290. package/src/memory/scope.ts +0 -182
  291. package/src/memory/store.ts +0 -105
  292. package/src/memory/tools.ts +0 -99
  293. package/src/plugins/cli.ts +0 -119
  294. package/src/plugins/discover.ts +0 -108
  295. package/src/plugins/index.ts +0 -50
  296. package/src/plugins/install.ts +0 -184
  297. package/src/plugins/load.ts +0 -124
  298. package/src/plugins/manifest.ts +0 -92
  299. package/src/plugins/state.ts +0 -83
  300. package/src/providers/auth.ts +0 -408
  301. package/src/providers/cache.ts +0 -223
  302. package/src/providers/catalog-local.ts +0 -160
  303. package/src/providers/catalog.ts +0 -421
  304. package/src/providers/middleware-context.ts +0 -86
  305. package/src/providers/middleware.ts +0 -373
  306. package/src/providers/model-list.ts +0 -23
  307. package/src/providers/oauth/common.ts +0 -105
  308. package/src/providers/oauth/device-code.ts +0 -107
  309. package/src/providers/oauth/github-copilot.ts +0 -146
  310. package/src/providers/oauth/loopback.ts +0 -158
  311. package/src/providers/oauth/openai.ts +0 -163
  312. package/src/providers/oauth/openrouter.ts +0 -89
  313. package/src/providers/oauth/pkce.ts +0 -45
  314. package/src/providers/oauth/registry.ts +0 -39
  315. package/src/providers/oauth/seam.ts +0 -89
  316. package/src/providers/profile-glm53.ts +0 -111
  317. package/src/providers/profile-sonnet5-persona.ts +0 -65
  318. package/src/providers/profile-sonnet5-voice.ts +0 -23
  319. package/src/providers/profiles.ts +0 -156
  320. package/src/providers/provider-config.ts +0 -311
  321. package/src/providers/registry.ts +0 -333
  322. package/src/providers/responses.ts +0 -209
  323. package/src/providers/retry.ts +0 -234
  324. package/src/providers/router.ts +0 -294
  325. package/src/providers/sse.ts +0 -26
  326. package/src/providers/stream-errors.ts +0 -117
  327. package/src/providers/stream.ts +0 -566
  328. package/src/providers/thinking.ts +0 -189
  329. package/src/providers/wire-messages.ts +0 -129
  330. package/src/providers/wire-responses.ts +0 -79
  331. package/src/providers/wire-select.ts +0 -53
  332. package/src/server/http.ts +0 -291
  333. package/src/server/openapi.ts +0 -246
  334. package/src/sextant/card-hits.ts +0 -102
  335. package/src/sextant/card-keys.ts +0 -55
  336. package/src/sextant/context-source.ts +0 -157
  337. package/src/sextant/crew-cards.ts +0 -350
  338. package/src/sextant/draw-agents.ts +0 -273
  339. package/src/sextant/draw-code.ts +0 -388
  340. package/src/sextant/draw-context.ts +0 -222
  341. package/src/sextant/draw-frame.ts +0 -164
  342. package/src/sextant/draw-market.ts +0 -573
  343. package/src/sextant/draw-messages.ts +0 -386
  344. package/src/sextant/draw-pet.ts +0 -230
  345. package/src/sextant/draw-plan.ts +0 -187
  346. package/src/sextant/draw-tabs.ts +0 -85
  347. package/src/sextant/draw-util.ts +0 -65
  348. package/src/sextant/draw-wizard.ts +0 -378
  349. package/src/sextant/engine.ts +0 -230
  350. package/src/sextant/frame-hits.ts +0 -25
  351. package/src/sextant/frame.ts +0 -101
  352. package/src/sextant/git-status.ts +0 -197
  353. package/src/sextant/grid.ts +0 -59
  354. package/src/sextant/input.ts +0 -119
  355. package/src/sextant/keys.ts +0 -521
  356. package/src/sextant/layout.ts +0 -86
  357. package/src/sextant/local-commands.ts +0 -169
  358. package/src/sextant/market-source.ts +0 -287
  359. package/src/sextant/mentions.ts +0 -200
  360. package/src/sextant/message-hits.ts +0 -26
  361. package/src/sextant/model.ts +0 -387
  362. package/src/sextant/overlays.ts +0 -456
  363. package/src/sextant/panel-hits.ts +0 -38
  364. package/src/sextant/pet.ts +0 -399
  365. package/src/sextant/screen.ts +0 -324
  366. package/src/sextant/scroll-hits.ts +0 -66
  367. package/src/sextant/scrollbar.ts +0 -82
  368. package/src/sextant/sextant-bridge.ts +0 -174
  369. package/src/sextant/sextant-cards.ts +0 -142
  370. package/src/sextant/sextant-diff-base.ts +0 -63
  371. package/src/sextant/sextant-files.ts +0 -154
  372. package/src/sextant/sextant-frame-loop.ts +0 -335
  373. package/src/sextant/sextant-renderer.ts +0 -574
  374. package/src/sextant/sextant-repo.ts +0 -140
  375. package/src/sextant/theme.ts +0 -66
  376. package/src/sextant/tool-rows.ts +0 -189
  377. package/src/sextant/types.ts +0 -493
  378. package/src/skills/index.ts +0 -387
  379. package/src/skills/pack.ts +0 -220
  380. package/src/skills/spec.ts +0 -162
  381. package/src/skills/tools.ts +0 -69
  382. package/src/skills/versioned.ts +0 -227
  383. package/src/telemetry/otel-export.ts +0 -122
  384. package/src/telemetry/otel-lanes.ts +0 -89
  385. package/src/telemetry/otel-logs.ts +0 -131
  386. package/src/telemetry/otel-metrics.ts +0 -136
  387. package/src/telemetry/otel.ts +0 -397
  388. package/src/telemetry/otlp.ts +0 -76
  389. package/src/tools/ask-user.ts +0 -156
  390. package/src/tools/bash-bg.ts +0 -94
  391. package/src/tools/bash-jobs.ts +0 -237
  392. package/src/tools/design.ts +0 -151
  393. package/src/tools/evalcell.ts +0 -338
  394. package/src/tools/html-text.ts +0 -139
  395. package/src/tools/provider.ts +0 -149
  396. package/src/tools/task.ts +0 -250
  397. package/src/tools/todo.ts +0 -320
  398. package/src/tools/webfetch.ts +0 -332
  399. package/src/tools/websearch.ts +0 -359
  400. package/src/tui/agents-cmd.ts +0 -41
  401. package/src/tui/app.ts +0 -749
  402. package/src/tui/attach.ts +0 -127
  403. package/src/tui/boot-notes.ts +0 -41
  404. package/src/tui/builtin-prompts.ts +0 -59
  405. package/src/tui/checkpoints-cmd.ts +0 -70
  406. package/src/tui/clipboard-image.ts +0 -81
  407. package/src/tui/clipboard.ts +0 -78
  408. package/src/tui/commands.ts +0 -283
  409. package/src/tui/config-view.ts +0 -53
  410. package/src/tui/context-cmds.ts +0 -282
  411. package/src/tui/cost.ts +0 -108
  412. package/src/tui/crash-guard.ts +0 -173
  413. package/src/tui/focus-terminal.ts +0 -34
  414. package/src/tui/git-cmds.ts +0 -273
  415. package/src/tui/git-plain.ts +0 -58
  416. package/src/tui/info-cmd.ts +0 -150
  417. package/src/tui/input-plain.ts +0 -76
  418. package/src/tui/mcp-cmd.ts +0 -128
  419. package/src/tui/memory-note.ts +0 -77
  420. package/src/tui/modes-cmd.ts +0 -45
  421. package/src/tui/notify-seq.ts +0 -100
  422. package/src/tui/notify.ts +0 -318
  423. package/src/tui/overlays.ts +0 -97
  424. package/src/tui/pi-renderer.ts +0 -428
  425. package/src/tui/providers-cmd.ts +0 -377
  426. package/src/tui/reasoning-view.ts +0 -56
  427. package/src/tui/renderer.ts +0 -128
  428. package/src/tui/replay-marker.ts +0 -29
  429. package/src/tui/session-cmd.ts +0 -148
  430. package/src/tui/session-manage.ts +0 -95
  431. package/src/tui/sextant-attach.ts +0 -102
  432. package/src/tui/sextant-io.ts +0 -202
  433. package/src/tui/sextant-smoke.ts +0 -110
  434. package/src/tui/shell-cmd.ts +0 -158
  435. package/src/tui/smoke.ts +0 -72
  436. package/src/tui/staged-terminal.ts +0 -50
  437. package/src/tui/startup.ts +0 -12
  438. package/src/tui/theme.ts +0 -59
  439. package/src/tui/todo-label.ts +0 -7
  440. package/src/tui/trust-card.ts +0 -107
  441. package/src/tui/tui-commands.ts +0 -87
  442. package/tsconfig.json +0 -30
  443. package/vendor/pi-tui/LICENSE +0 -21
  444. package/vendor/pi-tui/PATCHES.md +0 -12
  445. package/vendor/pi-tui/PROVENANCE.md +0 -12
  446. package/vendor/pi-tui/README.upstream.md +0 -854
  447. package/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  448. package/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  449. package/vendor/pi-tui/src/alt-screen-search.ts +0 -158
  450. package/vendor/pi-tui/src/autocomplete.ts +0 -827
  451. package/vendor/pi-tui/src/components/alt-screen-flash.ts +0 -52
  452. package/vendor/pi-tui/src/components/box.ts +0 -138
  453. package/vendor/pi-tui/src/components/cancellable-loader.ts +0 -41
  454. package/vendor/pi-tui/src/components/editor.ts +0 -2364
  455. package/vendor/pi-tui/src/components/h-stack.ts +0 -45
  456. package/vendor/pi-tui/src/components/image.ts +0 -128
  457. package/vendor/pi-tui/src/components/input.ts +0 -448
  458. package/vendor/pi-tui/src/components/loader.ts +0 -93
  459. package/vendor/pi-tui/src/components/markdown.ts +0 -1016
  460. package/vendor/pi-tui/src/components/scroll-view.ts +0 -217
  461. package/vendor/pi-tui/src/components/select-list.ts +0 -230
  462. package/vendor/pi-tui/src/components/settings-list.ts +0 -277
  463. package/vendor/pi-tui/src/components/spacer.ts +0 -29
  464. package/vendor/pi-tui/src/components/stack.ts +0 -155
  465. package/vendor/pi-tui/src/components/text.ts +0 -108
  466. package/vendor/pi-tui/src/components/truncated-text.ts +0 -66
  467. package/vendor/pi-tui/src/components/v-stack.ts +0 -34
  468. package/vendor/pi-tui/src/editor-component.ts +0 -75
  469. package/vendor/pi-tui/src/fuzzy.ts +0 -138
  470. package/vendor/pi-tui/src/index.ts +0 -149
  471. package/vendor/pi-tui/src/keybindings.ts +0 -321
  472. package/vendor/pi-tui/src/keys.ts +0 -1402
  473. package/vendor/pi-tui/src/kill-ring.ts +0 -47
  474. package/vendor/pi-tui/src/latex.ts +0 -1381
  475. package/vendor/pi-tui/src/layout-node.ts +0 -52
  476. package/vendor/pi-tui/src/layout.ts +0 -411
  477. package/vendor/pi-tui/src/native-modifiers.ts +0 -60
  478. package/vendor/pi-tui/src/native-module-path.ts +0 -32
  479. package/vendor/pi-tui/src/stdin-buffer.ts +0 -445
  480. package/vendor/pi-tui/src/terminal-colors.ts +0 -74
  481. package/vendor/pi-tui/src/terminal-image.ts +0 -701
  482. package/vendor/pi-tui/src/terminal.ts +0 -554
  483. package/vendor/pi-tui/src/tui-alt-screen.ts +0 -1379
  484. package/vendor/pi-tui/src/tui-main-screen.ts +0 -655
  485. package/vendor/pi-tui/src/tui.ts +0 -1264
  486. package/vendor/pi-tui/src/undo-stack.ts +0 -29
  487. package/vendor/pi-tui/src/utils.ts +0 -1327
  488. package/vendor/pi-tui/src/word-navigation.ts +0 -118
  489. package/vendor/pi-tui/test/test-themes.ts +0 -39
  490. package/vendor/pi-tui/test/virtual-terminal.ts +0 -219
  491. /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
- }