rovecode 0.4.0-beta.2 → 0.4.0
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/README.md +67 -69
- package/THIRD_PARTY_NOTICES.md +0 -44
- package/bin/rovecode.ts +21 -0
- package/package.json +16 -37
- package/src/account/keys.ts +97 -0
- package/src/account/login.ts +158 -0
- package/src/account/provision.ts +47 -0
- package/src/account/store.ts +63 -0
- package/src/acp/server.ts +373 -0
- package/src/cli/account-cmd.ts +116 -0
- package/src/cli/connect.ts +244 -0
- package/src/cli/context-cmd.ts +199 -0
- package/src/cli/dispatch.ts +109 -0
- package/src/cli/doctor.ts +324 -0
- package/src/cli/export.ts +278 -0
- package/src/cli/help.ts +240 -0
- package/src/cli/is-tui-invocation.ts +8 -0
- package/src/cli/main.ts +599 -0
- package/src/cli/market-cmd.ts +658 -0
- package/src/cli/mcp-market-cmd.ts +299 -0
- package/src/cli/output.ts +382 -0
- package/src/cli/repl.ts +172 -0
- package/src/cli/resume.ts +32 -0
- package/src/cli/run-limits.ts +78 -0
- package/src/cli/runtime.ts +792 -0
- package/src/cli/setup.ts +187 -0
- package/src/cli/update-cmd.ts +78 -0
- package/src/cli/workflow-cmd.ts +100 -0
- package/src/coding/checkpoints.ts +270 -0
- package/src/coding/diff.ts +136 -0
- package/src/coding/files.ts +339 -0
- package/src/coding/hashline.ts +319 -0
- package/src/coding/lsp.ts +406 -0
- package/src/coding/repomap-cache.ts +99 -0
- package/src/coding/repomap-files.ts +110 -0
- package/src/coding/repomap.ts +392 -0
- package/src/core/compaction.ts +399 -0
- package/src/core/config.ts +289 -0
- package/src/core/context-report.ts +228 -0
- package/src/core/context.ts +60 -0
- package/src/core/count-remote.ts +107 -0
- package/src/core/execpolicy-rules.ts +196 -0
- package/src/core/execpolicy.ts +385 -0
- package/src/core/executor.ts +397 -0
- package/src/core/guardrails.ts +400 -0
- package/src/core/hooks.ts +398 -0
- package/src/core/images.ts +230 -0
- package/src/core/intro.ts +236 -0
- package/src/core/loop.ts +621 -0
- package/src/core/modes.ts +372 -0
- package/src/core/orchestrator.ts +207 -0
- package/src/core/reflection.ts +165 -0
- package/src/core/sandbox-config.ts +167 -0
- package/src/core/session-images.ts +73 -0
- package/src/core/session.ts +398 -0
- package/src/core/settings.ts +98 -0
- package/src/core/stuck-detector.ts +273 -0
- package/src/core/tasks.ts +374 -0
- package/src/core/token-scale.ts +108 -0
- package/src/core/tool-output-budget.ts +166 -0
- package/src/core/tools.ts +288 -0
- package/src/core/types.ts +330 -0
- package/src/core/update-check.ts +171 -0
- package/src/core/update.ts +158 -0
- package/src/core/usage.ts +204 -0
- package/src/core/validate.ts +121 -0
- package/src/core/verify-gate.ts +159 -0
- package/src/core/verify.ts +237 -0
- package/src/core/voice.ts +158 -0
- package/src/core/win-job.ts +183 -0
- package/src/design/audit.ts +797 -0
- package/src/design/direction.ts +190 -0
- package/src/design/rules.ts +157 -0
- package/src/eval/bench.ts +150 -0
- package/src/eval/gauntlet-runner.ts +218 -0
- package/src/eval/gauntlet.ts +226 -0
- package/src/eval/grader.ts +186 -0
- package/src/eval/record.ts +202 -0
- package/src/eval/redact.ts +141 -0
- package/src/eval/replay.ts +147 -0
- package/src/eval/trajectory.ts +373 -0
- package/src/index.ts +17 -0
- package/src/market/catalogs/mcp-docs.json +111 -0
- package/src/market/catalogs/plugins.json +111 -0
- package/src/market/catalogs/skills.json +478 -0
- package/src/market/clone.ts +72 -0
- package/src/market/context-cost.ts +121 -0
- package/src/market/digest.ts +106 -0
- package/src/market/index.ts +22 -0
- package/src/market/install.ts +578 -0
- package/src/market/manifest.ts +187 -0
- package/src/market/prereq.ts +145 -0
- package/src/market/registry.ts +363 -0
- package/src/market/resolve.ts +111 -0
- package/src/market/types.ts +236 -0
- package/src/market/validate.ts +227 -0
- package/src/mcp/client.ts +431 -0
- package/src/mcp/config.ts +239 -0
- package/src/mcp/local-package.ts +211 -0
- package/src/mcp/market-catalog.ts +84 -0
- package/src/mcp/market-install.ts +289 -0
- package/src/mcp/market.ts +0 -0
- package/src/mcp/tools.ts +131 -0
- package/src/mcp/trust.ts +49 -0
- package/src/memory/blocks.ts +175 -0
- package/src/memory/recall.ts +355 -0
- package/src/memory/store.ts +105 -0
- package/src/memory/tools.ts +99 -0
- package/src/plugins/cli.ts +123 -0
- package/src/plugins/discover.ts +108 -0
- package/src/plugins/index.ts +50 -0
- package/src/plugins/init.ts +140 -0
- package/src/plugins/install.ts +184 -0
- package/src/plugins/load.ts +149 -0
- package/src/plugins/manifest.ts +106 -0
- package/src/plugins/state.ts +83 -0
- package/src/providers/auth.ts +293 -0
- package/src/providers/cache.ts +223 -0
- package/src/providers/catalog-local.ts +160 -0
- package/src/providers/catalog.ts +408 -0
- package/src/providers/middleware-context.ts +86 -0
- package/src/providers/middleware.ts +373 -0
- package/src/providers/profile-glm53.ts +111 -0
- package/src/providers/profile-sonnet5-persona.ts +65 -0
- package/src/providers/profile-sonnet5-voice.ts +23 -0
- package/src/providers/profiles.ts +156 -0
- package/src/providers/provider-config.ts +311 -0
- package/src/providers/registry.ts +302 -0
- package/src/providers/response-validation.ts +80 -0
- package/src/providers/retry.ts +234 -0
- package/src/providers/router.ts +294 -0
- package/src/providers/sse.ts +26 -0
- package/src/providers/stream-errors.ts +117 -0
- package/src/providers/stream.ts +569 -0
- package/src/providers/thinking.ts +189 -0
- package/src/providers/wire-messages.ts +129 -0
- package/src/sdk/client.ts +225 -0
- package/src/sdk/index.ts +3 -0
- package/src/server/dashboard.ts +144 -0
- package/src/server/http.ts +343 -0
- package/src/server/openapi.ts +246 -0
- package/src/sextant/card-hits.ts +102 -0
- package/src/sextant/card-keys.ts +55 -0
- package/src/sextant/context-source.ts +157 -0
- package/src/sextant/draw-agents.ts +273 -0
- package/src/sextant/draw-code.ts +388 -0
- package/src/sextant/draw-context.ts +222 -0
- package/src/sextant/draw-frame.ts +164 -0
- package/src/sextant/draw-market.ts +573 -0
- package/src/sextant/draw-messages.ts +386 -0
- package/src/sextant/draw-pet.ts +230 -0
- package/src/sextant/draw-plan.ts +159 -0
- package/src/sextant/draw-tabs.ts +85 -0
- package/src/sextant/draw-util.ts +65 -0
- package/src/sextant/engine.ts +230 -0
- package/src/sextant/frame-hits.ts +25 -0
- package/src/sextant/frame.ts +101 -0
- package/src/sextant/git-status.ts +197 -0
- package/src/sextant/grid.ts +59 -0
- package/src/sextant/input.ts +119 -0
- package/src/sextant/keys.ts +488 -0
- package/src/sextant/layout.ts +86 -0
- package/src/sextant/local-commands.ts +156 -0
- package/src/sextant/market-source.ts +287 -0
- package/src/sextant/mentions.ts +141 -0
- package/src/sextant/message-hits.ts +26 -0
- package/src/sextant/model.ts +387 -0
- package/src/sextant/overlays.ts +451 -0
- package/src/sextant/panel-hits.ts +38 -0
- package/src/sextant/pet.ts +399 -0
- package/src/sextant/screen.ts +324 -0
- package/src/sextant/scroll-hits.ts +66 -0
- package/src/sextant/scrollbar.ts +82 -0
- package/src/sextant/selection.ts +123 -0
- package/src/sextant/sextant-bridge.ts +174 -0
- package/src/sextant/sextant-cards.ts +142 -0
- package/src/sextant/sextant-diff-base.ts +63 -0
- package/src/sextant/sextant-files.ts +154 -0
- package/src/sextant/sextant-frame-loop.ts +314 -0
- package/src/sextant/sextant-renderer.ts +478 -0
- package/src/sextant/sextant-repo.ts +131 -0
- package/src/sextant/theme.ts +66 -0
- package/src/sextant/tool-rows.ts +189 -0
- package/src/sextant/types.ts +473 -0
- package/src/skills/index.ts +306 -0
- package/src/skills/tools.ts +69 -0
- package/src/skills/versioned.ts +227 -0
- package/src/telemetry/otel.ts +353 -0
- package/src/telemetry/otlp.ts +68 -0
- package/src/tools/ask-user.ts +156 -0
- package/src/tools/design.ts +151 -0
- package/src/tools/evalcell.ts +338 -0
- package/src/tools/html-text.ts +139 -0
- package/src/tools/provider.ts +149 -0
- package/src/tools/task.ts +216 -0
- package/src/tools/todo.ts +320 -0
- package/src/tools/webfetch.ts +331 -0
- package/src/tui/app.ts +608 -0
- package/src/tui/attach.ts +127 -0
- package/src/tui/checkpoints-cmd.ts +70 -0
- package/src/tui/clipboard-image.ts +81 -0
- package/src/tui/commands.ts +277 -0
- package/src/tui/cost.ts +108 -0
- package/src/tui/info-cmd.ts +144 -0
- package/src/tui/mcp-cmd.ts +128 -0
- package/src/tui/modes-cmd.ts +45 -0
- package/src/tui/overlays.ts +97 -0
- package/src/tui/pi-renderer.ts +424 -0
- package/src/tui/providers-cmd.ts +366 -0
- package/src/tui/renderer.ts +101 -0
- package/src/tui/replay-marker.ts +29 -0
- package/src/tui/session-cmd.ts +146 -0
- package/src/tui/sextant-attach.ts +68 -0
- package/src/tui/sextant-io.ts +184 -0
- package/src/tui/sextant-smoke.ts +110 -0
- package/src/tui/smoke.ts +72 -0
- package/src/tui/theme.ts +59 -0
- package/src/tui/todo-label.ts +7 -0
- package/src/workflow/engine.ts +266 -0
- package/tsconfig.json +30 -0
- package/vendor/pi-tui/LICENSE +21 -0
- package/vendor/pi-tui/PATCHES.md +12 -0
- package/vendor/pi-tui/PROVENANCE.md +12 -0
- package/vendor/pi-tui/README.upstream.md +854 -0
- 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 +158 -0
- package/vendor/pi-tui/src/autocomplete.ts +827 -0
- package/vendor/pi-tui/src/components/alt-screen-flash.ts +52 -0
- package/vendor/pi-tui/src/components/box.ts +138 -0
- package/vendor/pi-tui/src/components/cancellable-loader.ts +41 -0
- package/vendor/pi-tui/src/components/editor.ts +2364 -0
- package/vendor/pi-tui/src/components/h-stack.ts +45 -0
- package/vendor/pi-tui/src/components/image.ts +128 -0
- package/vendor/pi-tui/src/components/input.ts +448 -0
- package/vendor/pi-tui/src/components/loader.ts +93 -0
- package/vendor/pi-tui/src/components/markdown.ts +1016 -0
- package/vendor/pi-tui/src/components/scroll-view.ts +217 -0
- package/vendor/pi-tui/src/components/select-list.ts +230 -0
- package/vendor/pi-tui/src/components/settings-list.ts +277 -0
- package/vendor/pi-tui/src/components/spacer.ts +29 -0
- package/vendor/pi-tui/src/components/stack.ts +155 -0
- package/vendor/pi-tui/src/components/text.ts +108 -0
- package/vendor/pi-tui/src/components/truncated-text.ts +66 -0
- package/vendor/pi-tui/src/components/v-stack.ts +34 -0
- package/vendor/pi-tui/src/editor-component.ts +75 -0
- package/vendor/pi-tui/src/fuzzy.ts +138 -0
- package/vendor/pi-tui/src/index.ts +149 -0
- package/vendor/pi-tui/src/keybindings.ts +321 -0
- package/vendor/pi-tui/src/keys.ts +1402 -0
- package/vendor/pi-tui/src/kill-ring.ts +47 -0
- package/vendor/pi-tui/src/latex.ts +1381 -0
- package/vendor/pi-tui/src/layout-node.ts +52 -0
- package/vendor/pi-tui/src/layout.ts +411 -0
- package/vendor/pi-tui/src/native-modifiers.ts +60 -0
- package/vendor/pi-tui/src/native-module-path.ts +32 -0
- package/vendor/pi-tui/src/stdin-buffer.ts +445 -0
- package/vendor/pi-tui/src/terminal-colors.ts +74 -0
- package/vendor/pi-tui/src/terminal-image.ts +701 -0
- package/vendor/pi-tui/src/terminal.ts +554 -0
- package/vendor/pi-tui/src/tui-alt-screen.ts +1379 -0
- package/vendor/pi-tui/src/tui-main-screen.ts +655 -0
- package/vendor/pi-tui/src/tui.ts +1264 -0
- package/vendor/pi-tui/src/undo-stack.ts +29 -0
- package/vendor/pi-tui/src/utils.ts +1327 -0
- package/vendor/pi-tui/src/word-navigation.ts +118 -0
- package/vendor/pi-tui/test/test-themes.ts +39 -0
- package/vendor/pi-tui/test/virtual-terminal.ts +219 -0
- package/CHANGELOG.md +0 -512
- package/bin/rovecode.js +0 -24
- package/dist/cli/app-dybnr56b.js +0 -2
- package/dist/cli/ask-user-p8hq4xgj.js +0 -2
- package/dist/cli/auth-login-ewpgw5sm.js +0 -2
- package/dist/cli/auth-m8p9grty.js +0 -2
- package/dist/cli/bench-xv3ypwev.js +0 -9
- package/dist/cli/catalog-737wb2s0.js +0 -2
- package/dist/cli/cli-arhg40m0.js +0 -2
- package/dist/cli/client-cf2pxx8q.js +0 -2
- package/dist/cli/commands-3p7e4xxs.js +0 -2
- package/dist/cli/connect-3q93d7cb.js +0 -2
- package/dist/cli/context-cmd-eqxmxhzq.js +0 -2
- package/dist/cli/context-report-hbw9zfes.js +0 -2
- package/dist/cli/count-remote-mby98cd0.js +0 -2
- package/dist/cli/design-122y0axd.js +0 -2
- package/dist/cli/dispatch-b4egzvvh.js +0 -2
- package/dist/cli/doctor-x4jkv72e.js +0 -3
- package/dist/cli/executor-ftvg6tsy.js +0 -2
- package/dist/cli/export-pdgdhkch.js +0 -2
- package/dist/cli/files-cez9a96p.js +0 -2
- package/dist/cli/gauntlet-r3xxaszc.js +0 -2
- package/dist/cli/gauntlet-runner-r515m7kk.js +0 -10
- package/dist/cli/gauntlet-wave3-bnkjk2v2.js +0 -5
- package/dist/cli/gauntlet-wave4-acs9s60q.js +0 -14
- package/dist/cli/hashline-ewg5hbe3.js +0 -2
- package/dist/cli/http-n0kehsk8.js +0 -5
- package/dist/cli/index-z5qt1s76.js +0 -2
- package/dist/cli/install-80mp63kx.js +0 -2
- package/dist/cli/loop-12twjcat.js +0 -2
- package/dist/cli/main-01pv9206.js +0 -4
- package/dist/cli/main-0jys2ccn.js +0 -3
- package/dist/cli/main-1ztz6fkj.js +0 -10
- package/dist/cli/main-23q7cmww.js +0 -9
- package/dist/cli/main-2rzbexn2.js +0 -3
- package/dist/cli/main-2wyax8k9.js +0 -9
- package/dist/cli/main-2yeveeve.js +0 -6
- package/dist/cli/main-2z3dek0b.js +0 -3
- package/dist/cli/main-2zgsknth.js +0 -3
- package/dist/cli/main-45ejth3a.js +0 -4
- package/dist/cli/main-45rn3trk.js +0 -22
- package/dist/cli/main-4p4e2w7x.js +0 -4
- package/dist/cli/main-4y0tnfpa.js +0 -16
- package/dist/cli/main-5py0rkmc.js +0 -4
- package/dist/cli/main-6dtqmbt6.js +0 -7
- package/dist/cli/main-6h9x282m.js +0 -4
- package/dist/cli/main-6vjeds42.js +0 -3
- package/dist/cli/main-78gq4bt9.js +0 -6
- package/dist/cli/main-7jd5vh3x.js +0 -4
- package/dist/cli/main-7kt6r53y.js +0 -4
- package/dist/cli/main-8c1tbazx.js +0 -58
- package/dist/cli/main-9a9rnh47.js +0 -19
- package/dist/cli/main-9ht36z12.js +0 -3
- package/dist/cli/main-a2yfvcy9.js +0 -7
- package/dist/cli/main-a3f51n0x.js +0 -5
- package/dist/cli/main-b8zq261k.js +0 -3
- package/dist/cli/main-bxtvnf6d.js +0 -13
- package/dist/cli/main-edxc3yzt.js +0 -4
- package/dist/cli/main-evgz4mp5.js +0 -21
- package/dist/cli/main-f33fc5je.js +0 -9
- package/dist/cli/main-fvnpq46y.js +0 -12
- package/dist/cli/main-gbbty4d4.js +0 -3
- package/dist/cli/main-gth53dnt.js +0 -25
- package/dist/cli/main-hqbz10aw.js +0 -9
- package/dist/cli/main-hrrvcfan.js +0 -38
- package/dist/cli/main-hzwtsb2m.js +0 -5
- package/dist/cli/main-j7ttv0sd.js +0 -34
- package/dist/cli/main-jak598k9.js +0 -5
- package/dist/cli/main-kba6zeyd.js +0 -6
- package/dist/cli/main-kwwsz6rq.js +0 -3
- package/dist/cli/main-m8vm17zq.js +0 -3
- package/dist/cli/main-mg4f96e1.js +0 -3
- package/dist/cli/main-mg9b20ac.js +0 -18
- package/dist/cli/main-mgb9ccnx.js +0 -3
- package/dist/cli/main-mjt2p7aj.js +0 -3
- package/dist/cli/main-n6qrdbmy.js +0 -3
- package/dist/cli/main-na7wse0x.js +0 -5
- package/dist/cli/main-nqveez48.js +0 -4
- package/dist/cli/main-ntqef02r.js +0 -10
- package/dist/cli/main-nvc3yjay.js +0 -136
- package/dist/cli/main-p0cfn6nr.js +0 -16
- package/dist/cli/main-qj2djy17.js +0 -19
- package/dist/cli/main-qsevpgsv.js +0 -3
- package/dist/cli/main-qvarybsp.js +0 -3
- package/dist/cli/main-rebtt91r.js +0 -5
- package/dist/cli/main-rpg7h8mb.js +0 -3
- package/dist/cli/main-rsy72qmw.js +0 -15
- package/dist/cli/main-rvetps99.js +0 -18
- package/dist/cli/main-s4bb0jav.js +0 -3
- package/dist/cli/main-s9v8k74e.js +0 -3
- package/dist/cli/main-tjvwmscs.js +0 -3
- package/dist/cli/main-tkgarpjj.js +0 -4
- package/dist/cli/main-v8y60bb2.js +0 -3
- package/dist/cli/main-vhrrq337.js +0 -3
- package/dist/cli/main-vp2dfb7s.js +0 -4
- package/dist/cli/main-vqbr22sz.js +0 -8
- package/dist/cli/main-vxnwe5xx.js +0 -18
- package/dist/cli/main-wgph00xf.js +0 -5
- package/dist/cli/main-wk2csfnj.js +0 -5
- package/dist/cli/main-wm997zjx.js +0 -3
- package/dist/cli/main-wpkyraxh.js +0 -3
- package/dist/cli/main-wqt32p5x.js +0 -4
- package/dist/cli/main-x9ct6y1a.js +0 -3
- package/dist/cli/main-xfekqh9m.js +0 -7
- package/dist/cli/main-xt9zc3n6.js +0 -7
- package/dist/cli/main-xx2z3zh5.js +0 -4
- package/dist/cli/main-y5c82rxr.js +0 -3
- package/dist/cli/main-yrjt2sqt.js +0 -14
- package/dist/cli/main-ys6zj3yr.js +0 -3
- package/dist/cli/main-ywbxshqc.js +0 -8
- package/dist/cli/main-z13755t8.js +0 -25
- package/dist/cli/main-zc7pyrbj.js +0 -4
- package/dist/cli/main.js +0 -279
- package/dist/cli/market-cmd-bm5xvn9f.js +0 -5
- package/dist/cli/mcp-login-bthtfpt7.js +0 -2
- package/dist/cli/mcp-market-cmd-mbeshfyd.js +0 -2
- package/dist/cli/notify-54v5z9dz.js +0 -2
- package/dist/cli/oauth-g5gme95c.js +0 -2
- package/dist/cli/output-satndjap.js +0 -16
- package/dist/cli/profiles-sfhpbq3m.js +0 -2
- package/dist/cli/provider-config-hv3xtdt4.js +0 -2
- package/dist/cli/provider-kwzq6g84.js +0 -2
- package/dist/cli/registry-fh0hdnyn.js +0 -2
- package/dist/cli/registry-y1y8e94r.js +0 -2
- package/dist/cli/repl-t4z03mqq.js +0 -11
- package/dist/cli/resume-fqt4chg8.js +0 -2
- package/dist/cli/run-flags-rysbag9t.js +0 -2
- package/dist/cli/runtime-j19fjbsa.js +0 -2
- package/dist/cli/sandbox-config-g4qxd7y5.js +0 -2
- package/dist/cli/server-r0b6bksk.js +0 -5
- package/dist/cli/session-arg-txmn5g4x.js +0 -2
- package/dist/cli/session-ed250d9j.js +0 -2
- package/dist/cli/sessions-cmd-adw7svfn.js +0 -7
- package/dist/cli/settings-y9rzcqx8.js +0 -2
- package/dist/cli/setup-jmbr11j0.js +0 -2
- package/dist/cli/sextant-smoke-tcth0vea.js +0 -5
- package/dist/cli/skills-cmd-zbdy99v6.js +0 -2
- package/dist/cli/smoke-1bg937kx.js +0 -8
- package/dist/cli/start-chat-p01cdks3.js +0 -12
- package/dist/cli/stream-4wmyaypz.js +0 -2
- package/dist/cli/task-eg4s093s.js +0 -2
- package/dist/cli/tasks-12v9rr9k.js +0 -2
- package/dist/cli/thinking-a5ngvqyh.js +0 -2
- package/dist/cli/todo-1wxpcecx.js +0 -2
- package/dist/cli/tools-2ftsya7w.js +0 -2
- package/dist/cli/tools-x1tj4fxm.js +0 -2
- package/dist/cli/trust-cmd-hccxehzb.js +0 -2
- package/dist/cli/update-check-ygt3vd7m.js +0 -2
- package/dist/cli/update-cmd-v23qhr8c.js +0 -2
- package/dist/cli/voice-g1gtck92.js +0 -2
- package/dist/cli/webfetch-0nnrjgb5.js +0 -2
- package/dist/cli/websearch-f0vr2p7d.js +0 -2
- package/dist/cli/workspace-9rq1w4ta.js +0 -2
- package/dist/lib/index.js +0 -62
- package/dist/lib/models-index.json +0 -1
- package/dist/lib/plugins.js +0 -6
- package/dist/lib/providers.js +0 -17
- package/dist/lib/public-api.js +0 -20
- package/dist/rovecode.exe +0 -4
- /package/{dist/cli → src/providers}/models-index.json +0 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/** Port #38: session export — markdown transcript or raw JSONL copy, LOCAL only.
|
|
2
|
+
* Pattern: opencode cli/cmd/export.ts @ ebece6e (MIT) — session resolution → serialize;
|
|
3
|
+
* their export emits the raw session data verbatim to stdout, which maps to --json here
|
|
4
|
+
* (verbatim byte copy of entries.jsonl, the whole tree incl. abandoned branches). The
|
|
5
|
+
* cloud-share half of opencode's feature (share/session.ts) is explicitly deferred
|
|
6
|
+
* (PORTS.md wave-3 ledger: "export stays local"), and the markdown layout is rovecode-native:
|
|
7
|
+
* the snapshot has no session→markdown renderer at ebece6e.
|
|
8
|
+
*
|
|
9
|
+
* Markdown walks the ACTIVE path only (store.path()), mirroring TUI replayHistory:
|
|
10
|
+
* user/assistant text, tool cards (args one-liner, bounded output, ok/ERROR badge),
|
|
11
|
+
* mode switches as "mode → plan" lines (wave-2 replay convention, never raw
|
|
12
|
+
* <mode_notice> XML), compaction markers, and a costs section over per-origin usage
|
|
13
|
+
* totals + buildCostNote. Output is deterministic: every timestamp comes from the
|
|
14
|
+
* entries themselves (ISO UTC), there is no "generated at" wall-clock line, and the
|
|
15
|
+
* catalog is the offline snapshot (lookup() never fetches). */
|
|
16
|
+
|
|
17
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
18
|
+
import { join, isAbsolute } from "node:path";
|
|
19
|
+
import { SessionStore, listSessions, type Entry } from "../core/session.ts";
|
|
20
|
+
import { modeSwitchOf } from "../core/modes.ts";
|
|
21
|
+
import { ModelCatalog } from "../providers/catalog.ts";
|
|
22
|
+
import { buildCostNote } from "../tui/cost.ts";
|
|
23
|
+
import { describeImage } from "../core/images.ts";
|
|
24
|
+
import type { ImagePart, Message, ToolCallPart, ToolResultPart } from "../core/types.ts";
|
|
25
|
+
|
|
26
|
+
/** Tool output cap (chars) per card. Clipped output gets an explicit marker line. */
|
|
27
|
+
export const TOOL_OUTPUT_CAP = 2000;
|
|
28
|
+
/** One-line args summary cap — same 120-char clip the TUI uses for tool cards. */
|
|
29
|
+
const ARGS_CAP = 120;
|
|
30
|
+
/** CLI usage line — thrown on a missing id or a dangling --out; cmdExport turns it into exit 2, the
|
|
31
|
+
* usage/startup class README documents, while a real export failure stays exit 1. */
|
|
32
|
+
const USAGE = "usage: rovecode export <session-id|prefix> [--json] [--out <path>] [--force]";
|
|
33
|
+
|
|
34
|
+
export interface ExportOptions {
|
|
35
|
+
/** raw JSONL copy (verbatim bytes) instead of markdown */
|
|
36
|
+
json?: boolean;
|
|
37
|
+
/** target path; default ./<sessionId-short>.(md|jsonl) under cwd */
|
|
38
|
+
out?: string;
|
|
39
|
+
/** overwrite an existing target file */
|
|
40
|
+
force?: boolean;
|
|
41
|
+
/** base dir for relative/default output paths; default process.cwd() */
|
|
42
|
+
cwd?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ExportResult { path: string; format: "markdown" | "jsonl" }
|
|
46
|
+
|
|
47
|
+
// ---------- session-prefix resolution (mirrors TUI /resume: app.ts cmdSessions) ----------
|
|
48
|
+
|
|
49
|
+
/** Exact id wins outright; a prefix must match exactly ONE session; an ambiguous
|
|
50
|
+
* prefix lists candidates instead of silently picking one (same rule as /resume). */
|
|
51
|
+
export function resolveSessionId(sessionsRoot: string, idOrPrefix: string): string {
|
|
52
|
+
const all = listSessions(sessionsRoot);
|
|
53
|
+
const exact = all.find((s) => s.id === idOrPrefix);
|
|
54
|
+
const matches = exact ? [exact] : all.filter((s) => s.id.startsWith(idOrPrefix));
|
|
55
|
+
if (matches.length === 1) return matches[0]!.id;
|
|
56
|
+
if (matches.length > 1) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`"${idOrPrefix}" matches ${matches.length} sessions: ` +
|
|
59
|
+
`${matches.slice(0, 4).map((s) => s.id.slice(0, 8)).join(", ")}${matches.length > 4 ? ", …" : ""} — be more specific`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`no session matching "${idOrPrefix}"`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ---------- markdown rendering ----------
|
|
66
|
+
|
|
67
|
+
function isMessage(e: Entry): e is Message { return "role" in e; }
|
|
68
|
+
|
|
69
|
+
/** Longest backtick run in s (0 when none) — a CommonMark span/fence must be longer. */
|
|
70
|
+
function tickRun(s: string): number {
|
|
71
|
+
let run = 0;
|
|
72
|
+
for (const m of s.matchAll(/`+/g)) run = Math.max(run, m[0].length);
|
|
73
|
+
return run;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Inline-code span that survives backticks in the content (args may contain them):
|
|
77
|
+
* delimiter = longest run + 1 (a fixed `` closes at the first inner double tick),
|
|
78
|
+
* space-padded so a leading/trailing tick stays inside the span. */
|
|
79
|
+
function inlineCode(s: string): string {
|
|
80
|
+
const run = tickRun(s);
|
|
81
|
+
if (run === 0) return `\`${s}\``;
|
|
82
|
+
const tick = "`".repeat(run + 1);
|
|
83
|
+
return `${tick} ${s} ${tick}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Fenced block whose fence is longer than any backtick run in the content. */
|
|
87
|
+
function fenced(content: string): string {
|
|
88
|
+
const fence = "`".repeat(Math.max(3, tickRun(content) + 1));
|
|
89
|
+
return `${fence}\n${content}\n${fence}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** One tool card: name + badge header, one-line args, bounded output block. */
|
|
93
|
+
function toolCard(tool: string, args: unknown, res: ToolResultPart | undefined): string {
|
|
94
|
+
const badge = res === undefined ? "no result recorded" : res.ok ? "ok" : "ERROR";
|
|
95
|
+
const argsLine = JSON.stringify(args) ?? "undefined";
|
|
96
|
+
const argsShown = argsLine.length > ARGS_CAP ? argsLine.slice(0, ARGS_CAP) + "…" : argsLine;
|
|
97
|
+
const parts = [`### tool: ${tool} — ${badge}`, `args: ${inlineCode(argsShown)}`];
|
|
98
|
+
if (res !== undefined) {
|
|
99
|
+
if (res.output.length === 0) parts.push("*(no output)*");
|
|
100
|
+
else {
|
|
101
|
+
const clipped = res.output.length > TOOL_OUTPUT_CAP;
|
|
102
|
+
parts.push(fenced(clipped ? res.output.slice(0, TOOL_OUTPUT_CAP) : res.output));
|
|
103
|
+
if (clipped) parts.push(`*+${res.output.length - TOOL_OUTPUT_CAP} chars clipped (cap ${TOOL_OUTPUT_CAP})*`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return parts.join("\n\n");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function textOf(m: Message): string {
|
|
110
|
+
return m.parts.filter((p) => p.kind === "text").map((p) => (p as { text: string }).text).join("");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Render the active path as markdown. Exported for tests; pure over the entries. */
|
|
114
|
+
export function renderSessionMarkdown(entries: readonly Entry[], sessionId: string, catalog: ModelCatalog): string {
|
|
115
|
+
const messages = entries.filter(isMessage);
|
|
116
|
+
// pair tool_call parts with their results up front so a card renders where the
|
|
117
|
+
// assistant issued the call; results without a visible call render as orphan cards
|
|
118
|
+
const results = new Map<string, ToolResultPart>();
|
|
119
|
+
for (const m of messages) {
|
|
120
|
+
if (m.role !== "tool") continue;
|
|
121
|
+
for (const p of m.parts) if (p.kind === "tool_result" && !results.has(p.callId)) results.set(p.callId, p);
|
|
122
|
+
}
|
|
123
|
+
const consumed = new Set<string>();
|
|
124
|
+
|
|
125
|
+
// title block: id, date range, model origins (first-appearance order)
|
|
126
|
+
const stamps = entries.map((e) => e.createdAt).filter((t) => typeof t === "number");
|
|
127
|
+
const range = stamps.length > 0
|
|
128
|
+
? `${new Date(Math.min(...stamps)).toISOString()} → ${new Date(Math.max(...stamps)).toISOString()}`
|
|
129
|
+
: "(empty)";
|
|
130
|
+
const origins: string[] = [];
|
|
131
|
+
for (const m of messages) {
|
|
132
|
+
if (!m.origin) continue;
|
|
133
|
+
const key = `${m.origin.provider}/${m.origin.model}`;
|
|
134
|
+
if (!origins.includes(key)) origins.push(key);
|
|
135
|
+
}
|
|
136
|
+
const blocks: string[] = [
|
|
137
|
+
`# rovecode session ${sessionId.slice(0, 8)}`,
|
|
138
|
+
[`- id: ${inlineCode(sessionId)}`, `- range: ${range}`, `- models: ${origins.length > 0 ? origins.join(", ") : "(none)"}`].join("\n"),
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
for (const e of entries) {
|
|
142
|
+
if (!isMessage(e)) {
|
|
143
|
+
// event entries: compaction becomes a marker (TUI wording, app.ts); others skipped
|
|
144
|
+
if (e.event.type === "compaction") {
|
|
145
|
+
blocks.push(`> compacted (${e.event.strategy}): ${e.event.tokensBefore} → ${e.event.tokensAfter} tokens`);
|
|
146
|
+
}
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const sw = modeSwitchOf(e);
|
|
150
|
+
if (sw) { blocks.push(`> mode → ${sw.to}`); continue; } // replay convention, never the raw XML
|
|
151
|
+
const text = textOf(e);
|
|
152
|
+
if (e.role === "user") {
|
|
153
|
+
// port #34: image parts render as one chip line each under the text (name, WxH, size), the
|
|
154
|
+
// same describeImage text the TUI notes use; the bytes stay in the session's attachments
|
|
155
|
+
// dir (header) so no image link that would dangle next to the export is emitted
|
|
156
|
+
const chips = e.parts.filter((p): p is ImagePart => p.kind === "image").map((p) => `[image: ${describeImage(p)}]`);
|
|
157
|
+
if (text || chips.length > 0) blocks.push("## User", ...(text ? [text] : []), ...chips);
|
|
158
|
+
} else if (e.role === "assistant") {
|
|
159
|
+
blocks.push("## Assistant");
|
|
160
|
+
if (text) blocks.push(text);
|
|
161
|
+
for (const p of e.parts) {
|
|
162
|
+
if (p.kind !== "tool_call") continue;
|
|
163
|
+
const call = p as ToolCallPart;
|
|
164
|
+
blocks.push(toolCard(call.tool, call.args, results.get(call.id)));
|
|
165
|
+
consumed.add(call.id);
|
|
166
|
+
}
|
|
167
|
+
} else if (e.role === "tool") {
|
|
168
|
+
for (const p of e.parts) {
|
|
169
|
+
if (p.kind === "tool_result" && !consumed.has(p.callId)) {
|
|
170
|
+
blocks.push(toolCard("(unknown)", undefined, p));
|
|
171
|
+
consumed.add(p.callId);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} else if (text) {
|
|
175
|
+
// plain system note (e.g. a compaction summary message)
|
|
176
|
+
blocks.push(text.split("\n").map((l) => `> ${l}`).join("\n"));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (messages.length === 0) blocks.push("*(no entries)*");
|
|
180
|
+
|
|
181
|
+
// costs: per-origin usage totals, then the /cost note (existing helpers, deterministic
|
|
182
|
+
// against the offline catalog; "current" = the last message origin on the path)
|
|
183
|
+
const byOrigin = new Map<string, { input: number; output: number; cacheRead: number; cacheWrite: number; msgs: number }>();
|
|
184
|
+
for (const m of messages) {
|
|
185
|
+
if (!m.usage) continue;
|
|
186
|
+
const key = m.origin ? `${m.origin.provider}/${m.origin.model}` : "(no origin)";
|
|
187
|
+
const row = byOrigin.get(key) ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, msgs: 0 };
|
|
188
|
+
row.input += m.usage.input; row.output += m.usage.output;
|
|
189
|
+
row.cacheRead += m.usage.cacheRead ?? 0; row.cacheWrite += m.usage.cacheWrite ?? 0;
|
|
190
|
+
row.msgs += 1;
|
|
191
|
+
byOrigin.set(key, row);
|
|
192
|
+
}
|
|
193
|
+
blocks.push("## Costs");
|
|
194
|
+
if (byOrigin.size > 0) {
|
|
195
|
+
blocks.push([
|
|
196
|
+
"| model | input | output | cache read | cache write | messages |",
|
|
197
|
+
"| --- | ---: | ---: | ---: | ---: | ---: |",
|
|
198
|
+
...[...byOrigin.entries()].map(([k, r]) => `| ${k} | ${r.input} | ${r.output} | ${r.cacheRead} | ${r.cacheWrite} | ${r.msgs} |`),
|
|
199
|
+
].join("\n"));
|
|
200
|
+
}
|
|
201
|
+
const current = [...messages].reverse().find((m) => m.origin)?.origin ?? { provider: "unknown", model: "unknown" };
|
|
202
|
+
blocks.push(buildCostNote(messages, catalog, current).split("\n").map((l) => `- ${l}`).join("\n"));
|
|
203
|
+
|
|
204
|
+
return blocks.join("\n\n") + "\n";
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ---------- export entrypoint ----------
|
|
208
|
+
|
|
209
|
+
function targetPath(out: string | undefined, id: string, format: "markdown" | "jsonl", cwd: string): string {
|
|
210
|
+
const fallback = `${id.slice(0, 8)}.${format === "jsonl" ? "jsonl" : "md"}`;
|
|
211
|
+
const p = out ?? fallback;
|
|
212
|
+
return isAbsolute(p) ? p : join(cwd, p);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Export a session (full id or unique prefix) to markdown or a raw JSONL copy.
|
|
216
|
+
* --json copies entries.jsonl BYTE-VERBATIM (whole tree, every branch); markdown
|
|
217
|
+
* renders the active path only. Never overwrites an existing file without force. */
|
|
218
|
+
export function exportSession(sessionsRoot: string, idOrPrefix: string, opts: ExportOptions = {}): ExportResult {
|
|
219
|
+
if (!idOrPrefix) throw new Error(USAGE);
|
|
220
|
+
const id = resolveSessionId(sessionsRoot, idOrPrefix);
|
|
221
|
+
const format: ExportResult["format"] = opts.json ? "jsonl" : "markdown";
|
|
222
|
+
const target = targetPath(opts.out, id, format, opts.cwd ?? process.cwd());
|
|
223
|
+
if (existsSync(target) && !opts.force) throw new Error(`refusing to overwrite ${target} — pass --force`);
|
|
224
|
+
if (opts.json) {
|
|
225
|
+
const src = join(sessionsRoot, id, "entries.jsonl");
|
|
226
|
+
if (!existsSync(src)) throw new Error(`session ${id.slice(0, 8)} has no entries.jsonl to copy`);
|
|
227
|
+
writeFileSync(target, readFileSync(src)); // Buffer in → Buffer out: verbatim bytes
|
|
228
|
+
} else {
|
|
229
|
+
const store = new SessionStore(sessionsRoot, id);
|
|
230
|
+
writeFileSync(target, renderSessionMarkdown(store.path(), id, new ModelCatalog()));
|
|
231
|
+
}
|
|
232
|
+
return { path: target, format };
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// ---------- CLI glue (rovecode export …) ----------
|
|
236
|
+
|
|
237
|
+
export interface ExportCliArgs { idOrPrefix?: string; json: boolean; out?: string; force: boolean }
|
|
238
|
+
|
|
239
|
+
/** Parse `rovecode export` argv. Flags may sit anywhere — parseCli accepts `rovecode --json
|
|
240
|
+
* export <id>` for every subcommand — so the whole argv after the script path is
|
|
241
|
+
* scanned and the single `export` command token skipped. parseCli strips flags but
|
|
242
|
+
* leaves flag VALUES in rest, so --out is consumed here (same reason main.ts hand-
|
|
243
|
+
* parses --resume: dispatch flags are boolean-only); a missing or flag-shaped --out
|
|
244
|
+
* value is a usage error, never a silent default. First remaining non-flag = the id. */
|
|
245
|
+
export function parseExportArgs(argv: readonly string[]): ExportCliArgs {
|
|
246
|
+
const args = argv.slice(2);
|
|
247
|
+
const parsed: ExportCliArgs = { json: false, force: false };
|
|
248
|
+
let cmdSeen = false;
|
|
249
|
+
for (let i = 0; i < args.length; i++) {
|
|
250
|
+
const a = args[i]!;
|
|
251
|
+
if (a === "--json") parsed.json = true;
|
|
252
|
+
else if (a === "--force") parsed.force = true;
|
|
253
|
+
else if (a === "--out") {
|
|
254
|
+
const v = args[++i];
|
|
255
|
+
if (v === undefined || v.startsWith("-")) throw new Error(`--out needs a path — ${USAGE}`);
|
|
256
|
+
parsed.out = v;
|
|
257
|
+
} else if (!a.startsWith("-")) { // other flags (--yolo, --plain, …) belong to dispatch
|
|
258
|
+
if (!cmdSeen && a === "export") cmdSeen = true; // the command token itself
|
|
259
|
+
else if (parsed.idOrPrefix === undefined) parsed.idOrPrefix = a;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return parsed;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** `rovecode export <session> [--json] [--out <path>] [--force]` — errors exit 1. */
|
|
266
|
+
export function cmdExport(argv: readonly string[]): void {
|
|
267
|
+
try {
|
|
268
|
+
const a = parseExportArgs(argv); // inside: a dangling --out is a usage error too
|
|
269
|
+
const res = exportSession(join(process.cwd(), ".rovecode", "sessions"), a.idOrPrefix ?? "", a);
|
|
270
|
+
console.log(`exported ${res.format} → ${res.path}`);
|
|
271
|
+
} catch (e) {
|
|
272
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
273
|
+
console.error(`error: ${msg}`);
|
|
274
|
+
// "you typed it wrong" and "it did not work" are different answers to a script: 2 is the usage class
|
|
275
|
+
// (README: 0 done · 1 error/budget · 2 usage/startup), and every other command already answers that way
|
|
276
|
+
process.exit(msg.startsWith("usage:") ? 2 : 1);
|
|
277
|
+
}
|
|
278
|
+
}
|
package/src/cli/help.ts
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/** `rovecode help [topic]` — short and grouped by default; `env`, `advanced` and `all` hold the full
|
|
2
|
+
* reference. Pure text so it is unit-testable (main.ts dispatches on import). Wording follows
|
|
3
|
+
* core/voice.ts: plain sentences, the two permission modes by their screen names. */
|
|
4
|
+
|
|
5
|
+
import { MODE_ASK, MODE_AUTO } from "../core/voice.ts";
|
|
6
|
+
|
|
7
|
+
export const HELP_TOPICS = ["", "env", "advanced", "all"] as const;
|
|
8
|
+
export type HelpTopic = (typeof HELP_TOPICS)[number];
|
|
9
|
+
|
|
10
|
+
const SHORT = `rovecode — your coding agent
|
|
11
|
+
|
|
12
|
+
start here
|
|
13
|
+
1 rovecode connect connect a model (about a minute)
|
|
14
|
+
2 rovecode open the cockpit and describe what you need
|
|
15
|
+
3 rovecode "fix the failing test" run one task, then exit
|
|
16
|
+
|
|
17
|
+
tip Start with a sentence. Rovecode reads first and asks before changing anything.
|
|
18
|
+
|
|
19
|
+
everyday
|
|
20
|
+
rovecode model choose a model
|
|
21
|
+
rovecode doctor diagnose setup problems
|
|
22
|
+
rovecode --resume <id> continue a session
|
|
23
|
+
rovecode run "<prompt>" --yolo run without approval prompts (${MODE_AUTO})
|
|
24
|
+
rovecode market search <q> find skills, plugins and MCP servers
|
|
25
|
+
|
|
26
|
+
safety
|
|
27
|
+
${MODE_ASK} (default) read freely; ask before writes, shell commands and subagents
|
|
28
|
+
accept edits (--accept-edits) write in this folder; still ask for shell, network and outside writes
|
|
29
|
+
auto (--yolo, ROVECODE_YOLO=1) never ask; deny rules still apply
|
|
30
|
+
plan mode (/plan in the TUI) inspect and plan without changing files
|
|
31
|
+
|
|
32
|
+
more
|
|
33
|
+
rovecode help advanced every command and option
|
|
34
|
+
rovecode help env every ROVECODE_* setting
|
|
35
|
+
rovecode help all both reference pages`;
|
|
36
|
+
|
|
37
|
+
const ADVANCED = `advanced — the full command reference
|
|
38
|
+
rovecode interactive TUI chat — the sextant surface (files · code · messages · plan · usage · pet)
|
|
39
|
+
on a colour TTY of at least 100x30 (truecolor, or 256 colours through the
|
|
40
|
+
quantizer), else the classic pi-tui chat;
|
|
41
|
+
--classic forces the classic chat · --pet <name> names the pet · --plain = readline REPL
|
|
42
|
+
--no-intro (or ROVECODE_INTRO=0) skips the ~0.9s opening animation
|
|
43
|
+
rovecode chat · rovecode repl the same as bare rovecode (repl still needs --plain for the readline REPL)
|
|
44
|
+
rovecode --help | -h this help (only with no command in front of it) · rovecode --version prints the
|
|
45
|
+
version to stdout and the update check’s answer to stderr
|
|
46
|
+
rovecode --resume <id> open the TUI resuming a session (full id or unique prefix)
|
|
47
|
+
rovecode --continue reopen the newest session that holds something (also: --resume with no id);
|
|
48
|
+
nothing to continue from → a fresh session
|
|
49
|
+
rovecode "prompt" one-shot task (same as run; a lone path-shaped word — ./x, x.ts, an existing
|
|
50
|
+
name — is confirmed on a TTY and refused with exit 2 off one: use "rovecode run" to send it)
|
|
51
|
+
rovecode setup connect a model step by step (TTY only; piped stdin prints the recipe and exits 2)
|
|
52
|
+
rovecode connect the same wizard when given no arguments
|
|
53
|
+
rovecode connect <id> [<baseUrl>] [--model <id>] [--key | --key-stdin | --key-env NAME | --no-key]
|
|
54
|
+
[--protocol openai|anthropic] [--project] [--no-test]
|
|
55
|
+
one line: register the endpoint, store the key, pick the model, one tiny real
|
|
56
|
+
call, persist the default. A key is never a flag value (shell history, ps):
|
|
57
|
+
--key prompts hidden, --key-stdin reads one piped line (CI), --key-env names
|
|
58
|
+
an env var, --no-key marks a local server.
|
|
59
|
+
exit 0 connected · 1 the test call failed (config still written) · 2 usage
|
|
60
|
+
rovecode smoke-tui render check: full pipeline into an 80x24 terminal emulator (dev-only)
|
|
61
|
+
rovecode smoke-tui --sextant render check: the sextant surface at 160x44 through the full pipeline (no emulator needed)
|
|
62
|
+
rovecode run "<prompt>" run an agent task (--yolo = ${MODE_AUTO}; with no provider configured this is a
|
|
63
|
+
startup error, exit 2 — ROVECODE_MOCK=1 asks for the scripted mock on purpose)
|
|
64
|
+
"/name args" expands a custom command (.rovecode/commands/<name>.md, else ~/.rovecode/commands)
|
|
65
|
+
the way the TUI does; an unknown /name is sent verbatim; model:/mode: frontmatter is
|
|
66
|
+
TUI-only and not applied headlessly
|
|
67
|
+
piped stdin is appended to the prompt as a fenced block — git diff | rovecode run "review this"
|
|
68
|
+
(never read from a terminal; --no-stdin ignores it; an open pipe that sends nothing
|
|
69
|
+
for 3 s is skipped with a note; capped at 1 MB)
|
|
70
|
+
--max-turns N · --max-seconds S|off ceilings on one run; a hit ends it cleanly with status
|
|
71
|
+
"budget" (exit 1) and the work so far, instead of an external kill. Headless runs
|
|
72
|
+
default to a 20-minute wall clock; --max-seconds off removes it
|
|
73
|
+
--max-cost D|off a spend ceiling in dollars for one run, priced from each turn's usage as it lands
|
|
74
|
+
(the catalog's rates for the model that served it); the same clean "budget" end.
|
|
75
|
+
A turn the catalog cannot price adds nothing and is counted in the summary
|
|
76
|
+
--output <text|json|ndjson> text (default): progress + the final answer on stdout
|
|
77
|
+
json: exactly ONE result object on stdout {status, summary, sessionId,
|
|
78
|
+
model:{provider,model}, origin (served model|null), usage:{input,output,cacheRead,
|
|
79
|
+
cacheWrite}, costUsd (null when unpriced), toolCalls:[{tool,ok,ms?}], durationMs, exitCode}
|
|
80
|
+
ndjson: one JSON line per RunEvent, then a final {type:"result"} line
|
|
81
|
+
json/ndjson: stdout carries only JSON, progress goes to stderr
|
|
82
|
+
exit codes: 0 done · 1 error/budget · 2 usage/startup error · 130 aborted (Ctrl-C)
|
|
83
|
+
exit 2 = usage/startup error (bad --output value, sandbox misconfig or unavailable rung):
|
|
84
|
+
one stderr line, nothing on stdout; --output=<mode> is accepted as well
|
|
85
|
+
rovecode bench run cross-harness micro-benchmarks (edits, sessions)
|
|
86
|
+
rovecode gauntlet run the adversarial evaluation suite (offline, scripted model)
|
|
87
|
+
rovecode gauntlet --live the gauntlet's tasks minus loop-guard (9) against the configured REAL model through
|
|
88
|
+
the real prompt — --model <provider/model> and --effort pick; compare pass/calls/tokens
|
|
89
|
+
rovecode tools list registered tools
|
|
90
|
+
rovecode plugin list plugins in ~/.rovecode/plugins and .rovecode/plugins with status (active · disabled · untrusted · broken)
|
|
91
|
+
rovecode plugin add <folder|git-url> [--project] [--force] install a plugin folder (tools, hooks, commands, skills, MCP in one manifest)
|
|
92
|
+
rovecode plugin trust <name> approve a PROJECT plugin's current files on this machine (show <name> lists them first)
|
|
93
|
+
rovecode plugin remove|enable|disable|untrust|show <name> (docs/plugins.md; restart to load — read once per process, like hooks)
|
|
94
|
+
rovecode mcp search [query] MCP servers to install: the curated shelf, then the official registry (cached a day)
|
|
95
|
+
rovecode mcp info <name> publisher, version, the exact command or URL, the keys it asks for
|
|
96
|
+
rovecode mcp add <name> [--project] [--pick N] [--as <name>] [--yes] [--force] show the plan, ask for keys
|
|
97
|
+
masked, write ~/.rovecode/mcp.json (or .rovecode/mcp.json); --as renames it, --force replaces an entry
|
|
98
|
+
rovecode mcp remove <name> [--project] · rovecode mcp list (docs/mcp-market.md; /mcp does the same inside the TUI)
|
|
99
|
+
rovecode mcp show this repo's .rovecode/mcp.json + .mcp.json: exact commands/URLs, env names, trusted or not
|
|
100
|
+
rovecode mcp trust [--yes] · rovecode mcp untrust approve those files as they are now, or withdraw that
|
|
101
|
+
approval — until trusted nothing in them loads; your own add --project is trusted as you approve it
|
|
102
|
+
rovecode market search [query] [--kind mcp|skill|plugin] one shelf over MCP servers, skills and plugins
|
|
103
|
+
rovecode market info <id> publisher, licence, version, exactly what an install would write
|
|
104
|
+
rovecode market docs <id> the item's own documentation, as the catalog carries it — no network
|
|
105
|
+
rovecode market install <id|kind:id|git-url|npm-pkg> [--project] [--ref <branch|tag|commit>] [--yes]
|
|
106
|
+
plan first, write only after you agree
|
|
107
|
+
rovecode market list|remove|update|sources what is installed, what is behind, where each shelf came from
|
|
108
|
+
rovecode market verify [id] re-hash what is installed and say what has changed since
|
|
109
|
+
rovecode market validate <path|url> [--kind skill|plugin] check a catalog before anyone trusts it
|
|
110
|
+
(docs/market.md; /market does the same inside the TUI; every subcommand takes --json)
|
|
111
|
+
rovecode doctor [--json] [--no-connect] one pass over the setup: home (and a legacy ~/.cumulus), the default
|
|
112
|
+
provider and where its key comes from (names, never values), the permission level and
|
|
113
|
+
which rung set it, git/node/npm/npx/uvx on PATH with what each absence costs HERE,
|
|
114
|
+
every configured MCP server (loads? skipped for a placeholder or an unset variable?
|
|
115
|
+
untrusted file? connects?), the shadow checkpoints' size — and a list of what it did
|
|
116
|
+
NOT check. exit 0 nothing broken · 1 something to fix · a missing provider is a note
|
|
117
|
+
rovecode context [session] [--json] what fills the window, item by item, and how far our estimate is from
|
|
118
|
+
the provider's own count of the same prompt (cache reads included — they are the prompt too)
|
|
119
|
+
(--exact asks Anthropic to count it for real; --no-runtime skips the system prompt and tool schemas)
|
|
120
|
+
rovecode auth set <provider> [--key <name>] store an API key (prompts on stdin; ~/.rovecode/credentials.json)
|
|
121
|
+
rovecode auth list stored providers + key names (values redacted)
|
|
122
|
+
rovecode auth remove <provider> delete a stored credential
|
|
123
|
+
rovecode login [--api <url>] link this machine to a rovecode account: prints a code to approve at
|
|
124
|
+
<url>/cli-auth, then stores the issued token in ~/.rovecode/account.json
|
|
125
|
+
(--token rc_live_… links a hand-pasted key instead; --json for scripts)
|
|
126
|
+
rovecode account [--json] the linked account, its API base and when it was linked
|
|
127
|
+
rovecode logout unlink: remove ~/.rovecode/account.json
|
|
128
|
+
rovecode provider list [--all] providers with a key + every providers.json entry, and the default provider/model
|
|
129
|
+
rovecode provider add <id> <baseUrl> [--protocol openai|anthropic] [--key-env NAME] [--model <id>] [--no-key]
|
|
130
|
+
[--project | --user | --scope user|project] [--key]
|
|
131
|
+
register any OpenAI-compatible or Anthropic endpoint in ~/.rovecode/providers.json
|
|
132
|
+
(--project: ./.rovecode/providers.json); --key prompts for the secret (never echoed);
|
|
133
|
+
running TUIs/servers pick the change up live — no restart
|
|
134
|
+
rovecode provider remove <id> delete a providers.json entry (built-ins: rovecode auth remove <id> drops the key)
|
|
135
|
+
rovecode provider test <id> [model] one tiny real call — proves url + key + model together
|
|
136
|
+
rovecode model list [provider] model ids (providers.json "models" or the endpoint's /models); * = current default
|
|
137
|
+
rovecode models [provider] alias for model list
|
|
138
|
+
rovecode model no arguments on a terminal: every configured provider's models in one
|
|
139
|
+
numbered menu, the current one first; a pipe gets the usage line instead
|
|
140
|
+
rovecode model use <provider/model> [--project] persist the default (in the TUI: /model <provider/model> --save)
|
|
141
|
+
rovecode model show [provider/model] the model, its protocol, and the exact thinking field each /effort
|
|
142
|
+
level puts on the wire (docs/thinking.md)
|
|
143
|
+
rovecode trace <session-id> the session's messages, one line each (role · first 120 chars · tool-call count)
|
|
144
|
+
rovecode export <session> write a session as markdown (--json: raw JSONL copy; --out <path>; --force)
|
|
145
|
+
rovecode eval alias for gauntlet
|
|
146
|
+
rovecode acp Agent Client Protocol v1 endpoint over stdio (Zed/JetBrains)
|
|
147
|
+
rovecode serve headless HTTP server (ROVECODE_PORT, default 4100; loopback-only)`;
|
|
148
|
+
|
|
149
|
+
const ENV = `env — every ROVECODE_* setting
|
|
150
|
+
ROVECODE_BASE_URL any OpenAI-compatible or Anthropic endpoint
|
|
151
|
+
ROVECODE_API_KEY API key (falls back to OPENAI_API_KEY)
|
|
152
|
+
ROVECODE_MODEL model id (e.g. zai-org/glm-5.3)
|
|
153
|
+
ROVECODE_MODEL_<ROLE> role fallback chain, comma-separated provider/model list; on 429/5xx
|
|
154
|
+
the next candidate serves. Roles: DEFAULT SMOL PLAN COMMIT TASK
|
|
155
|
+
(e.g. ROVECODE_MODEL_DEFAULT=kaesra/zai-org/glm-5.3-flash,openai/gpt-4o-mini)
|
|
156
|
+
ROVECODE_STREAM streaming is on by default (both protocols); off|json|0|false|none use the one-shot JSON
|
|
157
|
+
adapters; sse forces the raw SSE adapter, without the tool-call middleware, for one-shot runs
|
|
158
|
+
ROVECODE_EFFORT auto|off|low|medium|high thinking before the answer (default auto: the provider's
|
|
159
|
+
own default stands). Anthropic gets output_config.effort or a thinking budget,
|
|
160
|
+
whichever the model takes (learned from its own 400, then remembered); OpenAI gets
|
|
161
|
+
reasoning_effort. Thinking is billed as output and delays the first word.
|
|
162
|
+
ROVECODE_PROFILE model profile: off, or an id (glm-5.3 | glm-5.3-plain) whose PROMPT section is forced onto
|
|
163
|
+
every model (request fields always follow the model id). Unset = by model id: GLM-5.3 / -Flash
|
|
164
|
+
get the Claude Sonnet 5 persona + the working agreement appended to the system prompt
|
|
165
|
+
(glm-5.3-plain = agreement only) plus, on OpenAI-compatible providers, Z.ai's
|
|
166
|
+
request fields (thinking always on, reasoning_effort low|high|max — off leaves the endpoint's
|
|
167
|
+
max, medium rounds up to high, high means max — and tool_stream when streaming). The text
|
|
168
|
+
comes from .rovecode/profiles/<id>.md (project) or ~/.rovecode/profiles/<id>.md when present.
|
|
169
|
+
ROVECODE_DESIGN off drops the interface-design section from the system prompt (for runs with no UI in
|
|
170
|
+
them). Otherwise every run carries it: propose three distinct directions before the first
|
|
171
|
+
UI in a project, let the human choose, record it with design_direction, then build to it.
|
|
172
|
+
The section prescribes NO palette, typeface or layout -- there is no default look, on
|
|
173
|
+
purpose -- and names the patterns to climb out of (amber accents, the reflex full-viewport
|
|
174
|
+
hero, Inter/Roboto/Poppins, hairlines round everything, all-square corners, everything
|
|
175
|
+
centred, violet gradients). The choice lives in .rovecode/design.json; design_audit counts
|
|
176
|
+
those patterns in the files you touched and checks them against it.
|
|
177
|
+
ROVECODE_PERMISSION ask|accept-edits|auto — the level this run starts at. Ladder, widest first:
|
|
178
|
+
a CLI flag, then this, then <cwd>/.rovecode/settings.json, then ~/.rovecode/settings.json,
|
|
179
|
+
then "ask". Write the files with /yolo --save or /accept-edits --save [--project].
|
|
180
|
+
ROVECODE_ACCEPT_EDITS=1 start in accept-edits (writes inside the workspace do not ask)
|
|
181
|
+
ROVECODE_YOLO=1 ${MODE_AUTO}: allow all tool actions
|
|
182
|
+
ROVECODE_TUI sextant | classic — force the TUI surface (sextant still needs a TTY; --classic wins)
|
|
183
|
+
ROVECODE_THEME sextant palette: night (default) | ember | contrast (/theme switches it live)
|
|
184
|
+
ROVECODE_PET=0 hide the sextant pet panel (rovecode); --pet <name> renames it
|
|
185
|
+
ROVECODE_SANDBOX executor rung for bash: direct (default) | wsl | docker; beats .rovecode/sandbox.json {"rung","dockerImage"}
|
|
186
|
+
ROVECODE_SANDBOX_IMAGE image for the docker rung (default debian:stable-slim; must contain bash)
|
|
187
|
+
ROVECODE_RETRY_MAX same-model retries after a 429/5xx/transport failure (default 3 = 4 attempts; 0 = off)
|
|
188
|
+
The wait is announced live, while it is happening, not in a summary after the run
|
|
189
|
+
ROVECODE_RETRY_BASE_MS cap of the FIRST backoff, ms (default 1000; full jitter; a Retry-After hint is a floor)
|
|
190
|
+
It doubles per attempt up to 20 s, and a server hint can raise the wait, never shorten it
|
|
191
|
+
ROVECODE_FIRST_BYTE_TIMEOUT_MS how long a provider may go without ANY response before the request
|
|
192
|
+
counts as failed and is retried (default 60000). Only the FIRST byte is on this clock:
|
|
193
|
+
once the model is talking, the body may take as long as it takes
|
|
194
|
+
ROVECODE_WEBFETCH_TIMEOUT_MS web_fetch request timeout in ms (default 30000)
|
|
195
|
+
ROVECODE_WEBFETCH_ALLOW_PRIVATE=1 let web_fetch reach loopback/private hosts (SSRF guard escape for local dev)
|
|
196
|
+
ROVECODE_COMPACTION history compaction strategy: head-summarize (default) | keep-window | provider-native
|
|
197
|
+
ROVECODE_TASKS_MAX concurrent background tasks (default 3; further task starts queue FIFO)
|
|
198
|
+
ROVECODE_OTEL_ENDPOINT OTLP/HTTP collector, e.g. http://host:4318 — one trace per run (run ⊃ turn ⊃ tool); unset = off
|
|
199
|
+
ROVECODE_OTEL_HEADERS extra OTLP headers as k=v,k2=v2 (e.g. authorization=Bearer …)
|
|
200
|
+
ROVECODE_REFLECTION=0 disable reflection nudges after failed edits; ROVECODE_REFLECTION_MAX caps them per run (default 2)
|
|
201
|
+
ROVECODE_PORT port for rovecode serve (default 4100; loopback-only)
|
|
202
|
+
ROVECODE_IMAGE_MAX_BYTES per-image cap in bytes for pasted and attached images (default 5 MB;
|
|
203
|
+
at most 8 images per message). Over it, the image is refused by name, not silently dropped.
|
|
204
|
+
ROVECODE_REPOMAP_TOKENS repo-map budget in tokens (default 1024); ROVECODE_NO_REPOMAP=1 drops the map entirely
|
|
205
|
+
ROVECODE_HOOK_TIMEOUT_MS per-hook-call budget in ms (default 5000); ROVECODE_NO_HOOKS=1 skips hook files
|
|
206
|
+
ROVECODE_PLUGIN_TIMEOUT_MS per-plugin import + tools() budget in ms (default 5000);
|
|
207
|
+
ROVECODE_NO_PLUGINS=1 skips plugin discovery
|
|
208
|
+
ROVECODE_NO_CHECKPOINTS=1 turn off the shadow-git checkpoints taken after mutating tools
|
|
209
|
+
ROVECODE_TOOL_MIDDLEWARE=1 force the text tool-call protocol (a prompt block + a parser) even for a model
|
|
210
|
+
the catalog says has native tool calling; ROVECODE_NO_TOOL_MIDDLEWARE=1 forces native only
|
|
211
|
+
ROVECODE_EVAL_CELL=1 register the persistent eval cell tool (a REPL that keeps state between calls)
|
|
212
|
+
ROVECODE_MAX_TURNS turn ceiling for one run, every surface (TUI included); a hit ends it with status
|
|
213
|
+
"budget" and exit 1
|
|
214
|
+
ROVECODE_MAX_SECONDS the same as a wall clock, or "off". Every surface honours it, but only
|
|
215
|
+
one-shot runs have a DEFAULT (1200 s) — the TUI has no clock unless this sets one
|
|
216
|
+
ROVECODE_MAX_COST the same in dollars for one run (--max-cost on a one-shot run), or "off"; no default
|
|
217
|
+
ROVECODE_FINISH_CHECK=0 turn off the once-per-run finish check: when the model stops right after a failed tool
|
|
218
|
+
call or an unanswered question, it is asked ONCE to finish or say what is left; the next
|
|
219
|
+
reply ends the run either way. "done · …" on run_end still names what was left
|
|
220
|
+
ROVECODE_VERIFY=1 turn ON the verify gate (off by default): a run that wrote files runs the project's configured
|
|
221
|
+
check before "done"; a failure goes back to the model once, then "done · check failed (…)" says
|
|
222
|
+
so. No check configured → nothing runs, run_end says "not verified". ROVECODE_VERIFY_TIMEOUT=<s> (120)
|
|
223
|
+
ROVECODE_HOME credentials + user-scope providers/commands dir (default ~/.rovecode)
|
|
224
|
+
providers: built in — kaesra openai anthropic deepseek groq openrouter ollama lmstudio
|
|
225
|
+
together mistral cerebras fireworks perplexity xai moondream vllm
|
|
226
|
+
plus anything in ~/.rovecode/providers.json or ./.rovecode/providers.json (rovecode provider add)
|
|
227
|
+
key: rovecode auth set <id>, or set <ID>_API_KEY — stored creds beat env;
|
|
228
|
+
default: providers.json "default" ("provider/model"), ROVECODE_MODEL overrides the model,
|
|
229
|
+
ROVECODE_BASE_URL/ROVECODE_API_KEY always wins`;
|
|
230
|
+
|
|
231
|
+
/** the text for a topic; an unknown topic gets the short page plus a one-line note */
|
|
232
|
+
export function helpText(topic = ""): string {
|
|
233
|
+
switch (topic) {
|
|
234
|
+
case "": return SHORT;
|
|
235
|
+
case "env": return ENV;
|
|
236
|
+
case "advanced": return ADVANCED;
|
|
237
|
+
case "all": return `${SHORT}\n\n${ADVANCED}\n\n${ENV}`;
|
|
238
|
+
default: return `${SHORT}\n\nno help topic "${topic}" — topics: env · advanced · all`;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Returns true when argv will start the interactive TUI (as opposed to a lightweight subcommand).
|
|
2
|
+
* Used by bin/rovecode.ts to decide whether to route through the pre-bundled dist/cli/main.js. */
|
|
3
|
+
import { parseCli } from "./dispatch.ts";
|
|
4
|
+
|
|
5
|
+
export function isTuiInvocation(argv: string[]): boolean {
|
|
6
|
+
const { cmd, plain } = parseCli(argv);
|
|
7
|
+
return (cmd === "" || cmd === "chat" || cmd === "repl") && !plain;
|
|
8
|
+
}
|