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,110 +0,0 @@
1
- /** `rovecode smoke-tui --sextant` (port #44): the sextant surface end-to-end through the real pipeline —
2
- * agentLoop → SextantRenderer → Screen → an in-memory TerminalIO at 160×44 (no @xterm/headless, so it
3
- * also runs from an installed tree or the compiled binary). Gated session: a scripted write, then an
4
- * anchored edit of that file, each raise the approval card and are allowed once the card is on
5
- * screen; a text turn closes the run; ⌃c quits and the terminal must be restored (leave sequence in
6
- * the output tail, frame interval cleared). Prints the edit's card frame and the final frame; the CLI
7
- * wrapper exits 0 iff every stage rendered. */
8
-
9
- import { mkdtempSync, rmSync } from "node:fs";
10
- import { tmpdir } from "node:os";
11
- import { join } from "node:path";
12
- import { fileTag, lineHash } from "../coding/hashline.ts";
13
- import { mockStream, textTurn, toolTurn } from "../providers/stream.ts";
14
- import { SextantRenderer } from "../sextant/sextant-renderer.ts";
15
- import { runTui } from "./app.ts";
16
- import { MemoryIO } from "./sextant-io.ts";
17
-
18
- export interface SextantSmokeResult {
19
- ok: boolean;
20
- reasons: string[];
21
- /** the frame with the edit's approval card on screen */
22
- cardFrame: string;
23
- /** the final frame */
24
- frame: string;
25
- /** the last 400 bytes written to the terminal (the leave sequence lives here) */
26
- tail: string;
27
- }
28
-
29
- const sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));
30
- /** the two approval cards, in order: the write's, then the edit's */
31
- const CARDS: readonly RegExp[] = [/needs your permission\s+write\b/, /needs your permission\s+edit\b/];
32
- /** what quitting must leave in the output: main screen, cursor shown, SGR mouse off, bracketed paste off */
33
- const LEAVE: readonly string[] = ["\x1b[?1049l", "\x1b[?25h", "\x1b[?1006l", "\x1b[?2004l"];
34
-
35
- /** drive the surface headlessly and report; never exits the process (runSextantSmoke does) */
36
- export async function sextantSmoke(opts: { cols?: number; rows?: number; deadlineMs?: number } = {}): Promise<SextantSmokeResult> {
37
- const cwd = mkdtempSync(join(tmpdir(), "rovecode-sextant-smoke-"));
38
- const io = new MemoryIO(opts.cols ?? 160, opts.rows ?? 44, { COLORTERM: "truecolor" });
39
- const renderer = new SextantRenderer({ io, cwd, pet: "rovecode" });
40
- const probe = join(cwd, "smoke.txt");
41
- const written = "smoke-ok\n";
42
- const stream = mockStream({
43
- turns: [
44
- toolTurn([{ id: "t1", tool: "write", args: { path: probe, content: written } }]),
45
- toolTurn([{ id: "t2", tool: "edit", args: { path: probe, edits: [{ tag: fileTag(written), anchorLine: 1, anchorHash: lineHash("smoke-ok"), newLines: ["smoke-edited"] }] } }]),
46
- textTurn("Smoke OK — the sextant surface rendered a write, an anchored edit and this summary."),
47
- ],
48
- });
49
- const reasons: string[] = [];
50
- // The whole assertion below is "two approval cards appear", so the permission level is pinned here rather
51
- // than inherited from the machine: a ~/.rovecode/settings.json with "permission":"auto" allowed the write
52
- // and the edit without a card and the smoke FAILED with "approval cards seen 0/2". `yolo: false` cannot
53
- // pin it — app.ts treats false as "no flag" and lets the settings file win; `permission` is the flag rung.
54
- const app = runTui({ renderer, stream, cwd, permission: "ask", exitOnClose: false, model: "scripted" });
55
- io.feed("hello rovecode\r");
56
- const deadline = Date.now() + (opts.deadlineMs ?? 15_000);
57
- const cardFrames: string[] = [];
58
- let frame = "", done = false;
59
- while (Date.now() < deadline) {
60
- renderer.tick();
61
- frame = renderer.frameText();
62
- if (cardFrames.length === CARDS.length && frame.includes("Smoke OK") && !frame.includes("needs your permission")) { done = true; break; }
63
- const want = CARDS[cardFrames.length];
64
- if (want !== undefined && want.test(frame) && frame.includes("allow")) { cardFrames.push(frame); io.feed("\r"); } // Enter = allow once
65
- await sleep(25);
66
- }
67
- // the boot reveal paints panels in 90 ms steps after bootAt (frame.ts REVEAL_STEP_MS); a fast host
68
- // finishes the scripted run before the right column and the pet have appeared — give the reveal its time
69
- const PANELS = ["─ files ─", "─ code ─", "─ messages ─", "─ plan ─", "─ usage ─", "─ rovecode ─"];
70
- const shown = (p: string): boolean => frame.includes(p) || (p === "─ code ─" && frame.includes("─ diff ─"));
71
- const revealBy = Date.now() + 2_000;
72
- while (done && Date.now() < revealBy && !PANELS.every(shown)) { await sleep(25); renderer.tick(); frame = renderer.frameText(); }
73
- if (!done) reasons.push(`final frame not reached (approval cards seen ${cardFrames.length}/${CARDS.length})`);
74
- if (!/~ edit\s+smoke\.txt/.test(frame)) reasons.push("no `~ edit smoke.txt` tool row in the messages panel");
75
- if (!/\+ write\s+smoke\.txt/.test(frame)) reasons.push("no `+ write smoke.txt` tool row in the messages panel");
76
- for (const p of PANELS) if (!shown(p)) reasons.push(`panel ${p.trim()} missing at ${io.cols}×${io.rows}`);
77
- const wasActive = renderer.active;
78
- io.feed("\x03");
79
- await app;
80
- const tail = io.output().slice(-400);
81
- for (const seq of LEAVE) if (!tail.includes(seq)) reasons.push(`the output tail lacks ${JSON.stringify(seq)} — terminal not restored`);
82
- if (!wasActive) reasons.push("the frame interval was not running before quit");
83
- if (renderer.active) reasons.push("the frame interval survived quit");
84
- // the repo watcher's git children must be GONE before the scratch repo goes (sextant-renderer drain);
85
- // on Windows a live `git status` holds its cwd and rmSync answers EBUSY — the tui-sextant "flake".
86
- // The retry is the belt to that brace: handle release on Windows lags the process exit itself.
87
- await renderer.drain().catch(() => {});
88
- for (let attempt = 0; ; attempt++) {
89
- try { rmSync(cwd, { recursive: true, force: true }); break; }
90
- catch (e) {
91
- const code = (e as NodeJS.ErrnoException).code;
92
- if ((code !== "EBUSY" && code !== "EPERM" && code !== "ENOTEMPTY") || attempt >= 20) throw e;
93
- await sleep(25);
94
- }
95
- }
96
- return { ok: reasons.length === 0, reasons, cardFrame: cardFrames[1] ?? cardFrames[0] ?? "(no approval card rendered)", frame, tail };
97
- }
98
-
99
- export async function runSextantSmoke(): Promise<void> {
100
- const r = await sextantSmoke();
101
- console.log("── sextant: approval card for the anchored edit (160x44) ──────────────────────");
102
- console.log(r.cardFrame);
103
- console.log("── sextant: final frame (160x44) ────────────────────────────────────────────────");
104
- console.log(r.frame);
105
- console.log("─────────────────────────────────────────────────────────────────────────────────");
106
- console.log(r.ok
107
- ? "smoke-tui --sextant: PASS (files · code · messages · plan · usage · rovecode + two approval cards through the full pipeline; terminal restored on quit)"
108
- : `smoke-tui --sextant: FAIL — ${r.reasons.join("; ")}`);
109
- process.exit(r.ok ? 0 : 1);
110
- }
@@ -1,158 +0,0 @@
1
- /** `!cmd` shell mode: a prompt line that starts with `!` runs in the workspace shell through the ONE bash tool
2
- * dispatch — ToolRegistry.dispatch with the session's permission rules and the very approval chain a model-issued
3
- * `bash` call gets (permission rules → execpolicy → the approval hook → the human's card, cli/runtime.ts buildCfg)
4
- * behind the configured executor rung. Never a direct spawn, never a second policy path: the composer's `!` is a
5
- * convenience over the same door, not a way around it. The caller passes ITS human approver, so the surface's own
6
- * behaviour — the diff preview, the "all edits" door — applies here too rather than being reimplemented.
7
- *
8
- * No model turn starts. The command and its output are appended to the session as a user message the model reads
9
- * on its NEXT turn (shellRecord), so `!bun test` followed by "fix it" gives the model the failure without a tool
10
- * round-trip. Both surfaces share this module: a renderer with `onEvent` (sextant) builds its rows from the
11
- * dispatch events; one without (the classic pi-tui) gets the tool card pair plus a bounded output block.
12
- *
13
- * Pattern source (Apache-2.0, PATTERN ONLY, no code copied): gemini-cli packages/cli/src/ui/hooks/
14
- * useGeminiStream.ts (shell mode short-circuits the prompt before any model call) and atCommandProcessor.ts (a
15
- * client-initiated tool call whose result is folded into the user turn).
16
- *
17
- * Rules: `!` alone, `! x` (a space after the bang) and `!!x` are plain text for the model — the ONE classifier is
18
- * sextant/overlays.ts parseInput; a busy run refuses the line (the record would fork the run's chain); staged
19
- * /attach images never ride on a shell record; and a call refused BEFORE execution (a rule, execpolicy, a hook, a
20
- * denied card) leaves no record at all — the model learns only what actually ran. */
21
-
22
- import { randomUUID } from "node:crypto";
23
- import type { Runtime } from "../cli/runtime.ts";
24
- import type { SessionStore } from "../core/session.ts";
25
- import type { ApprovalFn, Message, PermissionLevel, RunEvent, ToolCallPart, ToolContext, ToolOutput } from "../core/types.ts";
26
- import { parseInput } from "../sextant/overlays.ts";
27
- import type { Renderer } from "./renderer.ts";
28
-
29
- /** the classic block shows this many output lines; the session record keeps the tool's full (≤10k) text */
30
- export const OUTPUT_BLOCK_LINES = 40;
31
- const OPEN = "<user_shell_command>", CLOSE = "</user_shell_command>", OUT_OPEN = "<user_shell_output", OUT_CLOSE = "</user_shell_output>";
32
-
33
- /** The command of a `!cmd` line, or null when the line is plain text (sextant/overlays.ts parseInput). */
34
- export function shellLine(text: string): string | null {
35
- const p = parseInput(text);
36
- return p.kind === "shell" && p.cmd ? p.cmd : null;
37
- }
38
-
39
- export interface ShellCtx {
40
- renderer: Renderer;
41
- rt: Pick<Runtime, "registry" | "hooks" | "buildCfg" | "cwd">;
42
- /** the ACTIVE store, read live */
43
- store(): SessionStore;
44
- /** the session's permission level, exactly as a model turn would run under */
45
- level(): PermissionLevel;
46
- /** the surface's own human approver (undefined under `auto`, where nothing is asked) */
47
- approve(): ApprovalFn | undefined;
48
- /** the app's busy flag (a live run, or another `!cmd`) */
49
- busy(): boolean;
50
- /** flip the app's busy flag (+ status) around the command */
51
- setBusy(b: boolean): void;
52
- /** the app's interrupt target — Esc / ⌃c / quit abort it; bound for the command's lifetime, then cleared */
53
- bindAbort(ac: AbortController | null): void;
54
- }
55
-
56
- const head = (cmd: string): string => { const one = cmd.replace(/\s+/g, " ").trim(); return one.length > 40 ? one.slice(0, 39) + "…" : one; };
57
-
58
- type FailedEvent = Extract<RunEvent, { type: "tool_call_failed" }>;
59
- export const REFUSED_DETAIL = "refused by a permission rule, exec policy or an approval hook (no approval prompt)";
60
-
61
- /** the event BOTH surfaces get for a call refused before execution. `asked` = the human saw the card and denied —
62
- * the raw event stands, its "user denied" is true; otherwise the chain settled it alone (a forbidden argv, a hook
63
- * deny) and dispatch's generic "user denied" would misreport a policy stop as the person's choice. */
64
- function refusal(ev: FailedEvent, asked: boolean): FailedEvent {
65
- return !asked && ev.detail === "user denied" ? { ...ev, detail: REFUSED_DETAIL } : ev;
66
- }
67
-
68
- /** Run one `!cmd` line. Echoes the typed line, dispatches the bash tool with the session's rules and approval
69
- * chain, records what ran, settles the surface — and never starts a model turn. */
70
- export async function runShellLine(ctx: ShellCtx, line: string): Promise<void> {
71
- const cmd = shellLine(line);
72
- if (cmd === null) return;
73
- const { renderer } = ctx;
74
- if (ctx.busy()) { renderer.addSystemNote("finish or interrupt the run first (Esc) — `!cmd` runs only while the agent is idle", "warn"); return; }
75
- renderer.addUser(line.trim());
76
- const ac = new AbortController();
77
- ctx.setBusy(true);
78
- ctx.bindAbort(ac);
79
- renderer.setBusy(true, `running ${head(cmd)}…`);
80
- const call: ToolCallPart = { kind: "tool_call", id: `shell-${randomUUID().slice(0, 8)}`, tool: "bash", args: { command: cmd } };
81
- let asked = false, executed = false;
82
- // the SAME chain a model-issued bash call gets: buildCfg wraps the surface's approver in the rules, execpolicy
83
- // and the hooks. The wrapper only records that the human was reached, so the refusal text can tell the truth.
84
- const human = ctx.approve();
85
- const cfg = ctx.rt.buildCfg(ctx.level(), human === undefined ? undefined : async (req) => { asked = true; return human(req); });
86
- const toolCtx: ToolContext = { sessionId: ctx.store().id, cwd: ctx.rt.cwd, signal: ac.signal, permissions: { effect: "allow" } };
87
- // onEvent FIRST — a renderer that has it owns the rows and ignores the card calls below; the classic surface
88
- // paints its `→ bash` / `← ok|FAIL` pair from them. Both are built from the ONE corrected event.
89
- const emit = (raw: RunEvent): void => {
90
- const ev = raw.type === "tool_call_failed" ? refusal(raw, asked) : raw;
91
- renderer.onEvent?.(ev);
92
- if (ev.type === "tool_execution_start") renderer.toolStart(ev.callId, ev.tool, JSON.stringify(ev.args).slice(0, 120));
93
- else if (ev.type === "tool_execution_update") renderer.toolUpdate(ev.callId, ev.note);
94
- else if (ev.type === "tool_execution_end") { executed = true; renderer.toolEnd(ev.callId, ev.ok, ev.output.slice(0, 160).replace(/\n/g, " ⏎ "), ev.durationMs); }
95
- else if (ev.type === "tool_call_failed") renderer.toolEnd(ev.callId, false, `${ev.reason}: ${ev.detail}`.slice(0, 160), 0);
96
- };
97
- let out: ToolOutput = { ok: false, output: "" };
98
- try {
99
- // no loop guard: the person's own repeats are not a model loop and must not count toward its streak
100
- out = await ctx.rt.registry.dispatch(call, toolCtx, ctx.rt.hooks, cfg.permissionRules, cfg.approval, emit, undefined);
101
- if (executed) {
102
- const store = ctx.store();
103
- const staged = store.stagedAttachments; // /attach images ride on the next TYPED message, never on a shell record
104
- store.stageAttachments([]);
105
- store.append(shellRecord(cmd, out, store.messages().at(-1)?.id ?? null));
106
- store.stageAttachments(staged);
107
- if (!renderer.onEvent) renderer.addSystemNote(outputBlock(out.output), out.ok ? "info" : "warn");
108
- } else {
109
- const why = ac.signal.aborted ? "was interrupted before it ran" : asked ? "was denied at the approval card" : "was refused before any approval prompt (a permission rule, exec policy or a hook)";
110
- renderer.addSystemNote(`\`${head(cmd)}\` ${why} — nothing ran, nothing recorded`, "warn");
111
- }
112
- } finally {
113
- ctx.bindAbort(null);
114
- renderer.setBusy(false, executed && out.ok ? "done" : "error");
115
- ctx.setBusy(false);
116
- }
117
- }
118
-
119
- /** The session record the model reads next turn: a role:"user" message —
120
- * `<user_shell_command>\n$ <cmd>\n</user_shell_command>\n<user_shell_output exit="N">\n<output>\n</user_shell_output>`
121
- * — exit = the bash tool's `exit=N` header (`?` when the output carries none), output = the rest. */
122
- export function shellRecord(cmd: string, out: ToolOutput, parentId: string | null): Message {
123
- const m = /^exit=(-?\d+)\r?\n?/.exec(out.output);
124
- const exit = m ? m[1]! : "?";
125
- const body = (m ? out.output.slice(m[0].length) : out.output).replace(/\r?\n$/, "");
126
- const text = [OPEN, `$ ${cmd}`, CLOSE, `${OUT_OPEN} exit="${exit}">`, ...(body ? [body] : []), OUT_CLOSE].join("\n");
127
- return { id: randomUUID(), role: "user", parts: [{ kind: "text", text }], parentId, createdAt: Date.now() };
128
- }
129
-
130
- const RECORD_RE = /^<user_shell_command>\n\$ ([\s\S]*?)\n<\/user_shell_command>\n<user_shell_output exit="(-?\d+|\?)">\n(?:([\s\S]*?)\n)?<\/user_shell_output>$/;
131
-
132
- /** the inverse of shellRecord for transcript replay; null for any other user text */
133
- export function parseShellRecord(text: string): { cmd: string; exit: string; output: string } | null {
134
- const m = RECORD_RE.exec(text);
135
- return m ? { cmd: m[1]!, exit: m[2]!, output: m[3] ?? "" } : null;
136
- }
137
-
138
- /** the classic surface's output block: the tool's text (its `exit=N` header first), at most OUTPUT_BLOCK_LINES lines */
139
- export function outputBlock(output: string): string {
140
- const lines = output.replace(/\r\n/g, "\n").replace(/\n$/, "").split("\n");
141
- const shown = lines.slice(0, OUTPUT_BLOCK_LINES);
142
- const more = lines.length - shown.length;
143
- return shown.join("\n") + (more > 0 ? `\n… ${more} more line${more === 1 ? "" : "s"} (the session record keeps the full output)` : "");
144
- }
145
-
146
- let replaySeq = 0;
147
- /** Transcript replay of a stored shell record: the typed `!cmd` line, then the bash tool card pair the live run
148
- * showed. false = not a record. */
149
- export function replayShellRecord(renderer: Renderer, text: string): boolean {
150
- const r = parseShellRecord(text);
151
- if (!r) return false;
152
- const id = `shell-replay-${++replaySeq}`;
153
- renderer.addUser(`!${r.cmd}`);
154
- renderer.toolStart(id, "bash", JSON.stringify({ command: r.cmd }).slice(0, 120));
155
- // the record's exact text as the preview: an empty output is `exit=N` alone, never a dangling line break
156
- renderer.toolEnd(id, r.exit === "0", [`exit=${r.exit}`, ...(r.output ? [r.output] : [])].join("\n").slice(0, 160).replace(/\n/g, " ⏎ "), 0);
157
- return true;
158
- }
package/src/tui/smoke.ts DELETED
@@ -1,72 +0,0 @@
1
- /** `rovecode smoke-tui`: end-to-end render check through the real pipeline —
2
- * agentLoop → Renderer → pi-tui → ANSI → @xterm/headless terminal emulator.
3
- * Gated session: a scripted write, then an anchored edit of that file, each raise the
4
- * approval overlay with its diff card (port #24) and are approved once the card is on
5
- * screen; a markdown turn closes the run. Prints the edit's diff-card screen and the
6
- * final 80x24 screen; exits 0 iff every stage rendered. */
7
-
8
- import { VirtualTerminal } from "../../vendor/pi-tui/test/virtual-terminal.ts";
9
- import { PiTuiRenderer } from "./pi-renderer.ts";
10
- import { runTui } from "./app.ts";
11
- import { mockStream, textTurn, toolTurn } from "../providers/stream.ts";
12
- import { fileTag, lineHash } from "../coding/hashline.ts";
13
- import { mkdtempSync, rmSync } from "node:fs";
14
- import { tmpdir } from "node:os";
15
- import { join } from "node:path";
16
-
17
- export async function runTuiSmoke(): Promise<void> {
18
- const cwd = mkdtempSync(join(tmpdir(), "rovecode-tui-smoke-"));
19
- const term = new VirtualTerminal(80, 24);
20
- const renderer = new PiTuiRenderer({ terminal: term, cwd });
21
- const probe = join(cwd, "smoke.txt");
22
- const written = "smoke-ok\n";
23
- const stream = mockStream({
24
- turns: [
25
- toolTurn([{ id: "t1", tool: "write", args: { path: probe, content: written } }]),
26
- // port #24: anchored edit of the file just written → the approval card shows -old/+new
27
- toolTurn([{ id: "t2", tool: "edit", args: { path: probe, edits: [
28
- { tag: fileTag(written), anchorLine: 1, anchorHash: lineHash("smoke-ok"), newLines: ["smoke-edited"] },
29
- ] } }]),
30
- textTurn("# Smoke OK\n\nrendered **markdown**, a tool card, and the status line."),
31
- ],
32
- });
33
-
34
- // pinned, not inherited: this smoke asserts approval cards, and a ~/.rovecode/settings.json with
35
- // "permission":"auto" would allow everything silently (`yolo: false` is "no flag" to app.ts, not "ask")
36
- const app = runTui({ renderer, stream, cwd, permission: "ask", exitOnClose: false, model: "scripted" });
37
-
38
- // type a prompt into the (focused) editor and submit
39
- term.sendInput("hello rovecode");
40
- term.sendInput("\r");
41
-
42
- // each approval overlay must show its diff card before Enter (= allow once) approves it:
43
- // the write is an all-adds create diff, the edit a modify diff with the removed line
44
- const cards = ["+smoke-ok", "-smoke-ok"];
45
- const cardScreens: string[][] = [];
46
- const deadline = Date.now() + 10_000;
47
- let screen: string[] = [];
48
- let ok = false;
49
- while (Date.now() < deadline) {
50
- screen = await term.flushAndGetViewport();
51
- const text = screen.join("\n");
52
- if (text.includes("Smoke OK") && text.includes("write") && cardScreens.length === cards.length) { ok = true; break; }
53
- const want = cards[cardScreens.length];
54
- if (want !== undefined && text.includes("allow once") && text.includes(want)) {
55
- cardScreens.push(screen);
56
- term.sendInput("\r");
57
- }
58
- await new Promise((r) => setTimeout(r, 50));
59
- }
60
-
61
- term.sendInput("\x03"); // Ctrl+C → clean exit path
62
- await app;
63
- rmSync(cwd, { recursive: true, force: true });
64
-
65
- console.log("── approval overlay with diff card (edit) ──────────────────────────────");
66
- for (const line of cardScreens[1] ?? ["(diff card never rendered)"]) console.log(line.trimEnd());
67
- console.log("── emulated 80x24 screen ──────────────────────────────────────────────");
68
- for (const line of screen) console.log(line.trimEnd());
69
- console.log("───────────────────────────────────────────────────────────────────────");
70
- console.log(ok ? "smoke-tui: PASS (markdown + tool card + diff card rendered through full pipeline)" : `smoke-tui: FAIL (diff cards seen: ${cardScreens.length}/${cards.length})`);
71
- process.exit(ok ? 0 : 1);
72
- }
@@ -1,50 +0,0 @@
1
- /** Classic TUI's first frame is measured AND serialized offscreen. No raw mode, terminal writes or
2
- * input subscription until reveal(). Re-preparing replaces the buffer (resize/status), never appends
3
- * an obsolete screen. Imported only by the optional classic renderer. */
4
- import type { Terminal } from "../../vendor/pi-tui/src/terminal.ts";
5
-
6
- export class StagedTerminal implements Terminal {
7
- private pending: (() => void)[] = [];
8
- private visible = false;
9
- private discarded = false;
10
- constructor(private readonly inner: Terminal) {}
11
- get columns(): number { return this.inner.columns; }
12
- get rows(): number { return this.inner.rows; }
13
- get kittyProtocolActive(): boolean { return this.inner.kittyProtocolActive; }
14
- prepare(render: () => void): void { this.pending = []; render(); }
15
- reveal(start: () => void, handoff?: () => void): void {
16
- if (this.discarded || this.visible) return;
17
- const frame = this.pending; this.pending = [];
18
- const esc = String.fromCharCode(27);
19
- this.inner.write(`${esc}[?2026h`);
20
- try {
21
- handoff?.();
22
- this.visible = true;
23
- start(); // protocol setup/input first, followed immediately by the already-computed complete frame
24
- for (const write of frame) write();
25
- } finally { this.inner.write(`${esc}[?2026l`); }
26
- }
27
- private emit(write: () => void): void {
28
- if (this.discarded) return;
29
- if (this.visible) write(); else this.pending.push(write);
30
- }
31
- start(input: (data: string) => void, resize: () => void): void {
32
- if (this.visible) this.inner.start(input, resize);
33
- }
34
- stop(): void {
35
- this.discarded = true; this.pending = [];
36
- if (this.visible) this.inner.stop();
37
- }
38
- drainInput(maxMs?: number, idleMs?: number): Promise<void> {
39
- return this.visible ? this.inner.drainInput(maxMs, idleMs) : Promise.resolve();
40
- }
41
- write(data: string): void { this.emit(() => this.inner.write(data)); }
42
- moveBy(lines: number): void { this.emit(() => this.inner.moveBy(lines)); }
43
- hideCursor(): void { this.emit(() => this.inner.hideCursor()); }
44
- showCursor(): void { this.emit(() => this.inner.showCursor()); }
45
- clearLine(): void { this.emit(() => this.inner.clearLine()); }
46
- clearFromCursor(): void { this.emit(() => this.inner.clearFromCursor()); }
47
- clearScreen(): void { this.emit(() => this.inner.clearScreen()); }
48
- setTitle(title: string): void { this.emit(() => this.inner.setTitle(title)); }
49
- setProgress(active: boolean): void { this.emit(() => this.inner.setProgress(active)); }
50
- }
@@ -1,12 +0,0 @@
1
- /** Wait for required startup work without trapping Ctrl+C behind a slow probe. The readiness promise
2
- * stays observed after cancellation, so a late rejection cannot become an unhandled rejection. */
3
- export function waitForStartup(ready: Promise<void>, signal?: AbortSignal): Promise<void> {
4
- if (!signal) return ready;
5
- return new Promise((resolve, reject) => {
6
- const abort = () => { reject(signal.reason ?? new Error("startup cancelled")); };
7
- signal.addEventListener("abort", abort, { once: true });
8
- const cleanup = () => signal.removeEventListener("abort", abort);
9
- if (signal.aborted) { cleanup(); abort(); }
10
- ready.then(() => { cleanup(); resolve(); }, (error) => { cleanup(); reject(error); });
11
- });
12
- }
package/src/tui/theme.ts DELETED
@@ -1,59 +0,0 @@
1
- /** Rovecode TUI theme: raw ANSI styling (no chalk dep) + theme objects for vendored pi-tui
2
- * components (EditorTheme / MarkdownTheme / SelectListTheme shapes from vendor). */
3
-
4
- import type { EditorTheme, MarkdownTheme, SelectListTheme } from "../../vendor/pi-tui/src/index.ts";
5
-
6
- const esc = (open: string, close: string) => (s: string) => `\x1b[${open}m${s}\x1b[${close}m`;
7
-
8
- export const st = {
9
- bold: esc("1", "22"),
10
- dim: esc("2", "22"),
11
- italic: esc("3", "23"),
12
- underline: esc("4", "24"),
13
- inverse: esc("7", "27"),
14
- strike: esc("9", "29"),
15
- fg: (n: number) => esc(`38;5;${n}`, "39"),
16
- bg: (n: number) => esc(`48;5;${n}`, "49"),
17
- };
18
-
19
- // palette (256-color): calm blues/teals for chrome, amber for warnings
20
- export const pal = {
21
- accent: st.fg(75), // sky blue — headings, borders
22
- accentDim: st.fg(67),
23
- ok: st.fg(114), // green
24
- warn: st.fg(215), // amber
25
- err: st.fg(203), // red
26
- muted: st.dim,
27
- code: st.fg(180),
28
- link: st.fg(75),
29
- };
30
-
31
- export const rovecodeSelectListTheme: SelectListTheme = {
32
- selectedPrefix: (t) => pal.accent(t),
33
- selectedText: (t) => st.bold(t),
34
- description: (t) => st.dim(t),
35
- scrollInfo: (t) => st.dim(t),
36
- noMatch: (t) => st.dim(t),
37
- };
38
-
39
- export const rovecodeEditorTheme: EditorTheme = {
40
- borderColor: (t) => pal.accentDim(t),
41
- selectList: rovecodeSelectListTheme,
42
- };
43
-
44
- export const rovecodeMarkdownTheme: MarkdownTheme = {
45
- heading: (t) => st.bold(pal.accent(t)),
46
- link: (t) => pal.link(st.underline(t)),
47
- linkUrl: (t) => st.dim(t),
48
- code: (t) => pal.code(t),
49
- codeBlock: (t) => pal.code(t),
50
- codeBlockBorder: (t) => st.dim(t),
51
- quote: (t) => st.italic(st.dim(t)),
52
- quoteBorder: (t) => st.dim(t),
53
- hr: (t) => st.dim(t),
54
- listBullet: (t) => pal.accent(t),
55
- bold: (t) => st.bold(t),
56
- italic: (t) => st.italic(t),
57
- strikethrough: (t) => st.strike(t),
58
- underline: (t) => st.underline(t),
59
- };
@@ -1,7 +0,0 @@
1
- /** Tiny status-bar helper split from info-cmd.ts so app.ts can import it statically
2
- * without pulling in the full info-cmd module at startup. */
3
- import { loadTodos, todoStatusLabel } from "../tools/todo.ts";
4
-
5
- export function todoLabel(sessionDir: string): string | undefined {
6
- return todoStatusLabel(loadTodos(sessionDir).items) || undefined;
7
- }
@@ -1,107 +0,0 @@
1
- /** `/trust` in the TUI — the approval card for the project trust gate (core/trust.ts, 08f355a), which until now could
2
- * only be answered by QUITTING the TUI and running `rovecode trust`. A security gate whose only yes is "leave the thing
3
- * you are doing" is a gate people switch off, so this is the same decision without the exit.
4
- *
5
- * NOT the aion port of the same file name. aion's src/tui/trust-card.ts asks about a FOLDER (decideTrust, trust.json,
6
- * "trust this folder / just this session / never", and a PreBootHooks so runTui can ask before createRuntime); rovecode's
7
- * gate is per-FILE and keyed by sha256 in the user home, so there is no folder answer to give and no boot ordering to
8
- * bend — the decision here is "these bytes of THIS file", one file at a time. Everything the person reads before
9
- * answering comes from core/project-trust.ts (projectTrustRows → trustShowLines), the same lines `rovecode trust show`
10
- * prints: the terminal and the TUI must not describe the same file differently.
11
- *
12
- * Two rules the card is built around, both of them Berkay's:
13
- * - approving is a DECISION, not a keystroke: the first item of the picker — the one Enter lands on — is "keep them
14
- * untrusted". There is no default yes, and Esc is the same refusal.
15
- * - no bulk yes without showing what "all" is: the carries lines are printed BEFORE the picker every time, and
16
- * "approve all N files" only appears when N > 1 (with one file it would be a second spelling of the same item).
17
- * Approving does not retro-load anything — hooks.ts is imported at boot, sandbox.json picks the executor at boot — so
18
- * the card closes with the CLI's own sentence: restart to apply. */
19
-
20
- import { relative } from "node:path";
21
- import { projectTrustRows, trustRows, trustShowLines, untrustedRows, untrustRows, type TrustRow } from "../core/project-trust.ts";
22
- import { trustFile } from "../core/trust.ts";
23
- import { rovecodeHome } from "../providers/auth.ts";
24
- import type { PickItem, Renderer } from "./renderer.ts";
25
-
26
- export const TRUST_CARD_USAGE = "/trust — review this repo's gated files and approve them · /trust show — review only · /trust untrust — withdraw";
27
-
28
- /** the palette entry (the mcp-cmd.ts idiom, so app.ts's table gains ONE line) */
29
- export const TRUST_SUBCOMMANDS = ["show", "untrust"] as const;
30
- export const TRUST_COMMAND = { name: "trust", choices: TRUST_SUBCOMMANDS, choicesThen: "submit" as const, description: "Review what this repo's config would run and approve it: /trust · /trust show · /trust untrust", group: "modes & safety" };
31
-
32
- /** picker value of the refusal (first item) and of the bulk approval — neither can collide with a file path */
33
- export const KEEP_UNTRUSTED = "\u0000keep-untrusted";
34
- export const TRUST_ALL = "\u0000trust-all";
35
-
36
- export const RESTART_NOTE = "restart rovecode to apply — an edit to any of these files asks again";
37
-
38
- export interface TrustCardCtx {
39
- renderer: Renderer;
40
- cwd: string;
41
- /** the trust store's home; default rovecodeHome() (tests point it at a scratch dir) */
42
- home?: string;
43
- }
44
-
45
- /** the picker for the untrusted rows: refusal FIRST, then one item per file, then the bulk item when there are several */
46
- export function trustPickItems(untrusted: readonly TrustRow[], cwd: string): PickItem[] {
47
- const items: PickItem[] = [{ value: KEEP_UNTRUSTED, label: "keep them untrusted", description: "nothing from these files is used; you will be asked again next launch" }];
48
- for (const r of untrusted) items.push({ value: r.file, label: `approve ${rel(r.file, cwd)}`, description: r.carries.join(" · ") });
49
- if (untrusted.length > 1) items.push({ value: TRUST_ALL, label: `approve all ${untrusted.length} files`, description: untrusted.map((r) => rel(r.file, cwd)).join(", ") });
50
- return items;
51
- }
52
-
53
- const rel = (file: string, cwd: string): string => { const r = relative(cwd, file); return r === "" || r.startsWith("..") ? file : r; };
54
-
55
- export function trustCardTitle(cwd: string, untrusted: readonly TrustRow[]): string {
56
- const what = untrusted.length === 1 ? "1 file" : `${untrusted.length} files`;
57
- return `${cwd}: ${what} would make rovecode run something and ${untrusted.length === 1 ? "is" : "are"} not trusted on this machine — the lines above say what each one carries. Enter on the first item changes nothing (Esc the same).`;
58
- }
59
-
60
- /** `/trust [show|untrust]` — the review lines, then (bare verb only) the approval card */
61
- export async function cmdTrustCard(ctx: TrustCardCtx, arg = ""): Promise<void> {
62
- const { renderer } = ctx;
63
- const home = ctx.home ?? rovecodeHome();
64
- const verb = arg.trim().split(/\s+/).filter(Boolean)[0] ?? "";
65
- if (verb !== "" && verb !== "show" && verb !== "untrust") { renderer.addSystemNote(`unknown /trust verb "${verb}" — ${TRUST_CARD_USAGE}`, "warn"); return; }
66
- const rows = projectTrustRows(ctx.cwd, home);
67
- if (verb === "untrust") { for (const l of untrustRows(home, rows)) renderer.addSystemNote(l); return; }
68
- show(ctx, rows);
69
- if (verb === "show" || rows.length === 0) return;
70
- if (untrustedRows(rows).length === 0) { renderer.addSystemNote("every gated file here is already trusted — nothing to approve"); return; }
71
- await ask(ctx, home);
72
- }
73
-
74
- /** the `trust show` lines, verbatim from project-trust.ts; an untrusted file's header is a warn so it is not read as prose */
75
- function show(ctx: TrustCardCtx, rows: readonly TrustRow[]): void {
76
- for (const line of trustShowLines([...rows])) ctx.renderer.addSystemNote(line, line.startsWith("· UNTRUSTED") ? "warn" : "info");
77
- }
78
-
79
- /** one card per remaining untrusted file: approve one → re-list what is left → ask again, until the person refuses
80
- * (Enter on the first item / Esc) or nothing is left. `trustFile` records the file's CURRENT bytes. */
81
- async function ask(ctx: TrustCardCtx, home: string): Promise<void> {
82
- const { renderer } = ctx;
83
- let approved = 0;
84
- for (;;) {
85
- const untrusted = untrustedRows(projectTrustRows(ctx.cwd, home));
86
- if (untrusted.length === 0) break;
87
- const picked = await renderer.pickOne(trustPickItems(untrusted, ctx.cwd), trustCardTitle(ctx.cwd, untrusted));
88
- if (picked === null || picked === KEEP_UNTRUSTED) {
89
- renderer.addSystemNote(`${untrusted.length} file${untrusted.length === 1 ? "" : "s"} left untrusted — ${untrusted.map((r) => rel(r.file, ctx.cwd)).join(", ")} contribute nothing this session`, "warn");
90
- break;
91
- }
92
- if (picked === TRUST_ALL) {
93
- for (const l of trustRows(home, untrusted)) renderer.addSystemNote(l);
94
- approved += untrusted.length;
95
- break;
96
- }
97
- const row = untrusted.find((r) => r.file === picked);
98
- if (row === undefined) break; // a file that vanished between the card and the answer: nothing to record
99
- const t = trustFile(home, row.file);
100
- if (!t.ok) { renderer.addSystemNote(t.reason, "warn"); break; }
101
- renderer.addSystemNote(`trusted ${row.file} (${t.digest.slice(0, 12)}…)`);
102
- approved++;
103
- if (untrusted.length === 1) break; // that was the last one; the loop's re-list would only confirm it
104
- show(ctx, untrustedRows(projectTrustRows(ctx.cwd, home)));
105
- }
106
- if (approved > 0) ctx.renderer.addSystemNote(RESTART_NOTE);
107
- }