rovecode 0.3.3 → 0.4.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +512 -0
- package/README.md +33 -48
- package/bin/rovecode.js +24 -0
- package/dist/cli/app-dybnr56b.js +2 -0
- package/dist/cli/ask-user-p8hq4xgj.js +2 -0
- package/dist/cli/auth-login-ewpgw5sm.js +2 -0
- package/dist/cli/auth-m8p9grty.js +2 -0
- package/dist/cli/bench-xv3ypwev.js +9 -0
- package/dist/cli/catalog-737wb2s0.js +2 -0
- package/dist/cli/cli-arhg40m0.js +2 -0
- package/dist/cli/client-cf2pxx8q.js +2 -0
- package/dist/cli/commands-3p7e4xxs.js +2 -0
- package/dist/cli/connect-3q93d7cb.js +2 -0
- package/dist/cli/context-cmd-eqxmxhzq.js +2 -0
- package/dist/cli/context-report-hbw9zfes.js +2 -0
- package/dist/cli/count-remote-mby98cd0.js +2 -0
- package/dist/cli/design-122y0axd.js +2 -0
- package/dist/cli/dispatch-b4egzvvh.js +2 -0
- package/dist/cli/doctor-x4jkv72e.js +3 -0
- package/dist/cli/executor-ftvg6tsy.js +2 -0
- package/dist/cli/export-pdgdhkch.js +2 -0
- package/dist/cli/files-cez9a96p.js +2 -0
- package/dist/cli/gauntlet-r3xxaszc.js +2 -0
- package/dist/cli/gauntlet-runner-r515m7kk.js +10 -0
- package/dist/cli/gauntlet-wave3-bnkjk2v2.js +5 -0
- package/dist/cli/gauntlet-wave4-acs9s60q.js +14 -0
- package/dist/cli/hashline-ewg5hbe3.js +2 -0
- package/dist/cli/http-n0kehsk8.js +5 -0
- package/dist/cli/index-z5qt1s76.js +2 -0
- package/dist/cli/install-80mp63kx.js +2 -0
- package/dist/cli/loop-12twjcat.js +2 -0
- package/dist/cli/main-01pv9206.js +4 -0
- package/dist/cli/main-0jys2ccn.js +3 -0
- package/dist/cli/main-1ztz6fkj.js +10 -0
- package/dist/cli/main-23q7cmww.js +9 -0
- package/dist/cli/main-2rzbexn2.js +3 -0
- package/dist/cli/main-2wyax8k9.js +9 -0
- package/dist/cli/main-2yeveeve.js +6 -0
- package/dist/cli/main-2z3dek0b.js +3 -0
- package/dist/cli/main-2zgsknth.js +3 -0
- package/dist/cli/main-45ejth3a.js +4 -0
- package/dist/cli/main-45rn3trk.js +22 -0
- package/dist/cli/main-4p4e2w7x.js +4 -0
- package/dist/cli/main-4y0tnfpa.js +16 -0
- package/dist/cli/main-5py0rkmc.js +4 -0
- package/dist/cli/main-6dtqmbt6.js +7 -0
- package/dist/cli/main-6h9x282m.js +4 -0
- package/dist/cli/main-6vjeds42.js +3 -0
- package/dist/cli/main-78gq4bt9.js +6 -0
- package/dist/cli/main-7jd5vh3x.js +4 -0
- package/dist/cli/main-7kt6r53y.js +4 -0
- package/dist/cli/main-8c1tbazx.js +58 -0
- package/dist/cli/main-9a9rnh47.js +19 -0
- package/dist/cli/main-9ht36z12.js +3 -0
- package/dist/cli/main-a2yfvcy9.js +7 -0
- package/dist/cli/main-a3f51n0x.js +5 -0
- package/dist/cli/main-b8zq261k.js +3 -0
- package/dist/cli/main-bxtvnf6d.js +13 -0
- package/dist/cli/main-edxc3yzt.js +4 -0
- package/dist/cli/main-evgz4mp5.js +21 -0
- package/dist/cli/main-f33fc5je.js +9 -0
- package/dist/cli/main-fvnpq46y.js +12 -0
- package/dist/cli/main-gbbty4d4.js +3 -0
- package/dist/cli/main-gth53dnt.js +25 -0
- package/dist/cli/main-hqbz10aw.js +9 -0
- package/dist/cli/main-hrrvcfan.js +38 -0
- package/dist/cli/main-hzwtsb2m.js +5 -0
- package/dist/cli/main-j7ttv0sd.js +34 -0
- package/dist/cli/main-jak598k9.js +5 -0
- package/dist/cli/main-kba6zeyd.js +6 -0
- package/dist/cli/main-kwwsz6rq.js +3 -0
- package/dist/cli/main-m8vm17zq.js +3 -0
- package/dist/cli/main-mg4f96e1.js +3 -0
- package/dist/cli/main-mg9b20ac.js +18 -0
- package/dist/cli/main-mgb9ccnx.js +3 -0
- package/dist/cli/main-mjt2p7aj.js +3 -0
- package/dist/cli/main-n6qrdbmy.js +3 -0
- package/dist/cli/main-na7wse0x.js +5 -0
- package/dist/cli/main-nqveez48.js +4 -0
- package/dist/cli/main-ntqef02r.js +10 -0
- package/dist/cli/main-nvc3yjay.js +136 -0
- package/dist/cli/main-p0cfn6nr.js +16 -0
- package/dist/cli/main-qj2djy17.js +19 -0
- package/dist/cli/main-qsevpgsv.js +3 -0
- package/dist/cli/main-qvarybsp.js +3 -0
- package/dist/cli/main-rebtt91r.js +5 -0
- package/dist/cli/main-rpg7h8mb.js +3 -0
- package/dist/cli/main-rsy72qmw.js +15 -0
- package/dist/cli/main-rvetps99.js +18 -0
- package/dist/cli/main-s4bb0jav.js +3 -0
- package/dist/cli/main-s9v8k74e.js +3 -0
- package/dist/cli/main-tjvwmscs.js +3 -0
- package/dist/cli/main-tkgarpjj.js +4 -0
- package/dist/cli/main-v8y60bb2.js +3 -0
- package/dist/cli/main-vhrrq337.js +3 -0
- package/dist/cli/main-vp2dfb7s.js +4 -0
- package/dist/cli/main-vqbr22sz.js +8 -0
- package/dist/cli/main-vxnwe5xx.js +18 -0
- package/dist/cli/main-wgph00xf.js +5 -0
- package/dist/cli/main-wk2csfnj.js +5 -0
- package/dist/cli/main-wm997zjx.js +3 -0
- package/dist/cli/main-wpkyraxh.js +3 -0
- package/dist/cli/main-wqt32p5x.js +4 -0
- package/dist/cli/main-x9ct6y1a.js +3 -0
- package/dist/cli/main-xfekqh9m.js +7 -0
- package/dist/cli/main-xt9zc3n6.js +7 -0
- package/dist/cli/main-xx2z3zh5.js +4 -0
- package/dist/cli/main-y5c82rxr.js +3 -0
- package/dist/cli/main-yrjt2sqt.js +14 -0
- package/dist/cli/main-ys6zj3yr.js +3 -0
- package/dist/cli/main-ywbxshqc.js +8 -0
- package/dist/cli/main-z13755t8.js +25 -0
- package/dist/cli/main-zc7pyrbj.js +4 -0
- package/dist/cli/main.js +279 -0
- package/dist/cli/market-cmd-bm5xvn9f.js +5 -0
- package/dist/cli/mcp-login-bthtfpt7.js +2 -0
- package/dist/cli/mcp-market-cmd-mbeshfyd.js +2 -0
- package/dist/cli/notify-54v5z9dz.js +2 -0
- package/dist/cli/oauth-g5gme95c.js +2 -0
- package/dist/cli/output-satndjap.js +16 -0
- package/dist/cli/profiles-sfhpbq3m.js +2 -0
- package/dist/cli/provider-config-hv3xtdt4.js +2 -0
- package/dist/cli/provider-kwzq6g84.js +2 -0
- package/dist/cli/registry-fh0hdnyn.js +2 -0
- package/dist/cli/registry-y1y8e94r.js +2 -0
- package/dist/cli/repl-t4z03mqq.js +11 -0
- package/dist/cli/resume-fqt4chg8.js +2 -0
- package/dist/cli/run-flags-rysbag9t.js +2 -0
- package/dist/cli/runtime-j19fjbsa.js +2 -0
- package/dist/cli/sandbox-config-g4qxd7y5.js +2 -0
- package/dist/cli/server-r0b6bksk.js +5 -0
- package/dist/cli/session-arg-txmn5g4x.js +2 -0
- package/dist/cli/session-ed250d9j.js +2 -0
- package/dist/cli/sessions-cmd-adw7svfn.js +7 -0
- package/dist/cli/settings-y9rzcqx8.js +2 -0
- package/dist/cli/setup-jmbr11j0.js +2 -0
- package/dist/cli/sextant-smoke-tcth0vea.js +5 -0
- package/dist/cli/skills-cmd-zbdy99v6.js +2 -0
- package/dist/cli/smoke-1bg937kx.js +8 -0
- package/dist/cli/start-chat-p01cdks3.js +12 -0
- package/dist/cli/stream-4wmyaypz.js +2 -0
- package/dist/cli/task-eg4s093s.js +2 -0
- package/dist/cli/tasks-12v9rr9k.js +2 -0
- package/dist/cli/thinking-a5ngvqyh.js +2 -0
- package/dist/cli/todo-1wxpcecx.js +2 -0
- package/dist/cli/tools-2ftsya7w.js +2 -0
- package/dist/cli/tools-x1tj4fxm.js +2 -0
- package/dist/cli/trust-cmd-hccxehzb.js +2 -0
- package/dist/cli/update-check-ygt3vd7m.js +2 -0
- package/dist/cli/update-cmd-v23qhr8c.js +2 -0
- package/dist/cli/voice-g1gtck92.js +2 -0
- package/dist/cli/webfetch-0nnrjgb5.js +2 -0
- package/dist/cli/websearch-f0vr2p7d.js +2 -0
- package/dist/cli/workspace-9rq1w4ta.js +2 -0
- package/dist/lib/index.js +62 -0
- package/dist/lib/models-index.json +1 -0
- package/dist/lib/plugins.js +6 -0
- package/dist/lib/providers.js +17 -0
- package/dist/lib/public-api.js +20 -0
- package/dist/rovecode.exe +4 -0
- package/package.json +83 -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/tui/session-cmd.ts
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
/** TUI session navigation (port #2 session tree), extracted from app.ts for the ADR-002
|
|
2
|
-
* cap: /sessions + /resume pick or resolve a session to switch to, /rewind (alias /tree)
|
|
3
|
-
* jumps to an earlier turn for edit-and-resubmit, /new branches back to the session
|
|
4
|
-
* start. The CALLER owns the swappable store and the rebind routine (switchSession), so
|
|
5
|
-
* store reads and switches run through the injected ctx — same shape as checkpoints-cmd.
|
|
6
|
-
* Also home to the pure session helpers the app calls around a switch: transcript replay,
|
|
7
|
-
* usage recount, and the `--resume <prefix>` boot resolution (wiring pass, ADR-002 cap). */
|
|
8
|
-
|
|
9
|
-
import { partsText } from "../core/loop.ts";
|
|
10
|
-
import { listSessions, type SessionStore } from "../core/session.ts";
|
|
11
|
-
import { ambiguityMessage, matchSessions } from "../core/session-ops.ts";
|
|
12
|
-
import { userTurnLine } from "./attach.ts";
|
|
13
|
-
import { replayLabel } from "./modes-cmd.ts";
|
|
14
|
-
import { replayMarkerLine } from "./replay-marker.ts";
|
|
15
|
-
import { replayShellRecord } from "./shell-cmd.ts";
|
|
16
|
-
import type { Renderer } from "./renderer.ts";
|
|
17
|
-
import { randomUUID } from "node:crypto";
|
|
18
|
-
|
|
19
|
-
/** Re-render the whole transcript from the active session path (boot replay, /resume, /rewind,
|
|
20
|
-
* /new, checkpoint restores). Tool calls replay as start+end card pairs; mode switches render
|
|
21
|
-
* as a human line (port #20 LOW-3), never the raw <mode_notice> XML the entry carries; user
|
|
22
|
-
* turns carry their image chips (port #34), so an image-only turn is not a blank line; persisted
|
|
23
|
-
* compaction events replay as the live run's note (port #25 LOW-4, replay-marker.ts). */
|
|
24
|
-
export function replayTranscript(renderer: Renderer, store: SessionStore): void {
|
|
25
|
-
renderer.clearTranscript();
|
|
26
|
-
for (const m of store.path()) {
|
|
27
|
-
if (!("role" in m)) { const line = replayMarkerLine(m); if (line !== null) renderer.addSystemNote(line); continue; } // event entry (appendEvent): marker or nothing
|
|
28
|
-
const text = partsText(m.parts);
|
|
29
|
-
// a `!cmd` record is a user message in the store, but it replays as the typed line plus its bash card pair
|
|
30
|
-
// (tui/shell-cmd.ts) rather than as the raw <user_shell_command> block the model reads
|
|
31
|
-
if (m.role === "user" && replayShellRecord(renderer, text)) continue;
|
|
32
|
-
if (m.role === "user") { const line = userTurnLine(text, m.parts); if (line) renderer.addUser(line); }
|
|
33
|
-
else if (m.role === "assistant") {
|
|
34
|
-
if (text) { const v = renderer.beginAssistant(); v.append(text); v.done(); }
|
|
35
|
-
for (const p of m.parts) {
|
|
36
|
-
if (p.kind === "tool_call") renderer.toolStart(p.id, p.tool, JSON.stringify(p.args).slice(0, 120));
|
|
37
|
-
}
|
|
38
|
-
} else if (m.role === "tool") {
|
|
39
|
-
for (const p of m.parts) {
|
|
40
|
-
if (p.kind === "tool_result") renderer.toolEnd(p.callId, p.ok, p.output.slice(0, 160).replace(/\n/g, " ⏎ "), 0);
|
|
41
|
-
}
|
|
42
|
-
} else if (m.role === "system" && text) renderer.addSystemNote(replayLabel(m, text));
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Token usage summed over the active path — the status line's counters. */
|
|
47
|
-
export function usageOf(store: SessionStore): { tokensIn: number; tokensOut: number } {
|
|
48
|
-
let tokensIn = 0, tokensOut = 0;
|
|
49
|
-
for (const m of store.messages()) { tokensIn += m.usage?.input ?? 0; tokensOut += m.usage?.output ?? 0; }
|
|
50
|
-
return { tokensIn, tokensOut };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** The in-TUI /resume rule (matchSessions, core/session-ops.ts — the same one `--resume`, `trace`, `export` and the
|
|
54
|
-
* `sessions` verbs use): a unique match resolves, an AMBIGUOUS prefix must not silently pick one — start fresh (id
|
|
55
|
-
* undefined) and say so in `warn`. The CLI's `--resume <id>` no longer comes through here: cli/resume.ts refuses an
|
|
56
|
-
* unknown or ambiguous id before the TUI boots (2026-09-07). */
|
|
57
|
-
export function resolveBootSession(sessionsDir: string, id: string | undefined): { id: string | undefined; warn?: string } {
|
|
58
|
-
if (id === undefined) return { id };
|
|
59
|
-
const pre = matchSessions(listSessions(sessionsDir, { includeHollow: true }), id);
|
|
60
|
-
if (pre.length === 1) return { id: pre[0]!.id };
|
|
61
|
-
if (pre.length > 1) return { id: undefined, warn: `"${id}" matches ${pre.length} sessions — started fresh; use /resume to pick one` };
|
|
62
|
-
return { id };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface SessionCmdCtx {
|
|
66
|
-
renderer: Renderer;
|
|
67
|
-
/** the run's cwd — `/sessions delete` removes the session's checkpoints shadow dir under it (session-manage.ts) */
|
|
68
|
-
cwd: string;
|
|
69
|
-
/** <cwd>/.rovecode/sessions — where listSessions looks */
|
|
70
|
-
sessionsDir: string;
|
|
71
|
-
busy(): boolean;
|
|
72
|
-
/** the ACTIVE session store, read live: /sessions and a root /rewind swap it */
|
|
73
|
-
store(): SessionStore;
|
|
74
|
-
/** rebind the app to session id (store, memory, mode) and replay it; announce defaults on */
|
|
75
|
-
switchSession(id: string, announce?: boolean): void;
|
|
76
|
-
/** re-render the whole transcript from the active session path */
|
|
77
|
-
replayHistory(): void;
|
|
78
|
-
/** recount token usage from the active store */
|
|
79
|
-
refreshUsage(): void;
|
|
80
|
-
pushStatus(): void;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** /rewind (alias /tree) — pick an earlier turn in the overlay; Enter branches the session
|
|
84
|
-
* to before that turn and prefills the editor with its FULL text for edit-and-resubmit. */
|
|
85
|
-
export async function cmdRewind(ctx: SessionCmdCtx): Promise<void> {
|
|
86
|
-
if (ctx.busy()) { ctx.renderer.addSystemNote("finish or interrupt the run first (Esc)", "warn"); return; }
|
|
87
|
-
const points = ctx.store().turnPoints();
|
|
88
|
-
if (points.length === 0) { ctx.renderer.addSystemNote("nothing to rewind — no turns yet"); return; }
|
|
89
|
-
const items = [...points].reverse().map((p) => ({
|
|
90
|
-
value: p.entryId,
|
|
91
|
-
label: `#${p.index} ${p.text}`,
|
|
92
|
-
description: p.branches > 0 ? `◆ ${p.branches} other branch${p.branches > 1 ? "es" : ""}` : undefined,
|
|
93
|
-
}));
|
|
94
|
-
const picked = await ctx.renderer.pickOne(items, "rewind to a turn (Enter = edit & resubmit, Esc = cancel)");
|
|
95
|
-
if (!picked) { ctx.replayHistory(); return; } // cancel: clear the overlay title note
|
|
96
|
-
const point = points.find((p) => p.entryId === picked);
|
|
97
|
-
if (!point) return;
|
|
98
|
-
if (point.parentId === null) {
|
|
99
|
-
// pi resets the leaf to an empty conversation (sessions.md:116); root reset would need
|
|
100
|
-
// core support — v1 approximates it with a fresh session, old one untouched
|
|
101
|
-
ctx.switchSession(randomUUID(), false);
|
|
102
|
-
ctx.renderer.addSystemNote("rewound to the start — fresh session, previous one kept");
|
|
103
|
-
} else {
|
|
104
|
-
if (!ctx.store().branch(point.parentId)) { ctx.renderer.addSystemNote("rewind failed: turn not found", "error"); return; }
|
|
105
|
-
ctx.replayHistory();
|
|
106
|
-
ctx.renderer.addSystemNote(`rewound to before turn #${point.index} — edit and resubmit (branch kept)`);
|
|
107
|
-
}
|
|
108
|
-
ctx.renderer.prefillEditor(point.fullText); // FULL text, never the ≤80-char overlay label
|
|
109
|
-
ctx.pushStatus();
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/** /sessions — pick a previous session in the overlay; /resume <id> resolves an exact id
|
|
113
|
-
* or a UNIQUE prefix directly (an ambiguous prefix must not silently pick one). */
|
|
114
|
-
export async function cmdSessions(ctx: SessionCmdCtx, directId?: string): Promise<void> {
|
|
115
|
-
if (ctx.busy()) { ctx.renderer.addSystemNote("finish or interrupt the run first (Esc)", "warn"); return; }
|
|
116
|
-
const all = listSessions(ctx.sessionsDir); // the picker: sessions that hold something (hollow dirs stay out of the list)
|
|
117
|
-
if (directId) {
|
|
118
|
-
// the ONE matching rule (core/session-ops.ts): exact id wins outright; a prefix must match exactly ONE session
|
|
119
|
-
// — resolving an ambiguous prefix silently to the first hit resumed the wrong session
|
|
120
|
-
const matches = matchSessions(listSessions(ctx.sessionsDir, { includeHollow: true }), directId);
|
|
121
|
-
if (matches.length === 1) ctx.switchSession(matches[0]!.id);
|
|
122
|
-
else if (matches.length > 1) ctx.renderer.addSystemNote(ambiguityMessage(directId, matches), "warn");
|
|
123
|
-
else ctx.renderer.addSystemNote(`no session matching "${directId}"`, "warn");
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const items = all.slice(0, 20).map((s) => ({
|
|
127
|
-
value: s.id,
|
|
128
|
-
label: s.title ?? (s.preview || "(empty session)"), // a title stands in for the first prompt, as `rovecode sessions list` does (cli/sessions-cmd.ts) — otherwise /sessions rename is invisible where you resume
|
|
129
|
-
description: `${new Date(s.updatedAt).toLocaleString()} · ${s.entryCount} entries · ${s.id.slice(0, 8)}${s.id === ctx.store().id ? " · current" : ""}`,
|
|
130
|
-
}));
|
|
131
|
-
if (items.length === 0) { ctx.renderer.addSystemNote("no sessions found"); return; }
|
|
132
|
-
const picked = await ctx.renderer.pickOne(items, "resume a session (Esc = cancel)");
|
|
133
|
-
if (picked && picked !== ctx.store().id) ctx.switchSession(picked);
|
|
134
|
-
else if (!picked) ctx.replayHistory(); // cancel: clear the overlay title note
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/** /new — branch the leaf back to the session's first entry; the old turns stay in the
|
|
138
|
-
* tree. Synchronous on purpose: no overlay, nothing to await. */
|
|
139
|
-
export function cmdNew(ctx: SessionCmdCtx): void {
|
|
140
|
-
// busy gate (same as /rewind //sessions): moving the leaf mid-run would make the
|
|
141
|
-
// run's next append chain off a moved leaf while its parentId points elsewhere
|
|
142
|
-
if (ctx.busy()) { ctx.renderer.addSystemNote("finish or interrupt the run first (Esc)", "warn"); return; }
|
|
143
|
-
const store = ctx.store();
|
|
144
|
-
if (store.branch(store.messages()[0]?.id ?? "")) {
|
|
145
|
-
ctx.replayHistory(); ctx.refreshUsage(); ctx.pushStatus();
|
|
146
|
-
ctx.renderer.addSystemNote("branched to session start");
|
|
147
|
-
} else ctx.renderer.addSystemNote("nothing to branch — no turns yet");
|
|
148
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/** TUI `/sessions <verb>` (aion port #84): rename · delete · fork · search over core/session-ops.ts — the same ops as
|
|
2
|
-
* the headless `rovecode sessions …` (cli/sessions-cmd.ts, 5ceb21e), through the SessionCmdCtx seam app.ts already hands
|
|
3
|
-
* the session navigator (session-cmd.ts), so the classic and sextant surfaces share it via app.ts handleSlash. Rules:
|
|
4
|
-
* - every verb sits behind the /rewind busy gate (moving or removing session state mid-run is refused);
|
|
5
|
-
* - `rename <title…>` titles the CURRENT session through the LIVE store instance (`ctx.store().patchMeta`) — a second
|
|
6
|
-
* SessionStore on the same dir would be clobbered by this instance's next persistLeaf (/new, /rewind);
|
|
7
|
-
* - `delete <id|prefix>` resolves first, shows ONE askApproval card (deny → nothing removed); deleting the ACTIVE
|
|
8
|
-
* session switches the app to a fresh session first (the root-rewind pattern of session-cmd.ts cmdRewind) so no
|
|
9
|
-
* live store points at a removed dir; then session-ops.deleteSession removes the dir AND its checkpoints shadow
|
|
10
|
-
* repo — a half-delete leaves the space used with nothing pointing at it, so the test pins the shadow dir too;
|
|
11
|
-
* - `fork [<id|prefix>]` (default: the current session) forks and switches to the fork (announced, transcript replayed);
|
|
12
|
-
* - `search <terms…>` opens pickOne over the hits (label = preview, description = title · id8 · time); Enter switches
|
|
13
|
-
* to the hit's session, Esc replays the current transcript (the /sessions picker's cancel rule).
|
|
14
|
-
* Bare `/sessions` stays the picker (cmdSessions). `--plain` has none of this (README honesty). Pattern sources: see
|
|
15
|
-
* core/session-ops.ts (opencode MIT session.ts fork / remove / setTitle; codex Apache-2.0 DeleteConfirmation, pattern only). */
|
|
16
|
-
|
|
17
|
-
import { randomUUID } from "node:crypto";
|
|
18
|
-
import { deleteSession, forkSession, oneLineTitle, resolveSession, searchSessions } from "../core/session-ops.ts";
|
|
19
|
-
import { cmdSessions, type SessionCmdCtx } from "./session-cmd.ts";
|
|
20
|
-
|
|
21
|
-
const BUSY = "finish or interrupt the run first (Esc)";
|
|
22
|
-
const USAGE = "/sessions rename <title…> | delete <id|prefix> | fork [<id|prefix>] | search <terms…>";
|
|
23
|
-
|
|
24
|
-
/** app.ts `case "sessions"`: `arg` is the collapsed remainder after `/sessions` */
|
|
25
|
-
export async function cmdSessionsVerb(ctx: SessionCmdCtx, arg: string): Promise<void> {
|
|
26
|
-
const [verb, ...rest] = arg.split(/\s+/).filter(Boolean);
|
|
27
|
-
if (verb === undefined) return cmdSessions(ctx); // bare /sessions: the picker, unchanged (it carries its own busy gate)
|
|
28
|
-
if (ctx.busy()) { ctx.renderer.addSystemNote(BUSY, "warn"); return; }
|
|
29
|
-
switch (verb) {
|
|
30
|
-
case "rename": return rename(ctx, rest.join(" "));
|
|
31
|
-
case "delete": return remove(ctx, rest[0]);
|
|
32
|
-
case "fork": return fork(ctx, rest[0]);
|
|
33
|
-
case "search": return search(ctx, rest.join(" "));
|
|
34
|
-
default: ctx.renderer.addSystemNote(`unknown /sessions verb "${verb}" — ${USAGE}`, "warn");
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function rename(ctx: SessionCmdCtx, raw: string): void {
|
|
39
|
-
const title = oneLineTitle(raw);
|
|
40
|
-
if (title === undefined) { ctx.renderer.addSystemNote("usage: /sessions rename <title…>", "warn"); return; }
|
|
41
|
-
const store = ctx.store(); // the LIVE instance — its later persistLeaf carries the title forward
|
|
42
|
-
store.patchMeta({ title });
|
|
43
|
-
ctx.renderer.addSystemNote(`session ${store.id.slice(0, 8)} titled "${title}"`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async function remove(ctx: SessionCmdCtx, ref: string | undefined): Promise<void> {
|
|
47
|
-
if (ref === undefined) { ctx.renderer.addSystemNote("usage: /sessions delete <id|prefix>", "warn"); return; }
|
|
48
|
-
const found = resolveSession(ctx.sessionsDir, ref);
|
|
49
|
-
if (!found.ok) { ctx.renderer.addSystemNote(found.error, "warn"); return; }
|
|
50
|
-
const s = found.summary;
|
|
51
|
-
const active = found.id === ctx.store().id;
|
|
52
|
-
const label = s.title ?? (s.preview || "(empty session)");
|
|
53
|
-
const answer = await ctx.renderer.askApproval(
|
|
54
|
-
"sessions delete",
|
|
55
|
-
`${s.id.slice(0, 8)} · ${label} · ${s.entryCount} entries${active ? " · the current session" : ""}`,
|
|
56
|
-
"removes the session directory (entries, meta, attachments, todos) and its checkpoints shadow repo — not undoable",
|
|
57
|
-
);
|
|
58
|
-
if (answer === "deny") { ctx.renderer.addSystemNote("delete cancelled — nothing removed", "warn"); return; }
|
|
59
|
-
if (active) {
|
|
60
|
-
// the root-rewind pattern (session-cmd.ts cmdRewind): the app moves to a fresh session BEFORE the old dir goes
|
|
61
|
-
ctx.switchSession(randomUUID(), false);
|
|
62
|
-
ctx.renderer.addSystemNote("deleting the active session — switched to a fresh one first");
|
|
63
|
-
}
|
|
64
|
-
const { removed } = deleteSession(ctx.cwd, ctx.sessionsDir, found.id);
|
|
65
|
-
ctx.renderer.addSystemNote(`deleted session ${found.id.slice(0, 8)} (${removed.length} path${removed.length === 1 ? "" : "s"} removed)`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function fork(ctx: SessionCmdCtx, ref: string | undefined): void {
|
|
69
|
-
const found = resolveSession(ctx.sessionsDir, ref ?? ctx.store().id);
|
|
70
|
-
if (!found.ok) { ctx.renderer.addSystemNote(found.error, "warn"); return; }
|
|
71
|
-
let r: { id: string; from: string; title: string };
|
|
72
|
-
try { r = forkSession(ctx.sessionsDir, found.summary); }
|
|
73
|
-
catch (e) { ctx.renderer.addSystemNote(e instanceof Error ? e.message : String(e), "warn"); return; } // over FORK_MAX_ATTACHMENT_BYTES
|
|
74
|
-
ctx.switchSession(r.id); // rebinds store / memory / mode / checkpoints, replays the copied transcript, announces
|
|
75
|
-
ctx.renderer.addSystemNote(`forked ${r.from.slice(0, 8)} → ${r.id.slice(0, 8)} "${r.title}"`);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async function search(ctx: SessionCmdCtx, raw: string): Promise<void> {
|
|
79
|
-
const query = raw.trim();
|
|
80
|
-
if (query === "") { ctx.renderer.addSystemNote("usage: /sessions search <terms…>", "warn"); return; }
|
|
81
|
-
const rows = searchSessions(ctx.sessionsDir, query, 10);
|
|
82
|
-
if (rows.length === 0) { ctx.renderer.addSystemNote(`no matches for "${query}"`); return; }
|
|
83
|
-
const current = ctx.store().id;
|
|
84
|
-
const items = rows.map((r, i) => ({
|
|
85
|
-
value: String(i), // several hits may share a session: the index is the unique pick value
|
|
86
|
-
label: r.preview || r.title || "(empty session)",
|
|
87
|
-
description: `${r.title !== undefined ? `${r.title} · ` : ""}${r.sessionId.slice(0, 8)}${r.sessionId === current ? " · current" : ""} · ${new Date(r.timestamp).toLocaleString()}`,
|
|
88
|
-
}));
|
|
89
|
-
const picked = await ctx.renderer.pickOne(items, "search hits (Enter = resume, Esc = cancel)");
|
|
90
|
-
if (picked === null) { ctx.replayHistory(); return; } // cancel: clear the overlay title note
|
|
91
|
-
const row = rows[Number(picked)];
|
|
92
|
-
if (row === undefined) return;
|
|
93
|
-
if (row.sessionId === current) { ctx.renderer.addSystemNote("that hit is in the current session"); return; }
|
|
94
|
-
ctx.switchSession(row.sessionId);
|
|
95
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/** Port #44: the attach context the app hands a Renderer that implements `attach` (the sextant surface)
|
|
2
|
-
* — extracted from app.ts for the ADR-002 line cap. The panels read the runtime through these closures
|
|
3
|
-
* ONLY: the active store (swapped by /sessions, /resume and a root /rewind — read live, never captured),
|
|
4
|
-
* the task manager, the current mode's model, the catalog's context window and the /cost math over the
|
|
5
|
-
* active transcript (tui/cost.ts sessionUsage — priced per message at its origin model). */
|
|
6
|
-
|
|
7
|
-
import type { SessionStore } from "../core/session.ts";
|
|
8
|
-
import type { TaskManager } from "../core/tasks.ts";
|
|
9
|
-
import type { ModelCatalog } from "../providers/catalog.ts";
|
|
10
|
-
import type { SextantAttach } from "../sextant/types.ts";
|
|
11
|
-
import type { LiveRuntime } from "../sextant/context-source.ts";
|
|
12
|
-
import { sessionUsage } from "./cost.ts";
|
|
13
|
-
import { checkImageCount, loadImageAttachment } from "../core/images.ts";
|
|
14
|
-
|
|
15
|
-
/** slash names the sextant surface handles itself before onSubmit (keys.ts runLocal — the future
|
|
16
|
-
* src/sextant/local-commands.ts); reserved against custom commands like the built-ins, so a
|
|
17
|
-
* `.rovecode/commands/theme.md` warns and loses instead of silently never being reachable. */
|
|
18
|
-
export const SEXTANT_LOCAL_NAMES: readonly string[] = ["theme", "open", "diff", "focus", "agents", "notices", "context"];
|
|
19
|
-
|
|
20
|
-
export interface AttachSources {
|
|
21
|
-
cwd: string;
|
|
22
|
-
sessionsDir: string;
|
|
23
|
-
/** the ACTIVE store, read live */
|
|
24
|
-
store(): SessionStore;
|
|
25
|
-
tasks: TaskManager;
|
|
26
|
-
/** the current mode's model */
|
|
27
|
-
model(): { provider: string; model: string };
|
|
28
|
-
catalog: ModelCatalog;
|
|
29
|
-
/** the LIVE runtime, for /context. A function rather than a value: /sessions and /resume swap what is
|
|
30
|
-
* underneath, and a captured runtime would report on the session the human left. Returning null is
|
|
31
|
-
* allowed and means the panel says its total is a floor. */
|
|
32
|
-
runtime?: () => LiveRuntime | null;
|
|
33
|
-
/** `--pet <name>` */
|
|
34
|
-
petName?: string;
|
|
35
|
-
/** the connect wizard (draw-wizard.ts): the provider registry + credentials, behind the same
|
|
36
|
-
* live-runtime optionality as `runtime` — a surface without them degrades to honest errors. */
|
|
37
|
-
wizard?: {
|
|
38
|
-
providers(): { key: string; label: string; configured?: boolean; local?: boolean; url?: "openai" | "anthropic" }[];
|
|
39
|
-
register(id: string, url: string, protocol: "openai" | "anthropic"): { ok: boolean; error?: string };
|
|
40
|
-
storeKey(provider: string, secret: string): { ok: boolean; error?: string };
|
|
41
|
-
models(provider: string): Promise<{ id: string; note?: string }[]>;
|
|
42
|
-
/** the model step's activate answer: pin the checked rows as the active list (registry
|
|
43
|
-
* setModels — spec.models), empty = un-pin ("use them all"); makeDefault also switches */
|
|
44
|
-
activateModels(provider: string, models: readonly string[], makeDefault?: string): { ok: boolean; error?: string; models?: string[] };
|
|
45
|
-
test(provider: string, model: string): Promise<{ ok: boolean; detail: string }>;
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function buildSextantAttach(a: AttachSources): SextantAttach {
|
|
50
|
-
return {
|
|
51
|
-
cwd: a.cwd,
|
|
52
|
-
sessionsDir: a.sessionsDir,
|
|
53
|
-
store: () => ({ id: a.store().id }),
|
|
54
|
-
tasks: a.tasks,
|
|
55
|
-
model: a.model,
|
|
56
|
-
contextWindow: () => { const m = a.model(); return a.catalog.lookup(m.provider, m.model)?.contextWindow; },
|
|
57
|
-
usage: () => sessionUsage(a.store().messages(), a.catalog, a.model()),
|
|
58
|
-
// /context counts the real transcript against the real catalog, and asks the live runtime for the
|
|
59
|
-
// system prompt and the tool schemas — the two rows a transcript cannot know and a fresh window is
|
|
60
|
-
// mostly made of. The tier travels with the pricing, or a long xAI turn is billed at half rate.
|
|
61
|
-
contextInputs: () => ({
|
|
62
|
-
messages: a.store().messages(),
|
|
63
|
-
lookup: (r) => {
|
|
64
|
-
const info = a.catalog.lookup(r.provider, r.model);
|
|
65
|
-
if (!info) return undefined;
|
|
66
|
-
return {
|
|
67
|
-
...(info.contextWindow !== undefined ? { contextWindow: info.contextWindow } : {}),
|
|
68
|
-
...(info.pricing ? { pricing: info.pricing } : {}),
|
|
69
|
-
...(info.tier ? { tier: info.tier } : {}),
|
|
70
|
-
};
|
|
71
|
-
},
|
|
72
|
-
runtime: a.runtime?.() ?? null,
|
|
73
|
-
}),
|
|
74
|
-
// /market installs an MCP server into a file this session already read; without this the only way to
|
|
75
|
-
// reach it was to quit and start again, which is a poor answer to "I just installed it"
|
|
76
|
-
reloadMcp: async () => { const rt = a.runtime?.(); return (await rt?.reloadMcp?.()) ?? { added: [], removed: [], failed: [], skipped: [] }; },
|
|
77
|
-
// the images staged for the next message (tui/attach.ts /attach, /paste) — read live, the store owns them
|
|
78
|
-
staged: () => a.store().stagedAttachments.map((p) => p.name ?? "image"),
|
|
79
|
-
// port #54: an @image mention stages onto the SAME store stage /attach writes — one stage, one cap
|
|
80
|
-
// count, one chip row. The note comes from the expansion (sextant/mentions.ts); the caps and the
|
|
81
|
-
// magic-byte sniff are loadImageAttachment's, the same seam /attach runs through.
|
|
82
|
-
attachImage: (abs) => {
|
|
83
|
-
const store = a.store();
|
|
84
|
-
const loaded = loadImageAttachment(abs);
|
|
85
|
-
if ("error" in loaded) return;
|
|
86
|
-
const staged = store.stagedAttachments;
|
|
87
|
-
if (checkImageCount(staged.length + 1) !== undefined) return;
|
|
88
|
-
store.stageAttachments([...staged, loaded]);
|
|
89
|
-
},
|
|
90
|
-
// the connect wizard's seams — absent when the surface has no wizard sources, and the
|
|
91
|
-
// overlay's own degradation covers that
|
|
92
|
-
...(a.wizard !== undefined ? {
|
|
93
|
-
wizardProviders: () => a.wizard!.providers(),
|
|
94
|
-
wizardRegister: (id: string, url: string, protocol: "openai" | "anthropic") => a.wizard!.register(id, url, protocol),
|
|
95
|
-
wizardStoreKey: (provider: string, secret: string) => a.wizard!.storeKey(provider, secret),
|
|
96
|
-
wizardModels: (provider: string) => a.wizard!.models(provider),
|
|
97
|
-
wizardActivateModels: (provider: string, models: readonly string[], makeDefault?: string) => a.wizard!.activateModels(provider, models, makeDefault),
|
|
98
|
-
wizardTest: (provider: string, model: string) => a.wizard!.test(provider, model),
|
|
99
|
-
} : {}),
|
|
100
|
-
...(a.petName !== undefined ? { petName: a.petName } : {}),
|
|
101
|
-
};
|
|
102
|
-
}
|
package/src/tui/sextant-io.ts
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
/** Sextant terminal I/O + surface choice (port #44). The ONE module on the sextant path that touches
|
|
2
|
-
* vendor: ProcessIO drives process.stdin/stdout (raw mode, utf8, resize, and pi-tui's Windows
|
|
3
|
-
* ENABLE_VIRTUAL_TERMINAL_INPUT helper — without it libuv's console reader drops modifier state and
|
|
4
|
-
* Shift+Tab arrives as a plain \t instead of CSI Z; the helper is loaded AFTER setRawMode(true), which
|
|
5
|
-
* resets the console mode, exactly as vendor/pi-tui/src/terminal.ts:186-190 does). MemoryIO is the
|
|
6
|
-
* in-memory double tests and the smoke drive. chooseSurface() is the pure `rovecode` default rule:
|
|
7
|
-
* sextant only on a TTY of at least 100×30 that renders truecolor or 256 colors (the #40 quantizer
|
|
8
|
-
* paints the latter); `--classic` beats everything; ROVECODE_TUI=classic|sextant overrides the heuristics
|
|
9
|
-
* (a non-TTY still never gets sextant, nor does a TTY under the 40×12 Screen floor). */
|
|
10
|
-
|
|
11
|
-
import { createRequire } from "node:module";
|
|
12
|
-
import { join } from "node:path";
|
|
13
|
-
import { getNativeModuleCandidates } from "../../vendor/pi-tui/src/native-module-path.ts";
|
|
14
|
-
import { MIN_COLS, MIN_ROWS } from "../sextant/screen.ts";
|
|
15
|
-
import { SEXTANT_MIN_COLS, SEXTANT_MIN_ROWS, type TerminalIO } from "../sextant/types.ts";
|
|
16
|
-
import type { Renderer } from "./renderer.ts";
|
|
17
|
-
import type { FocusTracker } from "./notify-seq.ts";
|
|
18
|
-
|
|
19
|
-
const cjsRequire = createRequire(import.meta.url);
|
|
20
|
-
/** the vendored pi-tui source dir — getNativeModuleCandidates resolves `native/…` beside it */
|
|
21
|
-
const VENDOR_TUI_URL = new URL("../../vendor/pi-tui/src/terminal.ts", import.meta.url).href;
|
|
22
|
-
|
|
23
|
-
export type Env = Readonly<Record<string, string | undefined>>;
|
|
24
|
-
|
|
25
|
-
/** where pi-tui's prebuilt console-mode helper may live (vendor tree, or beside a compiled binary) */
|
|
26
|
-
export function vtInputCandidates(arch: string = process.arch, execPath: string = process.execPath): string[] {
|
|
27
|
-
return getNativeModuleCandidates(join("native", "win32", "prebuilds", `win32-${arch}`, "win32-console-mode.node"), { moduleUrl: VENDOR_TUI_URL, execPath });
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** pi-tui terminal.ts enableWindowsVTInput: flip ENABLE_VIRTUAL_TERMINAL_INPUT on the stdin console;
|
|
31
|
-
* false when the helper is unavailable (Shift+Tab is then indistinguishable from Tab) */
|
|
32
|
-
export function enableWindowsVTInput(arch: string = process.arch): boolean {
|
|
33
|
-
if (arch !== "x64" && arch !== "arm64") return false;
|
|
34
|
-
for (const p of vtInputCandidates(arch)) {
|
|
35
|
-
try {
|
|
36
|
-
const helper = cjsRequire(p) as { enableVirtualTerminalInput?: () => boolean };
|
|
37
|
-
return helper.enableVirtualTerminalInput?.() ?? false;
|
|
38
|
-
} catch { /* try the next packaging location */ }
|
|
39
|
-
}
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** the slice of process.stdin the surface uses (tests inject a fake) */
|
|
44
|
-
export interface RawStdin {
|
|
45
|
-
isRaw?: boolean;
|
|
46
|
-
isTTY?: boolean;
|
|
47
|
-
setRawMode?(mode: boolean): unknown;
|
|
48
|
-
setEncoding(enc: BufferEncoding): unknown;
|
|
49
|
-
resume(): unknown;
|
|
50
|
-
pause(): unknown;
|
|
51
|
-
on(event: "data", cb: (chunk: string | Buffer) => void): unknown;
|
|
52
|
-
on(event: "end", cb: () => void): unknown;
|
|
53
|
-
off(event: "data", cb: (chunk: string | Buffer) => void): unknown;
|
|
54
|
-
off(event: "end", cb: () => void): unknown;
|
|
55
|
-
}
|
|
56
|
-
/** the slice of process.stdout the surface uses */
|
|
57
|
-
export interface RawStdout {
|
|
58
|
-
write(s: string): unknown;
|
|
59
|
-
isTTY?: boolean;
|
|
60
|
-
columns?: number;
|
|
61
|
-
rows?: number;
|
|
62
|
-
on(event: "resize", cb: () => void): unknown;
|
|
63
|
-
off(event: "resize", cb: () => void): unknown;
|
|
64
|
-
}
|
|
65
|
-
export interface ProcessIOOptions {
|
|
66
|
-
/** default process.platform; the VT helper runs on win32 only */
|
|
67
|
-
platform?: string;
|
|
68
|
-
/** the VT-input helper (default enableWindowsVTInput) */
|
|
69
|
-
vtInput?: () => boolean;
|
|
70
|
-
/** consumes CSI I / CSI O focus reports BEFORE the sextant's parser sees the chunk (tui/notify.ts) */
|
|
71
|
-
focus?: FocusTracker;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export class ProcessIO implements TerminalIO {
|
|
75
|
-
private wasRaw = false;
|
|
76
|
-
constructor(
|
|
77
|
-
private readonly stdin: RawStdin = process.stdin,
|
|
78
|
-
private readonly stdout: RawStdout = process.stdout,
|
|
79
|
-
readonly env: Env = process.env,
|
|
80
|
-
private readonly opts: ProcessIOOptions = {},
|
|
81
|
-
) {}
|
|
82
|
-
write(s: string): void { this.stdout.write(s); }
|
|
83
|
-
onInput(cb: (chunk: string) => void): () => void {
|
|
84
|
-
const h = (d: string | Buffer): void => {
|
|
85
|
-
const text = typeof d === "string" ? d : d.toString("utf8");
|
|
86
|
-
const rest = this.opts.focus ? this.opts.focus.feed(text) : text; // focus reports are consumed here, never parsed as keys
|
|
87
|
-
if (rest.length > 0) cb(rest);
|
|
88
|
-
};
|
|
89
|
-
this.stdin.on("data", h);
|
|
90
|
-
// EOF: the pipe on the other end closed. A TUI that keeps waiting on a dead stdin hangs forever —
|
|
91
|
-
// measured 60 s+ (killed only by the outer timeout) when rovecode was launched from a pipe, a
|
|
92
|
-
// script or a wrapper that closes stdin. Deliver Ctrl-C's shape (ETX) so the input layer treats
|
|
93
|
-
// this exactly as an interrupt: a running turn aborts, an idle surface exits, and the terminal
|
|
94
|
-
// is restored by the normal close path. Without input there is nothing to wait FOR.
|
|
95
|
-
const end = (): void => { cb("\x03"); };
|
|
96
|
-
this.stdin.on("end", end);
|
|
97
|
-
return () => { this.stdin.off("data", h); this.stdin.off("end", end); };
|
|
98
|
-
}
|
|
99
|
-
onResize(cb: (cols: number, rows: number) => void): () => void {
|
|
100
|
-
const h = (): void => { const { cols, rows } = this.size(); cb(cols, rows); };
|
|
101
|
-
this.stdout.on("resize", h);
|
|
102
|
-
return () => { this.stdout.off("resize", h); };
|
|
103
|
-
}
|
|
104
|
-
size(): { cols: number; rows: number } { return { cols: this.stdout.columns || 80, rows: this.stdout.rows || 24 }; }
|
|
105
|
-
/** raw mode + utf8 + flowing, then the Windows VT-input helper (must follow setRawMode, which resets the console flags) */
|
|
106
|
-
enterRaw(): void {
|
|
107
|
-
this.wasRaw = this.stdin.isRaw ?? false;
|
|
108
|
-
this.stdin.setRawMode?.(true);
|
|
109
|
-
this.stdin.setEncoding("utf8");
|
|
110
|
-
this.stdin.resume();
|
|
111
|
-
if ((this.opts.platform ?? process.platform) === "win32") (this.opts.vtInput ?? enableWindowsVTInput)();
|
|
112
|
-
}
|
|
113
|
-
/** restore the previous raw state and pause stdin so buffered bytes never reach the parent shell */
|
|
114
|
-
leaveRaw(): void {
|
|
115
|
-
this.stdin.setRawMode?.(this.wasRaw);
|
|
116
|
-
this.stdin.pause();
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/** in-memory TerminalIO: records writes, replays fed input, emulates resizes (tests + `smoke-tui --sextant`) */
|
|
121
|
-
export class MemoryIO implements TerminalIO {
|
|
122
|
-
readonly writes: string[] = [];
|
|
123
|
-
raw = false;
|
|
124
|
-
private readonly inputs = new Set<(chunk: string) => void>();
|
|
125
|
-
private readonly resizes = new Set<(cols: number, rows: number) => void>();
|
|
126
|
-
constructor(public cols = 160, public rows = 44, readonly env: Env = {}) {}
|
|
127
|
-
write(s: string): void { this.writes.push(s); }
|
|
128
|
-
onInput(cb: (chunk: string) => void): () => void { this.inputs.add(cb); return () => { this.inputs.delete(cb); }; }
|
|
129
|
-
onResize(cb: (cols: number, rows: number) => void): () => void { this.resizes.add(cb); return () => { this.resizes.delete(cb); }; }
|
|
130
|
-
size(): { cols: number; rows: number } { return { cols: this.cols, rows: this.rows }; }
|
|
131
|
-
enterRaw(): void { this.raw = true; }
|
|
132
|
-
leaveRaw(): void { this.raw = false; }
|
|
133
|
-
/** deliver raw terminal bytes (keys, mouse, paste) */
|
|
134
|
-
feed(chunk: string): void { for (const cb of [...this.inputs]) cb(chunk); }
|
|
135
|
-
resize(cols: number, rows: number): void { this.cols = cols; this.rows = rows; for (const cb of [...this.resizes]) cb(cols, rows); }
|
|
136
|
-
/** everything written so far */
|
|
137
|
-
output(): string { return this.writes.join(""); }
|
|
138
|
-
/** live input + resize subscriptions (0 after stop) */
|
|
139
|
-
get listeners(): number { return this.inputs.size + this.resizes.size; }
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// ------------------------------------------------------------------ surface choice
|
|
143
|
-
|
|
144
|
-
const TC_PROGRAMS = new Set(["vscode", "iTerm.app", "WezTerm", "ghostty"]);
|
|
145
|
-
|
|
146
|
-
/** the terminal renders 24-bit color: COLORTERM truecolor/24bit, Windows Terminal (WT_SESSION), a
|
|
147
|
-
* known TERM_PROGRAM (vscode, iTerm.app, WezTerm, ghostty) or a kitty/`-direct` TERM */
|
|
148
|
-
export function truecolor(env: Env): boolean {
|
|
149
|
-
const ct = (env.COLORTERM ?? "").toLowerCase();
|
|
150
|
-
if (ct === "truecolor" || ct === "24bit") return true;
|
|
151
|
-
if (env.WT_SESSION) return true;
|
|
152
|
-
if (TC_PROGRAMS.has(env.TERM_PROGRAM ?? "")) return true;
|
|
153
|
-
return /kitty|direct/.test(env.TERM ?? "");
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export type ColorDepth = "truecolor" | "256" | "none";
|
|
157
|
-
|
|
158
|
-
/** what the terminal renders: truecolor per the heuristics above; else 256 colors when TERM says so
|
|
159
|
-
* (xterm-256color, screen-/tmux-256color) and COLORTERM is silent — the surface then paints through the
|
|
160
|
-
* #40 quantizer (SGR 38;5); else nothing sextant can use */
|
|
161
|
-
export function colorDepth(env: Env): ColorDepth {
|
|
162
|
-
if (truecolor(env)) return "truecolor";
|
|
163
|
-
if (!(env.COLORTERM ?? "").trim() && /256color/.test(env.TERM ?? "")) return "256";
|
|
164
|
-
return "none";
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export interface StdoutInfo { isTTY?: boolean; columns?: number; rows?: number }
|
|
168
|
-
|
|
169
|
-
/** the heuristic: a TTY of at least SEXTANT_MIN_COLS×SEXTANT_MIN_ROWS with truecolor or 256 colors */
|
|
170
|
-
export function sextantOk(env: Env, stdout: StdoutInfo): boolean {
|
|
171
|
-
return !!stdout.isTTY && (stdout.columns ?? 0) >= SEXTANT_MIN_COLS && (stdout.rows ?? 0) >= SEXTANT_MIN_ROWS && colorDepth(env) !== "none";
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/** the Screen floor (screen.ts MIN_COLS×MIN_ROWS): below it the cell buffer is larger than the terminal
|
|
175
|
-
* (39-cell rows into a 30-column window), so even a forced sextant yields; an unknown size counts as
|
|
176
|
-
* the 80×24 ProcessIO.size() falls back to */
|
|
177
|
-
export function fitsFloor(stdout: StdoutInfo): boolean {
|
|
178
|
-
return (stdout.columns ?? 80) >= MIN_COLS && (stdout.rows ?? 24) >= MIN_ROWS;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export type Surface = "sextant" | "classic";
|
|
182
|
-
|
|
183
|
-
/** `--classic` wins; ROVECODE_TUI=classic forces classic, ROVECODE_TUI=sextant forces sextant on any TTY at or
|
|
184
|
-
* above the 40×12 floor (the 100×30 and color heuristics skipped); otherwise sextantOk(). A non-TTY
|
|
185
|
-
* stdout never gets sextant. */
|
|
186
|
-
export function chooseSurface(cli: { classic: boolean }, env: Env, stdout: StdoutInfo): Surface {
|
|
187
|
-
if (cli.classic) return "classic";
|
|
188
|
-
const force = (env.ROVECODE_TUI ?? "").trim().toLowerCase();
|
|
189
|
-
if (force === "classic") return "classic";
|
|
190
|
-
if (force === "sextant") return stdout.isTTY && fitsFloor(stdout) ? "sextant" : "classic";
|
|
191
|
-
return sextantOk(env, stdout) ? "sextant" : "classic";
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/** main.ts: the renderer to hand runTui — a SextantRenderer over the process terminal (truecolor SGR, or
|
|
195
|
-
* the 256-color quantizer when that is all the terminal declares), or undefined (runTui then builds the
|
|
196
|
-
* classic PiTuiRenderer exactly as before) */
|
|
197
|
-
/** `io.focus`: the FocusTracker the notifications decorator reads (tui/notify.ts); `io.stdin` for tests */
|
|
198
|
-
export function pickRenderer(cli: { classic: boolean; pet?: string }, env: Env = process.env, stdout: RawStdout = process.stdout, io: { stdin?: RawStdin; focus?: FocusTracker } = {}): Renderer | undefined {
|
|
199
|
-
if (chooseSurface(cli, env, stdout) !== "sextant") return undefined;
|
|
200
|
-
const { SextantRenderer } = require("../sextant/sextant-renderer.ts") as typeof import("../sextant/sextant-renderer.ts");
|
|
201
|
-
return new SextantRenderer({ io: new ProcessIO(io.stdin ?? process.stdin, stdout, env, io.focus ? { focus: io.focus } : {}), truecolor: colorDepth(env) === "truecolor", ...(cli.pet !== undefined ? { pet: cli.pet } : {}), ...(env.ROVECODE_THEME ? { theme: env.ROVECODE_THEME } : {}) });
|
|
202
|
-
}
|