rovecode 0.3.3 → 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 -48
  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 +83 -72
  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,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
- }