rovecode 0.3.3 → 0.4.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +527 -0
- package/README.md +46 -48
- package/bin/rovecode.js +24 -0
- package/dist/cli/app-j6gn14w3.js +2 -0
- package/dist/cli/ask-user-cwstt8fz.js +2 -0
- package/dist/cli/auth-login-9bbp9915.js +2 -0
- package/dist/cli/auth-m8p9grty.js +2 -0
- package/dist/cli/bench-16zqdms5.js +9 -0
- package/dist/cli/catalog-1xchffa4.js +2 -0
- package/dist/cli/cli-1n1zb64f.js +2 -0
- package/dist/cli/client-2t9gjkck.js +2 -0
- package/dist/cli/commands-exafvm2b.js +2 -0
- package/dist/cli/connect-6zde0kn3.js +2 -0
- package/dist/cli/context-cmd-5t43wgqt.js +2 -0
- package/dist/cli/context-report-kt01pw8y.js +2 -0
- package/dist/cli/count-remote-ap7x3vh6.js +2 -0
- package/dist/cli/design-ne5zszyh.js +2 -0
- package/dist/cli/dispatch-2r5myxye.js +2 -0
- package/dist/cli/doctor-ws4fh4tn.js +3 -0
- package/dist/cli/executor-bdrjn634.js +2 -0
- package/dist/cli/export-1mxb9g5p.js +2 -0
- package/dist/cli/files-g104xghh.js +2 -0
- package/dist/cli/gauntlet-07xrjpj7.js +2 -0
- package/dist/cli/gauntlet-runner-xvy64436.js +10 -0
- package/dist/cli/gauntlet-wave3-jm91yt5w.js +5 -0
- package/dist/cli/gauntlet-wave4-r13py7p1.js +14 -0
- package/dist/cli/hashline-znvrat11.js +2 -0
- package/dist/cli/http-xafw6fsh.js +143 -0
- package/dist/cli/index-1sgjm25y.js +2 -0
- package/dist/cli/init-g2m0tn4m.js +51 -0
- package/dist/cli/install-avaqjjqq.js +2 -0
- package/dist/cli/loop-mmpfft01.js +2 -0
- package/dist/cli/main-0904f6ps.js +5 -0
- package/dist/cli/main-0ab9fc26.js +9 -0
- package/dist/cli/main-0jys2ccn.js +3 -0
- package/dist/cli/main-0mtcdbs7.js +3 -0
- package/dist/cli/main-0z1w2zsg.js +3 -0
- package/dist/cli/main-1dchs7xv.js +18 -0
- package/dist/cli/main-1ereejm1.js +3 -0
- package/dist/cli/main-1k1kw6b5.js +3 -0
- package/dist/cli/main-27y4sm2k.js +38 -0
- package/dist/cli/main-2wwjex5j.js +58 -0
- package/dist/cli/main-2yeveeve.js +6 -0
- package/dist/cli/main-2yfck9b5.js +3 -0
- package/dist/cli/main-2zmzgkwh.js +3 -0
- package/dist/cli/main-351pz3z7.js +7 -0
- package/dist/cli/main-3gjqfh7a.js +6 -0
- package/dist/cli/main-3nf3kgve.js +3 -0
- package/dist/cli/main-3pjrb2hd.js +3 -0
- package/dist/cli/main-3rxcvgna.js +19 -0
- package/dist/cli/main-4b3jgy66.js +19 -0
- package/dist/cli/main-4wndhjdc.js +7 -0
- package/dist/cli/main-4xcmvxnk.js +3 -0
- package/dist/cli/main-5tbz0wbz.js +4 -0
- package/dist/cli/main-5ywnwthm.js +3 -0
- package/dist/cli/main-6b62vkz0.js +14 -0
- package/dist/cli/main-6dnk69vp.js +3 -0
- package/dist/cli/main-6genrmhs.js +136 -0
- package/dist/cli/main-73g7eff4.js +15 -0
- package/dist/cli/main-7c5thhjd.js +5 -0
- package/dist/cli/main-7rn6bqje.js +3 -0
- package/dist/cli/main-80haw7qk.js +4 -0
- package/dist/cli/main-875s60s2.js +4 -0
- package/dist/cli/main-8kjxbpw4.js +8 -0
- package/dist/cli/main-90ds1z4e.js +10 -0
- package/dist/cli/main-9etavkew.js +3 -0
- package/dist/cli/main-a9njrkk1.js +3 -0
- package/dist/cli/main-aecrjq2d.js +12 -0
- package/dist/cli/main-ck9asesq.js +9 -0
- package/dist/cli/main-cta9racd.js +4 -0
- package/dist/cli/main-ddv7j2ag.js +3 -0
- package/dist/cli/main-dfreez27.js +10 -0
- package/dist/cli/main-f7rw7des.js +3 -0
- package/dist/cli/main-ggcn7rd7.js +5 -0
- package/dist/cli/main-gzkmycnv.js +3 -0
- package/dist/cli/main-hq51jg8v.js +18 -0
- package/dist/cli/main-jft389w9.js +8 -0
- package/dist/cli/main-k1eqkg83.js +3 -0
- package/dist/cli/main-k2y8a2aw.js +9 -0
- package/dist/cli/main-kcpbykxz.js +4 -0
- package/dist/cli/main-kd488vje.js +22 -0
- package/dist/cli/main-kh32yvgk.js +5 -0
- package/dist/cli/main-kqxnqjnv.js +25 -0
- package/dist/cli/main-kyn0xnsg.js +3 -0
- package/dist/cli/main-m1kk6fp5.js +21 -0
- package/dist/cli/main-mv40pcr2.js +4 -0
- package/dist/cli/main-n0t3973w.js +3 -0
- package/dist/cli/main-nqveez48.js +4 -0
- package/dist/cli/main-pknhvrmj.js +3 -0
- package/dist/cli/main-pn1w7a7j.js +3 -0
- package/dist/cli/main-prxxs70n.js +4 -0
- package/dist/cli/main-q3vsesf9.js +3 -0
- package/dist/cli/main-qsevpgsv.js +3 -0
- package/dist/cli/main-rdgdw24b.js +25 -0
- package/dist/cli/main-rfth4tbm.js +16 -0
- package/dist/cli/main-rg0wn0xf.js +5 -0
- package/dist/cli/main-sdmxhtv8.js +4 -0
- package/dist/cli/main-skbp13js.js +18 -0
- package/dist/cli/main-t4xnd213.js +7 -0
- package/dist/cli/main-vqak588n.js +4 -0
- package/dist/cli/main-w2n1303f.js +9 -0
- package/dist/cli/main-wbrdspr2.js +5 -0
- package/dist/cli/main-wsrg79c1.js +7 -0
- package/dist/cli/main-x4r0fne4.js +5 -0
- package/dist/cli/main-xea2f3tn.js +6 -0
- package/dist/cli/main-xg704a3c.js +3 -0
- package/dist/cli/main-xvnrabfp.js +16 -0
- package/dist/cli/main-xy53xf0r.js +4 -0
- package/dist/cli/main-y1fqy60y.js +3 -0
- package/dist/cli/main-yn8cd281.js +34 -0
- package/dist/cli/main-yr0ksc0h.js +4 -0
- package/dist/cli/main-z2ex2vyf.js +4 -0
- package/dist/cli/main-z3aayzvq.js +3 -0
- package/dist/cli/main-zaqh35jg.js +3 -0
- package/dist/cli/main-zc2e8e46.js +4 -0
- package/dist/cli/main-zzrfw6cf.js +13 -0
- package/dist/cli/main.js +280 -0
- package/dist/cli/market-cmd-e14kmx9n.js +5 -0
- package/dist/cli/mcp-login-wq7ktdek.js +2 -0
- package/dist/cli/mcp-market-cmd-9mg3jecy.js +2 -0
- package/dist/cli/notify-b7qc0cjb.js +2 -0
- package/dist/cli/oauth-z8whcgfx.js +2 -0
- package/dist/cli/output-b3ewj3ps.js +16 -0
- package/dist/cli/profiles-6mr5he5e.js +2 -0
- package/dist/cli/provider-config-g7j42q8x.js +2 -0
- package/dist/cli/provider-jr1y8vvm.js +2 -0
- package/dist/cli/registry-s8yk86g0.js +2 -0
- package/dist/cli/registry-t6p8d4mn.js +2 -0
- package/dist/cli/repl-bajwe1mh.js +11 -0
- package/dist/cli/resume-rwn9nz7y.js +2 -0
- package/dist/cli/run-flags-nah7ndpt.js +2 -0
- package/dist/cli/runtime-n7gafzhb.js +2 -0
- package/dist/cli/sandbox-config-emdy18x4.js +2 -0
- package/dist/cli/server-b0nvs2bn.js +5 -0
- package/dist/cli/session-arg-y75wd4kj.js +2 -0
- package/dist/cli/session-j62evmjq.js +2 -0
- package/dist/cli/sessions-cmd-tsnwz0ns.js +7 -0
- package/dist/cli/settings-df10wfez.js +2 -0
- package/dist/cli/setup-jzvv72fg.js +2 -0
- package/dist/cli/sextant-smoke-37m81ke6.js +5 -0
- package/dist/cli/skills-cmd-gjxnxnhx.js +2 -0
- package/dist/cli/smoke-p7748apt.js +8 -0
- package/dist/cli/start-chat-s4st3mm0.js +12 -0
- package/dist/cli/stream-gmeyewds.js +2 -0
- package/dist/cli/task-gh0kkp3n.js +2 -0
- package/dist/cli/tasks-z1kfpe8e.js +2 -0
- package/dist/cli/thinking-0eqkrz6t.js +2 -0
- package/dist/cli/todo-5brcrt9m.js +2 -0
- package/dist/cli/tools-7pzm0vj9.js +2 -0
- package/dist/cli/tools-s635p6s8.js +2 -0
- package/dist/cli/trust-cmd-cjav8zgm.js +2 -0
- package/dist/cli/update-check-pt31bm2f.js +2 -0
- package/dist/cli/update-cmd-tk131s9t.js +2 -0
- package/dist/cli/voice-56nabd8d.js +2 -0
- package/dist/cli/webfetch-xd8q596m.js +2 -0
- package/dist/cli/websearch-5hkf98k1.js +2 -0
- package/dist/cli/workflow-cmd-cy3cvzjp.js +4 -0
- package/dist/cli/workspace-q10g5z3e.js +2 -0
- package/dist/lib/index.js +62 -0
- package/dist/lib/models-index.json +1 -0
- package/dist/lib/plugins.js +55 -0
- package/dist/lib/providers.js +17 -0
- package/dist/lib/public-api.js +20 -0
- package/dist/lib/sdk.js +360 -0
- package/package.json +84 -72
- package/bin/rovecode.ts +0 -21
- package/src/acp/server.ts +0 -374
- package/src/cli/auth-login.ts +0 -122
- package/src/cli/connect.ts +0 -244
- package/src/cli/context-cmd.ts +0 -199
- package/src/cli/dispatch.ts +0 -82
- package/src/cli/doctor.ts +0 -362
- package/src/cli/export.ts +0 -276
- package/src/cli/help.ts +0 -293
- package/src/cli/is-tui-invocation.ts +0 -8
- package/src/cli/main.ts +0 -583
- package/src/cli/market-cmd.ts +0 -658
- package/src/cli/mcp-login.ts +0 -141
- package/src/cli/mcp-market-cmd.ts +0 -302
- package/src/cli/output.ts +0 -382
- package/src/cli/repl.ts +0 -250
- package/src/cli/repomap-root.ts +0 -14
- package/src/cli/resume.ts +0 -57
- package/src/cli/run-flags.ts +0 -43
- package/src/cli/run-limits.ts +0 -78
- package/src/cli/runtime.ts +0 -931
- package/src/cli/session-arg.ts +0 -30
- package/src/cli/sessions-cmd.ts +0 -145
- package/src/cli/setup.ts +0 -153
- package/src/cli/skills-cmd.ts +0 -194
- package/src/cli/start-chat.ts +0 -65
- package/src/cli/trust-cmd.ts +0 -52
- package/src/coding/bash.ts +0 -148
- package/src/coding/checkpoints.ts +0 -327
- package/src/coding/diff.ts +0 -138
- package/src/coding/files.ts +0 -341
- package/src/coding/hashline.ts +0 -274
- package/src/coding/lsp-gate.ts +0 -254
- package/src/coding/lsp-servers.ts +0 -147
- package/src/coding/lsp.ts +0 -283
- package/src/coding/repomap-cache.ts +0 -99
- package/src/coding/repomap-files.ts +0 -192
- package/src/coding/repomap.ts +0 -481
- package/src/core/agents.ts +0 -255
- package/src/core/compaction.ts +0 -259
- package/src/core/config.ts +0 -289
- package/src/core/context-report.ts +0 -228
- package/src/core/context.ts +0 -60
- package/src/core/count-remote.ts +0 -107
- package/src/core/execpolicy-rules.ts +0 -196
- package/src/core/execpolicy.ts +0 -385
- package/src/core/executor.ts +0 -454
- package/src/core/guardrails.ts +0 -400
- package/src/core/hooks.ts +0 -411
- package/src/core/images.ts +0 -230
- package/src/core/intro.ts +0 -266
- package/src/core/loop.ts +0 -567
- package/src/core/modes.ts +0 -372
- package/src/core/orchestrator.ts +0 -245
- package/src/core/proc-group.ts +0 -48
- package/src/core/project-trust.ts +0 -98
- package/src/core/reflection.ts +0 -165
- package/src/core/sandbox-config.ts +0 -186
- package/src/core/session-id.ts +0 -24
- package/src/core/session-images.ts +0 -73
- package/src/core/session-ops.ts +0 -183
- package/src/core/session-text.ts +0 -29
- package/src/core/session.ts +0 -469
- package/src/core/settings.ts +0 -170
- package/src/core/tasks.ts +0 -646
- package/src/core/token-scale.ts +0 -108
- package/src/core/tools.ts +0 -309
- package/src/core/trust.ts +0 -104
- package/src/core/types.ts +0 -330
- package/src/core/update-check.ts +0 -171
- package/src/core/usage.ts +0 -204
- package/src/core/validate.ts +0 -121
- package/src/core/verify-gate.ts +0 -159
- package/src/core/verify.ts +0 -236
- package/src/core/voice.ts +0 -158
- package/src/core/win-job.ts +0 -183
- package/src/core/workspace.ts +0 -184
- package/src/design/audit.ts +0 -797
- package/src/design/direction.ts +0 -190
- package/src/design/rules.ts +0 -157
- package/src/eval/bench.ts +0 -150
- package/src/eval/gauntlet-runner.ts +0 -215
- package/src/eval/gauntlet-support.ts +0 -84
- package/src/eval/gauntlet-wave3.ts +0 -269
- package/src/eval/gauntlet-wave4.ts +0 -217
- package/src/eval/gauntlet.ts +0 -253
- package/src/index.ts +0 -17
- package/src/lanes/agy.ts +0 -95
- package/src/lanes/approval.ts +0 -24
- package/src/lanes/claude.ts +0 -129
- package/src/lanes/codex.ts +0 -127
- package/src/lanes/events.ts +0 -130
- package/src/lanes/job.ts +0 -142
- package/src/lanes/opencode.ts +0 -122
- package/src/lanes/process.ts +0 -184
- package/src/lanes/progress.ts +0 -183
- package/src/lanes/registry.ts +0 -178
- package/src/lanes/runner.ts +0 -124
- package/src/lanes/types.ts +0 -112
- package/src/market/catalogs/mcp-docs.json +0 -111
- package/src/market/catalogs/plugins.json +0 -111
- package/src/market/catalogs/skills.json +0 -478
- package/src/market/clone.ts +0 -72
- package/src/market/context-cost.ts +0 -121
- package/src/market/digest.ts +0 -106
- package/src/market/index.ts +0 -22
- package/src/market/install.ts +0 -578
- package/src/market/manifest.ts +0 -187
- package/src/market/prereq.ts +0 -145
- package/src/market/registry.ts +0 -363
- package/src/market/resolve.ts +0 -111
- package/src/market/types.ts +0 -236
- package/src/market/validate.ts +0 -227
- package/src/mcp/client.ts +0 -449
- package/src/mcp/config.ts +0 -252
- package/src/mcp/local-package.ts +0 -211
- package/src/mcp/market-catalog.ts +0 -84
- package/src/mcp/market-install.ts +0 -289
- package/src/mcp/market.ts +0 -362
- package/src/mcp/oauth.ts +0 -251
- package/src/mcp/prompts-resources.ts +0 -249
- package/src/mcp/shared.ts +0 -149
- package/src/mcp/status.ts +0 -67
- package/src/mcp/tools.ts +0 -275
- package/src/mcp/transport.ts +0 -122
- package/src/mcp/trust.ts +0 -25
- package/src/memory/blocks.ts +0 -278
- package/src/memory/recall.ts +0 -355
- package/src/memory/scope.ts +0 -182
- package/src/memory/store.ts +0 -105
- package/src/memory/tools.ts +0 -99
- package/src/plugins/cli.ts +0 -119
- package/src/plugins/discover.ts +0 -108
- package/src/plugins/index.ts +0 -50
- package/src/plugins/install.ts +0 -184
- package/src/plugins/load.ts +0 -124
- package/src/plugins/manifest.ts +0 -92
- package/src/plugins/state.ts +0 -83
- package/src/providers/auth.ts +0 -408
- package/src/providers/cache.ts +0 -223
- package/src/providers/catalog-local.ts +0 -160
- package/src/providers/catalog.ts +0 -421
- package/src/providers/middleware-context.ts +0 -86
- package/src/providers/middleware.ts +0 -373
- package/src/providers/model-list.ts +0 -23
- package/src/providers/oauth/common.ts +0 -105
- package/src/providers/oauth/device-code.ts +0 -107
- package/src/providers/oauth/github-copilot.ts +0 -146
- package/src/providers/oauth/loopback.ts +0 -158
- package/src/providers/oauth/openai.ts +0 -163
- package/src/providers/oauth/openrouter.ts +0 -89
- package/src/providers/oauth/pkce.ts +0 -45
- package/src/providers/oauth/registry.ts +0 -39
- package/src/providers/oauth/seam.ts +0 -89
- package/src/providers/profile-glm53.ts +0 -111
- package/src/providers/profile-sonnet5-persona.ts +0 -65
- package/src/providers/profile-sonnet5-voice.ts +0 -23
- package/src/providers/profiles.ts +0 -156
- package/src/providers/provider-config.ts +0 -311
- package/src/providers/registry.ts +0 -333
- package/src/providers/responses.ts +0 -209
- package/src/providers/retry.ts +0 -234
- package/src/providers/router.ts +0 -294
- package/src/providers/sse.ts +0 -26
- package/src/providers/stream-errors.ts +0 -117
- package/src/providers/stream.ts +0 -566
- package/src/providers/thinking.ts +0 -189
- package/src/providers/wire-messages.ts +0 -129
- package/src/providers/wire-responses.ts +0 -79
- package/src/providers/wire-select.ts +0 -53
- package/src/server/http.ts +0 -291
- package/src/server/openapi.ts +0 -246
- package/src/sextant/card-hits.ts +0 -102
- package/src/sextant/card-keys.ts +0 -55
- package/src/sextant/context-source.ts +0 -157
- package/src/sextant/crew-cards.ts +0 -350
- package/src/sextant/draw-agents.ts +0 -273
- package/src/sextant/draw-code.ts +0 -388
- package/src/sextant/draw-context.ts +0 -222
- package/src/sextant/draw-frame.ts +0 -164
- package/src/sextant/draw-market.ts +0 -573
- package/src/sextant/draw-messages.ts +0 -386
- package/src/sextant/draw-pet.ts +0 -230
- package/src/sextant/draw-plan.ts +0 -187
- package/src/sextant/draw-tabs.ts +0 -85
- package/src/sextant/draw-util.ts +0 -65
- package/src/sextant/draw-wizard.ts +0 -378
- package/src/sextant/engine.ts +0 -230
- package/src/sextant/frame-hits.ts +0 -25
- package/src/sextant/frame.ts +0 -101
- package/src/sextant/git-status.ts +0 -197
- package/src/sextant/grid.ts +0 -59
- package/src/sextant/input.ts +0 -119
- package/src/sextant/keys.ts +0 -521
- package/src/sextant/layout.ts +0 -86
- package/src/sextant/local-commands.ts +0 -169
- package/src/sextant/market-source.ts +0 -287
- package/src/sextant/mentions.ts +0 -200
- package/src/sextant/message-hits.ts +0 -26
- package/src/sextant/model.ts +0 -387
- package/src/sextant/overlays.ts +0 -456
- package/src/sextant/panel-hits.ts +0 -38
- package/src/sextant/pet.ts +0 -399
- package/src/sextant/screen.ts +0 -324
- package/src/sextant/scroll-hits.ts +0 -66
- package/src/sextant/scrollbar.ts +0 -82
- package/src/sextant/sextant-bridge.ts +0 -174
- package/src/sextant/sextant-cards.ts +0 -142
- package/src/sextant/sextant-diff-base.ts +0 -63
- package/src/sextant/sextant-files.ts +0 -154
- package/src/sextant/sextant-frame-loop.ts +0 -335
- package/src/sextant/sextant-renderer.ts +0 -574
- package/src/sextant/sextant-repo.ts +0 -140
- package/src/sextant/theme.ts +0 -66
- package/src/sextant/tool-rows.ts +0 -189
- package/src/sextant/types.ts +0 -493
- package/src/skills/index.ts +0 -387
- package/src/skills/pack.ts +0 -220
- package/src/skills/spec.ts +0 -162
- package/src/skills/tools.ts +0 -69
- package/src/skills/versioned.ts +0 -227
- package/src/telemetry/otel-export.ts +0 -122
- package/src/telemetry/otel-lanes.ts +0 -89
- package/src/telemetry/otel-logs.ts +0 -131
- package/src/telemetry/otel-metrics.ts +0 -136
- package/src/telemetry/otel.ts +0 -397
- package/src/telemetry/otlp.ts +0 -76
- package/src/tools/ask-user.ts +0 -156
- package/src/tools/bash-bg.ts +0 -94
- package/src/tools/bash-jobs.ts +0 -237
- package/src/tools/design.ts +0 -151
- package/src/tools/evalcell.ts +0 -338
- package/src/tools/html-text.ts +0 -139
- package/src/tools/provider.ts +0 -149
- package/src/tools/task.ts +0 -250
- package/src/tools/todo.ts +0 -320
- package/src/tools/webfetch.ts +0 -332
- package/src/tools/websearch.ts +0 -359
- package/src/tui/agents-cmd.ts +0 -41
- package/src/tui/app.ts +0 -749
- package/src/tui/attach.ts +0 -127
- package/src/tui/boot-notes.ts +0 -41
- package/src/tui/builtin-prompts.ts +0 -59
- package/src/tui/checkpoints-cmd.ts +0 -70
- package/src/tui/clipboard-image.ts +0 -81
- package/src/tui/clipboard.ts +0 -78
- package/src/tui/commands.ts +0 -283
- package/src/tui/config-view.ts +0 -53
- package/src/tui/context-cmds.ts +0 -282
- package/src/tui/cost.ts +0 -108
- package/src/tui/crash-guard.ts +0 -173
- package/src/tui/focus-terminal.ts +0 -34
- package/src/tui/git-cmds.ts +0 -273
- package/src/tui/git-plain.ts +0 -58
- package/src/tui/info-cmd.ts +0 -150
- package/src/tui/input-plain.ts +0 -76
- package/src/tui/mcp-cmd.ts +0 -128
- package/src/tui/memory-note.ts +0 -77
- package/src/tui/modes-cmd.ts +0 -45
- package/src/tui/notify-seq.ts +0 -100
- package/src/tui/notify.ts +0 -318
- package/src/tui/overlays.ts +0 -97
- package/src/tui/pi-renderer.ts +0 -428
- package/src/tui/providers-cmd.ts +0 -377
- package/src/tui/reasoning-view.ts +0 -56
- package/src/tui/renderer.ts +0 -128
- package/src/tui/replay-marker.ts +0 -29
- package/src/tui/session-cmd.ts +0 -148
- package/src/tui/session-manage.ts +0 -95
- package/src/tui/sextant-attach.ts +0 -102
- package/src/tui/sextant-io.ts +0 -202
- package/src/tui/sextant-smoke.ts +0 -110
- package/src/tui/shell-cmd.ts +0 -158
- package/src/tui/smoke.ts +0 -72
- package/src/tui/staged-terminal.ts +0 -50
- package/src/tui/startup.ts +0 -12
- package/src/tui/theme.ts +0 -59
- package/src/tui/todo-label.ts +0 -7
- package/src/tui/trust-card.ts +0 -107
- package/src/tui/tui-commands.ts +0 -87
- package/tsconfig.json +0 -30
- package/vendor/pi-tui/LICENSE +0 -21
- package/vendor/pi-tui/PATCHES.md +0 -12
- package/vendor/pi-tui/PROVENANCE.md +0 -12
- package/vendor/pi-tui/README.upstream.md +0 -854
- package/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/vendor/pi-tui/src/alt-screen-search.ts +0 -158
- package/vendor/pi-tui/src/autocomplete.ts +0 -827
- package/vendor/pi-tui/src/components/alt-screen-flash.ts +0 -52
- package/vendor/pi-tui/src/components/box.ts +0 -138
- package/vendor/pi-tui/src/components/cancellable-loader.ts +0 -41
- package/vendor/pi-tui/src/components/editor.ts +0 -2364
- package/vendor/pi-tui/src/components/h-stack.ts +0 -45
- package/vendor/pi-tui/src/components/image.ts +0 -128
- package/vendor/pi-tui/src/components/input.ts +0 -448
- package/vendor/pi-tui/src/components/loader.ts +0 -93
- package/vendor/pi-tui/src/components/markdown.ts +0 -1016
- package/vendor/pi-tui/src/components/scroll-view.ts +0 -217
- package/vendor/pi-tui/src/components/select-list.ts +0 -230
- package/vendor/pi-tui/src/components/settings-list.ts +0 -277
- package/vendor/pi-tui/src/components/spacer.ts +0 -29
- package/vendor/pi-tui/src/components/stack.ts +0 -155
- package/vendor/pi-tui/src/components/text.ts +0 -108
- package/vendor/pi-tui/src/components/truncated-text.ts +0 -66
- package/vendor/pi-tui/src/components/v-stack.ts +0 -34
- package/vendor/pi-tui/src/editor-component.ts +0 -75
- package/vendor/pi-tui/src/fuzzy.ts +0 -138
- package/vendor/pi-tui/src/index.ts +0 -149
- package/vendor/pi-tui/src/keybindings.ts +0 -321
- package/vendor/pi-tui/src/keys.ts +0 -1402
- package/vendor/pi-tui/src/kill-ring.ts +0 -47
- package/vendor/pi-tui/src/latex.ts +0 -1381
- package/vendor/pi-tui/src/layout-node.ts +0 -52
- package/vendor/pi-tui/src/layout.ts +0 -411
- package/vendor/pi-tui/src/native-modifiers.ts +0 -60
- package/vendor/pi-tui/src/native-module-path.ts +0 -32
- package/vendor/pi-tui/src/stdin-buffer.ts +0 -445
- package/vendor/pi-tui/src/terminal-colors.ts +0 -74
- package/vendor/pi-tui/src/terminal-image.ts +0 -701
- package/vendor/pi-tui/src/terminal.ts +0 -554
- package/vendor/pi-tui/src/tui-alt-screen.ts +0 -1379
- package/vendor/pi-tui/src/tui-main-screen.ts +0 -655
- package/vendor/pi-tui/src/tui.ts +0 -1264
- package/vendor/pi-tui/src/undo-stack.ts +0 -29
- package/vendor/pi-tui/src/utils.ts +0 -1327
- package/vendor/pi-tui/src/word-navigation.ts +0 -118
- package/vendor/pi-tui/test/test-themes.ts +0 -39
- package/vendor/pi-tui/test/virtual-terminal.ts +0 -219
- /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
|
-
}
|
package/src/mcp/local-package.ts
DELETED
|
@@ -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
|
-
];
|