rovecode 0.3.2 → 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 -45
  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 +38 -11
  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
package/src/mcp/config.ts DELETED
@@ -1,252 +0,0 @@
1
- /** MCP server configuration loading (port #3).
2
- * Merges `.rovecode/mcp.json` (ours) with `.mcp.json` (harvested, claude-code
3
- * format `{ mcpServers: { name: {command,args,env,url,type} } }`); ours wins
4
- * on a name clash. With a `home`, the USER file `<home>/mcp.json` is the lowest
5
- * layer under both (that is where `rovecode mcp add` writes by default).
6
- * `${NAME}` in args, env, headers or url is filled from the environment — so a
7
- * project file can name a secret without holding it; an unset name skips the
8
- * entry with a warning rather than launching a server with an empty key.
9
- * Malformed files/entries are skipped with a warning — this loader never throws. */
10
-
11
- import { existsSync, readFileSync } from "node:fs";
12
- import { join } from "node:path";
13
- import { fileDigest } from "../core/trust.ts";
14
-
15
- /** sha256 (hex) of a file's bytes — the trust key for a project file; since 2026-09-07 core/trust.ts's memoised one */
16
- export { fileDigest };
17
-
18
- /** the one line an untrusted project file gets — names the file, the count, the review and the approval command */
19
- export function untrustedNote(file: string, count: number): string {
20
- return `${file}: not trusted on this machine — its ${count} MCP server${count === 1 ? "" : "s"} stay off (they would run commands from this repo). Review: rovecode mcp show · approve: rovecode mcp trust (or rovecode trust for every gated file)`;
21
- }
22
-
23
- /** the PROJECT file — what the status hint and `mcp login` name (mcpConfigFiles(cwd).project) */
24
- export function mcpConfigPath(cwd: string): string {
25
- return mcpConfigFiles(cwd).project;
26
- }
27
-
28
- /** where each scope's file lives; the market's `add`/`remove` write exactly these */
29
- export function mcpConfigFiles(cwd: string, home?: string): { user?: string; harvest: string; project: string } {
30
- return { ...(home !== undefined ? { user: join(home, "mcp.json") } : {}), harvest: join(cwd, ".mcp.json"), project: join(cwd, ".rovecode", "mcp.json") };
31
- }
32
-
33
- const VAR_REF = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
34
- /** an unfilled market placeholder: `<directory the server may touch>`. Angle brackets around prose, which
35
- * is not something a real argument, URL or header value looks like. */
36
- const PLACEHOLDER_REF = /<[^<>]*[a-z][^<>]*>/g;
37
- /** `${NAME}` → env value; every missing name lands in `missing` (the caller decides that it is fatal) */
38
- export function expandVars(text: string, env: Record<string, string | undefined>, missing: string[]): string {
39
- return text.replace(VAR_REF, (_m, name: string) => { const v = env[name]; if (v === undefined) { missing.push(name); return ""; } return v; });
40
- }
41
-
42
- export interface McpServerConfig {
43
- name: string;
44
- /** `sse` is the legacy HTTP+SSE wire (port #57): a first-class url transport, and the wire an `http`
45
- * entry falls back to ONCE when its initialize POST answers 404/405 (client.ts) */
46
- transport: "stdio" | "http" | "sse";
47
- command?: string;
48
- args?: string[];
49
- env?: Record<string, string>;
50
- url?: string;
51
- /** extra HTTP headers (auth tokens etc.) for http transports */
52
- headers?: Record<string, string>;
53
- /** port #76 (mcp/oauth.ts): a configured client id beats dynamic registration; scope rides the authorize request */
54
- oauth?: { clientId?: string; scope?: string };
55
- enabled?: boolean;
56
- }
57
-
58
- /** Shared narrow helper (also used by the manager in client.ts). */
59
- export function isRecord(v: unknown): v is Record<string, unknown> {
60
- return typeof v === "object" && v !== null && !Array.isArray(v);
61
- }
62
-
63
- /** Shared error-to-string helper (also used by the manager in client.ts). */
64
- export function message(err: unknown): string {
65
- return err instanceof Error ? err.message : String(err);
66
- }
67
-
68
- /** Normalize one server entry (claude-code `.mcp.json` style or ours). Returns
69
- * undefined (and records a warning) when the entry cannot produce a usable config. */
70
- export function normalizeEntry(name: string, raw: unknown, file: string, warnings: string[], envSource: Record<string, string | undefined> = process.env, opts: { allowPlaceholders?: boolean } = {}): McpServerConfig | undefined {
71
- if (!isRecord(raw)) {
72
- warnings.push(`${file}: server "${name}" is not an object; skipped`);
73
- return undefined;
74
- }
75
- const missing: string[] = [];
76
- const fill = (s: string): string => expandVars(s, envSource, missing);
77
- const command = typeof raw.command === "string" && raw.command.length > 0 ? raw.command : undefined;
78
- const url = typeof raw.url === "string" && raw.url.length > 0 ? fill(raw.url) : undefined;
79
- const declared = typeof raw.transport === "string" ? raw.transport : typeof raw.type === "string" ? raw.type : undefined;
80
-
81
- let transport: McpServerConfig["transport"] | undefined;
82
- if (declared === "stdio") transport = "stdio";
83
- else if (declared === "http" || declared === "streamable-http" || declared === "streamable_http") transport = "http";
84
- else if (declared === "sse") transport = "sse"; // port #57: legacy HTTP+SSE, spoken by client.ts
85
- else if (declared !== undefined) {
86
- warnings.push(`${file}: server "${name}" has unknown transport "${declared}"; skipped`);
87
- return undefined;
88
- } else transport = url !== undefined ? "http" : command !== undefined ? "stdio" : undefined;
89
-
90
- if (transport === undefined) {
91
- warnings.push(`${file}: server "${name}" has neither command nor url; skipped`);
92
- return undefined;
93
- }
94
- if (transport === "stdio" && command === undefined) {
95
- warnings.push(`${file}: stdio server "${name}" is missing command; skipped`);
96
- return undefined;
97
- }
98
- if (transport === "http" || transport === "sse") {
99
- if (url === undefined) {
100
- warnings.push(`${file}: ${transport} server "${name}" is missing url; skipped`);
101
- return undefined;
102
- }
103
- try {
104
- new URL(url);
105
- } catch {
106
- warnings.push(`${file}: ${transport} server "${name}" has invalid url "${url}"; skipped`);
107
- return undefined;
108
- }
109
- }
110
-
111
- let args: string[] | undefined;
112
- if (raw.args !== undefined) {
113
- if (Array.isArray(raw.args) && raw.args.every((x): x is string => typeof x === "string")) {
114
- args = raw.args.map(fill);
115
- } else {
116
- warnings.push(`${file}: server "${name}" has non-string args; skipped`);
117
- return undefined;
118
- }
119
- }
120
- let env: Record<string, string> | undefined;
121
- if (isRecord(raw.env)) {
122
- env = {};
123
- for (const [k, v] of Object.entries(raw.env)) if (typeof v === "string") env[k] = fill(v);
124
- }
125
- let headers: Record<string, string> | undefined;
126
- if (isRecord(raw.headers)) {
127
- headers = {};
128
- for (const [k, v] of Object.entries(raw.headers)) if (typeof v === "string") headers[k] = fill(v);
129
- }
130
- let oauth: McpServerConfig["oauth"];
131
- if (isRecord(raw.oauth)) {
132
- oauth = {};
133
- if (typeof raw.oauth.clientId === "string" && raw.oauth.clientId.length > 0) oauth.clientId = raw.oauth.clientId;
134
- if (typeof raw.oauth.scope === "string" && raw.oauth.scope.length > 0) oauth.scope = raw.oauth.scope;
135
- if (Object.keys(oauth).length === 0) oauth = undefined;
136
- }
137
- if (missing.length > 0) {
138
- // an empty key would launch a server that fails on its first call; naming the variable is the fix
139
- warnings.push(`${file}: server "${name}" needs ${[...new Set(missing)].map((m) => `\${${m}}`).join(", ")} set in the environment; skipped`);
140
- return undefined;
141
- }
142
- // The other half of the same rule, for the values a market install could not fill: a required argument
143
- // that only the human knows (which directory the filesystem server may touch) is written into the file
144
- // as `<directory the server may touch>`, and a server still carrying one is not launched. Launching it
145
- // means npx starts, the server rejects its own arguments, and the failure surfaces as a connect error
146
- // several layers from the thing that is actually wrong — an editable line in a file rovecode named.
147
- const holes = placeholderHoles({ args, env, headers, url });
148
- if (holes.length > 0 && opts.allowPlaceholders !== true) {
149
- warnings.push(`${file}: server "${name}" still has ${holes.join(", ")} to fill in; skipped (edit that line and it will connect)`);
150
- return undefined;
151
- }
152
-
153
- const out: McpServerConfig = { name, transport };
154
- if (command !== undefined) out.command = command;
155
- if (args !== undefined) out.args = args;
156
- if (env !== undefined) out.env = env;
157
- if (url !== undefined) out.url = url;
158
- if (headers !== undefined) out.headers = headers;
159
- if (oauth !== undefined) out.oauth = oauth;
160
- if (typeof raw.enabled === "boolean") out.enabled = raw.enabled;
161
- return out;
162
- }
163
-
164
- /** Parse one config file. Accepts the claude-code map form
165
- * `{ mcpServers: { name: {...} } }` and, additionally (ours), a
166
- * `{ servers: McpServerConfig[] }` array form. */
167
- /** The `<…>` placeholders an entry still carries, in file order, each once. Empty = launchable as far as
168
- * arguments go. Shared by the loader (which refuses to launch while any remain) and the listing surfaces
169
- * (which must SHOW such an entry, marked, rather than pretend it was never written). */
170
- export function placeholderHoles(s: { args?: string[]; env?: Record<string, string>; headers?: Record<string, string>; url?: string }): string[] {
171
- return [...new Set([...(s.args ?? []), ...Object.values(s.env ?? {}), ...Object.values(s.headers ?? {}), ...(s.url !== undefined ? [s.url] : [])]
172
- .flatMap((v) => [...v.matchAll(PLACEHOLDER_REF)].map((m) => m[0])))];
173
- }
174
-
175
- /** `opts.allowPlaceholders`: keep entries that still carry a `<…>` hole (a LISTING wants to show them, marked);
176
- * the loader leaves it off and such an entry is skipped with a warning naming the hole. */
177
- export function parseConfigFile(path: string, warnings: string[], envSource: Record<string, string | undefined> = process.env, opts: { allowPlaceholders?: boolean } = {}): McpServerConfig[] {
178
- if (!existsSync(path)) return [];
179
- let text: string;
180
- try {
181
- text = readFileSync(path, "utf8");
182
- } catch (err) {
183
- warnings.push(`${path}: unreadable (${message(err)}); file skipped`);
184
- return [];
185
- }
186
- let json: unknown;
187
- try {
188
- json = JSON.parse(text);
189
- } catch (err) {
190
- warnings.push(`${path}: invalid JSON (${message(err)}); file skipped`);
191
- return [];
192
- }
193
- if (!isRecord(json)) {
194
- warnings.push(`${path}: root is not an object; file skipped`);
195
- return [];
196
- }
197
- const out: McpServerConfig[] = [];
198
- if (json.mcpServers !== undefined) {
199
- if (isRecord(json.mcpServers)) {
200
- for (const [name, raw] of Object.entries(json.mcpServers)) {
201
- const cfg = normalizeEntry(name, raw, path, warnings, envSource, opts);
202
- if (cfg) out.push(cfg);
203
- }
204
- } else warnings.push(`${path}: "mcpServers" is not an object; ignored`);
205
- }
206
- if (json.servers !== undefined) {
207
- if (Array.isArray(json.servers)) {
208
- for (const raw of json.servers) {
209
- const name = isRecord(raw) && typeof raw.name === "string" && raw.name.length > 0 ? raw.name : undefined;
210
- if (name === undefined) {
211
- warnings.push(`${path}: servers[] entry without a name; skipped`);
212
- continue;
213
- }
214
- const cfg = normalizeEntry(name, raw, path, warnings, envSource, opts);
215
- if (cfg) out.push(cfg);
216
- }
217
- } else warnings.push(`${path}: "servers" is not an array; ignored`);
218
- }
219
- return out;
220
- }
221
-
222
- export interface LoadMcpOptions {
223
- /** the user home; without it the user file is not read (existing callers and tests) */
224
- home?: string;
225
- /** what `${NAME}` is filled from (default process.env) */
226
- env?: Record<string, string | undefined>;
227
- /** the trust gate for PROJECT files (mcp/trust.ts trustedPredicate). Without it project files load as
228
- * they always did; with it an unapproved file contributes nothing and leaves one warning. The user
229
- * file is never gated — it is yours. */
230
- trusted?: (file: string, digest: string) => boolean;
231
- }
232
-
233
- /** Merge the user file (`<home>/mcp.json`, only when a home is given) under `.mcp.json` (harvest)
234
- * under `.rovecode/mcp.json` (ours). The most local wins on a name clash. Pass a `warnings` array
235
- * to collect human-readable skip reasons. */
236
- export function loadMcpConfig(cwd: string, warnings: string[] = [], opts: LoadMcpOptions = {}): McpServerConfig[] {
237
- const files = mcpConfigFiles(cwd, opts.home);
238
- const byName = new Map<string, McpServerConfig>();
239
- const anySet = new Proxy({}, { get: () => "set" }) as Record<string, string>; // counting entries, not launching them
240
- for (const [scope, path] of [["user", files.user], ["harvest", files.harvest], ["project", files.project]] as const) {
241
- if (path === undefined) continue;
242
- if (scope !== "user" && opts.trusted !== undefined) {
243
- const digest = fileDigest(path);
244
- if (digest !== undefined && !opts.trusted(path, digest)) {
245
- warnings.push(untrustedNote(path, parseConfigFile(path, [], anySet).length));
246
- continue; // absence, not "loaded but marked"
247
- }
248
- }
249
- for (const c of parseConfigFile(path, warnings, opts.env)) byName.set(c.name, c); // later layers win
250
- }
251
- return [...byName.values()];
252
- }
@@ -1,211 +0,0 @@
1
- /** Install-once for MCP servers the market would otherwise launch with `npx -y <package>`.
2
- *
3
- * Why this exists, in numbers (Windows 11, node 24, npm 11, the memory and filesystem servers, medians of
4
- * 3–5 runs through McpManager, measured 2026-09-06): a warm `npx -y` takes 1.8–2.1 s from spawn to the
5
- * initialize handshake; the same package installed once and launched with `node <its bin>` takes
6
- * 0.35–0.47 s. The difference is npx itself — `npx --version` alone is 0.6 s, and every warm launch still
7
- * asks registry.npmjs.org to revalidate the package (0.3–1.3 s, and no network means a timeout path). A
8
- * cold cache is 7 s and a 47 MB download, repeated whenever upstream publishes, because `-y <package>`
9
- * means "latest". The one-time install is ~6 s and ~30 MB for two servers sharing one SDK copy.
10
- *
11
- * What it is NOT: silent, or the only path. The human is asked, in the plan they approve, and "no" leaves
12
- * the npx line exactly as it is today. Installing code is a bigger act than writing a config line, and
13
- * the plan says so in those words. The record in installed.json carries the package name, the version
14
- * that landed and npm's integrity hash from the lockfile — an install that is recorded is auditable; an
15
- * `npx -y` that runs whatever "latest" is at every start is not.
16
- *
17
- * Where: one shared prefix, `~/.rovecode/mcp/`, with its own package.json so npm never mistakes a parent
18
- * folder for the project. N servers share one node_modules and one SDK copy. The launch line is `node`
19
- * plus the ABSOLUTE path of the package's bin — never the .cmd shim (it means cmd.exe and its quoting),
20
- * and the path survives a space because it is one argv entry, not a shell string. */
21
-
22
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
23
- import { join, resolve } from "node:path";
24
- import type { McpServerConfig } from "./config.ts";
25
- import type { MarketInstall } from "./market.ts";
26
-
27
- export type Spawn = (cmd: string[], cwd: string) => Promise<{ code: number; stderr: string }>;
28
-
29
- /** the package an `npx …` launch line runs, taken apart */
30
- export interface NpxPackage {
31
- /** the package name, `@scope/name` or `name` */
32
- name: string;
33
- /** what npx was given: name, or `name@version` when the catalog pinned one */
34
- spec: string;
35
- /** the pinned version, when the spec carried one */
36
- version?: string;
37
- /** the arguments the SERVER receives — everything after the package spec */
38
- rest: string[];
39
- }
40
-
41
- const NPX_FLAGS_NO_VALUE = new Set(["-y", "--yes", "-q", "--quiet", "--no-install", "--prefer-offline", "--prefer-online"]);
42
- /** `@scope/name`, `name`, optionally `@version` — a registry package and nothing else (no git URL, no tarball, no path) */
43
- const PACKAGE_SPEC = /^(@[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*|[a-z0-9][a-z0-9._-]*)(?:@([^@\s/]+))?$/;
44
-
45
- /** The package a stdio `npx` launch runs, or undefined when the line is not a plain `npx [flags] <package>
46
- * [args]` — an `npx -p x cmd`, a git URL or a tarball is left to npx, since we cannot say what we would be
47
- * installing. Undefined means "no offer", never an error: the npx line still works. */
48
- export function npxPackage(install: MarketInstall): NpxPackage | undefined {
49
- if (install.kind !== "stdio" || install.runtime !== "npx" || install.command !== "npx") return undefined;
50
- let i = 0;
51
- while (i < install.args.length && install.args[i]!.startsWith("-")) {
52
- if (!NPX_FLAGS_NO_VALUE.has(install.args[i]!)) return undefined; // a flag with a value (-p, --package, -c): not our shape
53
- i += 1;
54
- }
55
- const spec = install.args[i];
56
- if (spec === undefined) return undefined;
57
- const m = PACKAGE_SPEC.exec(spec);
58
- if (!m) return undefined;
59
- const out: NpxPackage = { name: m[1]!, spec, rest: install.args.slice(i + 1) };
60
- if (m[2] !== undefined) out.version = m[2];
61
- return out;
62
- }
63
-
64
- /** the shared prefix every install-once server lives in */
65
- export function localPrefix(home: string): string { return join(home, "mcp"); }
66
-
67
- /** what landed on disk, read back after npm finished — the record's source of truth */
68
- export interface LocalPackage {
69
- name: string;
70
- version: string;
71
- /** ABSOLUTE path of the package's bin script — what `node` runs */
72
- bin: string;
73
- /** npm's integrity hash for the tarball, from package-lock.json */
74
- integrity?: string;
75
- /** the tarball URL npm resolved, from package-lock.json */
76
- resolved?: string;
77
- /** what could not be recorded and why — an empty list is the normal case. Written into installed.json
78
- * as it is, so a record with a hole says where the hole is instead of leaving a field silently absent. */
79
- missing: string[];
80
- }
81
-
82
- export interface InstallLocalDeps {
83
- /** how `npm install` runs — tests inject one that writes a fake node_modules and never touches the network */
84
- spawn?: Spawn;
85
- }
86
-
87
- const defaultSpawn: Spawn = async (cmd, cwd) => {
88
- const p = Bun.spawn(cmd, { cwd, stdout: "ignore", stderr: "pipe", stdin: "ignore" });
89
- return { code: await p.exited, stderr: await new Response(p.stderr).text() };
90
- };
91
-
92
- /** the exact argv `installLocalPackage` runs — exported so the plan can show it verbatim */
93
- export function npmInstallArgv(pkg: NpxPackage, prefix: string): string[] {
94
- return ["npm", "install", "--prefix", prefix, "--save", "--no-fund", "--no-audit", "--loglevel=error", pkg.spec];
95
- }
96
-
97
- /** Run `npm install` for one package into the shared prefix, then read back what landed. Never throws for
98
- * an npm failure — the caller shows the error and nothing has been written to mcp.json yet. */
99
- export async function installLocalPackage(pkg: NpxPackage, prefix: string, deps: InstallLocalDeps = {}): Promise<{ ok: true; pkg: LocalPackage } | { ok: false; error: string }> {
100
- const spawn = deps.spawn ?? defaultSpawn;
101
- try {
102
- mkdirSync(prefix, { recursive: true });
103
- // a package.json of its own, so npm treats the prefix as the project: without one it can walk up and
104
- // install into whatever package.json it finds above ~/.rovecode
105
- const manifest = join(prefix, "package.json");
106
- if (!existsSync(manifest)) {
107
- writeFileSync(manifest, JSON.stringify({ name: "rovecode-mcp-servers", private: true, description: "MCP servers installed once by rovecode's market — launched with node, not npx (docs/mcp-market.md)" }, null, 2) + "\n");
108
- }
109
- const r = await spawn(npmInstallArgv(pkg, prefix), prefix);
110
- if (r.code !== 0) return { ok: false, error: `npm install ${pkg.spec} failed (exit ${r.code})${r.stderr.trim() ? `: ${r.stderr.trim().split("\n").slice(-3).join(" · ")}` : ""}` };
111
- } catch (e) {
112
- return { ok: false, error: `npm install ${pkg.spec} could not run: ${e instanceof Error ? e.message : String(e)}` };
113
- }
114
- return readLocalPackage(pkg.name, prefix);
115
- }
116
-
117
- /** What is on disk for one package under the prefix: version and bin from its package.json, integrity from
118
- * the lockfile. `ok: false` when the package or its bin is not there — then there is nothing to launch. */
119
- export function readLocalPackage(name: string, prefix: string): { ok: true; pkg: LocalPackage } | { ok: false; error: string } {
120
- const dir = join(prefix, "node_modules", ...name.split("/"));
121
- const manifestPath = join(dir, "package.json");
122
- if (!existsSync(manifestPath)) return { ok: false, error: `npm reported success but ${manifestPath} is not there` };
123
- let manifest: Record<string, unknown>;
124
- try { manifest = JSON.parse(readFileSync(manifestPath, "utf8")) as Record<string, unknown>; }
125
- catch (e) { return { ok: false, error: `${manifestPath}: ${e instanceof Error ? e.message : String(e)}` }; }
126
- const version = typeof manifest.version === "string" ? manifest.version : undefined;
127
- if (version === undefined) return { ok: false, error: `${manifestPath} states no version` };
128
- const binRel = binOf(name, manifest.bin);
129
- if (binRel === undefined) return { ok: false, error: `${name} declares no bin — there is nothing for node to run; npx would have failed the same way` };
130
- const bin = resolve(dir, binRel);
131
- if (!existsSync(bin)) return { ok: false, error: `${name}'s bin ${bin} is not on disk` };
132
- const missing: string[] = [];
133
- const lock = lockEntry(prefix, name, missing);
134
- const pkg: LocalPackage = { name, version, bin, missing };
135
- if (lock?.integrity !== undefined) pkg.integrity = lock.integrity;
136
- if (lock?.resolved !== undefined) pkg.resolved = lock.resolved;
137
- return { ok: true, pkg };
138
- }
139
-
140
- /** the bin a package declares: a string, or a map — the entry named like the package, else the only one */
141
- function binOf(name: string, bin: unknown): string | undefined {
142
- if (typeof bin === "string") return bin;
143
- if (typeof bin !== "object" || bin === null) return undefined;
144
- const entries = Object.entries(bin as Record<string, unknown>).filter((e): e is [string, string] => typeof e[1] === "string");
145
- if (entries.length === 0) return undefined;
146
- const short = name.split("/").pop()!;
147
- return (entries.find(([k]) => k === short) ?? entries[0]!)[1];
148
- }
149
-
150
- /** package-lock.json (lockfileVersion 2/3) → the entry for `node_modules/<name>`. Every way it can fall
151
- * short is written into `missing` in words, because a silent undefined here becomes a record that looks
152
- * complete and is not. */
153
- function lockEntry(prefix: string, name: string, missing: string[]): { integrity?: string; resolved?: string } | undefined {
154
- const lockPath = join(prefix, "package-lock.json");
155
- if (!existsSync(lockPath)) { missing.push(`integrity: ${lockPath} was not written by npm`); return undefined; }
156
- let lock: unknown;
157
- try { lock = JSON.parse(readFileSync(lockPath, "utf8")); }
158
- catch { missing.push(`integrity: ${lockPath} is not valid JSON`); return undefined; }
159
- const packages = typeof lock === "object" && lock !== null ? (lock as { packages?: unknown }).packages : undefined;
160
- if (typeof packages !== "object" || packages === null) { missing.push(`integrity: ${lockPath} has no "packages" map (lockfileVersion 1?)`); return undefined; }
161
- const entry = (packages as Record<string, unknown>)[`node_modules/${name}`];
162
- if (typeof entry !== "object" || entry === null) { missing.push(`integrity: ${lockPath} has no entry for node_modules/${name}`); return undefined; }
163
- const e = entry as { integrity?: unknown; resolved?: unknown };
164
- const out: { integrity?: string; resolved?: string } = {};
165
- if (typeof e.integrity === "string") out.integrity = e.integrity; else missing.push(`integrity: the lockfile entry for ${name} carries no integrity field`);
166
- if (typeof e.resolved === "string") out.resolved = e.resolved;
167
- return out;
168
- }
169
-
170
- /** the mcp.json launch line for an installed package: `node` + the bin's absolute path + the server's own
171
- * arguments. One argv entry per item — a path with a space in it is still one argument, because nothing
172
- * here goes through a shell (mcp/client.ts spawns with shell: false). */
173
- export function localLaunch(pkg: LocalPackage, rest: string[]): { command: "node"; args: string[] } {
174
- return { command: "node", args: [pkg.bin, ...rest] };
175
- }
176
-
177
- /** the launch line as the plan can show it BEFORE the install: the bin's exact filename is read from the
178
- * package after npm has put it there, so the preview names the folder and marks the file as pending */
179
- export function plannedLaunchLabel(pkg: NpxPackage, prefix: string): string {
180
- return ["node", `${join(prefix, "node_modules", ...pkg.name.split("/"))}${process.platform === "win32" ? "\\" : "/"}<its bin, read after the install>`, ...pkg.rest].join(" ");
181
- }
182
-
183
- /** the plan rows that say what installing once means — every word the human should read before the yes */
184
- export function localPlanLines(pkg: NpxPackage, prefix: string): string[] {
185
- return [
186
- ` installs ${npmInstallArgv(pkg, prefix).join(" ")}`,
187
- ` rovecode runs a package manager for you here. npm downloads ${pkg.spec} and everything it depends`,
188
- ` on and puts their CODE on this machine, under ${prefix} — typically 20–30 MB and a few seconds, once.`,
189
- ` In return the server starts in ~0.4 s instead of ~2 s and needs no network to start.`,
190
- ` Requires npm (it comes with Node.js, as npx does).`,
191
- ` records package name, version and npm's integrity hash in installed.json — what ran is on record`,
192
- ` (an npx line runs whatever "latest" is at every start, and records nothing)`,
193
- ];
194
- }
195
-
196
- /** a configured server that still launches through npx — the rows `mcp list` may offer the install-once line for */
197
- export function launchesViaNpx(server: McpServerConfig): boolean {
198
- return server.transport === "stdio" && server.command === "npx" && server.enabled !== false;
199
- }
200
-
201
- /** the one-line offer `mcp list` prints under the rows when some of them start through npx. Says what
202
- * changes, what it costs and that nothing happens until the human runs the command — no config is
203
- * rewritten by a listing. */
204
- export function npxOfferLine(names: string[]): string | undefined {
205
- if (names.length === 0) return undefined;
206
- const n = names.length;
207
- // `<catalog name>`, not the server name the row shows: `mcp add` takes the name you installed it by (a
208
- // registry server is `io.github.acme/widgets`, its row is `widgets`), and a renamed one needs its `--as` back
209
- return `${n} server${n === 1 ? "" : "s"} start${n === 1 ? "s" : ""} through npx, which re-resolves the package at every start (~2 s each): ${names.join(", ")}. `
210
- + `To start in ~0.4 s, reinstall with \`rovecode mcp add <catalog name> --local --force\` (the name you installed it by; add \`--as <server name>\` if you renamed it; installs the package once, ~25 MB). Nothing changes until you do.`;
211
- }
@@ -1,84 +0,0 @@
1
- /** The curated half of the MCP market: servers we have looked at, from publishers we can name, with
2
- * the exact launch line spelled out. Offline by design — `rovecode mcp search` answers from this list
3
- * before it asks the registry, and /mcp with an empty query shows only this list. Rules for an entry:
4
- * the publisher is the org that owns the package or the host; secrets travel by environment variable
5
- * (or a header for a remote), never as an argument; anything OAuth-only is left out because our http
6
- * transport carries a header, not a browser flow. Keep it short — this is a shelf, not a mirror. */
7
-
8
- import type { MarketEntry } from "./market.ts";
9
-
10
- const npx = (pkg: string, ...rest: string[]): string[] => ["-y", pkg, ...rest];
11
-
12
- export const CURATED: readonly MarketEntry[] = [
13
- { key: "filesystem", title: "Filesystem", source: "curated", publisher: "modelcontextprotocol (Anthropic)",
14
- description: "Read, write, search and move files under the directories you name.",
15
- repository: "https://github.com/modelcontextprotocol/servers",
16
- installs: [{ kind: "stdio", runtime: "npx", command: "npx", args: npx("@modelcontextprotocol/server-filesystem"), env: [], pending: ["<directory the server may touch>"] }] },
17
- { key: "memory", title: "Memory", source: "curated", publisher: "modelcontextprotocol (Anthropic)",
18
- description: "A knowledge graph the model can remember across sessions with (entities, relations, observations).",
19
- repository: "https://github.com/modelcontextprotocol/servers",
20
- installs: [{ kind: "stdio", runtime: "npx", command: "npx", args: npx("@modelcontextprotocol/server-memory"), env: [], pending: [] }] },
21
- { key: "sequential-thinking", title: "Sequential Thinking", source: "curated", publisher: "modelcontextprotocol (Anthropic)",
22
- description: "A scratchpad tool for step-by-step reasoning with revisions and branches.",
23
- repository: "https://github.com/modelcontextprotocol/servers",
24
- installs: [{ kind: "stdio", runtime: "npx", command: "npx", args: npx("@modelcontextprotocol/server-sequential-thinking"), env: [], pending: [] }] },
25
- { key: "everything", title: "Everything (test server)", source: "curated", publisher: "modelcontextprotocol (Anthropic)",
26
- description: "Exercises every MCP feature — prompts, resources, sampling, progress. For testing a client, not for work.",
27
- repository: "https://github.com/modelcontextprotocol/servers",
28
- installs: [{ kind: "stdio", runtime: "npx", command: "npx", args: npx("@modelcontextprotocol/server-everything"), env: [], pending: [] }] },
29
- { key: "fetch", title: "Fetch", source: "curated", publisher: "modelcontextprotocol (Anthropic)",
30
- description: "Fetch a URL and hand the page back as markdown (Python; needs uv).",
31
- repository: "https://github.com/modelcontextprotocol/servers",
32
- installs: [{ kind: "stdio", runtime: "uvx", command: "uvx", args: ["mcp-server-fetch"], env: [], pending: [] }] },
33
- { key: "git", title: "Git", source: "curated", publisher: "modelcontextprotocol (Anthropic)",
34
- description: "Read and search git repositories: log, diff, show, status (Python; needs uv).",
35
- repository: "https://github.com/modelcontextprotocol/servers",
36
- installs: [{ kind: "stdio", runtime: "uvx", command: "uvx", args: ["mcp-server-git"], env: [], pending: [] }] },
37
- { key: "time", title: "Time", source: "curated", publisher: "modelcontextprotocol (Anthropic)",
38
- description: "Current time and timezone conversion (Python; needs uv).",
39
- repository: "https://github.com/modelcontextprotocol/servers",
40
- installs: [{ kind: "stdio", runtime: "uvx", command: "uvx", args: ["mcp-server-time"], env: [], pending: [] }] },
41
- { key: "github", title: "GitHub", source: "curated", publisher: "GitHub",
42
- description: "Issues, pull requests, code search and Actions on GitHub — remote with a personal access token, or the official image via docker.",
43
- repository: "https://github.com/github/github-mcp-server",
44
- installs: [
45
- { kind: "http", url: "https://api.githubcopilot.com/mcp/", headers: [{ name: "Authorization", template: "Bearer {GITHUB_PAT}", required: true, secret: true, description: "a GitHub personal access token" }] },
46
- { kind: "stdio", runtime: "docker", command: "docker", args: ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
47
- env: [{ name: "GITHUB_PERSONAL_ACCESS_TOKEN", required: true, secret: true, description: "a GitHub personal access token" }], pending: [] },
48
- ] },
49
- { key: "playwright", title: "Playwright", source: "curated", publisher: "Microsoft",
50
- description: "Drive a real browser through accessibility snapshots: navigate, click, type, screenshot.",
51
- repository: "https://github.com/microsoft/playwright-mcp",
52
- installs: [{ kind: "stdio", runtime: "npx", command: "npx", args: npx("@playwright/mcp@latest"), env: [], pending: [] }] },
53
- { key: "context7", title: "Context7", source: "curated", publisher: "Upstash",
54
- description: "Up-to-date library documentation and code examples for the versions you actually use.",
55
- repository: "https://github.com/upstash/context7",
56
- installs: [
57
- { kind: "http", url: "https://mcp.context7.com/mcp", headers: [{ name: "CONTEXT7_API_KEY", required: false, secret: true, description: "optional API key for higher limits" }] },
58
- { kind: "stdio", runtime: "npx", command: "npx", args: npx("@upstash/context7-mcp"), env: [{ name: "CONTEXT7_API_KEY", required: false, secret: true, description: "optional API key for higher limits" }], pending: [] },
59
- ] },
60
- { key: "brave-search", title: "Brave Search", source: "curated", publisher: "Brave",
61
- description: "Web, news, image and local search through the Brave Search API.",
62
- repository: "https://github.com/brave/brave-search-mcp-server",
63
- installs: [{ kind: "stdio", runtime: "npx", command: "npx", args: npx("@brave/brave-search-mcp-server"), env: [{ name: "BRAVE_API_KEY", required: true, secret: true, description: "Brave Search API key" }], pending: [] }] },
64
- { key: "firecrawl", title: "Firecrawl", source: "curated", publisher: "Firecrawl (Mendable)",
65
- description: "Scrape, crawl and extract structured data from websites.",
66
- repository: "https://github.com/mendableai/firecrawl-mcp-server",
67
- installs: [{ kind: "stdio", runtime: "npx", command: "npx", args: npx("firecrawl-mcp"), env: [{ name: "FIRECRAWL_API_KEY", required: true, secret: true, description: "Firecrawl API key" }], pending: [] }] },
68
- { key: "tavily", title: "Tavily", source: "curated", publisher: "Tavily",
69
- description: "Search and extract built for agents: web search, page extraction, site crawl.",
70
- repository: "https://github.com/tavily-ai/tavily-mcp",
71
- installs: [{ kind: "stdio", runtime: "npx", command: "npx", args: npx("tavily-mcp"), env: [{ name: "TAVILY_API_KEY", required: true, secret: true, description: "Tavily API key" }], pending: [] }] },
72
- { key: "exa", title: "Exa", source: "curated", publisher: "Exa",
73
- description: "Neural web search and page contents for AI; the remote works without a key at a low rate.",
74
- repository: "https://github.com/exa-labs/exa-mcp-server",
75
- installs: [{ kind: "http", url: "https://mcp.exa.ai/mcp", headers: [] }] },
76
- { key: "deepwiki", title: "DeepWiki", source: "curated", publisher: "Cognition (Devin)",
77
- description: "Ask questions about any public GitHub repository, answered from its generated wiki. No key.",
78
- homepage: "https://docs.devin.ai/work-with-devin/deepwiki-mcp",
79
- installs: [{ kind: "http", url: "https://mcp.deepwiki.com/mcp", headers: [] }] },
80
- { key: "cloudflare-docs", title: "Cloudflare Docs", source: "curated", publisher: "Cloudflare",
81
- description: "Search Cloudflare's developer documentation. No key.",
82
- repository: "https://github.com/cloudflare/mcp-server-cloudflare",
83
- installs: [{ kind: "http", url: "https://docs.mcp.cloudflare.com/mcp", headers: [] }] },
84
- ];