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,30 +0,0 @@
1
- /** A session id typed on the command line (aion hygiene h2, brought over 2026-09-07): the CLI's ONE gate for the entry
2
- * points that used to take an id straight into a path join — `rovecode --resume <id|prefix>` (main.ts hand-parses the
3
- * value) and `rovecode trace <id|prefix>`. Both resolve here through core/session-ops.ts resolveSession: validity
4
- * first (core/session-id.ts), then an exact id or a UNIQUE prefix among the sessions under the root; a miss or an
5
- * ambiguity is the usage error, never a fresh session dir under the typed name (which is what `--resume typo` used to
6
- * create, silently). A bad id is exit 2 with ONE stderr line; `fail` is injectable for tests. */
7
-
8
- import { describeBadSessionId } from "../core/session-id.ts";
9
- import { resolveSession } from "../core/session-ops.ts";
10
-
11
- const usageExit = (msg: string): never => {
12
- process.stderr.write(`error: ${msg}\n`); // ONE stderr line
13
- return process.exit(2);
14
- };
15
-
16
- /** `<what> <id>`: the id, or the usage error — missing, empty, `.`/`..`, a separator (core/session-id.ts). */
17
- export function sessionIdArg(what: string, id: string | undefined, fail: (msg: string) => never = usageExit): string {
18
- if (id === undefined) return fail(`${what} needs a session id or prefix`);
19
- const bad = describeBadSessionId(id);
20
- return bad === undefined ? id : fail(`${what}: ${bad}`);
21
- }
22
-
23
- /** Validity (sessionIdArg) + resolution against the sessions under `root`: an exact id wins, else exactly ONE prefix
24
- * match; several or none is the usage error naming them (never the first hit, never a new directory). */
25
- export function resolveSessionArg(what: string, root: string, id: string | undefined, fail: (msg: string) => never = usageExit): string {
26
- const wanted = sessionIdArg(what, id, fail);
27
- const r = resolveSession(root, wanted);
28
- if (r.ok) return r.id;
29
- return fail(r.error.startsWith("no session matching") ? `${what}: ${r.error} in ${root} (rovecode sessions lists them)` : `${what}: ${r.error}`);
30
- }
@@ -1,145 +0,0 @@
1
- /** `rovecode sessions [--json]` (aion port #59, brought over 2026-09-07): the headless view of the TUI's /sessions picker
2
- * over the ONE scanner (core/session.ts scanSessions — no second directory walk). Rows carry id, created, updated, cwd
3
- * (the workspace whose sessions were listed — sessions are per project dir), the first prompt and the user-turn
4
- * count; newest (updatedAt) first. `--json` prints the row array; the text table prints the cwd once in its header
5
- * and, when there are any, ONE footer line counting the hollow directories (a meta.json, nothing ever written) from
6
- * the stat alone — they are not rows, and whether to delete them is Berkay's open question; the count keeps it
7
- * askable. Exit 0, also for an empty list.
8
- * Port #84 — four verbs over core/session-ops.ts: `rename <id|prefix> <title…>`, `delete <id|prefix> [--yes]`,
9
- * `fork <id|prefix> [--json]`, `search <terms…> [--json]`. Rows and the table show a set `title` (`--json` rows carry
10
- * the key ONLY when set). Ids resolve by the /resume rule BEFORE any write; a usage error (unknown verb, missing id,
11
- * bad / ambiguous / unknown id, empty title or query, an oversize fork) is exit 2 + ONE stderr line, nothing removed
12
- * or created. Nothing boots a runtime or provider. `--yes` (codex's DeleteConfirmation Skip, pattern only) skips the
13
- * y/N confirmation; a non-TTY stdin without it is refused (exit 2) — the TTY prompt itself (Bun's synchronous
14
- * `confirm`, default N) is not hermetically tested. `--json` / `--yes` are booleans: no dispatch.ts VALUE_FLAGS entry.
15
- * aion's `--cwd <dir>` is not brought: rovecode commands act on the cwd. */
16
-
17
- import { scanSessions } from "../core/session.ts";
18
- import { deleteSession, forkSession, oneLineTitle, renameSession, resolveSession, searchSessions, sessionsRoot, type SearchRow } from "../core/session-ops.ts";
19
-
20
- export interface SessionRow {
21
- id: string;
22
- /** ISO 8601 */
23
- created: string;
24
- updated: string;
25
- cwd: string;
26
- /** first user-message text, single line, ≤80 chars ("" for an empty session) */
27
- firstPrompt: string;
28
- /** user messages recorded in the session file (every branch) */
29
- turns: number;
30
- /** all entries (messages + event markers) */
31
- entries: number;
32
- /** the user-given title — the key is present ONLY when one is set */
33
- title?: string;
34
- }
35
-
36
- export interface SessionListing { rows: SessionRow[]; hollow: number; root: string }
37
-
38
- /** the rows (sessions that hold something) plus the hollow count, from one scan */
39
- export function sessionListing(cwd: string): SessionListing {
40
- const root = sessionsRoot(cwd);
41
- const scan = scanSessions(root);
42
- const rows = scan.sessions.map((s) => ({
43
- id: s.id, created: new Date(s.createdAt).toISOString(), updated: new Date(s.updatedAt).toISOString(),
44
- cwd, firstPrompt: s.preview, turns: s.turns, entries: s.entryCount,
45
- ...(s.title !== undefined ? { title: s.title } : {}),
46
- }));
47
- return { rows, hollow: scan.hollow.length, root };
48
- }
49
-
50
- export function sessionRows(cwd: string): SessionRow[] {
51
- return sessionListing(cwd).rows;
52
- }
53
-
54
- /** the one footer line for the hollow directories, or undefined when there are none */
55
- export function hollowLine(count: number, root: string): string | undefined {
56
- if (count === 0) return undefined;
57
- return `${count} empty session director${count === 1 ? "y" : "ies"} in ${root} — nothing was ever written to them`;
58
- }
59
-
60
- export function formatSessions(listing: SessionListing, json: boolean): string {
61
- const { rows, hollow, root } = listing;
62
- if (json) return JSON.stringify(rows);
63
- const footer = hollowLine(hollow, root);
64
- if (rows.length === 0) return [`no sessions in ${root} — a \`rovecode run\` or a TUI turn starts one`, ...(footer ? [footer] : [])].join("\n");
65
- const lines = [`sessions in ${root} (newest first; --json for the full rows):`, `${"id".padEnd(36)} ${"created".padEnd(24)} turns first prompt`];
66
- for (const r of rows) lines.push(`${r.id.padEnd(36)} ${r.created.padEnd(24)} ${String(r.turns).padStart(5)} ${r.title ?? (r.firstPrompt || "(empty session)")}`); // a title stands in for the first prompt
67
- if (footer) lines.push(footer);
68
- return lines.join("\n");
69
- }
70
-
71
- /** one search hit per line: session id8 · ISO time · entry id8 (or `title` for a title-tier hit) · [title] preview */
72
- export function formatSearchHit(r: SearchRow): string {
73
- const where = r.entryId === "" ? "title" : r.entryId.slice(0, 8);
74
- return `${r.sessionId.slice(0, 8)} ${new Date(r.timestamp).toISOString()} ${where.padEnd(8)} ${r.title !== undefined ? `[${r.title}] ` : ""}${r.preview}`;
75
- }
76
-
77
- export const SESSIONS_USAGE = "usage: rovecode sessions [--json] | rename <id|prefix> <title…> | delete <id|prefix> [--yes] | fork <id|prefix> [--json] | search <terms…> [--json]";
78
- const VERBS: ReadonlySet<string> = new Set(["rename", "delete", "fork", "search"]);
79
-
80
- /** a token that is a flag, not a value: `-x`, `--x` (a lone `-` would be stdin, a value) */
81
- const isFlag = (a: string): boolean => a.length > 1 && a.startsWith("-");
82
-
83
- /** the words after the `sessions` token minus every flag token */
84
- export function sessionWords(argv: readonly string[]): string[] {
85
- const at = argv.indexOf("sessions");
86
- return at === -1 ? [] : argv.slice(at + 1).filter((a) => !isFlag(a));
87
- }
88
-
89
- export interface SessionsCmdIo {
90
- out: (text: string) => void;
91
- err: (text: string) => void;
92
- /** stdin is a terminal (the y/N prompt is possible); default process.stdin.isTTY */
93
- tty?: boolean;
94
- /** the y/N prompt; default Bun's global confirm */
95
- confirm?: (question: string) => boolean;
96
- }
97
-
98
- /** main.ts dispatch: the sessions of `cwd`. Returns the exit code. */
99
- export function cmdSessions(argv: readonly string[], cwd: string, io: Partial<SessionsCmdIo> = {}): number {
100
- const out = io.out ?? ((t: string) => console.log(t));
101
- const err = io.err ?? ((t: string) => process.stderr.write(`${t}\n`));
102
- const usageError = (msg: string): number => { err(`error: ${msg} — ${SESSIONS_USAGE}`); return 2; }; // ONE stderr line, exit 2
103
- const json = argv.includes("--json");
104
- const words = sessionWords(argv);
105
- const verb = words[0];
106
- if (verb === undefined) { out(formatSessions(sessionListing(cwd), json)); return 0; }
107
- if (!VERBS.has(verb)) return usageError(`unknown sessions verb "${verb}"`);
108
- const root = sessionsRoot(cwd);
109
- if (verb === "search") {
110
- const q = words.slice(1).join(" ").trim();
111
- if (q === "") return usageError("search needs at least one term");
112
- const rows = searchSessions(root, q, 10);
113
- if (json) out(JSON.stringify(rows));
114
- else out(rows.length === 0 ? `no matches for "${q}" in ${root}` : rows.map(formatSearchHit).join("\n"));
115
- return 0;
116
- }
117
- const ref = words[1];
118
- if (ref === undefined) return usageError(`${verb} needs a session id or prefix`);
119
- const found = resolveSession(root, ref); // validity + the /resume rule over readdir names — nothing is created or removed before this
120
- if (!found.ok) return usageError(found.error);
121
- if (verb === "rename") {
122
- const title = oneLineTitle(words.slice(2).join(" "));
123
- if (title === undefined) return usageError("rename needs a non-empty title");
124
- renameSession(root, found.id, title);
125
- out(`renamed ${found.id} → "${title}"`);
126
- return 0;
127
- }
128
- if (verb === "fork") {
129
- let r;
130
- try { r = forkSession(root, found.summary); } catch (e) { return usageError(e instanceof Error ? e.message : String(e)); }
131
- out(json ? JSON.stringify(r) : `${r.id} fork of ${r.from.slice(0, 8)} · "${r.title}"`);
132
- return 0;
133
- }
134
- // delete — codex DeleteConfirmation { Prompt, Skip }: `--yes` = Skip; Prompt only on a TTY (default N); otherwise refused
135
- if (!argv.includes("--yes")) {
136
- const tty = io.tty ?? process.stdin.isTTY === true;
137
- if (!tty) return usageError(`delete ${found.id.slice(0, 8)} needs --yes when stdin is not a terminal`);
138
- const label = found.summary.title ?? (found.summary.preview || "(empty session)");
139
- const ask = io.confirm ?? ((q: string) => confirm(q));
140
- if (!ask(`delete session ${found.id} (${label}, ${found.summary.entryCount} entries) and its checkpoints?`)) { out("delete cancelled — nothing removed"); return 0; }
141
- }
142
- const { removed } = deleteSession(cwd, root, found.id);
143
- out(removed.length === 0 ? `nothing to remove for ${found.id}` : removed.map((p) => `removed ${p}`).join("\n"));
144
- return 0;
145
- }
package/src/cli/setup.ts DELETED
@@ -1,153 +0,0 @@
1
- /** `rovecode setup` — connect a model in one sitting: pick a provider, name the model, paste the key
2
- * (masked, via auth.ts readSecret), one tiny real call, and the pick becomes the default in
3
- * ~/.rovecode/providers.json. Every step reads through an injectable seam (ask / secret / save /
4
- * probe) so the whole flow is unit-testable with scripted answers and no network. Piped stdin
5
- * (no TTY) prints the three-line recipe and exits 2 — a wizard must not consume a script's input.
6
- * Wording: core/voice.ts rules — rovecode speaks, short lines, every problem ends with "→ next:". */
7
-
8
- import { createInterface } from "node:readline";
9
- import { readSecret, saveCredential } from "../providers/auth.ts";
10
- import { PROVIDER_ID_RE, inferProtocol, isConfigured } from "../providers/provider-config.ts";
11
- import type { ProviderRegistry } from "../providers/registry.ts";
12
- import { next, noModelHint } from "../core/voice.ts";
13
-
14
- export interface ProbeResult { ok: boolean; model: string; detail: string }
15
-
16
- export interface SetupDeps {
17
- registry: ProviderRegistry;
18
- /** default console.log */
19
- out?: (line: string) => void;
20
- /** one plain-text answer (default: readline on stdin, echoed) */
21
- ask?: (prompt: string) => Promise<string>;
22
- /** one secret (default: readSecret — masked on a TTY) */
23
- secret?: (prompt: string) => Promise<string>;
24
- /** default auth.ts saveCredential */
25
- save?: (id: string, secret: string, keyEnv: string) => void;
26
- /** default registry.probe (one tiny real call) */
27
- probe?: (id: string, model?: string) => Promise<ProbeResult>;
28
- /** default process.stdin.isTTY === true */
29
- tty?: boolean;
30
- }
31
-
32
- interface Pick { key: string; label: string; id?: string; local?: boolean; url?: "openai" | "anthropic" }
33
-
34
- /** the numbered menu: the common hosted providers, the two local servers, and two "your own URL" doors */
35
- export const SETUP_PICKS: readonly Pick[] = [
36
- { key: "1", id: "anthropic", label: "anthropic — Claude models" },
37
- { key: "2", id: "openai", label: "openai" },
38
- { key: "3", id: "openrouter", label: "openrouter — many models behind one key" },
39
- { key: "4", id: "deepseek", label: "deepseek" },
40
- { key: "5", id: "groq", label: "groq" },
41
- { key: "6", id: "ollama", label: "ollama — local, no key needed", local: true },
42
- { key: "7", id: "lmstudio", label: "lmstudio — local, no key needed", local: true },
43
- { key: "8", label: "another OpenAI-compatible URL (a proxy, vLLM, …)", url: "openai" },
44
- { key: "9", label: "another Anthropic-protocol URL", url: "anthropic" },
45
- ];
46
-
47
- export const SETUP_DONE = 'Done. Try: rovecode "explain this repo"';
48
-
49
- /** one echoed line from the terminal — shared with main.ts's numbered model picker */
50
- export function askLine(prompt: string): Promise<string> {
51
- return new Promise((resolve) => {
52
- const rl = createInterface({ input: process.stdin, output: process.stdout });
53
- let settled = false;
54
- rl.question(prompt, (a) => { if (settled) return; settled = true; rl.close(); resolve(a.trim()); });
55
- rl.once("close", () => { if (!settled) { settled = true; resolve(""); } });
56
- });
57
- }
58
-
59
- /** exit code: 0 connected (or added with a clear next step), 2 not a TTY / cancelled / invalid input */
60
- export async function runSetup(deps: SetupDeps): Promise<number> {
61
- const out = deps.out ?? console.log;
62
- const ask = deps.ask ?? askLine;
63
- const secret = deps.secret ?? ((p: string) => readSecret(p));
64
- const save = deps.save ?? saveCredential;
65
- const reg = deps.registry;
66
- const probe = deps.probe ?? ((id: string, model?: string) => reg.probe(id, model));
67
- const tty = deps.tty ?? process.stdin.isTTY === true;
68
-
69
- if (!tty) { out(noModelHint("cli")); out(" (rovecode setup needs a terminal — this stdin is a pipe)"); return 2; }
70
-
71
- out("◆ rovecode setup — let's connect a model. Two or three questions.");
72
- out("");
73
- for (const p of SETUP_PICKS) out(` ${p.key} ${p.label}`);
74
- out("");
75
- let pick: Pick | undefined;
76
- for (let tries = 0; tries < 3 && pick === undefined; tries++) {
77
- const a = (await ask("Which one? [1-9, empty = cancel]: ")).trim();
78
- if (a.length === 0) { out(`cancelled — nothing changed. ${next("rovecode setup")} whenever you like`); return 2; }
79
- pick = SETUP_PICKS.find((p) => p.key === a || p.id === a);
80
- if (pick === undefined) out(` "${a}" is not on the list — a number from 1 to 9, please.`);
81
- }
82
- if (pick === undefined) return 2;
83
-
84
- // ---- the provider: a built-in, a keyless local server, or a URL of your own ----
85
- let id: string;
86
- if (pick.url !== undefined) {
87
- id = (await ask("Short name for it (letters, digits, - _ .): ")).trim().toLowerCase();
88
- if (!PROVIDER_ID_RE.test(id)) { out(` "${id}" won't work as an id. ${next("rovecode setup, and pick a name like myproxy")}`); return 2; }
89
- const baseUrl = (await ask("Base URL (e.g. https://host/v1): ")).trim();
90
- if (!/^https?:\/\//.test(baseUrl)) { out(` "${baseUrl}" is not an http(s) URL. ${next("rovecode setup")}`); return 2; }
91
- const protocol = pick.url === "anthropic" ? "anthropic" : baseUrl.includes("anthropic.com") ? inferProtocol(baseUrl) : "openai";
92
- const noKey = (await ask("Does it need an API key? [Y/n]: ")).trim().toLowerCase().startsWith("n");
93
- const r = reg.add({ id, baseUrl, protocol, ...(noKey ? { noKey: true } : {}) }, "user");
94
- if ("error" in r) { out(` ${r.error}. ${next("rovecode setup")}`); return 2; }
95
- out(`◆ ${id} registered (${protocol} protocol, ${baseUrl}).`);
96
- } else {
97
- id = pick.id!;
98
- const known = reg.get(id);
99
- if (known === undefined) { out(` ${id} is missing from the built-in table — that is a bug. ${next("rovecode provider add " + id + " <baseUrl>")}`); return 2; }
100
- if (pick.local === true && known.noKey !== true) {
101
- // the built-in row expects a key env; a local server needs none — the user entry says so
102
- const r = reg.add({ id, baseUrl: known.baseUrl, protocol: known.protocol, noKey: true, ...(known.defaultModel !== undefined ? { defaultModel: known.defaultModel } : {}) }, "user");
103
- if ("error" in r) { out(` ${r.error}. ${next("rovecode setup")}`); return 2; }
104
- out(`◆ ${id} marked as a local server (${known.baseUrl}, no key).`);
105
- }
106
- }
107
-
108
- // ---- the model ----
109
- const spec = reg.get(id)!;
110
- const suggested = spec.defaultModel;
111
- const modelAnswer = (await ask(suggested !== undefined ? `Model id [${suggested}]: ` : "Model id (empty = choose later with rovecode model list): ")).trim();
112
- const model = modelAnswer.length > 0 ? modelAnswer : suggested;
113
-
114
- // ---- the key ----
115
- let hasKey = isConfigured(spec);
116
- if (!hasKey) {
117
- const s = await secret(`${spec.keyEnv} (hidden): `);
118
- if (s.trim().length === 0) {
119
- out(`◆ no key stored — I can't call ${id} without one.`);
120
- out(` ${next(`rovecode auth set ${id}`)} (or set ${spec.keyEnv} in your environment)`);
121
- } else {
122
- save(id, s.trim(), spec.keyEnv);
123
- reg.refresh();
124
- hasKey = true;
125
- out(`◆ key stored for ${id} (hidden; ~/.rovecode/credentials.json).`);
126
- }
127
- } else out(`◆ ${id} already has a key (${spec.keySource === "stored" ? "stored" : `env ${spec.keyEnv}`}).`);
128
-
129
- // ---- one tiny real call ----
130
- if (hasKey && model !== undefined) {
131
- out(`◆ testing ${id}/${model} …`);
132
- const r = await probe(id, model);
133
- if (r.ok) out(` ${r.detail}`);
134
- else {
135
- out(` that didn't work: ${r.detail}`);
136
- out(` ${next(`check the key and the URL, then rovecode provider test ${id} ${model}`)}`);
137
- }
138
- }
139
-
140
- // ---- make it the default ----
141
- if (model !== undefined) {
142
- const d = reg.setDefault(`${id}/${model}`, "user");
143
- if ("error" in d) { out(` ${d.error}. ${next(`rovecode model use ${id}/<model>`)}`); return 2; }
144
- out(`◆ default → ${d.provider}/${d.model} (~/.rovecode/providers.json; running TUIs switch live).`);
145
- } else {
146
- out(`◆ ${id} is set up but has no model yet.`);
147
- out(` ${next(`rovecode model list ${id}, then rovecode model use ${id}/<model>`)}`);
148
- }
149
- out("");
150
- out(SETUP_DONE);
151
- out(" or open the cockpit: rovecode");
152
- return 0;
153
- }
@@ -1,194 +0,0 @@
1
- /** `rovecode skills list|validate|pack|install` (port #72): the agentskills.io-shaped skill catalogue on the command
2
- * line. Mirrors cli/mcp-market-cmd.ts — hand-parsed argv, an io seam, ONE dispatch line in main.ts — plus an
3
- * injectable fetch and DNS resolver for the URL install. Exit codes: 0 ok · 1 usage / strict finding / refused
4
- * overwrite / non-http(s) URL / symlink / a refused address · 2 io (unreadable, not an archive, unsafe entries, an
5
- * invalid staged skill, HTTP or network failure). `list` is the LENIENT loader the runtime uses (every loaded skill,
6
- * every loader warning, the files it refused); `validate` and `pack` are STRICT (spec violations are errors, unknown
7
- * keys notes, nothing is written after a finding). Scopes are skills/index.ts skillsDir(cwd, scope):
8
- * `<cwd>/.rovecode/skills`, or `<home>/skills` with --user (ROVECODE_HOME honoured). allowed-tools is never enforced.
9
- *
10
- * `install <url>` goes through the SAME SSRF guard as web_fetch and web_search (tools/webfetch.ts ssrfDenyReason:
11
- * loopback, private, link-local and reserved ranges refused, names resolved through the injectable resolver) — on the
12
- * URL and on every redirect hop, http(s) only, ≤ 5 hops. The reason is that a human typing a URL is not the only
13
- * caller: a model with bash can run `rovecode skills install http://169.254.169.254/…`, and cloud metadata is exactly
14
- * what that guard is for. A CLI that skips the check its own tools make is the soft spot in the boundary, so do not
15
- * remove this. There is deliberately NO allow-private knob: an intranet-hosted archive is refused, and `curl` +
16
- * `skills install <file.tar.gz>` is the local path — one env knob is a decision for Berkay, not a default.
17
- * Body bounded at 64 MiB (webfetch readBounded) under a ref'd timeout. */
18
-
19
- import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
20
- import { basename, join, resolve } from "node:path";
21
- import { SKILL_FILE, SkillStore, skillsDir } from "../skills/index.ts";
22
- import { parseSkillFrontmatter, validateSkillMeta, type Validation } from "../skills/spec.ts";
23
- import { installFromBytes, installFromDir, MAX_ARCHIVE_BYTES, packSkill, SkillCmdError, type InstallResult } from "../skills/pack.ts";
24
- import { abortable, dnsResolver, readBounded, ssrfDenyReason, type FetchLike, type Resolver } from "../tools/webfetch.ts";
25
-
26
- export interface SkillsCmdIo { out(line: string): void; err(line: string): void }
27
- export interface SkillsCmdDeps {
28
- io?: SkillsCmdIo;
29
- /** the URL install's fetch (tests inject a loopback / scripted one) */
30
- fetch?: FetchLike;
31
- /** the SSRF guard's name resolver (tests inject one that answers for their loopback fixture) */
32
- resolve?: Resolver;
33
- /** the user-scope skills dir (default `<user state dir>/skills`) */
34
- globalDir?: string;
35
- }
36
- const stdio: SkillsCmdIo = { out: (l) => console.log(l), err: (l) => console.error(l) };
37
-
38
- export const SKILLS_USAGE =
39
- "usage: rovecode skills list [--json] | rovecode skills validate <dir> | rovecode skills pack <dir> [--out <file>] [--force] | " +
40
- "rovecode skills install <dir|file.tar.gz|http(s)-url> [--user] [--force]";
41
- export const INSTALL_TIMEOUT_MS = 60_000;
42
- export const MAX_REDIRECTS = 5;
43
- const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
44
- const URL_SCHEME = /^([a-z][a-z0-9+.-]*):\/\//i;
45
-
46
- /** Entry point: `args` are the argv words AFTER `skills`. Returns the exit code. */
47
- export async function cmdSkills(args: string[], cwd: string, deps: SkillsCmdDeps = {}): Promise<number> {
48
- const io = deps.io ?? stdio;
49
- const action = args[0] ?? "";
50
- const rest = args.slice(1);
51
- const flags = new Set(rest.filter((a) => a.startsWith("--")));
52
- const outIx = rest.indexOf("--out");
53
- const outFile = outIx !== -1 ? rest[outIx + 1] : undefined;
54
- const positional = rest.filter((a, i) => !a.startsWith("--") && rest[i - 1] !== "--out");
55
- const globalDir = deps.globalDir ?? skillsDir(cwd, "global");
56
- try {
57
- if (action === "list") return list(cwd, globalDir, flags.has("--json"), io);
58
- if (action === "validate" && positional[0] !== undefined) return validate(resolve(cwd, positional[0]), io);
59
- if (action === "pack" && positional[0] !== undefined) {
60
- return await pack(resolve(cwd, positional[0]), outFile !== undefined ? resolve(cwd, outFile) : undefined, flags.has("--force"), cwd, io);
61
- }
62
- if (action === "install" && positional[0] !== undefined) {
63
- const target = flags.has("--user") ? globalDir : skillsDir(cwd, "project");
64
- return await install(positional[0], cwd, target, flags.has("--force"), deps.fetch ?? ((u, i) => fetch(u, i)), deps.resolve ?? dnsResolver, io);
65
- }
66
- } catch (err) {
67
- io.err(`error: ${err instanceof Error ? err.message : String(err)}`);
68
- return err instanceof SkillCmdError ? err.code : 2;
69
- }
70
- io.err(SKILLS_USAGE);
71
- return 1;
72
- }
73
-
74
- function list(cwd: string, globalDir: string, json: boolean, io: SkillsCmdIo): number {
75
- const r = new SkillStore(cwd, { globalDir }).scan();
76
- const byPath = new Map<string, string[]>();
77
- for (const w of r.warnings) byPath.set(w.path, [...(byPath.get(w.path) ?? []), w.reason]);
78
- const rows = r.skills.map((s) => ({
79
- name: s.name, version: s.version, scope: s.scope, path: s.path, dir: s.dir, description: s.fullDescription,
80
- license: s.license, compatibility: s.compatibility, metadata: s.metadata, allowedTools: s.allowedTools,
81
- warnings: byPath.get(s.path) ?? [],
82
- }));
83
- if (json) {
84
- io.out(JSON.stringify({ skills: rows, invalid: r.invalid }, null, 2));
85
- return 0;
86
- }
87
- if (rows.length === 0 && r.invalid.length === 0) {
88
- io.out(`no skills installed (${skillsDir(cwd, "project")} or ${globalDir}) — rovecode skills install <dir|file.tar.gz|url>`);
89
- return 0;
90
- }
91
- for (const row of rows) io.out(`${row.name.padEnd(24)} ${(row.version || "-").padEnd(10)} ${row.scope.padEnd(8)} ${row.path}`);
92
- for (const row of rows) for (const w of row.warnings) io.err(`warning: ${row.path}: ${w}`);
93
- for (const i of r.invalid) io.err(`warning: ${i.path}: not loaded — ${i.reason}`);
94
- return 0;
95
- }
96
-
97
- /** The strict spec check of `<dir>/SKILL.md`; unreadable → 2, no frontmatter → a finding (1). */
98
- function strictCheck(dir: string): Validation {
99
- const file = join(dir, SKILL_FILE);
100
- let text: string;
101
- try { text = readFileSync(file, "utf8"); }
102
- catch (e) { throw new SkillCmdError(`cannot read ${file}: ${e instanceof Error ? e.message : String(e)}`, 2); }
103
- const fm = parseSkillFrontmatter(text);
104
- if (fm === null) throw new SkillCmdError(`${file}: missing or unterminated frontmatter block`, 1);
105
- return validateSkillMeta(fm, basename(dir), "strict");
106
- }
107
-
108
- /** one stderr line per finding, notes on stdout; true when there are no errors */
109
- function report(v: Validation, dir: string, io: SkillsCmdIo): boolean {
110
- for (const e of v.errors) io.err(`${join(dir, SKILL_FILE)}: ${e}`);
111
- for (const n of v.notes) io.out(`note: ${n}`);
112
- return v.errors.length === 0;
113
- }
114
-
115
- function validate(dir: string, io: SkillsCmdIo): number {
116
- const v = strictCheck(dir);
117
- if (!report(v, dir, io)) return 1;
118
- io.out(`ok: ${v.meta.name}${v.meta.version ? ` (v${v.meta.version})` : ""} — ${join(dir, SKILL_FILE)}`);
119
- return 0;
120
- }
121
-
122
- async function pack(dir: string, outFile: string | undefined, force: boolean, cwd: string, io: SkillsCmdIo): Promise<number> {
123
- const v = strictCheck(dir);
124
- if (!report(v, dir, io)) return 1; // any finding → nothing written
125
- const out = outFile ?? join(cwd, `${v.meta.name}.tar.gz`);
126
- if (existsSync(out) && !force) {
127
- io.err(`error: ${out} already exists (use --force to overwrite)`);
128
- return 1;
129
- }
130
- const bytes = await packSkill(dir, v.meta.name); // a symlink inside → SkillCmdError(1) before any write
131
- writeFileSync(out, bytes);
132
- io.out(`packed ${v.meta.name} → ${out} (${bytes.length} bytes)`);
133
- return 0;
134
- }
135
-
136
- async function install(src: string, cwd: string, dir: string, force: boolean, fetchImpl: FetchLike, resolve_: Resolver, io: SkillsCmdIo): Promise<number> {
137
- const scheme = URL_SCHEME.exec(src)?.[1]?.toLowerCase();
138
- let result: InstallResult;
139
- if (scheme !== undefined) {
140
- if (scheme !== "http" && scheme !== "https") throw new SkillCmdError(`only http(s) URLs can be installed (got ${scheme}:)`, 1);
141
- result = await installFromBytes(await download(src, fetchImpl, resolve_), dir, { force });
142
- } else {
143
- const path = resolve(cwd, src);
144
- let isDir: boolean;
145
- try { isDir = statSync(path).isDirectory(); }
146
- catch { throw new SkillCmdError(`${path}: no such file or directory`, 2); }
147
- result = isDir ? installFromDir(path, dir, { force }) : await installFromBytes(readFileSync(path), dir, { force });
148
- }
149
- io.out(`installed ${result.name}${result.version ? ` (v${result.version})` : ""} → ${result.path}`);
150
- for (const w of result.warnings) io.err(`warning: ${w}`);
151
- return 0;
152
- }
153
-
154
- /** The archive body under the SSRF guard (see the header): the address is checked BEFORE the request and again on
155
- * every redirect hop — `redirect: "manual"`, so a public URL cannot redirect us into the metadata service — http(s)
156
- * only, ≤ MAX_REDIRECTS. A REF'D timeout drives the abort (Bun's AbortSignal.timeout timer is unref'd — webfetch.ts
157
- * pattern). A refused address is 1 (nothing was fetched); non-2xx / network failure / over the cap are 2. */
158
- async function download(url: string, fetchImpl: FetchLike, resolve_: Resolver): Promise<Uint8Array> {
159
- const ac = new AbortController();
160
- const timer = setTimeout(() => ac.abort(), INSTALL_TIMEOUT_MS);
161
- (timer as unknown as { ref?: () => void }).ref?.();
162
- const failure = (e: unknown): SkillCmdError => new SkillCmdError(
163
- `download failed: ${ac.signal.aborted ? `timed out after ${INSTALL_TIMEOUT_MS}ms` : e instanceof Error ? e.message : String(e)}`, 2);
164
- try {
165
- let current = new URL(url);
166
- let hops = 0;
167
- for (;;) {
168
- if (current.protocol !== "http:" && current.protocol !== "https:") {
169
- throw new SkillCmdError(`only http(s) URLs can be installed (got ${current.protocol})`, 1);
170
- }
171
- let reason: string | null;
172
- try { reason = await abortable(ssrfDenyReason(current.hostname, resolve_), ac.signal); }
173
- catch (e) { throw failure(e); }
174
- if (reason !== null) throw new SkillCmdError(`refused ${current.href}: ${reason}`, 1);
175
- let res: Response;
176
- try { res = await abortable(fetchImpl(current.href, { signal: ac.signal, redirect: "manual" }), ac.signal); }
177
- catch (e) { throw failure(e); }
178
- if (REDIRECT_STATUSES.has(res.status)) {
179
- const location = res.headers.get("location");
180
- await res.body?.cancel().catch(() => {});
181
- if (!location) throw new SkillCmdError(`download failed: HTTP ${res.status} from ${current.href} without a Location header`, 2);
182
- if (++hops > MAX_REDIRECTS) throw new SkillCmdError(`download failed: too many redirects (more than ${MAX_REDIRECTS}) starting from ${url}`, 2);
183
- try { current = new URL(location, current); } catch { throw new SkillCmdError(`download failed: invalid redirect target ${location}`, 2); }
184
- continue; // the guard runs again on the new host — that is the point of the manual loop
185
- }
186
- if (!res.ok) throw new SkillCmdError(`download failed: HTTP ${res.status} for ${current.href}`, 2);
187
- const { bytes, truncated } = await readBounded(res, MAX_ARCHIVE_BYTES);
188
- if (truncated) throw new SkillCmdError(`download exceeds ${MAX_ARCHIVE_BYTES} bytes`, 2);
189
- return bytes;
190
- }
191
- } finally {
192
- clearTimeout(timer);
193
- }
194
- }
@@ -1,65 +0,0 @@
1
- /** Interactive startup only. The loading screen owns stdout through module loading, resume resolution,
2
- * runtime construction and the sandbox probe. runTui hands it over immediately before its first complete
3
- * frame. Plain chat never loads the renderers; optional network/cache work is not a readiness barrier. */
4
- import { join } from "node:path";
5
- import { startIntro } from "../core/intro.ts";
6
- import type { CliInvocation } from "./dispatch.ts";
7
- import pkg from "../../package.json";
8
-
9
- export async function startChat(cli: CliInvocation, argv: string[] = process.argv): Promise<void> {
10
- if (cli.plain) {
11
- const [{ runRepl }, { parseAddDirs }, { resolveBoot }] = await Promise.all([
12
- import("./repl.ts"), import("./run-flags.ts"), import("./resume.ts"),
13
- ]);
14
- resolveBoot(argv, join(process.cwd(), ".rovecode", "sessions")); // keep the existing invalid-resume diagnostic
15
- await runRepl({ yolo: cli.yolo, addDirs: parseAddDirs(argv) });
16
- return;
17
- }
18
- const intro = startIntro({
19
- write: (text) => { process.stdout.write(text); },
20
- tty: process.stdout.isTTY === true && !argv.includes("--no-intro") && process.env.ROVECODE_INTRO !== "0",
21
- version: pkg.version, holdUntilReady: true,
22
- size: () => ({ columns: process.stdout.columns || 80, rows: process.stdout.rows || 24 }),
23
- onResize: (paint) => { process.stdout.on("resize", paint); return () => { process.stdout.off("resize", paint); }; },
24
- });
25
- const ac = new AbortController();
26
- let signalExit = 130;
27
- const interrupt = () => { signalExit = 130; ac.abort(new Error("startup interrupted")); };
28
- const terminate = () => { signalExit = 143; ac.abort(new Error("startup terminated")); };
29
- const finish = () => {
30
- intro.finish();
31
- process.off("SIGINT", interrupt); process.off("SIGTERM", terminate);
32
- };
33
- // Also covers parsers that exit(2) instead of throwing. No raw input or keystroke consumption here.
34
- process.once("exit", finish);
35
- process.once("SIGINT", interrupt); process.once("SIGTERM", terminate);
36
- const t0 = Number(process.env._ROVECODE_BOOT_T0 ?? -1);
37
- const trace = (label: string) => { if (t0 >= 0) process.stderr.write(`[boot] +${Date.now() - t0}ms ${label}\n`); };
38
- try {
39
- trace("intro started");
40
- intro.status("loading modules");
41
- const [{ runTui }, { interactiveRenderer }, { parseAddDirs }, { resolveBoot }] = await Promise.all([
42
- import("../tui/app.ts"), import("../tui/notify.ts"), import("./run-flags.ts"), import("./resume.ts"),
43
- ]);
44
- ac.signal.throwIfAborted();
45
- trace("surface modules loaded");
46
- intro.status("opening session");
47
- const cwd = process.cwd();
48
- const boot = resolveBoot(argv, join(cwd, ".rovecode", "sessions"));
49
- const addDirs = parseAddDirs(argv);
50
- await runTui({
51
- yolo: cli.yolo, acceptEdits: cli.acceptEdits,
52
- ...(cli.effort !== undefined ? { effort: cli.effort } : {}),
53
- sessionId: boot.id, ...(boot.note !== undefined ? { bootNote: boot.note } : {}),
54
- renderer: interactiveRenderer(cli, process.env, process.stdout, process.stdin, cwd),
55
- ...(cli.pet !== undefined ? { pet: cli.pet } : {}), ...(addDirs.length > 0 ? { addDirs } : {}),
56
- startup: { status: intro.status, finish, animationDone: intro.animationDone, signal: ac.signal },
57
- });
58
- } catch (error) {
59
- if (ac.signal.aborted) { process.exitCode = signalExit; return; }
60
- throw error;
61
- } finally {
62
- finish();
63
- process.off("exit", finish);
64
- }
65
- }
@@ -1,52 +0,0 @@
1
- /** `rovecode trust` — the approval verb for every project file the trust gate covers (core/trust.ts): settings.json's
2
- * command-bearing keys, hooks.ts, sandbox.json, the MCP files. `trust show` says what each file WOULD do; `trust [--yes]`
3
- * approves them as they are now (a TTY confirms after the listing; off a TTY --yes is required); `trust untrust` withdraws.
4
- * `rovecode mcp trust` keeps working and acts on the MCP files only — the same store, so nothing already approved is lost. */
5
-
6
- import { rovecodeHome } from "../providers/auth.ts";
7
- import { projectTrustRows, trustRows, trustShowLines, untrustRows } from "../core/project-trust.ts";
8
-
9
- export const TRUST_USAGE = [
10
- "usage: rovecode trust list this repo's gated files with what they would do, then approve them (asks on a TTY)",
11
- " rovecode trust --yes approve without asking (after reading `trust show`)",
12
- " rovecode trust show list only — nothing changes",
13
- " rovecode trust untrust withdraw the approval; the files contribute nothing again until trusted",
14
- " gated: .rovecode/settings.json (verify, lsp, notify_command) · .rovecode/hooks.ts|js · .rovecode/sandbox.json · .rovecode/mcp.json · .mcp.json",
15
- " the store is ~/.rovecode/plugins.json (path → sha256): any edit to a file asks again",
16
- ];
17
-
18
- export interface TrustCmdIo {
19
- out?: (line: string) => void;
20
- err?: (line: string) => void;
21
- /** default rovecodeHome() */
22
- home?: string;
23
- /** default process.stdin.isTTY */
24
- tty?: boolean;
25
- /** the confirmation prompt (default Bun's confirm()) */
26
- confirm?: (question: string) => Promise<boolean> | boolean;
27
- }
28
-
29
- export async function cmdTrust(argv: string[], cwd: string = process.cwd(), io: TrustCmdIo = {}): Promise<number> {
30
- const out = io.out ?? ((l: string) => console.log(l));
31
- const err = io.err ?? ((l: string) => console.error(l));
32
- const home = io.home ?? rovecodeHome();
33
- const words = argv.filter((a) => !a.startsWith("--"));
34
- const yes = argv.includes("--yes");
35
- const verb = words[0] ?? "";
36
- if (verb === "-h" || verb === "help" || argv.includes("--help")) { for (const l of TRUST_USAGE) out(l); return 0; }
37
- if (verb !== "" && verb !== "show" && verb !== "untrust") { err(`unknown trust command "${verb}"`); for (const l of TRUST_USAGE) err(l); return 2; }
38
- const rows = projectTrustRows(cwd, home);
39
- if (verb === "show") { for (const l of trustShowLines(rows)) out(l); return 0; }
40
- if (verb === "untrust") { for (const l of untrustRows(home, rows)) out(l); return 0; }
41
- if (rows.length === 0) { for (const l of trustShowLines(rows)) out(l); return 1; }
42
- for (const l of trustShowLines(rows)) out(l);
43
- if (!yes) {
44
- const tty = io.tty ?? process.stdin.isTTY === true;
45
- if (!tty) { err("nothing trusted: no terminal to confirm on — re-run with --yes after reading the lines above"); return 1; }
46
- const ask = io.confirm ?? ((q: string) => confirm(q));
47
- if (!(await ask("trust these files as they are now? [y/N]"))) { out("nothing trusted"); return 1; }
48
- }
49
- for (const l of trustRows(home, rows)) out(l);
50
- out("restart rovecode to apply — an edit to any of these files asks again");
51
- return 0;
52
- }