rovecode 0.3.3 → 0.4.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +527 -0
- package/README.md +46 -48
- package/bin/rovecode.js +24 -0
- package/dist/cli/app-j6gn14w3.js +2 -0
- package/dist/cli/ask-user-cwstt8fz.js +2 -0
- package/dist/cli/auth-login-9bbp9915.js +2 -0
- package/dist/cli/auth-m8p9grty.js +2 -0
- package/dist/cli/bench-16zqdms5.js +9 -0
- package/dist/cli/catalog-1xchffa4.js +2 -0
- package/dist/cli/cli-1n1zb64f.js +2 -0
- package/dist/cli/client-2t9gjkck.js +2 -0
- package/dist/cli/commands-exafvm2b.js +2 -0
- package/dist/cli/connect-6zde0kn3.js +2 -0
- package/dist/cli/context-cmd-5t43wgqt.js +2 -0
- package/dist/cli/context-report-kt01pw8y.js +2 -0
- package/dist/cli/count-remote-ap7x3vh6.js +2 -0
- package/dist/cli/design-ne5zszyh.js +2 -0
- package/dist/cli/dispatch-2r5myxye.js +2 -0
- package/dist/cli/doctor-ws4fh4tn.js +3 -0
- package/dist/cli/executor-bdrjn634.js +2 -0
- package/dist/cli/export-1mxb9g5p.js +2 -0
- package/dist/cli/files-g104xghh.js +2 -0
- package/dist/cli/gauntlet-07xrjpj7.js +2 -0
- package/dist/cli/gauntlet-runner-xvy64436.js +10 -0
- package/dist/cli/gauntlet-wave3-jm91yt5w.js +5 -0
- package/dist/cli/gauntlet-wave4-r13py7p1.js +14 -0
- package/dist/cli/hashline-znvrat11.js +2 -0
- package/dist/cli/http-xafw6fsh.js +143 -0
- package/dist/cli/index-1sgjm25y.js +2 -0
- package/dist/cli/init-g2m0tn4m.js +51 -0
- package/dist/cli/install-avaqjjqq.js +2 -0
- package/dist/cli/loop-mmpfft01.js +2 -0
- package/dist/cli/main-0904f6ps.js +5 -0
- package/dist/cli/main-0ab9fc26.js +9 -0
- package/dist/cli/main-0jys2ccn.js +3 -0
- package/dist/cli/main-0mtcdbs7.js +3 -0
- package/dist/cli/main-0z1w2zsg.js +3 -0
- package/dist/cli/main-1dchs7xv.js +18 -0
- package/dist/cli/main-1ereejm1.js +3 -0
- package/dist/cli/main-1k1kw6b5.js +3 -0
- package/dist/cli/main-27y4sm2k.js +38 -0
- package/dist/cli/main-2wwjex5j.js +58 -0
- package/dist/cli/main-2yeveeve.js +6 -0
- package/dist/cli/main-2yfck9b5.js +3 -0
- package/dist/cli/main-2zmzgkwh.js +3 -0
- package/dist/cli/main-351pz3z7.js +7 -0
- package/dist/cli/main-3gjqfh7a.js +6 -0
- package/dist/cli/main-3nf3kgve.js +3 -0
- package/dist/cli/main-3pjrb2hd.js +3 -0
- package/dist/cli/main-3rxcvgna.js +19 -0
- package/dist/cli/main-4b3jgy66.js +19 -0
- package/dist/cli/main-4wndhjdc.js +7 -0
- package/dist/cli/main-4xcmvxnk.js +3 -0
- package/dist/cli/main-5tbz0wbz.js +4 -0
- package/dist/cli/main-5ywnwthm.js +3 -0
- package/dist/cli/main-6b62vkz0.js +14 -0
- package/dist/cli/main-6dnk69vp.js +3 -0
- package/dist/cli/main-6genrmhs.js +136 -0
- package/dist/cli/main-73g7eff4.js +15 -0
- package/dist/cli/main-7c5thhjd.js +5 -0
- package/dist/cli/main-7rn6bqje.js +3 -0
- package/dist/cli/main-80haw7qk.js +4 -0
- package/dist/cli/main-875s60s2.js +4 -0
- package/dist/cli/main-8kjxbpw4.js +8 -0
- package/dist/cli/main-90ds1z4e.js +10 -0
- package/dist/cli/main-9etavkew.js +3 -0
- package/dist/cli/main-a9njrkk1.js +3 -0
- package/dist/cli/main-aecrjq2d.js +12 -0
- package/dist/cli/main-ck9asesq.js +9 -0
- package/dist/cli/main-cta9racd.js +4 -0
- package/dist/cli/main-ddv7j2ag.js +3 -0
- package/dist/cli/main-dfreez27.js +10 -0
- package/dist/cli/main-f7rw7des.js +3 -0
- package/dist/cli/main-ggcn7rd7.js +5 -0
- package/dist/cli/main-gzkmycnv.js +3 -0
- package/dist/cli/main-hq51jg8v.js +18 -0
- package/dist/cli/main-jft389w9.js +8 -0
- package/dist/cli/main-k1eqkg83.js +3 -0
- package/dist/cli/main-k2y8a2aw.js +9 -0
- package/dist/cli/main-kcpbykxz.js +4 -0
- package/dist/cli/main-kd488vje.js +22 -0
- package/dist/cli/main-kh32yvgk.js +5 -0
- package/dist/cli/main-kqxnqjnv.js +25 -0
- package/dist/cli/main-kyn0xnsg.js +3 -0
- package/dist/cli/main-m1kk6fp5.js +21 -0
- package/dist/cli/main-mv40pcr2.js +4 -0
- package/dist/cli/main-n0t3973w.js +3 -0
- package/dist/cli/main-nqveez48.js +4 -0
- package/dist/cli/main-pknhvrmj.js +3 -0
- package/dist/cli/main-pn1w7a7j.js +3 -0
- package/dist/cli/main-prxxs70n.js +4 -0
- package/dist/cli/main-q3vsesf9.js +3 -0
- package/dist/cli/main-qsevpgsv.js +3 -0
- package/dist/cli/main-rdgdw24b.js +25 -0
- package/dist/cli/main-rfth4tbm.js +16 -0
- package/dist/cli/main-rg0wn0xf.js +5 -0
- package/dist/cli/main-sdmxhtv8.js +4 -0
- package/dist/cli/main-skbp13js.js +18 -0
- package/dist/cli/main-t4xnd213.js +7 -0
- package/dist/cli/main-vqak588n.js +4 -0
- package/dist/cli/main-w2n1303f.js +9 -0
- package/dist/cli/main-wbrdspr2.js +5 -0
- package/dist/cli/main-wsrg79c1.js +7 -0
- package/dist/cli/main-x4r0fne4.js +5 -0
- package/dist/cli/main-xea2f3tn.js +6 -0
- package/dist/cli/main-xg704a3c.js +3 -0
- package/dist/cli/main-xvnrabfp.js +16 -0
- package/dist/cli/main-xy53xf0r.js +4 -0
- package/dist/cli/main-y1fqy60y.js +3 -0
- package/dist/cli/main-yn8cd281.js +34 -0
- package/dist/cli/main-yr0ksc0h.js +4 -0
- package/dist/cli/main-z2ex2vyf.js +4 -0
- package/dist/cli/main-z3aayzvq.js +3 -0
- package/dist/cli/main-zaqh35jg.js +3 -0
- package/dist/cli/main-zc2e8e46.js +4 -0
- package/dist/cli/main-zzrfw6cf.js +13 -0
- package/dist/cli/main.js +280 -0
- package/dist/cli/market-cmd-e14kmx9n.js +5 -0
- package/dist/cli/mcp-login-wq7ktdek.js +2 -0
- package/dist/cli/mcp-market-cmd-9mg3jecy.js +2 -0
- package/dist/cli/notify-b7qc0cjb.js +2 -0
- package/dist/cli/oauth-z8whcgfx.js +2 -0
- package/dist/cli/output-b3ewj3ps.js +16 -0
- package/dist/cli/profiles-6mr5he5e.js +2 -0
- package/dist/cli/provider-config-g7j42q8x.js +2 -0
- package/dist/cli/provider-jr1y8vvm.js +2 -0
- package/dist/cli/registry-s8yk86g0.js +2 -0
- package/dist/cli/registry-t6p8d4mn.js +2 -0
- package/dist/cli/repl-bajwe1mh.js +11 -0
- package/dist/cli/resume-rwn9nz7y.js +2 -0
- package/dist/cli/run-flags-nah7ndpt.js +2 -0
- package/dist/cli/runtime-n7gafzhb.js +2 -0
- package/dist/cli/sandbox-config-emdy18x4.js +2 -0
- package/dist/cli/server-b0nvs2bn.js +5 -0
- package/dist/cli/session-arg-y75wd4kj.js +2 -0
- package/dist/cli/session-j62evmjq.js +2 -0
- package/dist/cli/sessions-cmd-tsnwz0ns.js +7 -0
- package/dist/cli/settings-df10wfez.js +2 -0
- package/dist/cli/setup-jzvv72fg.js +2 -0
- package/dist/cli/sextant-smoke-37m81ke6.js +5 -0
- package/dist/cli/skills-cmd-gjxnxnhx.js +2 -0
- package/dist/cli/smoke-p7748apt.js +8 -0
- package/dist/cli/start-chat-s4st3mm0.js +12 -0
- package/dist/cli/stream-gmeyewds.js +2 -0
- package/dist/cli/task-gh0kkp3n.js +2 -0
- package/dist/cli/tasks-z1kfpe8e.js +2 -0
- package/dist/cli/thinking-0eqkrz6t.js +2 -0
- package/dist/cli/todo-5brcrt9m.js +2 -0
- package/dist/cli/tools-7pzm0vj9.js +2 -0
- package/dist/cli/tools-s635p6s8.js +2 -0
- package/dist/cli/trust-cmd-cjav8zgm.js +2 -0
- package/dist/cli/update-check-pt31bm2f.js +2 -0
- package/dist/cli/update-cmd-tk131s9t.js +2 -0
- package/dist/cli/voice-56nabd8d.js +2 -0
- package/dist/cli/webfetch-xd8q596m.js +2 -0
- package/dist/cli/websearch-5hkf98k1.js +2 -0
- package/dist/cli/workflow-cmd-cy3cvzjp.js +4 -0
- package/dist/cli/workspace-q10g5z3e.js +2 -0
- package/dist/lib/index.js +62 -0
- package/dist/lib/models-index.json +1 -0
- package/dist/lib/plugins.js +55 -0
- package/dist/lib/providers.js +17 -0
- package/dist/lib/public-api.js +20 -0
- package/dist/lib/sdk.js +360 -0
- package/package.json +84 -72
- package/bin/rovecode.ts +0 -21
- package/src/acp/server.ts +0 -374
- package/src/cli/auth-login.ts +0 -122
- package/src/cli/connect.ts +0 -244
- package/src/cli/context-cmd.ts +0 -199
- package/src/cli/dispatch.ts +0 -82
- package/src/cli/doctor.ts +0 -362
- package/src/cli/export.ts +0 -276
- package/src/cli/help.ts +0 -293
- package/src/cli/is-tui-invocation.ts +0 -8
- package/src/cli/main.ts +0 -583
- package/src/cli/market-cmd.ts +0 -658
- package/src/cli/mcp-login.ts +0 -141
- package/src/cli/mcp-market-cmd.ts +0 -302
- package/src/cli/output.ts +0 -382
- package/src/cli/repl.ts +0 -250
- package/src/cli/repomap-root.ts +0 -14
- package/src/cli/resume.ts +0 -57
- package/src/cli/run-flags.ts +0 -43
- package/src/cli/run-limits.ts +0 -78
- package/src/cli/runtime.ts +0 -931
- package/src/cli/session-arg.ts +0 -30
- package/src/cli/sessions-cmd.ts +0 -145
- package/src/cli/setup.ts +0 -153
- package/src/cli/skills-cmd.ts +0 -194
- package/src/cli/start-chat.ts +0 -65
- package/src/cli/trust-cmd.ts +0 -52
- package/src/coding/bash.ts +0 -148
- package/src/coding/checkpoints.ts +0 -327
- package/src/coding/diff.ts +0 -138
- package/src/coding/files.ts +0 -341
- package/src/coding/hashline.ts +0 -274
- package/src/coding/lsp-gate.ts +0 -254
- package/src/coding/lsp-servers.ts +0 -147
- package/src/coding/lsp.ts +0 -283
- package/src/coding/repomap-cache.ts +0 -99
- package/src/coding/repomap-files.ts +0 -192
- package/src/coding/repomap.ts +0 -481
- package/src/core/agents.ts +0 -255
- package/src/core/compaction.ts +0 -259
- package/src/core/config.ts +0 -289
- package/src/core/context-report.ts +0 -228
- package/src/core/context.ts +0 -60
- package/src/core/count-remote.ts +0 -107
- package/src/core/execpolicy-rules.ts +0 -196
- package/src/core/execpolicy.ts +0 -385
- package/src/core/executor.ts +0 -454
- package/src/core/guardrails.ts +0 -400
- package/src/core/hooks.ts +0 -411
- package/src/core/images.ts +0 -230
- package/src/core/intro.ts +0 -266
- package/src/core/loop.ts +0 -567
- package/src/core/modes.ts +0 -372
- package/src/core/orchestrator.ts +0 -245
- package/src/core/proc-group.ts +0 -48
- package/src/core/project-trust.ts +0 -98
- package/src/core/reflection.ts +0 -165
- package/src/core/sandbox-config.ts +0 -186
- package/src/core/session-id.ts +0 -24
- package/src/core/session-images.ts +0 -73
- package/src/core/session-ops.ts +0 -183
- package/src/core/session-text.ts +0 -29
- package/src/core/session.ts +0 -469
- package/src/core/settings.ts +0 -170
- package/src/core/tasks.ts +0 -646
- package/src/core/token-scale.ts +0 -108
- package/src/core/tools.ts +0 -309
- package/src/core/trust.ts +0 -104
- package/src/core/types.ts +0 -330
- package/src/core/update-check.ts +0 -171
- package/src/core/usage.ts +0 -204
- package/src/core/validate.ts +0 -121
- package/src/core/verify-gate.ts +0 -159
- package/src/core/verify.ts +0 -236
- package/src/core/voice.ts +0 -158
- package/src/core/win-job.ts +0 -183
- package/src/core/workspace.ts +0 -184
- package/src/design/audit.ts +0 -797
- package/src/design/direction.ts +0 -190
- package/src/design/rules.ts +0 -157
- package/src/eval/bench.ts +0 -150
- package/src/eval/gauntlet-runner.ts +0 -215
- package/src/eval/gauntlet-support.ts +0 -84
- package/src/eval/gauntlet-wave3.ts +0 -269
- package/src/eval/gauntlet-wave4.ts +0 -217
- package/src/eval/gauntlet.ts +0 -253
- package/src/index.ts +0 -17
- package/src/lanes/agy.ts +0 -95
- package/src/lanes/approval.ts +0 -24
- package/src/lanes/claude.ts +0 -129
- package/src/lanes/codex.ts +0 -127
- package/src/lanes/events.ts +0 -130
- package/src/lanes/job.ts +0 -142
- package/src/lanes/opencode.ts +0 -122
- package/src/lanes/process.ts +0 -184
- package/src/lanes/progress.ts +0 -183
- package/src/lanes/registry.ts +0 -178
- package/src/lanes/runner.ts +0 -124
- package/src/lanes/types.ts +0 -112
- package/src/market/catalogs/mcp-docs.json +0 -111
- package/src/market/catalogs/plugins.json +0 -111
- package/src/market/catalogs/skills.json +0 -478
- package/src/market/clone.ts +0 -72
- package/src/market/context-cost.ts +0 -121
- package/src/market/digest.ts +0 -106
- package/src/market/index.ts +0 -22
- package/src/market/install.ts +0 -578
- package/src/market/manifest.ts +0 -187
- package/src/market/prereq.ts +0 -145
- package/src/market/registry.ts +0 -363
- package/src/market/resolve.ts +0 -111
- package/src/market/types.ts +0 -236
- package/src/market/validate.ts +0 -227
- package/src/mcp/client.ts +0 -449
- package/src/mcp/config.ts +0 -252
- package/src/mcp/local-package.ts +0 -211
- package/src/mcp/market-catalog.ts +0 -84
- package/src/mcp/market-install.ts +0 -289
- package/src/mcp/market.ts +0 -362
- package/src/mcp/oauth.ts +0 -251
- package/src/mcp/prompts-resources.ts +0 -249
- package/src/mcp/shared.ts +0 -149
- package/src/mcp/status.ts +0 -67
- package/src/mcp/tools.ts +0 -275
- package/src/mcp/transport.ts +0 -122
- package/src/mcp/trust.ts +0 -25
- package/src/memory/blocks.ts +0 -278
- package/src/memory/recall.ts +0 -355
- package/src/memory/scope.ts +0 -182
- package/src/memory/store.ts +0 -105
- package/src/memory/tools.ts +0 -99
- package/src/plugins/cli.ts +0 -119
- package/src/plugins/discover.ts +0 -108
- package/src/plugins/index.ts +0 -50
- package/src/plugins/install.ts +0 -184
- package/src/plugins/load.ts +0 -124
- package/src/plugins/manifest.ts +0 -92
- package/src/plugins/state.ts +0 -83
- package/src/providers/auth.ts +0 -408
- package/src/providers/cache.ts +0 -223
- package/src/providers/catalog-local.ts +0 -160
- package/src/providers/catalog.ts +0 -421
- package/src/providers/middleware-context.ts +0 -86
- package/src/providers/middleware.ts +0 -373
- package/src/providers/model-list.ts +0 -23
- package/src/providers/oauth/common.ts +0 -105
- package/src/providers/oauth/device-code.ts +0 -107
- package/src/providers/oauth/github-copilot.ts +0 -146
- package/src/providers/oauth/loopback.ts +0 -158
- package/src/providers/oauth/openai.ts +0 -163
- package/src/providers/oauth/openrouter.ts +0 -89
- package/src/providers/oauth/pkce.ts +0 -45
- package/src/providers/oauth/registry.ts +0 -39
- package/src/providers/oauth/seam.ts +0 -89
- package/src/providers/profile-glm53.ts +0 -111
- package/src/providers/profile-sonnet5-persona.ts +0 -65
- package/src/providers/profile-sonnet5-voice.ts +0 -23
- package/src/providers/profiles.ts +0 -156
- package/src/providers/provider-config.ts +0 -311
- package/src/providers/registry.ts +0 -333
- package/src/providers/responses.ts +0 -209
- package/src/providers/retry.ts +0 -234
- package/src/providers/router.ts +0 -294
- package/src/providers/sse.ts +0 -26
- package/src/providers/stream-errors.ts +0 -117
- package/src/providers/stream.ts +0 -566
- package/src/providers/thinking.ts +0 -189
- package/src/providers/wire-messages.ts +0 -129
- package/src/providers/wire-responses.ts +0 -79
- package/src/providers/wire-select.ts +0 -53
- package/src/server/http.ts +0 -291
- package/src/server/openapi.ts +0 -246
- package/src/sextant/card-hits.ts +0 -102
- package/src/sextant/card-keys.ts +0 -55
- package/src/sextant/context-source.ts +0 -157
- package/src/sextant/crew-cards.ts +0 -350
- package/src/sextant/draw-agents.ts +0 -273
- package/src/sextant/draw-code.ts +0 -388
- package/src/sextant/draw-context.ts +0 -222
- package/src/sextant/draw-frame.ts +0 -164
- package/src/sextant/draw-market.ts +0 -573
- package/src/sextant/draw-messages.ts +0 -386
- package/src/sextant/draw-pet.ts +0 -230
- package/src/sextant/draw-plan.ts +0 -187
- package/src/sextant/draw-tabs.ts +0 -85
- package/src/sextant/draw-util.ts +0 -65
- package/src/sextant/draw-wizard.ts +0 -378
- package/src/sextant/engine.ts +0 -230
- package/src/sextant/frame-hits.ts +0 -25
- package/src/sextant/frame.ts +0 -101
- package/src/sextant/git-status.ts +0 -197
- package/src/sextant/grid.ts +0 -59
- package/src/sextant/input.ts +0 -119
- package/src/sextant/keys.ts +0 -521
- package/src/sextant/layout.ts +0 -86
- package/src/sextant/local-commands.ts +0 -169
- package/src/sextant/market-source.ts +0 -287
- package/src/sextant/mentions.ts +0 -200
- package/src/sextant/message-hits.ts +0 -26
- package/src/sextant/model.ts +0 -387
- package/src/sextant/overlays.ts +0 -456
- package/src/sextant/panel-hits.ts +0 -38
- package/src/sextant/pet.ts +0 -399
- package/src/sextant/screen.ts +0 -324
- package/src/sextant/scroll-hits.ts +0 -66
- package/src/sextant/scrollbar.ts +0 -82
- package/src/sextant/sextant-bridge.ts +0 -174
- package/src/sextant/sextant-cards.ts +0 -142
- package/src/sextant/sextant-diff-base.ts +0 -63
- package/src/sextant/sextant-files.ts +0 -154
- package/src/sextant/sextant-frame-loop.ts +0 -335
- package/src/sextant/sextant-renderer.ts +0 -574
- package/src/sextant/sextant-repo.ts +0 -140
- package/src/sextant/theme.ts +0 -66
- package/src/sextant/tool-rows.ts +0 -189
- package/src/sextant/types.ts +0 -493
- package/src/skills/index.ts +0 -387
- package/src/skills/pack.ts +0 -220
- package/src/skills/spec.ts +0 -162
- package/src/skills/tools.ts +0 -69
- package/src/skills/versioned.ts +0 -227
- package/src/telemetry/otel-export.ts +0 -122
- package/src/telemetry/otel-lanes.ts +0 -89
- package/src/telemetry/otel-logs.ts +0 -131
- package/src/telemetry/otel-metrics.ts +0 -136
- package/src/telemetry/otel.ts +0 -397
- package/src/telemetry/otlp.ts +0 -76
- package/src/tools/ask-user.ts +0 -156
- package/src/tools/bash-bg.ts +0 -94
- package/src/tools/bash-jobs.ts +0 -237
- package/src/tools/design.ts +0 -151
- package/src/tools/evalcell.ts +0 -338
- package/src/tools/html-text.ts +0 -139
- package/src/tools/provider.ts +0 -149
- package/src/tools/task.ts +0 -250
- package/src/tools/todo.ts +0 -320
- package/src/tools/webfetch.ts +0 -332
- package/src/tools/websearch.ts +0 -359
- package/src/tui/agents-cmd.ts +0 -41
- package/src/tui/app.ts +0 -749
- package/src/tui/attach.ts +0 -127
- package/src/tui/boot-notes.ts +0 -41
- package/src/tui/builtin-prompts.ts +0 -59
- package/src/tui/checkpoints-cmd.ts +0 -70
- package/src/tui/clipboard-image.ts +0 -81
- package/src/tui/clipboard.ts +0 -78
- package/src/tui/commands.ts +0 -283
- package/src/tui/config-view.ts +0 -53
- package/src/tui/context-cmds.ts +0 -282
- package/src/tui/cost.ts +0 -108
- package/src/tui/crash-guard.ts +0 -173
- package/src/tui/focus-terminal.ts +0 -34
- package/src/tui/git-cmds.ts +0 -273
- package/src/tui/git-plain.ts +0 -58
- package/src/tui/info-cmd.ts +0 -150
- package/src/tui/input-plain.ts +0 -76
- package/src/tui/mcp-cmd.ts +0 -128
- package/src/tui/memory-note.ts +0 -77
- package/src/tui/modes-cmd.ts +0 -45
- package/src/tui/notify-seq.ts +0 -100
- package/src/tui/notify.ts +0 -318
- package/src/tui/overlays.ts +0 -97
- package/src/tui/pi-renderer.ts +0 -428
- package/src/tui/providers-cmd.ts +0 -377
- package/src/tui/reasoning-view.ts +0 -56
- package/src/tui/renderer.ts +0 -128
- package/src/tui/replay-marker.ts +0 -29
- package/src/tui/session-cmd.ts +0 -148
- package/src/tui/session-manage.ts +0 -95
- package/src/tui/sextant-attach.ts +0 -102
- package/src/tui/sextant-io.ts +0 -202
- package/src/tui/sextant-smoke.ts +0 -110
- package/src/tui/shell-cmd.ts +0 -158
- package/src/tui/smoke.ts +0 -72
- package/src/tui/staged-terminal.ts +0 -50
- package/src/tui/startup.ts +0 -12
- package/src/tui/theme.ts +0 -59
- package/src/tui/todo-label.ts +0 -7
- package/src/tui/trust-card.ts +0 -107
- package/src/tui/tui-commands.ts +0 -87
- package/tsconfig.json +0 -30
- package/vendor/pi-tui/LICENSE +0 -21
- package/vendor/pi-tui/PATCHES.md +0 -12
- package/vendor/pi-tui/PROVENANCE.md +0 -12
- package/vendor/pi-tui/README.upstream.md +0 -854
- package/vendor/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/vendor/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/vendor/pi-tui/src/alt-screen-search.ts +0 -158
- package/vendor/pi-tui/src/autocomplete.ts +0 -827
- package/vendor/pi-tui/src/components/alt-screen-flash.ts +0 -52
- package/vendor/pi-tui/src/components/box.ts +0 -138
- package/vendor/pi-tui/src/components/cancellable-loader.ts +0 -41
- package/vendor/pi-tui/src/components/editor.ts +0 -2364
- package/vendor/pi-tui/src/components/h-stack.ts +0 -45
- package/vendor/pi-tui/src/components/image.ts +0 -128
- package/vendor/pi-tui/src/components/input.ts +0 -448
- package/vendor/pi-tui/src/components/loader.ts +0 -93
- package/vendor/pi-tui/src/components/markdown.ts +0 -1016
- package/vendor/pi-tui/src/components/scroll-view.ts +0 -217
- package/vendor/pi-tui/src/components/select-list.ts +0 -230
- package/vendor/pi-tui/src/components/settings-list.ts +0 -277
- package/vendor/pi-tui/src/components/spacer.ts +0 -29
- package/vendor/pi-tui/src/components/stack.ts +0 -155
- package/vendor/pi-tui/src/components/text.ts +0 -108
- package/vendor/pi-tui/src/components/truncated-text.ts +0 -66
- package/vendor/pi-tui/src/components/v-stack.ts +0 -34
- package/vendor/pi-tui/src/editor-component.ts +0 -75
- package/vendor/pi-tui/src/fuzzy.ts +0 -138
- package/vendor/pi-tui/src/index.ts +0 -149
- package/vendor/pi-tui/src/keybindings.ts +0 -321
- package/vendor/pi-tui/src/keys.ts +0 -1402
- package/vendor/pi-tui/src/kill-ring.ts +0 -47
- package/vendor/pi-tui/src/latex.ts +0 -1381
- package/vendor/pi-tui/src/layout-node.ts +0 -52
- package/vendor/pi-tui/src/layout.ts +0 -411
- package/vendor/pi-tui/src/native-modifiers.ts +0 -60
- package/vendor/pi-tui/src/native-module-path.ts +0 -32
- package/vendor/pi-tui/src/stdin-buffer.ts +0 -445
- package/vendor/pi-tui/src/terminal-colors.ts +0 -74
- package/vendor/pi-tui/src/terminal-image.ts +0 -701
- package/vendor/pi-tui/src/terminal.ts +0 -554
- package/vendor/pi-tui/src/tui-alt-screen.ts +0 -1379
- package/vendor/pi-tui/src/tui-main-screen.ts +0 -655
- package/vendor/pi-tui/src/tui.ts +0 -1264
- package/vendor/pi-tui/src/undo-stack.ts +0 -29
- package/vendor/pi-tui/src/utils.ts +0 -1327
- package/vendor/pi-tui/src/word-navigation.ts +0 -118
- package/vendor/pi-tui/test/test-themes.ts +0 -39
- package/vendor/pi-tui/test/virtual-terminal.ts +0 -219
- /package/{src/providers → dist/cli}/models-index.json +0 -0
package/src/sextant/card-keys.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/** Sextant card keys (port #43): the key route of the ONE modal card — ←→↑↓ (and Tab) move the
|
|
2
|
-
* selection, Enter resolves it (approval: once / always / deny; question: an option, the free-text
|
|
3
|
-
* row or skip), Esc dismisses (deny / null) and the free-text row takes typing and Backspace.
|
|
4
|
-
* Ported from the user's own sextant v0.4.0 prototype app.js:1503-1510 and :1434; split out of
|
|
5
|
-
* keys.ts for the line budget. Pure state mutation, no clock: the card leaves the state before
|
|
6
|
-
* its promise settles, so a re-entrant hook never sees a stale card. */
|
|
7
|
-
|
|
8
|
-
import type { CardState, KeyEvent, SextantState } from "./types.ts";
|
|
9
|
-
|
|
10
|
-
/** false = not a card key: it falls through to the prompt (typing a follow-up while a card waits) */
|
|
11
|
-
export function onCardKey(s: SextantState, c: CardState, ev: KeyEvent): boolean {
|
|
12
|
-
const { name } = ev;
|
|
13
|
-
const n = c.kind === "approval" ? c.verdicts.length // allow · always · [all edits] · deny
|
|
14
|
-
: (c.prompt.options?.length ?? 0) + (c.prompt.allowFreeText !== false ? 1 : 0) + 1; // options · free text · skip
|
|
15
|
-
if (name === "left" || name === "up") return move(c, n, -1);
|
|
16
|
-
if (name === "right" || name === "down" || name === "tab") return move(c, n, 1);
|
|
17
|
-
if (name === "escape") { dismissCard(s); return true; }
|
|
18
|
-
if (c.kind === "approval") {
|
|
19
|
-
if (name !== "enter") return false;
|
|
20
|
-
s.card = null;
|
|
21
|
-
c.resolve(c.verdicts[c.selected] ?? "deny");
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
const opts = c.prompt.options?.length ?? 0, freeIdx = c.prompt.allowFreeText !== false ? opts : -1;
|
|
25
|
-
if (name === "enter") {
|
|
26
|
-
if (c.selected === n - 1) { dismissCard(s); return true; } // skip
|
|
27
|
-
if (c.selected !== freeIdx) { s.card = null; c.resolve({ kind: "option", index: c.selected }); return true; }
|
|
28
|
-
const t = c.freeText.trim();
|
|
29
|
-
if (t) { s.card = null; c.resolve({ kind: "text", text: t }); }
|
|
30
|
-
return true; // an empty free-text row is not an answer yet
|
|
31
|
-
}
|
|
32
|
-
if (c.selected !== freeIdx) return false;
|
|
33
|
-
if (name === "backspace") { // by code point: 😀 is one glyph, two UTF-16 units
|
|
34
|
-
c.freeText = [...c.freeText].slice(0, -1).join("");
|
|
35
|
-
return true;
|
|
36
|
-
}
|
|
37
|
-
const ch = name === "space" ? " " : ev.ch;
|
|
38
|
-
if (!ch || ev.alt) return false;
|
|
39
|
-
c.freeText += ch;
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/** wrap the selection over the card's n rows */
|
|
44
|
-
function move(c: CardState, n: number, d: -1 | 1): true {
|
|
45
|
-
const v = (c.selected + d + n) % n;
|
|
46
|
-
c.selected = v;
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** approval → deny, question → null; the card leaves the state before the promise settles */
|
|
51
|
-
export function dismissCard(s: SextantState): void {
|
|
52
|
-
const c = s.card;
|
|
53
|
-
s.card = null;
|
|
54
|
-
if (c?.kind === "approval") c.resolve("deny"); else c?.resolve(null);
|
|
55
|
-
}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
/** The seam between the context overlay and core/context-report.ts.
|
|
2
|
-
*
|
|
3
|
-
* draw-context.ts is pure over `ContextState` and never counts anything. This file is the only place that
|
|
4
|
-
* knows the report module exists: it lazily imports it (the boot rule — nothing in that dependency tree is
|
|
5
|
-
* loaded until someone opens /context), asks the LIVE runtime for the two rows a transcript cannot know,
|
|
6
|
-
* and maps the report onto the overlay's flat view.
|
|
7
|
-
*
|
|
8
|
-
* The live runtime is the whole reason this overlay is worth having. `rovecode context` on a shell has to
|
|
9
|
-
* BUILD a runtime to learn the system prompt and the tool schemas, and in a fresh session those two are
|
|
10
|
-
* most of the window; here they are already in memory, so the number is complete without constructing
|
|
11
|
-
* anything. What is still missing is MCP tools — their schemas do not exist until a server is connected —
|
|
12
|
-
* and the panel says so on its own line rather than letting a complete-looking total imply otherwise.
|
|
13
|
-
*
|
|
14
|
-
* Two numbers travel, never one. `raw` is what o200k counted; `estimated` is that corrected towards the
|
|
15
|
-
* model's own tokenizer. Presenting only the second would be presenting a corrected figure as a
|
|
16
|
-
* measurement, and someone comparing this panel against a provider's dashboard needs to know which is
|
|
17
|
-
* which. `scale.note` says where the factor came from, including when nobody has measured this model.
|
|
18
|
-
*
|
|
19
|
-
* Nothing here throws. A runtime that cannot answer, a model the catalog does not know, an empty
|
|
20
|
-
* transcript — each is a state the overlay draws, because a panel that reports on the session must not be
|
|
21
|
-
* the thing that ends it. */
|
|
22
|
-
|
|
23
|
-
import type { ContextState } from "./draw-context.ts";
|
|
24
|
-
|
|
25
|
-
/** What the live runtime can tell us that the transcript cannot. Both optional: a session whose runtime
|
|
26
|
-
* is mid-rebuild still opens the panel, and `live: false` makes the total read as a floor. */
|
|
27
|
-
export interface ContextFixed {
|
|
28
|
-
/** the system prompt a real turn would send — buildDef's, not the base alone */
|
|
29
|
-
system?: string;
|
|
30
|
-
/** rovecode's own tool schemas, serialized. MCP tools are deliberately absent. */
|
|
31
|
-
toolSchemas?: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** the runtime shape this file needs, structurally — declared here so the overlay never imports the
|
|
35
|
-
* runtime's types and so a test can hand in three lines instead of a process */
|
|
36
|
-
export interface LiveRuntime {
|
|
37
|
-
registry: { list(): { schema: unknown }[] };
|
|
38
|
-
// method syntax, and `unknown` for the prompt: the real AgentDefinition types `systemPrompt` as a string
|
|
39
|
-
// or a function over its own AgentVars, and pinning either shape here would make this file depend on the
|
|
40
|
-
// runtime's types — which is exactly what the overlay must not do. It is narrowed where it is read.
|
|
41
|
-
buildDef(ref: { provider: string; model: string; effort: "auto" }): { systemPrompt: unknown };
|
|
42
|
-
/** optional: the market overlay uses it after installing an MCP server (types.ts SextantAttach) */
|
|
43
|
-
reloadMcp?(): Promise<{ added: string[]; removed: string[]; failed: { name: string; error: string }[]; skipped: string[] }>;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Pull the two fixed rows out of a runtime that is ALREADY running.
|
|
47
|
-
*
|
|
48
|
-
* Deliberately not `createRuntime`: the CLI builds one because it has none, and paid for that decision
|
|
49
|
-
* with a session directory it had to pass in to avoid creating a stray empty session. Inside the TUI the
|
|
50
|
-
* runtime is the one the next turn will use, so this is a read, not a construction — and it cannot leave
|
|
51
|
-
* anything behind.
|
|
52
|
-
*
|
|
53
|
-
* `buildDef`, not `systemPrompt()`: the prompt a run actually sends is the base plus the model profile,
|
|
54
|
-
* the design section, and — for a model without native tool calling — the tool block. Asking for the base
|
|
55
|
-
* alone under-counts the largest fixed row by everything that makes it large. */
|
|
56
|
-
export function fixedFrom(rt: LiveRuntime | null | undefined, ref: { provider: string; model: string }): ContextFixed {
|
|
57
|
-
if (!rt) return {};
|
|
58
|
-
try {
|
|
59
|
-
const schemas = rt.registry.list().map((t) => t.schema);
|
|
60
|
-
const def = rt.buildDef({ ...ref, effort: "auto" });
|
|
61
|
-
const sp = def.systemPrompt;
|
|
62
|
-
const system = typeof sp === "string" ? sp : typeof sp === "function" ? String((sp as (x: Record<string, unknown>) => unknown)({})) : undefined;
|
|
63
|
-
if (system === undefined) return {};
|
|
64
|
-
return { system, toolSchemas: JSON.stringify(schemas) };
|
|
65
|
-
} catch {
|
|
66
|
-
// a runtime that cannot describe itself is a panel that says so, not a crashed frame
|
|
67
|
-
return {};
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** the report module's shape, structurally: this file must compile and be testable without importing it */
|
|
72
|
-
interface Slice { label: string; tokens: number; share: number; note?: string }
|
|
73
|
-
interface Drift { estimated: number; reported: number; delta: number; fraction: number; beyondTolerance: boolean }
|
|
74
|
-
interface Report {
|
|
75
|
-
model: { provider: string; model: string };
|
|
76
|
-
window?: number;
|
|
77
|
-
estimated: number;
|
|
78
|
-
corrected: number;
|
|
79
|
-
scale: { factor: number; measured: boolean; note: string };
|
|
80
|
-
slices: Slice[];
|
|
81
|
-
remaining?: number;
|
|
82
|
-
fraction?: number;
|
|
83
|
-
nearLimit?: boolean;
|
|
84
|
-
drift?: Drift;
|
|
85
|
-
totals: { inputTokens?: number; outputTokens?: number; cacheReadTokens?: number; cacheWriteTokens?: number };
|
|
86
|
-
costUsd?: number;
|
|
87
|
-
unpricedTurns: number;
|
|
88
|
-
images: number;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export interface ContextLoadInput {
|
|
92
|
-
messages: readonly unknown[];
|
|
93
|
-
current: { provider: string; model: string };
|
|
94
|
-
/** window + pricing, however the caller has them */
|
|
95
|
-
lookup: (r: { provider: string; model: string }) => unknown;
|
|
96
|
-
fixed: ContextFixed;
|
|
97
|
-
/** the tolerance drift is judged against; printed by the panel, never assumed by a reader */
|
|
98
|
-
tolerance?: number;
|
|
99
|
-
/** tests inject the report function; production lazily imports the real one */
|
|
100
|
-
report?: (input: unknown) => Report;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** the fraction past which drift is called out rather than merely shown. Matches core/context-report.ts;
|
|
104
|
-
* it travels in the state so the panel can print it instead of asserting a number the reader cannot see. */
|
|
105
|
-
const TOLERANCE = 0.05;
|
|
106
|
-
|
|
107
|
-
/** Build the overlay's state. Never throws: every failure becomes something the panel can draw. */
|
|
108
|
-
export async function loadContext(input: ContextLoadInput): Promise<Omit<ContextState, "scroll">> {
|
|
109
|
-
const tolerance = input.tolerance ?? TOLERANCE;
|
|
110
|
-
const model = `${input.current.provider}/${input.current.model}`;
|
|
111
|
-
|
|
112
|
-
let report: Report;
|
|
113
|
-
try {
|
|
114
|
-
const fn = input.report ?? (await import("../core/context-report.ts")).contextReport as unknown as (i: unknown) => Report;
|
|
115
|
-
report = fn({
|
|
116
|
-
messages: input.messages,
|
|
117
|
-
current: input.current,
|
|
118
|
-
lookup: input.lookup,
|
|
119
|
-
...(input.fixed.system !== undefined ? { system: input.fixed.system } : {}),
|
|
120
|
-
...(input.fixed.toolSchemas !== undefined ? { toolSchemas: input.fixed.toolSchemas } : {}),
|
|
121
|
-
});
|
|
122
|
-
} catch {
|
|
123
|
-
// the panel opens and says it has nothing, which is more useful than a frame that died counting
|
|
124
|
-
return {
|
|
125
|
-
model, raw: 0, estimated: 0, scale: { factor: 1, measured: false, note: "the context report could not be built" },
|
|
126
|
-
slices: [], images: 0, billed: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
127
|
-
unpricedTurns: 0, live: false, tolerance,
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const t = report.totals;
|
|
132
|
-
return {
|
|
133
|
-
model,
|
|
134
|
-
...(report.window !== undefined ? { window: report.window } : {}),
|
|
135
|
-
// `estimated` on the panel is the CORRECTED number, because that is what the window and the bill are
|
|
136
|
-
// computed from; `raw` carries what o200k counted so the panel can show both
|
|
137
|
-
raw: report.estimated,
|
|
138
|
-
estimated: report.corrected,
|
|
139
|
-
scale: report.scale,
|
|
140
|
-
...(report.remaining !== undefined ? { remaining: report.remaining } : {}),
|
|
141
|
-
...(report.fraction !== undefined ? { fraction: report.fraction } : {}),
|
|
142
|
-
...(report.nearLimit !== undefined ? { nearLimit: report.nearLimit } : {}),
|
|
143
|
-
slices: report.slices.map((s) => ({ label: s.label, tokens: s.tokens, share: s.share, ...(s.note ? { note: s.note } : {}) })),
|
|
144
|
-
images: report.images,
|
|
145
|
-
...(report.drift ? { drift: { ...report.drift } } : {}),
|
|
146
|
-
billed: {
|
|
147
|
-
input: t.inputTokens ?? 0, output: t.outputTokens ?? 0,
|
|
148
|
-
cacheRead: t.cacheReadTokens ?? 0, cacheWrite: t.cacheWriteTokens ?? 0,
|
|
149
|
-
},
|
|
150
|
-
...(report.costUsd !== undefined ? { costUsd: report.costUsd } : {}),
|
|
151
|
-
unpricedTurns: report.unpricedTurns,
|
|
152
|
-
// "live" is about the two rows a transcript cannot know. The system prompt is the one that matters:
|
|
153
|
-
// tool schemas can legitimately be an empty list, so their absence proves nothing.
|
|
154
|
-
live: input.fixed.system !== undefined,
|
|
155
|
-
tolerance,
|
|
156
|
-
};
|
|
157
|
-
}
|
|
@@ -1,350 +0,0 @@
|
|
|
1
|
-
/** The CREW CARD (Berkay's pick, 2026-09-07): the plan panel's crew section as titled cards — one card per
|
|
2
|
-
* WORKFLOW rather than one row per task, with a chip per agent showing which CLI opened.
|
|
3
|
-
*
|
|
4
|
-
* crew 3 working
|
|
5
|
-
* test-project-scan ›
|
|
6
|
-
* 3 agents · 01s
|
|
7
|
-
* ▪▪▫ codex claude codex
|
|
8
|
-
*
|
|
9
|
-
* WHAT A WORKFLOW IS HERE. rovecode has no workflow concept and this file does not invent one: `s.crew` is a flat
|
|
10
|
-
* TaskInfo[], and the only grouping that exists in the data is "tasks started under the same run" — TaskManager
|
|
11
|
-
* stamps `batch` / `batchLabel` from bindRun (core/tasks.ts, nimbus-5f's slice), which every surface already calls
|
|
12
|
-
* once per run. No heuristic: no time buckets, no label-prefix matching. A task with no batch (started outside a
|
|
13
|
-
* bound run) gets its own single-task card titled by its own label, which is exactly what the flat list showed.
|
|
14
|
-
*
|
|
15
|
-
* THE CHIP RULE — a chip must never claim a CLI ran when it did not:
|
|
16
|
-
* - queued is a HOLLOW chip and a dim name; only running/done chips are filled. "codex is queued" and "codex is
|
|
17
|
-
* working" cannot look the same, because the difference is whether a process exists.
|
|
18
|
-
* - only an EXTERNAL lane (TaskInfo.kind "external") shows a CLI name, from its `lane` adapter id. One of our own
|
|
19
|
-
* subagents shows its AGENT name; if such a task were ever named after an adapter (the ids are reserved in
|
|
20
|
-
* tasks.ts, so this is a defence rather than a case) it renders as `agent:<name>` and never as a bare CLI name.
|
|
21
|
-
*
|
|
22
|
-
* WHAT GOES FIRST WHEN IT DOES NOT FIT (the panel is 32 cells; stated rather than discovered by clipping):
|
|
23
|
-
* 1. the blank row between cards — spacing carries no information;
|
|
24
|
-
* 2. the names row collapses: repeats become counts (`codex ×2`), then a `+N` tail. Whole names are dropped, never
|
|
25
|
-
* clipped mid-word — half a CLI's name is a different CLI's name;
|
|
26
|
-
* 3. the title is truncated with an ellipsis, at a word boundary when there is one;
|
|
27
|
-
* 4. the chips cap at what fits and the rest become `+N`;
|
|
28
|
-
* 5. whole cards go, newest kept, with a `+N more` footer.
|
|
29
|
-
* NEVER dropped: the agent count and the clock. A card that cannot show those two is not drawn at all — a title
|
|
30
|
-
* alone would say a workflow exists without saying whether anything is running.
|
|
31
|
-
*
|
|
32
|
-
* PURE: `now` is a parameter (the clock and the card's age), no timers, no process access, no state writes. The
|
|
33
|
-
* painter at the bottom is the only part that touches a screen. */
|
|
34
|
-
|
|
35
|
-
import type { TaskInfo } from "../core/tasks.ts";
|
|
36
|
-
import { isAdapterId } from "../lanes/types.ts";
|
|
37
|
-
import { laneElapsed } from "./draw-agents.ts";
|
|
38
|
-
import { fmtK } from "./model.ts";
|
|
39
|
-
import { st } from "./theme.ts";
|
|
40
|
-
import { ATTR, type ScreenLike, type Seg, type Theme } from "./types.ts";
|
|
41
|
-
|
|
42
|
-
/** TaskInfo as the card reads it. `batch` / `batchLabel` / `progress` / `files` are all on TaskInfo now (core/tasks.ts);
|
|
43
|
-
* the alias stays as this module's own name for what it consumes. */
|
|
44
|
-
export type CrewTask = TaskInfo;
|
|
45
|
-
|
|
46
|
-
export type CardTone = "fg" | "fg2" | "muted" | "dim" | "ok" | "err" | "accent" | "warn";
|
|
47
|
-
export interface CardSpan { text: string; tone: CardTone; bold?: boolean }
|
|
48
|
-
/** one painted row; `right` is anchored to the card's right edge (the `›` affordance) */
|
|
49
|
-
export interface CardLine { spans: CardSpan[]; right?: CardSpan }
|
|
50
|
-
|
|
51
|
-
export interface CrewGroup {
|
|
52
|
-
/** the batch id, or `task:<id>` for a task that has none */
|
|
53
|
-
key: string;
|
|
54
|
-
label: string;
|
|
55
|
-
tasks: CrewTask[];
|
|
56
|
-
/** min(startedAt ?? createdAt) over the group */
|
|
57
|
-
startedAt: number;
|
|
58
|
-
/** max(finishedAt) when EVERY task has finished; undefined while any is live (the clock still runs) */
|
|
59
|
-
finishedAt?: number;
|
|
60
|
-
working: number;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const oneLine = (s: string): string => s.replace(/\s+/g, " ").trim();
|
|
64
|
-
const cps = (s: string): string[] => [...s];
|
|
65
|
-
const width = (s: string): number => cps(s).length;
|
|
66
|
-
|
|
67
|
-
// ------------------------------------------------------------------ grouping
|
|
68
|
-
|
|
69
|
-
/** Group by `batch`, first-seen order kept (the crew list is already in start order). A task without a batch is its
|
|
70
|
-
* own group. The label is the batch label when the surface set one, else the first task's label — never invented. */
|
|
71
|
-
export function groupCrew(crew: readonly CrewTask[]): CrewGroup[] {
|
|
72
|
-
const out: CrewGroup[] = [];
|
|
73
|
-
const byKey = new Map<string, CrewGroup>();
|
|
74
|
-
for (const t of crew) {
|
|
75
|
-
const key = t.batch ?? `task:${t.id}`;
|
|
76
|
-
let g = byKey.get(key);
|
|
77
|
-
if (g === undefined) {
|
|
78
|
-
g = { key, label: oneLine(t.batchLabel ?? t.label) || "(no label)", tasks: [], startedAt: t.startedAt ?? t.createdAt, working: 0 };
|
|
79
|
-
byKey.set(key, g);
|
|
80
|
-
out.push(g);
|
|
81
|
-
}
|
|
82
|
-
g.tasks.push(t);
|
|
83
|
-
g.startedAt = Math.min(g.startedAt, t.startedAt ?? t.createdAt);
|
|
84
|
-
}
|
|
85
|
-
for (const g of out) {
|
|
86
|
-
g.working = g.tasks.filter((t) => t.status === "queued" || t.status === "running").length;
|
|
87
|
-
const ends = g.tasks.map((t) => t.finishedAt);
|
|
88
|
-
if (ends.every((e): e is number => e !== undefined)) g.finishedAt = Math.max(...ends);
|
|
89
|
-
}
|
|
90
|
-
return out;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** the card's age: the WHOLE workflow's span, live until every task in it has finished */
|
|
94
|
-
export function groupElapsed(g: CrewGroup, now: number): number {
|
|
95
|
-
if (g.finishedAt !== undefined) return Math.max(0, g.finishedAt - g.startedAt);
|
|
96
|
-
return Math.max(0, now - g.startedAt, ...g.tasks.map((t) => laneElapsed(t, now)));
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/** `01s` · `04m` · `1h02m` — the compact age from the card Berkay picked; mm:ss (laneClock) is the per-task form */
|
|
100
|
-
export function compactAge(ms: number): string {
|
|
101
|
-
const s = Math.max(0, Math.floor(ms / 1000));
|
|
102
|
-
if (s < 60) return `${String(s).padStart(2, "0")}s`;
|
|
103
|
-
const m = Math.floor(s / 60);
|
|
104
|
-
if (m < 60) return `${String(m).padStart(2, "0")}m`;
|
|
105
|
-
return `${Math.floor(m / 60)}h${String(m % 60).padStart(2, "0")}m`;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// ------------------------------------------------------------------ chips
|
|
109
|
-
|
|
110
|
-
/** ▫ queued (nothing has run) · ▪ running · ◆ done · × failed · · cancelled */
|
|
111
|
-
export function chipGlyph(status: TaskInfo["status"]): string {
|
|
112
|
-
switch (status) {
|
|
113
|
-
case "queued": return "▫";
|
|
114
|
-
case "running": return "▪";
|
|
115
|
-
case "done": return "◆";
|
|
116
|
-
case "failed": return "×";
|
|
117
|
-
default: return "·";
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
export function chipTone(status: TaskInfo["status"]): CardTone {
|
|
121
|
-
switch (status) {
|
|
122
|
-
case "queued": return "dim";
|
|
123
|
-
case "running": return "accent";
|
|
124
|
-
case "done": return "ok";
|
|
125
|
-
case "failed": return "err";
|
|
126
|
-
default: return "muted";
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/** the name under a chip: a CLI id ONLY for an external lane; our own agents show their agent name. An external
|
|
131
|
-
* lane with no adapter id recorded says `cli?` rather than borrowing a name we do not have. */
|
|
132
|
-
export function chipName(t: CrewTask): string {
|
|
133
|
-
if (t.kind === "external") return t.lane ?? "cli?";
|
|
134
|
-
return isAdapterId(t.agent) ? `agent:${t.agent}` : t.agent;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/** the chip row's glyphs, one per task in order; `+N` when more tasks than fit in `w` cells */
|
|
138
|
-
export function chipRow(tasks: readonly CrewTask[], w: number): CardSpan[] {
|
|
139
|
-
if (w <= 0 || tasks.length === 0) return [];
|
|
140
|
-
const spans: CardSpan[] = [];
|
|
141
|
-
let used = 0;
|
|
142
|
-
for (let i = 0; i < tasks.length; i++) {
|
|
143
|
-
const rest = tasks.length - i;
|
|
144
|
-
const tail = rest > 1 ? `+${rest}` : "";
|
|
145
|
-
if (used + 1 + width(tail) > w && i > 0) { spans.push({ text: `+${rest}`, tone: "dim" }); return spans; }
|
|
146
|
-
if (used + 1 > w) return spans;
|
|
147
|
-
const t = tasks[i]!;
|
|
148
|
-
spans.push({ text: chipGlyph(t.status), tone: chipTone(t.status), bold: t.status === "running" });
|
|
149
|
-
used += 1;
|
|
150
|
-
}
|
|
151
|
-
return spans;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/** The names, collapsed to fit: `codex claude codex` → `codex ×2 claude` when repeats cost less, then a `+N` tail.
|
|
155
|
-
* Whole names only — a clipped name is a lie about which CLI ran. Empty when nothing fits. */
|
|
156
|
-
export function nameRow(tasks: readonly CrewTask[], w: number): CardSpan[] {
|
|
157
|
-
if (w <= 0 || tasks.length === 0) return [];
|
|
158
|
-
const runs: { name: string; count: number; tone: CardTone }[] = [];
|
|
159
|
-
for (const t of tasks) {
|
|
160
|
-
const name = chipName(t), tone = chipTone(t.status);
|
|
161
|
-
const last = runs[runs.length - 1];
|
|
162
|
-
if (last !== undefined && last.name === name && last.tone === tone) last.count++;
|
|
163
|
-
else runs.push({ name, count: 1, tone });
|
|
164
|
-
}
|
|
165
|
-
const label = (r: { name: string; count: number }): string => (r.count > 1 ? `${r.name} ×${r.count}` : r.name);
|
|
166
|
-
const spans: CardSpan[] = [];
|
|
167
|
-
let used = 0;
|
|
168
|
-
for (let i = 0; i < runs.length; i++) {
|
|
169
|
-
const r = runs[i]!;
|
|
170
|
-
const text = label(r);
|
|
171
|
-
// the tail counts the AGENTS still unnamed, not the runs: "+2" when three agents are hidden would be a wrong number
|
|
172
|
-
const left = runs.slice(i).reduce((n, x) => n + x.count, 0);
|
|
173
|
-
const tail = ` +${left}`;
|
|
174
|
-
const sep = spans.length > 0 ? 1 : 0;
|
|
175
|
-
const more = i < runs.length - 1 ? width(` +${left - r.count}`) : 0;
|
|
176
|
-
if (used + sep + width(text) + more > w) {
|
|
177
|
-
if (spans.length > 0 && used + width(tail) <= w) spans.push({ text: tail, tone: "dim" });
|
|
178
|
-
return spans;
|
|
179
|
-
}
|
|
180
|
-
if (sep) { spans.push({ text: " ", tone: "dim" }); used += 1; }
|
|
181
|
-
spans.push({ text, tone: r.tone });
|
|
182
|
-
used += width(text);
|
|
183
|
-
}
|
|
184
|
-
return spans;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// ------------------------------------------------------------------ card rows
|
|
188
|
-
|
|
189
|
-
/** ellipsis truncation at a word boundary when there is one in the last third of the space */
|
|
190
|
-
export function fitTitle(title: string, w: number): string {
|
|
191
|
-
const c = cps(oneLine(title));
|
|
192
|
-
if (w <= 0) return "";
|
|
193
|
-
if (c.length <= w) return c.join("");
|
|
194
|
-
if (w === 1) return "…";
|
|
195
|
-
const head = c.slice(0, w - 1).join("");
|
|
196
|
-
const cut = head.lastIndexOf(" ");
|
|
197
|
-
return (cut >= Math.floor((w - 1) * 0.67) ? head.slice(0, cut) : head) + "…";
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/** the card: title (+ `›`), `N agents · age`, then the chips and the names on one row. The meta row is the
|
|
201
|
-
* honesty core — it is never dropped, so a card is only produced when `w` can hold it. */
|
|
202
|
-
export function cardLines(g: CrewGroup, w: number, now: number): CardLine[] {
|
|
203
|
-
const count = `${g.tasks.length} agent${g.tasks.length === 1 ? "" : "s"}`;
|
|
204
|
-
const meta = `${count} · ${compactAge(groupElapsed(g, now))}`;
|
|
205
|
-
if (w < width(meta)) return [];
|
|
206
|
-
const lines: CardLine[] = [];
|
|
207
|
-
const arrow = w >= width(meta) + 2 ? { text: "›", tone: "dim" as CardTone } : undefined;
|
|
208
|
-
lines.push({ spans: [{ text: fitTitle(g.label, w - (arrow ? 2 : 0)), tone: g.working > 0 ? "fg" : "fg2", bold: g.working > 0 }], ...(arrow ? { right: arrow } : {}) });
|
|
209
|
-
lines.push({ spans: [{ text: meta, tone: "dim" }] });
|
|
210
|
-
const chips = chipRow(g.tasks, Math.max(0, Math.min(g.tasks.length + 2, Math.floor(w / 2))));
|
|
211
|
-
const chipW = chips.reduce((n, s) => n + width(s.text), 0);
|
|
212
|
-
const names = nameRow(g.tasks, w - chipW - 2);
|
|
213
|
-
if (chips.length > 0) lines.push({ spans: names.length > 0 ? [...chips, { text: " ", tone: "dim" }, ...names] : chips });
|
|
214
|
-
const progress = progressRow(g, w);
|
|
215
|
-
if (progress.length > 0) lines.push({ spans: progress });
|
|
216
|
-
return lines;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/** THE PROGRESS ROW — `wrote 4 files · 12 calls · 4.2k`, summed over a workflow's tasks, and it is the second thing
|
|
220
|
-
* dropped at a narrow width (after the blank separator): the chips and the CLI names are what the card exists for.
|
|
221
|
-
* Four rules, all of them about not overstating what a CLI did (lanes/progress.ts, nimbus-24's measurements):
|
|
222
|
-
* - a RUNNING lane with nothing confirmed shows no file segment at all. `filesWritten` is what the CLI has
|
|
223
|
-
* confirmed so far, and one of the four (agy) confirms nothing until it ends — it sits at zero for minutes and
|
|
224
|
-
* then jumps to the measured count. "wrote 0 files" for a lane that is writing would be a wrong statement, and
|
|
225
|
-
* treating that zero as a stall would be wrong about exactly one CLI.
|
|
226
|
-
* - a FINISHED task's list is the worktree diff, so there zero is a measurement and is worth printing.
|
|
227
|
-
* - a task whose patch never reached the tree did not WRITE anything the person has: its count is reported as
|
|
228
|
-
* `discarded` / `so far`, never as `wrote`. The signal is `progress.applied` (tri-state, written by the code
|
|
229
|
-
* that does the applying): absent = nothing offered to the tree yet, true = merged back, false = the writes
|
|
230
|
-
* stayed in a worktree that was deleted. NOT `patchLines`, and not the status either: a lane that finishes
|
|
231
|
-
* cleanly whose patch git refuses — a concurrent task touched the same lines — still reports ok AND gets a
|
|
232
|
-
* patchLines, so both of those would print `wrote 4 files` about a tree that has none of them (nimbus-24's
|
|
233
|
-
* lanes-job tests cover the case). One of OUR isolated children has no progress object, and orchestrator.ts
|
|
234
|
-
* has the same hole — so the signal there is `files`, which tasks.ts sets only for a patch that applied
|
|
235
|
-
* (5f gated it on progress.applied, else the runner's own "patch-apply-failed" marker). `patchLines` is a
|
|
236
|
-
* SIZE and never a verdict; the one thing it still settles is the empty patch, where 0 lines means there was
|
|
237
|
-
* nothing to apply and nothing that could fail.
|
|
238
|
-
* - `usage` ABSENT is not zero. A lane we could not read reports nothing; a lane that burned nothing reports
|
|
239
|
-
* zeros. Absent contributes no token segment; explicit zeros show `0`.
|
|
240
|
-
* `calls` counts every tool the CLI reported, reads included, so the word stays `calls`. Only lanes report them,
|
|
241
|
-
* so a mixed workflow's row says what its lanes did without implying the native agents did nothing. */
|
|
242
|
-
/** Did this task's work reach the person's tree? `true` landed · `false` written and thrown away · `undefined`
|
|
243
|
-
* nothing offered yet. A lane answers from `progress.applied` (the code that applies, not the code beside it); one
|
|
244
|
-
* of our own children answers from `files`, which exists only for a patch that applied — except for the empty
|
|
245
|
-
* patch, where `patchLines === 0` means there was nothing to apply, and that counts as landed. */
|
|
246
|
-
export function landedOf(t: CrewTask): boolean | undefined {
|
|
247
|
-
if (t.progress !== undefined && "applied" in t.progress) return t.progress.applied;
|
|
248
|
-
if (t.status === "running" || t.status === "queued") return undefined;
|
|
249
|
-
if (t.files !== undefined) return true;
|
|
250
|
-
return t.status === "done" && t.patchLines === 0;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export function progressRow(g: CrewGroup, w: number): CardSpan[] {
|
|
254
|
-
let calls = 0, applied = 0, pending = 0, discarded = 0, tokens = 0, sawUsage = false;
|
|
255
|
-
for (const t of g.tasks) {
|
|
256
|
-
calls += t.progress?.toolCalls ?? 0;
|
|
257
|
-
const n = t.files?.length ?? t.progress?.filesWrittenTotal ?? 0;
|
|
258
|
-
const landed = landedOf(t);
|
|
259
|
-
if (landed === true) applied += n;
|
|
260
|
-
else if (landed === undefined) pending += n;
|
|
261
|
-
else discarded += n;
|
|
262
|
-
const u = t.progress?.usage ?? t.usage;
|
|
263
|
-
if (u !== undefined) { sawUsage = true; tokens += u.input + u.output; }
|
|
264
|
-
}
|
|
265
|
-
const parts: { text: string; tone: CardTone }[] = [];
|
|
266
|
-
if (applied > 0) parts.push({ text: `wrote ${applied} file${applied === 1 ? "" : "s"}`, tone: "ok" });
|
|
267
|
-
if (pending > 0) parts.push({ text: `${pending} file${pending === 1 ? "" : "s"} so far`, tone: "dim" });
|
|
268
|
-
if (discarded > 0) parts.push({ text: `${discarded} discarded`, tone: "muted" });
|
|
269
|
-
// every task settled and nothing landed: that zero IS the measurement, and saying so beats an empty row
|
|
270
|
-
const merged = g.tasks.some((t) => landedOf(t) === true);
|
|
271
|
-
if (parts.length === 0 && g.working === 0 && merged) parts.push({ text: "wrote 0 files", tone: "dim" });
|
|
272
|
-
if (calls > 0) parts.push({ text: `${calls} call${calls === 1 ? "" : "s"}`, tone: "dim" });
|
|
273
|
-
if (sawUsage) parts.push({ text: fmtK(tokens), tone: "dim" });
|
|
274
|
-
if (parts.length === 0) return [];
|
|
275
|
-
const spans: CardSpan[] = [];
|
|
276
|
-
let used = 0;
|
|
277
|
-
for (const part of parts) {
|
|
278
|
-
const sep = spans.length > 0 ? 3 : 0; // " · "
|
|
279
|
-
if (used + sep + width(part.text) > w) break;
|
|
280
|
-
if (sep) { spans.push({ text: " · ", tone: "dim" }); used += 3; }
|
|
281
|
-
spans.push(part);
|
|
282
|
-
used += width(part.text);
|
|
283
|
-
}
|
|
284
|
-
return spans;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
export interface CrewCardBlock {
|
|
288
|
-
lines: CardLine[];
|
|
289
|
-
/** cards that did not fit — the `+N more` footer is already the last line when this is > 0 */
|
|
290
|
-
hidden: number;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/** The card order: WORKING workflows first, newest of them at the top, then the settled ones newest first. The
|
|
294
|
-
* section's header says "2 working"; a panel that then shows two finished cards and hides the running one is
|
|
295
|
-
* answering a different question from the one it just asked. Within each half the newest card is first because
|
|
296
|
-
* the crew list is start-ordered, so its tail is the live work. */
|
|
297
|
-
export function crewCardOrder(groups: readonly CrewGroup[]): CrewGroup[] {
|
|
298
|
-
const newestFirst = [...groups].reverse();
|
|
299
|
-
return [...newestFirst.filter((g) => g.working > 0), ...newestFirst.filter((g) => g.working === 0)];
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/** Pack the cards into `rows` rows in crewCardOrder. Blank separators are dropped before any card is. */
|
|
303
|
-
export function crewCardBlock(groups: readonly CrewGroup[], w: number, rows: number, now: number): CrewCardBlock {
|
|
304
|
-
if (rows <= 0 || w <= 0 || groups.length === 0) return { lines: [], hidden: groups.length };
|
|
305
|
-
const order = crewCardOrder(groups);
|
|
306
|
-
const cards = order.map((g) => cardLines(g, w, now)).filter((c) => c.length > 0);
|
|
307
|
-
const pack = (gap: boolean): CrewCardBlock & { shown: number } => {
|
|
308
|
-
const lines: CardLine[] = [];
|
|
309
|
-
let used = 0, shown = 0;
|
|
310
|
-
for (const card of cards) {
|
|
311
|
-
const need = card.length + (gap && shown > 0 ? 1 : 0);
|
|
312
|
-
const footer = cards.length - shown - 1 > 0 ? 1 : 0;
|
|
313
|
-
if (used + need + footer > rows) break;
|
|
314
|
-
if (gap && shown > 0) { lines.push({ spans: [] }); used++; }
|
|
315
|
-
lines.push(...card);
|
|
316
|
-
used += card.length;
|
|
317
|
-
shown++;
|
|
318
|
-
}
|
|
319
|
-
const hidden = groups.length - shown;
|
|
320
|
-
if (hidden > 0 && shown > 0 && used < rows) lines.push({ spans: [{ text: `+${hidden} more`, tone: "dim" }] });
|
|
321
|
-
return { lines: shown > 0 ? lines : [], hidden: shown > 0 ? hidden : groups.length, shown };
|
|
322
|
-
};
|
|
323
|
-
// separators are spacing; a card is information. Take the spaced packing only when it costs no card.
|
|
324
|
-
const spaced = pack(true), dense = pack(false);
|
|
325
|
-
return dense.shown > spaced.shown ? { lines: dense.lines, hidden: dense.hidden } : { lines: spaced.lines, hidden: spaced.hidden };
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/** rows a full render of these groups would take (cards + separators), for a panel deciding its budget */
|
|
329
|
-
export function crewCardHeight(groups: readonly CrewGroup[], w: number, now: number): number {
|
|
330
|
-
const cards = groups.map((g) => cardLines(g, w, now)).filter((c) => c.length > 0);
|
|
331
|
-
return cards.reduce((n, c) => n + c.length, 0) + Math.max(0, cards.length - 1);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// ------------------------------------------------------------------ painter
|
|
335
|
-
|
|
336
|
-
const TONE: Record<CardTone, keyof Theme> = { fg: "fg", fg2: "fg2", muted: "muted", dim: "dim", ok: "ok", err: "err", accent: "accent", warn: "warn" };
|
|
337
|
-
|
|
338
|
-
/** paint `lines` at (x, y) in `w` cells — the only impure part, and it writes nothing but those rows */
|
|
339
|
-
export function paintCrewCards(scr: ScreenLike, x: number, y: number, w: number, lines: readonly CardLine[], theme: Theme): void {
|
|
340
|
-
lines.forEach((line, i) => {
|
|
341
|
-
const row = y + i;
|
|
342
|
-
if (line.right !== undefined) {
|
|
343
|
-
const r = line.right;
|
|
344
|
-
scr.put(x + w - width(r.text), row, r.text, st(theme[TONE[r.tone]] as number), width(r.text));
|
|
345
|
-
}
|
|
346
|
-
if (line.spans.length === 0) return;
|
|
347
|
-
const segs: Seg[] = line.spans.map((s) => [s.text, st(theme[TONE[s.tone]] as number, -1, s.bold ? ATTR.BOLD : 0)]);
|
|
348
|
-
scr.text(x, row, segs, w - (line.right ? width(line.right.text) + 1 : 0));
|
|
349
|
-
});
|
|
350
|
-
}
|