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,148 +0,0 @@
1
- /** TUI session navigation (port #2 session tree), extracted from app.ts for the ADR-002
2
- * cap: /sessions + /resume pick or resolve a session to switch to, /rewind (alias /tree)
3
- * jumps to an earlier turn for edit-and-resubmit, /new branches back to the session
4
- * start. The CALLER owns the swappable store and the rebind routine (switchSession), so
5
- * store reads and switches run through the injected ctx — same shape as checkpoints-cmd.
6
- * Also home to the pure session helpers the app calls around a switch: transcript replay,
7
- * usage recount, and the `--resume <prefix>` boot resolution (wiring pass, ADR-002 cap). */
8
-
9
- import { partsText } from "../core/loop.ts";
10
- import { listSessions, type SessionStore } from "../core/session.ts";
11
- import { ambiguityMessage, matchSessions } from "../core/session-ops.ts";
12
- import { userTurnLine } from "./attach.ts";
13
- import { replayLabel } from "./modes-cmd.ts";
14
- import { replayMarkerLine } from "./replay-marker.ts";
15
- import { replayShellRecord } from "./shell-cmd.ts";
16
- import type { Renderer } from "./renderer.ts";
17
- import { randomUUID } from "node:crypto";
18
-
19
- /** Re-render the whole transcript from the active session path (boot replay, /resume, /rewind,
20
- * /new, checkpoint restores). Tool calls replay as start+end card pairs; mode switches render
21
- * as a human line (port #20 LOW-3), never the raw <mode_notice> XML the entry carries; user
22
- * turns carry their image chips (port #34), so an image-only turn is not a blank line; persisted
23
- * compaction events replay as the live run's note (port #25 LOW-4, replay-marker.ts). */
24
- export function replayTranscript(renderer: Renderer, store: SessionStore): void {
25
- renderer.clearTranscript();
26
- for (const m of store.path()) {
27
- if (!("role" in m)) { const line = replayMarkerLine(m); if (line !== null) renderer.addSystemNote(line); continue; } // event entry (appendEvent): marker or nothing
28
- const text = partsText(m.parts);
29
- // a `!cmd` record is a user message in the store, but it replays as the typed line plus its bash card pair
30
- // (tui/shell-cmd.ts) rather than as the raw <user_shell_command> block the model reads
31
- if (m.role === "user" && replayShellRecord(renderer, text)) continue;
32
- if (m.role === "user") { const line = userTurnLine(text, m.parts); if (line) renderer.addUser(line); }
33
- else if (m.role === "assistant") {
34
- if (text) { const v = renderer.beginAssistant(); v.append(text); v.done(); }
35
- for (const p of m.parts) {
36
- if (p.kind === "tool_call") renderer.toolStart(p.id, p.tool, JSON.stringify(p.args).slice(0, 120));
37
- }
38
- } else if (m.role === "tool") {
39
- for (const p of m.parts) {
40
- if (p.kind === "tool_result") renderer.toolEnd(p.callId, p.ok, p.output.slice(0, 160).replace(/\n/g, " ⏎ "), 0);
41
- }
42
- } else if (m.role === "system" && text) renderer.addSystemNote(replayLabel(m, text));
43
- }
44
- }
45
-
46
- /** Token usage summed over the active path — the status line's counters. */
47
- export function usageOf(store: SessionStore): { tokensIn: number; tokensOut: number } {
48
- let tokensIn = 0, tokensOut = 0;
49
- for (const m of store.messages()) { tokensIn += m.usage?.input ?? 0; tokensOut += m.usage?.output ?? 0; }
50
- return { tokensIn, tokensOut };
51
- }
52
-
53
- /** The in-TUI /resume rule (matchSessions, core/session-ops.ts — the same one `--resume`, `trace`, `export` and the
54
- * `sessions` verbs use): a unique match resolves, an AMBIGUOUS prefix must not silently pick one — start fresh (id
55
- * undefined) and say so in `warn`. The CLI's `--resume <id>` no longer comes through here: cli/resume.ts refuses an
56
- * unknown or ambiguous id before the TUI boots (2026-09-07). */
57
- export function resolveBootSession(sessionsDir: string, id: string | undefined): { id: string | undefined; warn?: string } {
58
- if (id === undefined) return { id };
59
- const pre = matchSessions(listSessions(sessionsDir, { includeHollow: true }), id);
60
- if (pre.length === 1) return { id: pre[0]!.id };
61
- if (pre.length > 1) return { id: undefined, warn: `"${id}" matches ${pre.length} sessions — started fresh; use /resume to pick one` };
62
- return { id };
63
- }
64
-
65
- export interface SessionCmdCtx {
66
- renderer: Renderer;
67
- /** the run's cwd — `/sessions delete` removes the session's checkpoints shadow dir under it (session-manage.ts) */
68
- cwd: string;
69
- /** <cwd>/.rovecode/sessions — where listSessions looks */
70
- sessionsDir: string;
71
- busy(): boolean;
72
- /** the ACTIVE session store, read live: /sessions and a root /rewind swap it */
73
- store(): SessionStore;
74
- /** rebind the app to session id (store, memory, mode) and replay it; announce defaults on */
75
- switchSession(id: string, announce?: boolean): void;
76
- /** re-render the whole transcript from the active session path */
77
- replayHistory(): void;
78
- /** recount token usage from the active store */
79
- refreshUsage(): void;
80
- pushStatus(): void;
81
- }
82
-
83
- /** /rewind (alias /tree) — pick an earlier turn in the overlay; Enter branches the session
84
- * to before that turn and prefills the editor with its FULL text for edit-and-resubmit. */
85
- export async function cmdRewind(ctx: SessionCmdCtx): Promise<void> {
86
- if (ctx.busy()) { ctx.renderer.addSystemNote("finish or interrupt the run first (Esc)", "warn"); return; }
87
- const points = ctx.store().turnPoints();
88
- if (points.length === 0) { ctx.renderer.addSystemNote("nothing to rewind — no turns yet"); return; }
89
- const items = [...points].reverse().map((p) => ({
90
- value: p.entryId,
91
- label: `#${p.index} ${p.text}`,
92
- description: p.branches > 0 ? `◆ ${p.branches} other branch${p.branches > 1 ? "es" : ""}` : undefined,
93
- }));
94
- const picked = await ctx.renderer.pickOne(items, "rewind to a turn (Enter = edit & resubmit, Esc = cancel)");
95
- if (!picked) { ctx.replayHistory(); return; } // cancel: clear the overlay title note
96
- const point = points.find((p) => p.entryId === picked);
97
- if (!point) return;
98
- if (point.parentId === null) {
99
- // pi resets the leaf to an empty conversation (sessions.md:116); root reset would need
100
- // core support — v1 approximates it with a fresh session, old one untouched
101
- ctx.switchSession(randomUUID(), false);
102
- ctx.renderer.addSystemNote("rewound to the start — fresh session, previous one kept");
103
- } else {
104
- if (!ctx.store().branch(point.parentId)) { ctx.renderer.addSystemNote("rewind failed: turn not found", "error"); return; }
105
- ctx.replayHistory();
106
- ctx.renderer.addSystemNote(`rewound to before turn #${point.index} — edit and resubmit (branch kept)`);
107
- }
108
- ctx.renderer.prefillEditor(point.fullText); // FULL text, never the ≤80-char overlay label
109
- ctx.pushStatus();
110
- }
111
-
112
- /** /sessions — pick a previous session in the overlay; /resume <id> resolves an exact id
113
- * or a UNIQUE prefix directly (an ambiguous prefix must not silently pick one). */
114
- export async function cmdSessions(ctx: SessionCmdCtx, directId?: string): Promise<void> {
115
- if (ctx.busy()) { ctx.renderer.addSystemNote("finish or interrupt the run first (Esc)", "warn"); return; }
116
- const all = listSessions(ctx.sessionsDir); // the picker: sessions that hold something (hollow dirs stay out of the list)
117
- if (directId) {
118
- // the ONE matching rule (core/session-ops.ts): exact id wins outright; a prefix must match exactly ONE session
119
- // — resolving an ambiguous prefix silently to the first hit resumed the wrong session
120
- const matches = matchSessions(listSessions(ctx.sessionsDir, { includeHollow: true }), directId);
121
- if (matches.length === 1) ctx.switchSession(matches[0]!.id);
122
- else if (matches.length > 1) ctx.renderer.addSystemNote(ambiguityMessage(directId, matches), "warn");
123
- else ctx.renderer.addSystemNote(`no session matching "${directId}"`, "warn");
124
- return;
125
- }
126
- const items = all.slice(0, 20).map((s) => ({
127
- value: s.id,
128
- label: s.title ?? (s.preview || "(empty session)"), // a title stands in for the first prompt, as `rovecode sessions list` does (cli/sessions-cmd.ts) — otherwise /sessions rename is invisible where you resume
129
- description: `${new Date(s.updatedAt).toLocaleString()} · ${s.entryCount} entries · ${s.id.slice(0, 8)}${s.id === ctx.store().id ? " · current" : ""}`,
130
- }));
131
- if (items.length === 0) { ctx.renderer.addSystemNote("no sessions found"); return; }
132
- const picked = await ctx.renderer.pickOne(items, "resume a session (Esc = cancel)");
133
- if (picked && picked !== ctx.store().id) ctx.switchSession(picked);
134
- else if (!picked) ctx.replayHistory(); // cancel: clear the overlay title note
135
- }
136
-
137
- /** /new — branch the leaf back to the session's first entry; the old turns stay in the
138
- * tree. Synchronous on purpose: no overlay, nothing to await. */
139
- export function cmdNew(ctx: SessionCmdCtx): void {
140
- // busy gate (same as /rewind //sessions): moving the leaf mid-run would make the
141
- // run's next append chain off a moved leaf while its parentId points elsewhere
142
- if (ctx.busy()) { ctx.renderer.addSystemNote("finish or interrupt the run first (Esc)", "warn"); return; }
143
- const store = ctx.store();
144
- if (store.branch(store.messages()[0]?.id ?? "")) {
145
- ctx.replayHistory(); ctx.refreshUsage(); ctx.pushStatus();
146
- ctx.renderer.addSystemNote("branched to session start");
147
- } else ctx.renderer.addSystemNote("nothing to branch — no turns yet");
148
- }
@@ -1,95 +0,0 @@
1
- /** TUI `/sessions <verb>` (aion port #84): rename · delete · fork · search over core/session-ops.ts — the same ops as
2
- * the headless `rovecode sessions …` (cli/sessions-cmd.ts, 5ceb21e), through the SessionCmdCtx seam app.ts already hands
3
- * the session navigator (session-cmd.ts), so the classic and sextant surfaces share it via app.ts handleSlash. Rules:
4
- * - every verb sits behind the /rewind busy gate (moving or removing session state mid-run is refused);
5
- * - `rename <title…>` titles the CURRENT session through the LIVE store instance (`ctx.store().patchMeta`) — a second
6
- * SessionStore on the same dir would be clobbered by this instance's next persistLeaf (/new, /rewind);
7
- * - `delete <id|prefix>` resolves first, shows ONE askApproval card (deny → nothing removed); deleting the ACTIVE
8
- * session switches the app to a fresh session first (the root-rewind pattern of session-cmd.ts cmdRewind) so no
9
- * live store points at a removed dir; then session-ops.deleteSession removes the dir AND its checkpoints shadow
10
- * repo — a half-delete leaves the space used with nothing pointing at it, so the test pins the shadow dir too;
11
- * - `fork [<id|prefix>]` (default: the current session) forks and switches to the fork (announced, transcript replayed);
12
- * - `search <terms…>` opens pickOne over the hits (label = preview, description = title · id8 · time); Enter switches
13
- * to the hit's session, Esc replays the current transcript (the /sessions picker's cancel rule).
14
- * Bare `/sessions` stays the picker (cmdSessions). `--plain` has none of this (README honesty). Pattern sources: see
15
- * core/session-ops.ts (opencode MIT session.ts fork / remove / setTitle; codex Apache-2.0 DeleteConfirmation, pattern only). */
16
-
17
- import { randomUUID } from "node:crypto";
18
- import { deleteSession, forkSession, oneLineTitle, resolveSession, searchSessions } from "../core/session-ops.ts";
19
- import { cmdSessions, type SessionCmdCtx } from "./session-cmd.ts";
20
-
21
- const BUSY = "finish or interrupt the run first (Esc)";
22
- const USAGE = "/sessions rename <title…> | delete <id|prefix> | fork [<id|prefix>] | search <terms…>";
23
-
24
- /** app.ts `case "sessions"`: `arg` is the collapsed remainder after `/sessions` */
25
- export async function cmdSessionsVerb(ctx: SessionCmdCtx, arg: string): Promise<void> {
26
- const [verb, ...rest] = arg.split(/\s+/).filter(Boolean);
27
- if (verb === undefined) return cmdSessions(ctx); // bare /sessions: the picker, unchanged (it carries its own busy gate)
28
- if (ctx.busy()) { ctx.renderer.addSystemNote(BUSY, "warn"); return; }
29
- switch (verb) {
30
- case "rename": return rename(ctx, rest.join(" "));
31
- case "delete": return remove(ctx, rest[0]);
32
- case "fork": return fork(ctx, rest[0]);
33
- case "search": return search(ctx, rest.join(" "));
34
- default: ctx.renderer.addSystemNote(`unknown /sessions verb "${verb}" — ${USAGE}`, "warn");
35
- }
36
- }
37
-
38
- function rename(ctx: SessionCmdCtx, raw: string): void {
39
- const title = oneLineTitle(raw);
40
- if (title === undefined) { ctx.renderer.addSystemNote("usage: /sessions rename <title…>", "warn"); return; }
41
- const store = ctx.store(); // the LIVE instance — its later persistLeaf carries the title forward
42
- store.patchMeta({ title });
43
- ctx.renderer.addSystemNote(`session ${store.id.slice(0, 8)} titled "${title}"`);
44
- }
45
-
46
- async function remove(ctx: SessionCmdCtx, ref: string | undefined): Promise<void> {
47
- if (ref === undefined) { ctx.renderer.addSystemNote("usage: /sessions delete <id|prefix>", "warn"); return; }
48
- const found = resolveSession(ctx.sessionsDir, ref);
49
- if (!found.ok) { ctx.renderer.addSystemNote(found.error, "warn"); return; }
50
- const s = found.summary;
51
- const active = found.id === ctx.store().id;
52
- const label = s.title ?? (s.preview || "(empty session)");
53
- const answer = await ctx.renderer.askApproval(
54
- "sessions delete",
55
- `${s.id.slice(0, 8)} · ${label} · ${s.entryCount} entries${active ? " · the current session" : ""}`,
56
- "removes the session directory (entries, meta, attachments, todos) and its checkpoints shadow repo — not undoable",
57
- );
58
- if (answer === "deny") { ctx.renderer.addSystemNote("delete cancelled — nothing removed", "warn"); return; }
59
- if (active) {
60
- // the root-rewind pattern (session-cmd.ts cmdRewind): the app moves to a fresh session BEFORE the old dir goes
61
- ctx.switchSession(randomUUID(), false);
62
- ctx.renderer.addSystemNote("deleting the active session — switched to a fresh one first");
63
- }
64
- const { removed } = deleteSession(ctx.cwd, ctx.sessionsDir, found.id);
65
- ctx.renderer.addSystemNote(`deleted session ${found.id.slice(0, 8)} (${removed.length} path${removed.length === 1 ? "" : "s"} removed)`);
66
- }
67
-
68
- function fork(ctx: SessionCmdCtx, ref: string | undefined): void {
69
- const found = resolveSession(ctx.sessionsDir, ref ?? ctx.store().id);
70
- if (!found.ok) { ctx.renderer.addSystemNote(found.error, "warn"); return; }
71
- let r: { id: string; from: string; title: string };
72
- try { r = forkSession(ctx.sessionsDir, found.summary); }
73
- catch (e) { ctx.renderer.addSystemNote(e instanceof Error ? e.message : String(e), "warn"); return; } // over FORK_MAX_ATTACHMENT_BYTES
74
- ctx.switchSession(r.id); // rebinds store / memory / mode / checkpoints, replays the copied transcript, announces
75
- ctx.renderer.addSystemNote(`forked ${r.from.slice(0, 8)} → ${r.id.slice(0, 8)} "${r.title}"`);
76
- }
77
-
78
- async function search(ctx: SessionCmdCtx, raw: string): Promise<void> {
79
- const query = raw.trim();
80
- if (query === "") { ctx.renderer.addSystemNote("usage: /sessions search <terms…>", "warn"); return; }
81
- const rows = searchSessions(ctx.sessionsDir, query, 10);
82
- if (rows.length === 0) { ctx.renderer.addSystemNote(`no matches for "${query}"`); return; }
83
- const current = ctx.store().id;
84
- const items = rows.map((r, i) => ({
85
- value: String(i), // several hits may share a session: the index is the unique pick value
86
- label: r.preview || r.title || "(empty session)",
87
- description: `${r.title !== undefined ? `${r.title} · ` : ""}${r.sessionId.slice(0, 8)}${r.sessionId === current ? " · current" : ""} · ${new Date(r.timestamp).toLocaleString()}`,
88
- }));
89
- const picked = await ctx.renderer.pickOne(items, "search hits (Enter = resume, Esc = cancel)");
90
- if (picked === null) { ctx.replayHistory(); return; } // cancel: clear the overlay title note
91
- const row = rows[Number(picked)];
92
- if (row === undefined) return;
93
- if (row.sessionId === current) { ctx.renderer.addSystemNote("that hit is in the current session"); return; }
94
- ctx.switchSession(row.sessionId);
95
- }
@@ -1,102 +0,0 @@
1
- /** Port #44: the attach context the app hands a Renderer that implements `attach` (the sextant surface)
2
- * — extracted from app.ts for the ADR-002 line cap. The panels read the runtime through these closures
3
- * ONLY: the active store (swapped by /sessions, /resume and a root /rewind — read live, never captured),
4
- * the task manager, the current mode's model, the catalog's context window and the /cost math over the
5
- * active transcript (tui/cost.ts sessionUsage — priced per message at its origin model). */
6
-
7
- import type { SessionStore } from "../core/session.ts";
8
- import type { TaskManager } from "../core/tasks.ts";
9
- import type { ModelCatalog } from "../providers/catalog.ts";
10
- import type { SextantAttach } from "../sextant/types.ts";
11
- import type { LiveRuntime } from "../sextant/context-source.ts";
12
- import { sessionUsage } from "./cost.ts";
13
- import { checkImageCount, loadImageAttachment } from "../core/images.ts";
14
-
15
- /** slash names the sextant surface handles itself before onSubmit (keys.ts runLocal — the future
16
- * src/sextant/local-commands.ts); reserved against custom commands like the built-ins, so a
17
- * `.rovecode/commands/theme.md` warns and loses instead of silently never being reachable. */
18
- export const SEXTANT_LOCAL_NAMES: readonly string[] = ["theme", "open", "diff", "focus", "agents", "notices", "context"];
19
-
20
- export interface AttachSources {
21
- cwd: string;
22
- sessionsDir: string;
23
- /** the ACTIVE store, read live */
24
- store(): SessionStore;
25
- tasks: TaskManager;
26
- /** the current mode's model */
27
- model(): { provider: string; model: string };
28
- catalog: ModelCatalog;
29
- /** the LIVE runtime, for /context. A function rather than a value: /sessions and /resume swap what is
30
- * underneath, and a captured runtime would report on the session the human left. Returning null is
31
- * allowed and means the panel says its total is a floor. */
32
- runtime?: () => LiveRuntime | null;
33
- /** `--pet <name>` */
34
- petName?: string;
35
- /** the connect wizard (draw-wizard.ts): the provider registry + credentials, behind the same
36
- * live-runtime optionality as `runtime` — a surface without them degrades to honest errors. */
37
- wizard?: {
38
- providers(): { key: string; label: string; configured?: boolean; local?: boolean; url?: "openai" | "anthropic" }[];
39
- register(id: string, url: string, protocol: "openai" | "anthropic"): { ok: boolean; error?: string };
40
- storeKey(provider: string, secret: string): { ok: boolean; error?: string };
41
- models(provider: string): Promise<{ id: string; note?: string }[]>;
42
- /** the model step's activate answer: pin the checked rows as the active list (registry
43
- * setModels — spec.models), empty = un-pin ("use them all"); makeDefault also switches */
44
- activateModels(provider: string, models: readonly string[], makeDefault?: string): { ok: boolean; error?: string; models?: string[] };
45
- test(provider: string, model: string): Promise<{ ok: boolean; detail: string }>;
46
- };
47
- }
48
-
49
- export function buildSextantAttach(a: AttachSources): SextantAttach {
50
- return {
51
- cwd: a.cwd,
52
- sessionsDir: a.sessionsDir,
53
- store: () => ({ id: a.store().id }),
54
- tasks: a.tasks,
55
- model: a.model,
56
- contextWindow: () => { const m = a.model(); return a.catalog.lookup(m.provider, m.model)?.contextWindow; },
57
- usage: () => sessionUsage(a.store().messages(), a.catalog, a.model()),
58
- // /context counts the real transcript against the real catalog, and asks the live runtime for the
59
- // system prompt and the tool schemas — the two rows a transcript cannot know and a fresh window is
60
- // mostly made of. The tier travels with the pricing, or a long xAI turn is billed at half rate.
61
- contextInputs: () => ({
62
- messages: a.store().messages(),
63
- lookup: (r) => {
64
- const info = a.catalog.lookup(r.provider, r.model);
65
- if (!info) return undefined;
66
- return {
67
- ...(info.contextWindow !== undefined ? { contextWindow: info.contextWindow } : {}),
68
- ...(info.pricing ? { pricing: info.pricing } : {}),
69
- ...(info.tier ? { tier: info.tier } : {}),
70
- };
71
- },
72
- runtime: a.runtime?.() ?? null,
73
- }),
74
- // /market installs an MCP server into a file this session already read; without this the only way to
75
- // reach it was to quit and start again, which is a poor answer to "I just installed it"
76
- reloadMcp: async () => { const rt = a.runtime?.(); return (await rt?.reloadMcp?.()) ?? { added: [], removed: [], failed: [], skipped: [] }; },
77
- // the images staged for the next message (tui/attach.ts /attach, /paste) — read live, the store owns them
78
- staged: () => a.store().stagedAttachments.map((p) => p.name ?? "image"),
79
- // port #54: an @image mention stages onto the SAME store stage /attach writes — one stage, one cap
80
- // count, one chip row. The note comes from the expansion (sextant/mentions.ts); the caps and the
81
- // magic-byte sniff are loadImageAttachment's, the same seam /attach runs through.
82
- attachImage: (abs) => {
83
- const store = a.store();
84
- const loaded = loadImageAttachment(abs);
85
- if ("error" in loaded) return;
86
- const staged = store.stagedAttachments;
87
- if (checkImageCount(staged.length + 1) !== undefined) return;
88
- store.stageAttachments([...staged, loaded]);
89
- },
90
- // the connect wizard's seams — absent when the surface has no wizard sources, and the
91
- // overlay's own degradation covers that
92
- ...(a.wizard !== undefined ? {
93
- wizardProviders: () => a.wizard!.providers(),
94
- wizardRegister: (id: string, url: string, protocol: "openai" | "anthropic") => a.wizard!.register(id, url, protocol),
95
- wizardStoreKey: (provider: string, secret: string) => a.wizard!.storeKey(provider, secret),
96
- wizardModels: (provider: string) => a.wizard!.models(provider),
97
- wizardActivateModels: (provider: string, models: readonly string[], makeDefault?: string) => a.wizard!.activateModels(provider, models, makeDefault),
98
- wizardTest: (provider: string, model: string) => a.wizard!.test(provider, model),
99
- } : {}),
100
- ...(a.petName !== undefined ? { petName: a.petName } : {}),
101
- };
102
- }
@@ -1,202 +0,0 @@
1
- /** Sextant terminal I/O + surface choice (port #44). The ONE module on the sextant path that touches
2
- * vendor: ProcessIO drives process.stdin/stdout (raw mode, utf8, resize, and pi-tui's Windows
3
- * ENABLE_VIRTUAL_TERMINAL_INPUT helper — without it libuv's console reader drops modifier state and
4
- * Shift+Tab arrives as a plain \t instead of CSI Z; the helper is loaded AFTER setRawMode(true), which
5
- * resets the console mode, exactly as vendor/pi-tui/src/terminal.ts:186-190 does). MemoryIO is the
6
- * in-memory double tests and the smoke drive. chooseSurface() is the pure `rovecode` default rule:
7
- * sextant only on a TTY of at least 100×30 that renders truecolor or 256 colors (the #40 quantizer
8
- * paints the latter); `--classic` beats everything; ROVECODE_TUI=classic|sextant overrides the heuristics
9
- * (a non-TTY still never gets sextant, nor does a TTY under the 40×12 Screen floor). */
10
-
11
- import { createRequire } from "node:module";
12
- import { join } from "node:path";
13
- import { getNativeModuleCandidates } from "../../vendor/pi-tui/src/native-module-path.ts";
14
- import { MIN_COLS, MIN_ROWS } from "../sextant/screen.ts";
15
- import { SEXTANT_MIN_COLS, SEXTANT_MIN_ROWS, type TerminalIO } from "../sextant/types.ts";
16
- import type { Renderer } from "./renderer.ts";
17
- import type { FocusTracker } from "./notify-seq.ts";
18
-
19
- const cjsRequire = createRequire(import.meta.url);
20
- /** the vendored pi-tui source dir — getNativeModuleCandidates resolves `native/…` beside it */
21
- const VENDOR_TUI_URL = new URL("../../vendor/pi-tui/src/terminal.ts", import.meta.url).href;
22
-
23
- export type Env = Readonly<Record<string, string | undefined>>;
24
-
25
- /** where pi-tui's prebuilt console-mode helper may live (vendor tree, or beside a compiled binary) */
26
- export function vtInputCandidates(arch: string = process.arch, execPath: string = process.execPath): string[] {
27
- return getNativeModuleCandidates(join("native", "win32", "prebuilds", `win32-${arch}`, "win32-console-mode.node"), { moduleUrl: VENDOR_TUI_URL, execPath });
28
- }
29
-
30
- /** pi-tui terminal.ts enableWindowsVTInput: flip ENABLE_VIRTUAL_TERMINAL_INPUT on the stdin console;
31
- * false when the helper is unavailable (Shift+Tab is then indistinguishable from Tab) */
32
- export function enableWindowsVTInput(arch: string = process.arch): boolean {
33
- if (arch !== "x64" && arch !== "arm64") return false;
34
- for (const p of vtInputCandidates(arch)) {
35
- try {
36
- const helper = cjsRequire(p) as { enableVirtualTerminalInput?: () => boolean };
37
- return helper.enableVirtualTerminalInput?.() ?? false;
38
- } catch { /* try the next packaging location */ }
39
- }
40
- return false;
41
- }
42
-
43
- /** the slice of process.stdin the surface uses (tests inject a fake) */
44
- export interface RawStdin {
45
- isRaw?: boolean;
46
- isTTY?: boolean;
47
- setRawMode?(mode: boolean): unknown;
48
- setEncoding(enc: BufferEncoding): unknown;
49
- resume(): unknown;
50
- pause(): unknown;
51
- on(event: "data", cb: (chunk: string | Buffer) => void): unknown;
52
- on(event: "end", cb: () => void): unknown;
53
- off(event: "data", cb: (chunk: string | Buffer) => void): unknown;
54
- off(event: "end", cb: () => void): unknown;
55
- }
56
- /** the slice of process.stdout the surface uses */
57
- export interface RawStdout {
58
- write(s: string): unknown;
59
- isTTY?: boolean;
60
- columns?: number;
61
- rows?: number;
62
- on(event: "resize", cb: () => void): unknown;
63
- off(event: "resize", cb: () => void): unknown;
64
- }
65
- export interface ProcessIOOptions {
66
- /** default process.platform; the VT helper runs on win32 only */
67
- platform?: string;
68
- /** the VT-input helper (default enableWindowsVTInput) */
69
- vtInput?: () => boolean;
70
- /** consumes CSI I / CSI O focus reports BEFORE the sextant's parser sees the chunk (tui/notify.ts) */
71
- focus?: FocusTracker;
72
- }
73
-
74
- export class ProcessIO implements TerminalIO {
75
- private wasRaw = false;
76
- constructor(
77
- private readonly stdin: RawStdin = process.stdin,
78
- private readonly stdout: RawStdout = process.stdout,
79
- readonly env: Env = process.env,
80
- private readonly opts: ProcessIOOptions = {},
81
- ) {}
82
- write(s: string): void { this.stdout.write(s); }
83
- onInput(cb: (chunk: string) => void): () => void {
84
- const h = (d: string | Buffer): void => {
85
- const text = typeof d === "string" ? d : d.toString("utf8");
86
- const rest = this.opts.focus ? this.opts.focus.feed(text) : text; // focus reports are consumed here, never parsed as keys
87
- if (rest.length > 0) cb(rest);
88
- };
89
- this.stdin.on("data", h);
90
- // EOF: the pipe on the other end closed. A TUI that keeps waiting on a dead stdin hangs forever —
91
- // measured 60 s+ (killed only by the outer timeout) when rovecode was launched from a pipe, a
92
- // script or a wrapper that closes stdin. Deliver Ctrl-C's shape (ETX) so the input layer treats
93
- // this exactly as an interrupt: a running turn aborts, an idle surface exits, and the terminal
94
- // is restored by the normal close path. Without input there is nothing to wait FOR.
95
- const end = (): void => { cb("\x03"); };
96
- this.stdin.on("end", end);
97
- return () => { this.stdin.off("data", h); this.stdin.off("end", end); };
98
- }
99
- onResize(cb: (cols: number, rows: number) => void): () => void {
100
- const h = (): void => { const { cols, rows } = this.size(); cb(cols, rows); };
101
- this.stdout.on("resize", h);
102
- return () => { this.stdout.off("resize", h); };
103
- }
104
- size(): { cols: number; rows: number } { return { cols: this.stdout.columns || 80, rows: this.stdout.rows || 24 }; }
105
- /** raw mode + utf8 + flowing, then the Windows VT-input helper (must follow setRawMode, which resets the console flags) */
106
- enterRaw(): void {
107
- this.wasRaw = this.stdin.isRaw ?? false;
108
- this.stdin.setRawMode?.(true);
109
- this.stdin.setEncoding("utf8");
110
- this.stdin.resume();
111
- if ((this.opts.platform ?? process.platform) === "win32") (this.opts.vtInput ?? enableWindowsVTInput)();
112
- }
113
- /** restore the previous raw state and pause stdin so buffered bytes never reach the parent shell */
114
- leaveRaw(): void {
115
- this.stdin.setRawMode?.(this.wasRaw);
116
- this.stdin.pause();
117
- }
118
- }
119
-
120
- /** in-memory TerminalIO: records writes, replays fed input, emulates resizes (tests + `smoke-tui --sextant`) */
121
- export class MemoryIO implements TerminalIO {
122
- readonly writes: string[] = [];
123
- raw = false;
124
- private readonly inputs = new Set<(chunk: string) => void>();
125
- private readonly resizes = new Set<(cols: number, rows: number) => void>();
126
- constructor(public cols = 160, public rows = 44, readonly env: Env = {}) {}
127
- write(s: string): void { this.writes.push(s); }
128
- onInput(cb: (chunk: string) => void): () => void { this.inputs.add(cb); return () => { this.inputs.delete(cb); }; }
129
- onResize(cb: (cols: number, rows: number) => void): () => void { this.resizes.add(cb); return () => { this.resizes.delete(cb); }; }
130
- size(): { cols: number; rows: number } { return { cols: this.cols, rows: this.rows }; }
131
- enterRaw(): void { this.raw = true; }
132
- leaveRaw(): void { this.raw = false; }
133
- /** deliver raw terminal bytes (keys, mouse, paste) */
134
- feed(chunk: string): void { for (const cb of [...this.inputs]) cb(chunk); }
135
- resize(cols: number, rows: number): void { this.cols = cols; this.rows = rows; for (const cb of [...this.resizes]) cb(cols, rows); }
136
- /** everything written so far */
137
- output(): string { return this.writes.join(""); }
138
- /** live input + resize subscriptions (0 after stop) */
139
- get listeners(): number { return this.inputs.size + this.resizes.size; }
140
- }
141
-
142
- // ------------------------------------------------------------------ surface choice
143
-
144
- const TC_PROGRAMS = new Set(["vscode", "iTerm.app", "WezTerm", "ghostty"]);
145
-
146
- /** the terminal renders 24-bit color: COLORTERM truecolor/24bit, Windows Terminal (WT_SESSION), a
147
- * known TERM_PROGRAM (vscode, iTerm.app, WezTerm, ghostty) or a kitty/`-direct` TERM */
148
- export function truecolor(env: Env): boolean {
149
- const ct = (env.COLORTERM ?? "").toLowerCase();
150
- if (ct === "truecolor" || ct === "24bit") return true;
151
- if (env.WT_SESSION) return true;
152
- if (TC_PROGRAMS.has(env.TERM_PROGRAM ?? "")) return true;
153
- return /kitty|direct/.test(env.TERM ?? "");
154
- }
155
-
156
- export type ColorDepth = "truecolor" | "256" | "none";
157
-
158
- /** what the terminal renders: truecolor per the heuristics above; else 256 colors when TERM says so
159
- * (xterm-256color, screen-/tmux-256color) and COLORTERM is silent — the surface then paints through the
160
- * #40 quantizer (SGR 38;5); else nothing sextant can use */
161
- export function colorDepth(env: Env): ColorDepth {
162
- if (truecolor(env)) return "truecolor";
163
- if (!(env.COLORTERM ?? "").trim() && /256color/.test(env.TERM ?? "")) return "256";
164
- return "none";
165
- }
166
-
167
- export interface StdoutInfo { isTTY?: boolean; columns?: number; rows?: number }
168
-
169
- /** the heuristic: a TTY of at least SEXTANT_MIN_COLS×SEXTANT_MIN_ROWS with truecolor or 256 colors */
170
- export function sextantOk(env: Env, stdout: StdoutInfo): boolean {
171
- return !!stdout.isTTY && (stdout.columns ?? 0) >= SEXTANT_MIN_COLS && (stdout.rows ?? 0) >= SEXTANT_MIN_ROWS && colorDepth(env) !== "none";
172
- }
173
-
174
- /** the Screen floor (screen.ts MIN_COLS×MIN_ROWS): below it the cell buffer is larger than the terminal
175
- * (39-cell rows into a 30-column window), so even a forced sextant yields; an unknown size counts as
176
- * the 80×24 ProcessIO.size() falls back to */
177
- export function fitsFloor(stdout: StdoutInfo): boolean {
178
- return (stdout.columns ?? 80) >= MIN_COLS && (stdout.rows ?? 24) >= MIN_ROWS;
179
- }
180
-
181
- export type Surface = "sextant" | "classic";
182
-
183
- /** `--classic` wins; ROVECODE_TUI=classic forces classic, ROVECODE_TUI=sextant forces sextant on any TTY at or
184
- * above the 40×12 floor (the 100×30 and color heuristics skipped); otherwise sextantOk(). A non-TTY
185
- * stdout never gets sextant. */
186
- export function chooseSurface(cli: { classic: boolean }, env: Env, stdout: StdoutInfo): Surface {
187
- if (cli.classic) return "classic";
188
- const force = (env.ROVECODE_TUI ?? "").trim().toLowerCase();
189
- if (force === "classic") return "classic";
190
- if (force === "sextant") return stdout.isTTY && fitsFloor(stdout) ? "sextant" : "classic";
191
- return sextantOk(env, stdout) ? "sextant" : "classic";
192
- }
193
-
194
- /** main.ts: the renderer to hand runTui — a SextantRenderer over the process terminal (truecolor SGR, or
195
- * the 256-color quantizer when that is all the terminal declares), or undefined (runTui then builds the
196
- * classic PiTuiRenderer exactly as before) */
197
- /** `io.focus`: the FocusTracker the notifications decorator reads (tui/notify.ts); `io.stdin` for tests */
198
- export function pickRenderer(cli: { classic: boolean; pet?: string }, env: Env = process.env, stdout: RawStdout = process.stdout, io: { stdin?: RawStdin; focus?: FocusTracker } = {}): Renderer | undefined {
199
- if (chooseSurface(cli, env, stdout) !== "sextant") return undefined;
200
- const { SextantRenderer } = require("../sextant/sextant-renderer.ts") as typeof import("../sextant/sextant-renderer.ts");
201
- return new SextantRenderer({ io: new ProcessIO(io.stdin ?? process.stdin, stdout, env, io.focus ? { focus: io.focus } : {}), truecolor: colorDepth(env) === "truecolor", ...(cli.pet !== undefined ? { pet: cli.pet } : {}), ...(env.ROVECODE_THEME ? { theme: env.ROVECODE_THEME } : {}) });
202
- }