rovecode 0.3.2 → 0.4.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +512 -0
- package/README.md +33 -45
- 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 +38 -11
- 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/lanes/opencode.ts
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/** opencode lane adapter (#47) — agentic-clis.md §2 "opencode · opencode run", flags verified 2026-09-02:
|
|
2
|
-
* opencode run "<goal>" --format json --dir <dir> (+ -s <session> · + --attach <url> · + -m <model>)
|
|
3
|
-
* LIVE-VERIFIED 2026-09-03 against opencode 1.18.23 on Windows (fixture opencode-live-run.jsonl): `--format
|
|
4
|
-
* json` prints FLAT lines `{type, timestamp, sessionID, part}` where `type` is the part kind — `step_start`,
|
|
5
|
-
* `text`, `tool_use`, `step_finish` (reasoning parts: same shape, not yet seen live) — and `part` is the SDK
|
|
6
|
-
* part object (`part.type` step-start | text | tool | step-finish). Text parts arrive once, complete
|
|
7
|
-
* (`time.end`); a tool part carries `tool`, `state.{status,input,output,metadata}`; a step-finish part
|
|
8
|
-
* carries `reason` ("tool-calls" = more steps follow, "stop" = the turn is over — the process then exits 0,
|
|
9
|
-
* there is NO idle event) plus `tokens{input,output,cache{read,write}}` and `cost` (per step: summed by the
|
|
10
|
-
* runner). A provider that cannot be reached prints NOTHING (opencode retries it in its own log file) —
|
|
11
|
-
* the job's silent-lane note and the wall-clock cutter are the only signals. The `{type:"message.part.*",
|
|
12
|
-
* properties:{part}}` / `session.idle` / `permission.*` shapes below are the SDK `client.event.subscribe()`
|
|
13
|
-
* stream (synthetic fixture opencode.jsonl, the future `opencode serve` port) — kept, not live-verified.
|
|
14
|
-
* Permissions live in opencode's own config (`permission: "allow"` on the verified box auto-approved the
|
|
15
|
-
* write; an ask under `--format json` was not observed). SIGINT ends the turn → interruptFirst. */
|
|
16
|
-
|
|
17
|
-
import type { AgentAdapter, LaneCommand, LaneEvent, LaneOpts, LaneParseState, LaneTask } from "./types.ts";
|
|
18
|
-
import { clip, num, obj, parseJsonLine, str, toolEvent, usageFrom } from "./events.ts";
|
|
19
|
-
|
|
20
|
-
function argv(prompt: string, opts: LaneOpts, session?: string): LaneCommand {
|
|
21
|
-
const args = ["run", prompt, "--format", "json", "--dir", opts.cwd];
|
|
22
|
-
if (session) args.push("-s", session);
|
|
23
|
-
if (opts.attach) args.push("--attach", opts.attach);
|
|
24
|
-
if (opts.model) args.push("-m", opts.model);
|
|
25
|
-
return { bin: "opencode", args, cwd: opts.cwd };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** the flat `run --format json` line types (1.18.23) — each carries the part under `part` */
|
|
29
|
-
const FLAT: ReadonlySet<string> = new Set(["step_start", "step-start", "text", "reasoning", "tool_use", "tool", "step_finish", "step-finish"]);
|
|
30
|
-
|
|
31
|
-
type Seen = Record<string, string>;
|
|
32
|
-
const seen = (st: LaneParseState): Seen => (st.scratch["parts"] ??= {}) as Seen;
|
|
33
|
-
const ref = (st: LaneParseState): { sessionId?: string } => (st.sessionId ? { sessionId: st.sessionId } : {});
|
|
34
|
-
|
|
35
|
-
function part(p: Record<string, unknown>, st: LaneParseState): LaneEvent[] {
|
|
36
|
-
const sid = str(p["sessionID"]) ?? str(p["sessionId"]);
|
|
37
|
-
if (sid) st.sessionId = sid;
|
|
38
|
-
const type = str(p["type"]);
|
|
39
|
-
switch (type) {
|
|
40
|
-
case "text": case "reasoning": {
|
|
41
|
-
// parts are re-sent as they grow: emit a text part once, when it is finished (time.end) or
|
|
42
|
-
// carries no timing at all, and never the same text twice for one part id
|
|
43
|
-
const text = (str(p["text"]) ?? "").trim();
|
|
44
|
-
const time = obj(p["time"]);
|
|
45
|
-
if (!text || (time && time["end"] === undefined)) return [];
|
|
46
|
-
const id = str(p["id"]) ?? text;
|
|
47
|
-
if (seen(st)[id] === text) return [];
|
|
48
|
-
seen(st)[id] = text;
|
|
49
|
-
if (type === "reasoning") return [{ kind: "log", text: `thinking: ${clip(text, 160)}` }];
|
|
50
|
-
st.lastText = text;
|
|
51
|
-
return [{ kind: "log", text }];
|
|
52
|
-
}
|
|
53
|
-
case "tool": {
|
|
54
|
-
const state = obj(p["state"]);
|
|
55
|
-
const status = str(state?.["status"]);
|
|
56
|
-
const name = str(p["tool"]) ?? "tool";
|
|
57
|
-
if (status === "error") return [{ kind: "log", text: `tool ${name} error: ${clip(str(state?.["error"]) ?? str(state?.["output"]), 120)}` }];
|
|
58
|
-
if (status !== "completed") return [];
|
|
59
|
-
const exit = num(obj(state?.["metadata"])?.["exit"]);
|
|
60
|
-
// one tool part is updated repeatedly (running → completed, fixture opencode.jsonl lines 2-3 share
|
|
61
|
-
// callID call_1): the CLI's own callID is the dedupe key, and `completed` is what makes a write real
|
|
62
|
-
const callId = str(p["callID"]) ?? str(p["id"]);
|
|
63
|
-
return [toolEvent(name, obj(state?.["input"]), clip(str(state?.["output"]), 120) || undefined, exit, { wrote: true, ...(callId !== undefined ? { callId } : {}) })];
|
|
64
|
-
}
|
|
65
|
-
case "step-finish": case "step_finish": {
|
|
66
|
-
const usage = usageFrom(p["tokens"], p);
|
|
67
|
-
const out: LaneEvent[] = usage ? [{ kind: "usage", usage }] : [];
|
|
68
|
-
// live: "tool-calls" → another step follows; "stop" → the turn is complete (the CLI exits right after)
|
|
69
|
-
const reason = str(p["reason"]);
|
|
70
|
-
if (reason === "stop") out.push({ kind: "done", summary: st.lastText ?? "", ...ref(st) });
|
|
71
|
-
else if (reason === "error" || reason === "length" || reason === "content-filter") out.push({ kind: "fail", error: `step finished: ${reason}`, ...ref(st) });
|
|
72
|
-
return out;
|
|
73
|
-
}
|
|
74
|
-
default:
|
|
75
|
-
return [];
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export const opencodeAdapter: AgentAdapter = {
|
|
80
|
-
id: "opencode",
|
|
81
|
-
interruptFirst: true,
|
|
82
|
-
command: (task: LaneTask, opts: LaneOpts) => argv(task.goal, opts, opts.resume),
|
|
83
|
-
resume: (sessionId: string, followUp: string, opts: LaneOpts) => argv(followUp, opts, sessionId),
|
|
84
|
-
permissionSummary: (opts) => `permissions per opencode config (asks surface as lane events)${opts.attach ? ` · attach ${opts.attach}` : ""} · worktree`,
|
|
85
|
-
parse(line: string, st: LaneParseState): LaneEvent[] {
|
|
86
|
-
const o = parseJsonLine(line);
|
|
87
|
-
const type = o ? str(o["type"]) : undefined;
|
|
88
|
-
if (!o || !type) { st.garbage++; return []; }
|
|
89
|
-
const props = obj(o["properties"]) ?? o;
|
|
90
|
-
const sid = str(props["sessionID"]) ?? str(props["sessionId"]) ?? str(obj(props["info"])?.["sessionID"]);
|
|
91
|
-
if (sid) st.sessionId = sid;
|
|
92
|
-
// the CLI's flat shape (verified): the part rides at the top level
|
|
93
|
-
if (FLAT.has(type)) {
|
|
94
|
-
const p = obj(o["part"]);
|
|
95
|
-
return p ? part(p, st) : [];
|
|
96
|
-
}
|
|
97
|
-
if (type.startsWith("message.part.")) {
|
|
98
|
-
const p = obj(props["part"]) ?? obj(o["part"]);
|
|
99
|
-
return p ? part(p, st) : [];
|
|
100
|
-
}
|
|
101
|
-
if (type.startsWith("permission.")) {
|
|
102
|
-
const title = str(props["title"]) ?? str(obj(props["permission"])?.["title"]) ?? str(props["type"]) ?? "permission";
|
|
103
|
-
return [{ kind: "ask", text: title }];
|
|
104
|
-
}
|
|
105
|
-
switch (type) {
|
|
106
|
-
case "message.updated": {
|
|
107
|
-
const info = obj(props["info"]);
|
|
108
|
-
const usage = usageFrom(info?.["tokens"], info);
|
|
109
|
-
return usage && str(info?.["role"]) !== "user" ? [{ kind: "usage", usage }] : [];
|
|
110
|
-
}
|
|
111
|
-
case "session.idle":
|
|
112
|
-
return [{ kind: "done", summary: st.lastText ?? "", ...ref(st) }];
|
|
113
|
-
case "session.error": case "error": {
|
|
114
|
-
const e = obj(props["error"]) ?? obj(o["error"]);
|
|
115
|
-
const message = str(obj(e?.["data"])?.["message"]) ?? str(e?.["message"]) ?? str(props["message"]) ?? str(e?.["name"]) ?? "error";
|
|
116
|
-
return [{ kind: "fail", error: message, ...ref(st) }];
|
|
117
|
-
}
|
|
118
|
-
default:
|
|
119
|
-
return [];
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
|
-
};
|
package/src/lanes/process.ts
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
/** Streaming child-process seam for external lanes (#47). The executor's bunRunner (core/executor.ts)
|
|
2
|
-
* buffers stdout until exit; a lane needs its JSONL LINE BY LINE while it runs, so this is the
|
|
3
|
-
* streaming twin riding the SAME kill path: on Windows the launcher goes into a Job Object right after
|
|
4
|
-
* spawn (core/win-job.ts, KILL_ON_JOB_CLOSE — a rovecode crash takes the tree with it), kill() is
|
|
5
|
-
* TerminateJobObject plus a `taskkill /T /F` sweep of a live pid, and a normal exit release()s the job
|
|
6
|
-
* (executor.ts:122-149 choreography); POSIX (#67) spawns the CLI `detached` (its own process group, via
|
|
7
|
-
* core/proc-group.ts groupSpawnOptions) and kill() is SIGTERM to the GROUP (killGroup, `-pid`) then to the
|
|
8
|
-
* CLI itself as the fallback — the same choreography as bunRunner's POSIX abort, so a CLI's own tool children
|
|
9
|
-
* die with it (not live-verified from the Windows box). interrupt() is SIGINT, the "finish the turn"
|
|
10
|
-
* signal claude/opencode honor — deliverable on POSIX only: Bun's Windows kill() is TerminateProcess
|
|
11
|
-
* whatever the signal name, so on win32 interrupt() reports false and the runner goes straight to the
|
|
12
|
-
* tree kill. Lines are bounded (MAX_LINE_BYTES; longer ones are cut) and the reader can be abandoned
|
|
13
|
-
* when an orphan outside the job keeps the pipe open (executor.ts ABORT_GRACE_MS idiom).
|
|
14
|
-
* `bunLaneSpawn` is `makeLaneSpawn()` over an injectable `LaneSpawnDeps` (platform, spawn, kill, createJob —
|
|
15
|
-
* makeRunner's RunnerDeps shape; production passes nothing), so the POSIX branch is pinned BEHAVIOURALLY
|
|
16
|
-
* under `platform: "linux"` with a fake spawn (test/unit/lanes-process-group.test.ts) while the real-process
|
|
17
|
-
* pins run the Windows branch. Runner tests inject a fake LaneProcess — never a real CLI. */
|
|
18
|
-
|
|
19
|
-
import { groupSpawnOptions, killGroup } from "../core/proc-group.ts";
|
|
20
|
-
import type { KillFn, SpawnedProc } from "../core/proc-group.ts";
|
|
21
|
-
import { createWinJob, type WinJob } from "../core/win-job.ts";
|
|
22
|
-
import type { LaneCommand } from "./types.ts";
|
|
23
|
-
|
|
24
|
-
export interface LaneProcess {
|
|
25
|
-
pid: number;
|
|
26
|
-
/** stdout as lines (newline stripped); ends at EOF or abandon() */
|
|
27
|
-
lines(): AsyncIterable<string>;
|
|
28
|
-
/** resolves with the exit code; 143 when killed */
|
|
29
|
-
exited: Promise<number>;
|
|
30
|
-
/** SIGINT-style "finish the turn": true when delivered, false when not deliverable here */
|
|
31
|
-
interrupt(): boolean;
|
|
32
|
-
/** tree kill (Job Object + taskkill sweep on win32; SIGTERM on POSIX); idempotent */
|
|
33
|
-
kill(): void;
|
|
34
|
-
/** drop our stdout end so lines() ends even if something still holds the pipe */
|
|
35
|
-
abandon(): void;
|
|
36
|
-
/** bounded stderr tail for failure reports */
|
|
37
|
-
stderrTail(): string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export type LaneSpawn = (cmd: LaneCommand) => LaneProcess;
|
|
41
|
-
|
|
42
|
-
export const MAX_LINE_BYTES = 1 << 20;
|
|
43
|
-
const STDERR_TAIL = 2_000;
|
|
44
|
-
|
|
45
|
-
/** A lane is a NEW top-level CLI session, never a child of the Claude Code session rovecode itself may be
|
|
46
|
-
* running in. When rovecode is launched from a Claude Code terminal the environment carries `CLAUDECODE=1`
|
|
47
|
-
* and the parent session's plumbing under `CLAUDE_CODE_*` — verified on 2026-09-03 (claude 2.1.257,
|
|
48
|
-
* Windows): 25 names including the session id, the host-session id, the host-managed-provider marker +
|
|
49
|
-
* the name of its auth env var, the messaging socket AND its token, and the child-session marker. A
|
|
50
|
-
* nested `claude -p` did start under them (no refusal observed), but a lane must never present itself as
|
|
51
|
-
* the parent session's child nor carry its credentials, so both patterns are dropped (case-insensitive:
|
|
52
|
-
* Windows env names are) before `cmd.env` is applied. The other CLIs ignore these names — unconditional.
|
|
53
|
-
* EXCEPT the claude CLI's own DOCUMENTED user knobs, which share the prefix but are the user's
|
|
54
|
-
* configuration, not the host session's — KEPT_ENV_EXACT is checked before the prefix rule (a lane the
|
|
55
|
-
* user authenticated the documented token way otherwise got the CLI's "Not logged in" with no hint).
|
|
56
|
-
* Each name verified 2026-09-03 against `claude --help` (2.1.257) or code.claude.com/docs:
|
|
57
|
-
* CLAUDE_CODE_OAUTH_TOKEN docs/en/authentication — `claude setup-token`, the headless/CI login
|
|
58
|
-
* (precedence rank 5; `--bare` never reads it: key-only)
|
|
59
|
-
* CLAUDE_CODE_USE_BEDROCK / _USE_VERTEX / _USE_FOUNDRY
|
|
60
|
-
* docs/en/authentication — third-party-provider auth (rank 1)
|
|
61
|
-
* CLAUDE_CODE_SIMPLE `--help --bare`: "Sets CLAUDE_CODE_SIMPLE=1"
|
|
62
|
-
* CLAUDE_CODE_SAFE_MODE `--help --safe-mode`: "Sets CLAUDE_CODE_SAFE_MODE=1"
|
|
63
|
-
* CLAUDE_CODE_MAX_OUTPUT_TOKENS docs/en/env-vars
|
|
64
|
-
* CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC docs/en/env-vars
|
|
65
|
-
* None of the 24 names an enclosing session exported on this box is on the list (CLAUDE_CODE_OAUTH_SCOPES,
|
|
66
|
-
* _HOST_AUTH_ENV_VAR, _SESSION_ID, _MESSAGING_TOKEN, … are plumbing and stay dropped). */
|
|
67
|
-
export const SCRUBBED_ENV_EXACT: readonly string[] = ["CLAUDECODE"];
|
|
68
|
-
export const SCRUBBED_ENV_PREFIX = "CLAUDE_CODE_";
|
|
69
|
-
/** documented claude knobs under the scrubbed prefix — the user's, not the host session's; pass through */
|
|
70
|
-
export const KEPT_ENV_EXACT: readonly string[] = [
|
|
71
|
-
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
72
|
-
"CLAUDE_CODE_USE_BEDROCK", "CLAUDE_CODE_USE_VERTEX", "CLAUDE_CODE_USE_FOUNDRY",
|
|
73
|
-
"CLAUDE_CODE_SIMPLE", "CLAUDE_CODE_SAFE_MODE",
|
|
74
|
-
"CLAUDE_CODE_MAX_OUTPUT_TOKENS", "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC",
|
|
75
|
-
];
|
|
76
|
-
export function laneChildEnv(parent: Record<string, string | undefined>, extra?: Record<string, string>): Record<string, string> {
|
|
77
|
-
const out: Record<string, string> = {};
|
|
78
|
-
for (const [k, v] of Object.entries(parent)) {
|
|
79
|
-
if (v === undefined) continue;
|
|
80
|
-
const key = k.toUpperCase();
|
|
81
|
-
if (!KEPT_ENV_EXACT.includes(key) && (SCRUBBED_ENV_EXACT.includes(key) || key.startsWith(SCRUBBED_ENV_PREFIX))) continue;
|
|
82
|
-
out[k] = v;
|
|
83
|
-
}
|
|
84
|
-
return { ...out, ...(extra ?? {}) };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** Split a byte stream into lines; a line over MAX_LINE_BYTES is cut (the rest is dropped). */
|
|
88
|
-
export async function* splitLines(reader: ReadableStreamDefaultReader<Uint8Array>): AsyncGenerator<string> {
|
|
89
|
-
const dec = new TextDecoder();
|
|
90
|
-
let buf = "", dropping = false;
|
|
91
|
-
try {
|
|
92
|
-
for (;;) {
|
|
93
|
-
const c = await reader.read();
|
|
94
|
-
if (c.done) break;
|
|
95
|
-
buf += dec.decode(c.value, { stream: true });
|
|
96
|
-
for (let nl = buf.indexOf("\n"); nl >= 0; nl = buf.indexOf("\n")) {
|
|
97
|
-
let line = buf.slice(0, nl);
|
|
98
|
-
buf = buf.slice(nl + 1);
|
|
99
|
-
if (dropping) { dropping = false; continue; } // the tail of a line already cut below
|
|
100
|
-
if (line.endsWith("\r")) line = line.slice(0, -1);
|
|
101
|
-
yield line.length > MAX_LINE_BYTES ? line.slice(0, MAX_LINE_BYTES) : line;
|
|
102
|
-
}
|
|
103
|
-
if (buf.length > MAX_LINE_BYTES) { yield buf.slice(0, MAX_LINE_BYTES); buf = ""; dropping = true; }
|
|
104
|
-
}
|
|
105
|
-
buf += dec.decode();
|
|
106
|
-
if (buf && !dropping) yield buf;
|
|
107
|
-
} catch {
|
|
108
|
-
/* cancelled reader (abandon) — end the stream */
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// ---------- #67: the injectable process seam (makeRunner's RunnerDeps, twinned) ----------
|
|
113
|
-
|
|
114
|
-
/** The options object handed to spawn — tests pin it byte-for-byte (the Windows shape must never gain a key). */
|
|
115
|
-
export interface LaneSpawnOptions {
|
|
116
|
-
cwd?: string; env?: Record<string, string>; stdin?: Blob | "ignore";
|
|
117
|
-
stdout: "pipe" | "ignore"; stderr: "pipe" | "ignore"; detached?: boolean;
|
|
118
|
-
}
|
|
119
|
-
export type LaneSpawnFn = (argv: string[], options: LaneSpawnOptions) => SpawnedProc;
|
|
120
|
-
|
|
121
|
-
export interface LaneSpawnDeps {
|
|
122
|
-
/** defaults to process.platform — "win32" selects the Job Object path, anything else the group path */
|
|
123
|
-
platform?: NodeJS.Platform;
|
|
124
|
-
/** defaults to Bun.spawn (the CLI and the win32 taskkill sweep both go through it) */
|
|
125
|
-
spawn?: LaneSpawnFn;
|
|
126
|
-
/** defaults to process.kill (killGroup's own default) — `kill(-pid, signal)` addresses the group */
|
|
127
|
-
kill?: KillFn;
|
|
128
|
-
/** defaults to win-job.ts createWinJob (Windows only) */
|
|
129
|
-
createJob?: () => WinJob | null;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const defaultSpawn: LaneSpawnFn = (argv, options) => Bun.spawn(argv, options) as unknown as SpawnedProc;
|
|
133
|
-
|
|
134
|
-
/** Build the lane seam over `deps` (production: none — `bunLaneSpawn` below); the choreography is the header's. */
|
|
135
|
-
export function makeLaneSpawn(deps: LaneSpawnDeps = {}): LaneSpawn {
|
|
136
|
-
const platform = deps.platform ?? process.platform;
|
|
137
|
-
const spawn = deps.spawn ?? defaultSpawn;
|
|
138
|
-
const kill = deps.kill; // undefined → killGroup's default (process.kill)
|
|
139
|
-
const createJob = deps.createJob ?? createWinJob;
|
|
140
|
-
const win = platform === "win32";
|
|
141
|
-
return (cmd) => {
|
|
142
|
-
const proc = spawn([cmd.bin, ...cmd.args], {
|
|
143
|
-
cwd: cmd.cwd,
|
|
144
|
-
env: laneChildEnv(process.env, cmd.env),
|
|
145
|
-
stdin: cmd.stdin !== undefined ? new Blob([cmd.stdin]) : "ignore",
|
|
146
|
-
stdout: "pipe", stderr: "pipe",
|
|
147
|
-
...groupSpawnOptions(platform), // #67: POSIX `detached: true` (own process group); nothing on win32
|
|
148
|
-
});
|
|
149
|
-
let job: WinJob | null = win ? createJob() : null;
|
|
150
|
-
if (job && !job.assign(proc.pid)) job = null; // fail-safe: taskkill-only, as bunRunner reports "taskkill-only"
|
|
151
|
-
let killed = false, reader: ReadableStreamDefaultReader<Uint8Array> | null = null;
|
|
152
|
-
let err = "";
|
|
153
|
-
void (async () => {
|
|
154
|
-
const r = proc.stderr.getReader(), dec = new TextDecoder();
|
|
155
|
-
for (let c = await r.read(); !c.done; c = await r.read()) err = (err + dec.decode(c.value, { stream: true })).slice(-STDERR_TAIL);
|
|
156
|
-
})().catch(() => {});
|
|
157
|
-
const exited = proc.exited.then((code) => (killed ? 143 : code)).finally(() => { if (killed) job?.terminate(); else job?.release(); });
|
|
158
|
-
return {
|
|
159
|
-
pid: proc.pid,
|
|
160
|
-
exited,
|
|
161
|
-
lines: () => splitLines((reader = proc.stdout.getReader())),
|
|
162
|
-
interrupt() {
|
|
163
|
-
if (win || proc.exitCode !== null) return false;
|
|
164
|
-
try { proc.kill("SIGINT"); return true; } catch { return false; }
|
|
165
|
-
},
|
|
166
|
-
kill() {
|
|
167
|
-
if (killed) return;
|
|
168
|
-
killed = true;
|
|
169
|
-
if (win) {
|
|
170
|
-
job?.terminate();
|
|
171
|
-
if (proc.exitCode === null) { try { spawn(["taskkill", "/T", "/F", "/PID", String(proc.pid)], { stdout: "ignore", stderr: "ignore" }); } catch { /* best-effort sweep */ } }
|
|
172
|
-
} else {
|
|
173
|
-
killGroup(proc.pid, "SIGTERM", kill); // #67: the whole group first (bunRunner's POSIX abort order) …
|
|
174
|
-
try { proc.kill("SIGTERM"); } catch { /* already gone */ } // … then the CLI itself as the fallback
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
abandon() { reader?.cancel().catch(() => {}); },
|
|
178
|
-
stderrTail: () => err.trim(),
|
|
179
|
-
};
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/** Default seam: the process's own platform, Bun.spawn, process.kill, the real Job Object. */
|
|
184
|
-
export const bunLaneSpawn: LaneSpawn = makeLaneSpawn();
|
package/src/lanes/progress.ts
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
/** What a RUNNING lane has actually done (#47 follow-up): tool calls made, files written, tokens
|
|
2
|
-
* burned — folded from the same LaneEvents the log ring renders, so nothing new is parsed and nothing
|
|
3
|
-
* parsed is thrown away. Today job.ts collapses the whole stream into a log-tail string; this keeps the
|
|
4
|
-
* structure beside it so a surface can show "12 calls · 3 files · 5.3k in / 900 out" while the CLI is
|
|
5
|
-
* still running, instead of one log line whose meaning depends on which CLI produced it.
|
|
6
|
-
*
|
|
7
|
-
* Three rules, each of which is a way this could lie:
|
|
8
|
-
*
|
|
9
|
-
* 1. A CALL IS COUNTED ONCE. Two of the four CLIs report the same call twice — codex emits
|
|
10
|
-
* `item.started` then `item.completed` for one `command_execution`, opencode updates one tool part
|
|
11
|
-
* from `running` to `completed` — so a fold that counted events would climb at twice the rate for
|
|
12
|
-
* those two and nobody would notice, because there is no independent number to compare it against.
|
|
13
|
-
* Dedupe is by the adapter's own call id (`callId`: claude's `tool_use.id`, codex's `item.id`,
|
|
14
|
-
* opencode's `callID`). An event with no id counts as its own call, which is the honest reading for
|
|
15
|
-
* agy, whose stream carries no ids at all.
|
|
16
|
-
*
|
|
17
|
-
* 2. A FILE IS "WRITTEN" ONLY WHEN THE CLI SAID SO. `edit` events are issued at the tool CALL for
|
|
18
|
-
* claude (a `tool_use` block), so a path appearing in one means the model asked, not that anything
|
|
19
|
-
* changed — a refused, failed or hallucinated edit looks identical. Only an event carrying
|
|
20
|
-
* `wrote: true` counts, which each adapter sets exactly where its own CLI confirms the write
|
|
21
|
-
* (claude: a `tool_result` for that call id without `is_error`; codex: a `file_change` item whose
|
|
22
|
-
* status is completed; opencode: a tool part whose state is `completed`). agy confirms nothing —
|
|
23
|
-
* its `step_update` carries no result and its own header records that `status: SUCCESS` is not
|
|
24
|
-
* proof of work — so an agy lane reports 0 files written LIVE, and that is the truthful answer to
|
|
25
|
-
* "what do we know right now" rather than a guess dressed as a count.
|
|
26
|
-
*
|
|
27
|
-
* 3. THE PATCH IS THE ONLY PROOF AT THE END. When the lane finishes, its worktree diff names the files
|
|
28
|
-
* that really changed (`filesFromPatch`), which no stream can contradict: it is the tree. job.ts
|
|
29
|
-
* replaces the live list with that one, so a finished lane's count is measured, and the live count
|
|
30
|
-
* is understood as "what the CLI has told us so far". For agy this is the only count it ever gets.
|
|
31
|
-
*
|
|
32
|
-
* 4. A MEASURED WRITE IS NOT A LANDED WRITE. Every lane writes into its OWN worktree, and only a lane
|
|
33
|
-
* that finished has its patch merged back into the parent tree. So "the diff names these files" and
|
|
34
|
-
* "these files changed in your repo" are different claims, and three reachable cases separate them:
|
|
35
|
-
* a cancelled lane, a failed one, and — the one that is easy to miss — a lane that finished cleanly
|
|
36
|
-
* whose patch would not apply, because a concurrent task had already touched the same lines. That
|
|
37
|
-
* last one still reports `ok`, so status alone cannot tell you it landed. `applied` carries the
|
|
38
|
-
* answer from the code that did the applying: absent while the lane runs (nothing has been offered
|
|
39
|
-
* to the tree yet), true once the merge-back succeeded, false when the writes stayed in a worktree
|
|
40
|
-
* that was then deleted. Anything reading `filesWritten` as "your repo changed" must read this too.
|
|
41
|
-
*
|
|
42
|
-
* Usage is folded through events.ts addUsage and stays ABSENT when the CLI reported none — the same
|
|
43
|
-
* rule the OTel lane spans keep (telemetry/otel-lanes.ts): a lane that burned tokens we failed to read
|
|
44
|
-
* must not look identical to one that burned none. */
|
|
45
|
-
|
|
46
|
-
import type { TokenUsage } from "../core/types.ts";
|
|
47
|
-
import { addUsage } from "./events.ts";
|
|
48
|
-
import type { LaneEvent } from "./types.ts";
|
|
49
|
-
|
|
50
|
-
/** Paths kept by name; past this only the count grows (a thousand-file refactor must not be held in
|
|
51
|
-
* memory per lane, and no surface shows more than a handful). */
|
|
52
|
-
export const MAX_TRACKED_FILES = 100;
|
|
53
|
-
|
|
54
|
-
export interface LaneProgress {
|
|
55
|
-
/** distinct tool calls the CLI has reported (deduped by call id; see rule 1) */
|
|
56
|
-
toolCalls: number;
|
|
57
|
-
/** files the CLI CONFIRMED it wrote, sorted, at most MAX_TRACKED_FILES of them (see rule 2) */
|
|
58
|
-
filesWritten: readonly string[];
|
|
59
|
-
/** how many confirmed writes there were in total — ≥ filesWritten.length once the cap is hit */
|
|
60
|
-
filesWrittenTotal: number;
|
|
61
|
-
/** absent when the CLI reported no usage at all (see the header) */
|
|
62
|
-
usage?: TokenUsage;
|
|
63
|
-
/** whether these files reached the PARENT tree (rule 4): absent while the lane is still running,
|
|
64
|
-
* `true` once its patch merged back, `false` when it was cancelled, failed, or finished with a patch
|
|
65
|
-
* that would not apply. Not derivable from status — a done lane's patch can still fail to apply. */
|
|
66
|
-
applied?: boolean;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** The running fold. One per lane; the runner owns it and hands out snapshots. */
|
|
70
|
-
export class LaneTally {
|
|
71
|
-
private readonly calls = new Set<string>();
|
|
72
|
-
/** calls with no id of their own — counted, not deduped (agy) */
|
|
73
|
-
private anonymousCalls = 0;
|
|
74
|
-
private readonly files = new Set<string>();
|
|
75
|
-
private filesTotal = 0;
|
|
76
|
-
private usage: TokenUsage | undefined;
|
|
77
|
-
|
|
78
|
-
/** Fold one event. Anything that is not a tool call, a confirmed write or usage is ignored — a `log`,
|
|
79
|
-
* `progress`, `ask`, `done` or `fail` event tells us nothing countable, and guessing from their text
|
|
80
|
-
* is how a counter starts drifting. */
|
|
81
|
-
add(ev: LaneEvent): void {
|
|
82
|
-
switch (ev.kind) {
|
|
83
|
-
case "edit":
|
|
84
|
-
this.countCall(ev.callId);
|
|
85
|
-
if (ev.wrote === true && !this.files.has(ev.path)) {
|
|
86
|
-
this.filesTotal += 1;
|
|
87
|
-
if (this.files.size < MAX_TRACKED_FILES) this.files.add(ev.path);
|
|
88
|
-
}
|
|
89
|
-
return;
|
|
90
|
-
case "bash":
|
|
91
|
-
case "tool":
|
|
92
|
-
this.countCall(ev.callId);
|
|
93
|
-
return;
|
|
94
|
-
case "usage":
|
|
95
|
-
this.usage = addUsage(this.usage, ev.usage);
|
|
96
|
-
return;
|
|
97
|
-
default:
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private countCall(callId: string | undefined): void {
|
|
103
|
-
if (callId === undefined || callId === "") this.anonymousCalls += 1;
|
|
104
|
-
else this.calls.add(callId);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** An immutable snapshot — safe to hand to a surface that keeps it across frames. */
|
|
108
|
-
snapshot(): LaneProgress {
|
|
109
|
-
return {
|
|
110
|
-
toolCalls: this.calls.size + this.anonymousCalls,
|
|
111
|
-
filesWritten: [...this.files].sort(),
|
|
112
|
-
filesWrittenTotal: this.filesTotal,
|
|
113
|
-
...(this.usage ? { usage: { ...this.usage } } : {}),
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** Replace the live file list with the measured one (job.ts, once the worktree diff exists). */
|
|
118
|
-
withFiles(paths: readonly string[]): LaneProgress {
|
|
119
|
-
const sorted = [...new Set(paths)].sort();
|
|
120
|
-
return {
|
|
121
|
-
...this.snapshot(),
|
|
122
|
-
filesWritten: sorted.slice(0, MAX_TRACKED_FILES),
|
|
123
|
-
filesWrittenTotal: sorted.length,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** Files a unified diff actually changes — the proof at the end (rule 3).
|
|
129
|
-
*
|
|
130
|
-
* Reads the `diff --git a/<x> b/<y>` headers rather than the `+++` lines, because a deletion's `+++` is
|
|
131
|
-
* `/dev/null` and a rename's two sides differ: `b/` is the path that exists after the patch, `a/` the
|
|
132
|
-
* one that existed before, and a delete is only visible under `a/`. Quoted paths (git quotes anything
|
|
133
|
-
* with a space or a non-ASCII byte) are unquoted; a header we cannot read is skipped rather than
|
|
134
|
-
* guessed at, so a strange path is missing from the list instead of poisoning it. */
|
|
135
|
-
export function filesFromPatch(patch: string): string[] {
|
|
136
|
-
const out = new Set<string>();
|
|
137
|
-
for (const line of patch.split(/\r?\n/)) {
|
|
138
|
-
if (!line.startsWith("diff --git ")) continue;
|
|
139
|
-
const rest = line.slice("diff --git ".length);
|
|
140
|
-
const pair = splitDiffPair(rest);
|
|
141
|
-
if (pair === null) continue;
|
|
142
|
-
const [a, b] = pair;
|
|
143
|
-
const path = b === "/dev/null" ? a : b;
|
|
144
|
-
if (path !== "" && path !== "/dev/null") out.add(path);
|
|
145
|
-
}
|
|
146
|
-
return [...out].sort();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/** `a/x b/y` → ["x", "y"], honouring git's quoting; null when the halves cannot be told apart. */
|
|
150
|
-
function splitDiffPair(rest: string): [string, string] | null {
|
|
151
|
-
if (rest.startsWith('"')) {
|
|
152
|
-
const close = findQuoteEnd(rest);
|
|
153
|
-
if (close === -1) return null;
|
|
154
|
-
const first = unquote(rest.slice(0, close + 1));
|
|
155
|
-
const tail = rest.slice(close + 1).trimStart();
|
|
156
|
-
const second = tail.startsWith('"') ? unquote(tail) : tail;
|
|
157
|
-
return [strip(first), strip(second)];
|
|
158
|
-
}
|
|
159
|
-
// unquoted: split on " b/" so a path containing a space still resolves (git only quotes when it must,
|
|
160
|
-
// but a repository can carry `a/my file b/my file`)
|
|
161
|
-
const at = rest.indexOf(" b/");
|
|
162
|
-
if (at === -1) {
|
|
163
|
-
const sp = rest.indexOf(" ");
|
|
164
|
-
return sp === -1 ? null : [strip(rest.slice(0, sp)), strip(rest.slice(sp + 1))];
|
|
165
|
-
}
|
|
166
|
-
return [strip(rest.slice(0, at)), strip(rest.slice(at + 1))];
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const findQuoteEnd = (s: string): number => {
|
|
170
|
-
for (let i = 1; i < s.length; i++) {
|
|
171
|
-
if (s[i] === "\\") { i++; continue; }
|
|
172
|
-
if (s[i] === '"') return i;
|
|
173
|
-
}
|
|
174
|
-
return -1;
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
const unquote = (s: string): string => {
|
|
178
|
-
const inner = s.startsWith('"') ? s.slice(1, s.lastIndexOf('"')) : s;
|
|
179
|
-
return inner.replace(/\\(.)/g, "$1");
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
/** drop the `a/` or `b/` prefix git puts on both halves */
|
|
183
|
-
const strip = (p: string): string => (/^[ab]\//.test(p) ? p.slice(2) : p);
|