rovecode 0.3.3 → 0.4.0-beta.2

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