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/sextant/screen.ts
DELETED
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
/** ported from the user's sextant v0.4.0 prototype, src/term.js (Screen, sgr) — cell buffer + diff flush + SGR */
|
|
2
|
-
/* Pure over an injected Sink: no process access, no clock. The renderer (#44) owns stdout, resize
|
|
3
|
-
events and the frame interval; this module only turns a cell buffer into the minimal byte stream
|
|
4
|
-
that repaints what changed. Additions over the prototype: truecolor → xterm-256 quantization,
|
|
5
|
-
East-Asian width measurement (a width-2 glyph occupies two cells; a later write over either half
|
|
6
|
-
breaks the glyph into spaces so borders stay put), zero-width code points (combining marks, VS16,
|
|
7
|
-
ZWJ and the glyph it joins) ride on the cell before them so the terminal cursor never ends left of
|
|
8
|
-
the buffer, frame glyphs measure 1 cell even under ambiguousAsWide, and control characters never
|
|
9
|
-
reach a cell (toText()/flush cannot leak stray escape bytes). */
|
|
10
|
-
|
|
11
|
-
import { eastAsianWidth } from "get-east-asian-width";
|
|
12
|
-
import { hex } from "./theme.ts";
|
|
13
|
-
import { ATTR, type ScreenLike, type Seg, type Style } from "./types.ts";
|
|
14
|
-
|
|
15
|
-
export const ESC = "\x1b";
|
|
16
|
-
export const CSI = ESC + "[";
|
|
17
|
-
/** the prototype's floor (Screen.resize); layout() clamps to the same numbers */
|
|
18
|
-
export const MIN_COLS = 40;
|
|
19
|
-
export const MIN_ROWS = 12;
|
|
20
|
-
|
|
21
|
-
export interface Sink { write(s: string): void }
|
|
22
|
-
export interface Cursor { x: number; y: number }
|
|
23
|
-
export interface ScreenOptions {
|
|
24
|
-
/** emit 38;2/48;2 truecolor SGR (default true); false quantizes to the xterm 256 cube (38;5/48;5) */
|
|
25
|
-
truecolor?: boolean;
|
|
26
|
-
/** count East-Asian-ambiguous text (◆, ¡ …) as 2 cells; default false. Frame glyphs (box drawing,
|
|
27
|
-
* block elements, …) stay 1 cell either way — the option measures content, never the frame */
|
|
28
|
-
ambiguousAsWide?: boolean;
|
|
29
|
-
}
|
|
30
|
-
/** one buffer cell for tests/panels: width 2 = a wide glyph, 0 = the continuation half of one;
|
|
31
|
-
* ch holds the glyph plus any zero-width code points that joined it (e + U+0301, ZWJ sequences) */
|
|
32
|
-
export interface Cell { ch: string; fg: number; bg: number; a: number; width: number }
|
|
33
|
-
|
|
34
|
-
/* ------------------------------------------------------------ width */
|
|
35
|
-
|
|
36
|
-
/** zero-width code points join the glyph before them: combining marks (Mn/Me), format characters
|
|
37
|
-
* (Cf — ZWSP/ZWNJ/ZWJ U+200B–D, BOM, tags…) and variation selectors U+FE00–0F. Nothing below
|
|
38
|
-
* U+0300 qualifies (U+00AD soft hyphen stays 1 as in wcwidth), which keeps Latin text off the regex. */
|
|
39
|
-
const ZERO_WIDTH_RE = /^[\p{Mn}\p{Me}\p{Cf}\u200B-\u200D\uFE00-\uFE0F]$/u;
|
|
40
|
-
const isZeroWidth = (cp: number): boolean => cp >= 0x300 && ZERO_WIDTH_RE.test(String.fromCodePoint(cp));
|
|
41
|
-
/** Box Drawing + Block Elements (U+2500–259F) and the ellipsis: a frame is 1 cell whatever ambiguousAsWide says */
|
|
42
|
-
const isFrameGlyph = (cp: number): boolean => (cp >= 0x2500 && cp < 0x25a0) || cp === 0x2026;
|
|
43
|
-
const ZWJ = 0x200d;
|
|
44
|
-
const CONTROL_RE = /[\x00-\x1f\x7f-\x9f]/g;
|
|
45
|
-
|
|
46
|
-
/** display width of one code point: 0 (joins the previous glyph), else 1 or 2 via get-east-asian-width;
|
|
47
|
-
* no wide/ambiguous code point exists below U+1100/U+00A1 */
|
|
48
|
-
export function charWidth(cp: number, ambiguousAsWide = false): 0 | 1 | 2 {
|
|
49
|
-
if (cp < 0x80) return 1;
|
|
50
|
-
if (isZeroWidth(cp)) return 0;
|
|
51
|
-
if (ambiguousAsWide ? isFrameGlyph(cp) : cp < 0x1100) return 1;
|
|
52
|
-
return eastAsianWidth(cp, { ambiguousAsWide });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** a string as cells, [text, width] per glyph: zero-width code points — and the code point a ZWJ
|
|
56
|
-
* joins — ride on the glyph before them; a leading one has nothing to join and is dropped */
|
|
57
|
-
export function* glyphs(s: string, ambiguousAsWide = false): Generator<[string, 1 | 2], void> {
|
|
58
|
-
let cur = "", cw: 1 | 2 = 1, join = false;
|
|
59
|
-
for (const c of s) {
|
|
60
|
-
const cp = c.codePointAt(0)!;
|
|
61
|
-
const w = charWidth(cp, ambiguousAsWide);
|
|
62
|
-
if (cur && (w === 0 || (join && cp >= 0x80))) { cur += c; join = cp === ZWJ; continue; }
|
|
63
|
-
if (w === 0) continue;
|
|
64
|
-
if (cur) yield [cur, cw];
|
|
65
|
-
cur = c; cw = w; join = false;
|
|
66
|
-
}
|
|
67
|
-
if (cur) yield [cur, cw];
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** display width of a string in cells (control characters count as the space they become) */
|
|
71
|
-
export function strWidth(s: string, ambiguousAsWide = false): number {
|
|
72
|
-
let w = 0;
|
|
73
|
-
for (const [, cw] of glyphs(s, ambiguousAsWide)) w += cw;
|
|
74
|
-
return w;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/* ------------------------------------------------------------ colors */
|
|
78
|
-
|
|
79
|
-
const CUBE = [0, 95, 135, 175, 215, 255] as const;
|
|
80
|
-
/** xterm's default 16 ANSI colors — so color256() covers every index; sgr() never emits 0-15 */
|
|
81
|
-
const ANSI16 = [0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xc0c0c0, 0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff];
|
|
82
|
-
/** nearest cube level for one channel (the 0/95/135/175/215/255 ramp) */
|
|
83
|
-
const cubeLevel = (v: number): number => (v < 48 ? 0 : v < 115 ? 1 : Math.min(5, Math.floor((v - 35) / 40)));
|
|
84
|
-
function dist2(a: number, b: number): number {
|
|
85
|
-
const dr = ((a >> 16) & 255) - ((b >> 16) & 255), dg = ((a >> 8) & 255) - ((b >> 8) & 255), db = (a & 255) - (b & 255);
|
|
86
|
-
return dr * dr + dg * dg + db * db;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** packed rgb of an xterm-256 palette index */
|
|
90
|
-
export function color256(i: number): number {
|
|
91
|
-
if (i < 16) return ANSI16[i] ?? 0;
|
|
92
|
-
if (i < 232) { const k = i - 16; return (CUBE[Math.floor(k / 36)]! << 16) | (CUBE[Math.floor(k / 6) % 6]! << 8) | CUBE[k % 6]!; }
|
|
93
|
-
const g = 8 + 10 * Math.min(23, i - 232);
|
|
94
|
-
return (g << 16) | (g << 8) | g;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** nearest xterm-256 index (16..255) for a packed rgb: the 6×6×6 cube or the 24-step gray ramp, whichever is closer */
|
|
98
|
-
export function quantize256(c: number): number {
|
|
99
|
-
const r = (c >> 16) & 255, g = (c >> 8) & 255, b = c & 255;
|
|
100
|
-
const cube = 16 + 36 * cubeLevel(r) + 6 * cubeLevel(g) + cubeLevel(b);
|
|
101
|
-
const gray = 232 + Math.max(0, Math.min(23, Math.round(((r + g + b) / 3 - 8) / 10)));
|
|
102
|
-
return dist2(c, color256(gray)) < dist2(c, color256(cube)) ? gray : cube;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** SGR for a cell style: reset + attribute bits + fg/bg (truecolor 38;2 or quantized 38;5); -1 = default color */
|
|
106
|
-
export function sgr(fg: number, bg: number, a: number, truecolor = true): string {
|
|
107
|
-
let s = CSI + "0";
|
|
108
|
-
if (a & ATTR.BOLD) s += ";1";
|
|
109
|
-
if (a & ATTR.DIM) s += ";2";
|
|
110
|
-
if (a & ATTR.ITALIC) s += ";3";
|
|
111
|
-
if (a & ATTR.UNDERLINE) s += ";4";
|
|
112
|
-
if (a & ATTR.INVERSE) s += ";7";
|
|
113
|
-
if (a & ATTR.STRIKE) s += ";9";
|
|
114
|
-
if (fg >= 0) s += truecolor ? `;38;2;${(fg >> 16) & 255};${(fg >> 8) & 255};${fg & 255}` : `;38;5;${quantize256(fg)}`;
|
|
115
|
-
if (bg >= 0) s += truecolor ? `;48;2;${(bg >> 16) & 255};${(bg >> 8) & 255};${bg & 255}` : `;48;5;${quantize256(bg)}`;
|
|
116
|
-
return s + "m";
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/* ------------------------------------------------------------ screen */
|
|
120
|
-
|
|
121
|
-
interface Prev { ch: (string | null)[]; fg: Int32Array; bg: Int32Array; at: Uint8Array }
|
|
122
|
-
|
|
123
|
-
export class Screen implements ScreenLike {
|
|
124
|
-
w = 0;
|
|
125
|
-
h = 0;
|
|
126
|
-
private ch: string[] = [];
|
|
127
|
-
/** cell widths: 1, 2 (wide glyph) or 0 (continuation half of the wide glyph to its left) */
|
|
128
|
-
private wd = new Uint8Array(0);
|
|
129
|
-
private fg = new Int32Array(0);
|
|
130
|
-
private bg = new Int32Array(0);
|
|
131
|
-
private at = new Uint8Array(0);
|
|
132
|
-
private prev: Prev | null = null;
|
|
133
|
-
private readonly truecolor: boolean;
|
|
134
|
-
private readonly ambiguousAsWide: boolean;
|
|
135
|
-
|
|
136
|
-
constructor(private readonly sink: Sink, cols: number, rows: number, opts: ScreenOptions = {}) {
|
|
137
|
-
this.truecolor = opts.truecolor ?? true;
|
|
138
|
-
this.ambiguousAsWide = opts.ambiguousAsWide ?? false;
|
|
139
|
-
this.resize(cols, rows);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/** (re)allocate the buffer at ≥ 40×12; the next flush repaints everything */
|
|
143
|
-
resize(cols: number, rows: number): void {
|
|
144
|
-
this.w = Math.max(MIN_COLS, Number.isFinite(cols) ? Math.floor(cols) : 0);
|
|
145
|
-
this.h = Math.max(MIN_ROWS, Number.isFinite(rows) ? Math.floor(rows) : 0);
|
|
146
|
-
const n = this.w * this.h;
|
|
147
|
-
this.ch = new Array<string>(n).fill(" ");
|
|
148
|
-
this.wd = new Uint8Array(n).fill(1);
|
|
149
|
-
this.fg = new Int32Array(n).fill(-1);
|
|
150
|
-
this.bg = new Int32Array(n).fill(-1);
|
|
151
|
-
this.at = new Uint8Array(n);
|
|
152
|
-
this.prev = null;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/** start a frame: every cell becomes a plain space over the given background */
|
|
156
|
-
begin(bg?: number): void {
|
|
157
|
-
this.ch.fill(" "); this.wd.fill(1); this.fg.fill(-1); this.bg.fill(bg == null ? -1 : bg); this.at.fill(0);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
cellAt(x: number, y: number): Cell | null {
|
|
161
|
-
if (x < 0 || y < 0 || x >= this.w || y >= this.h) return null;
|
|
162
|
-
const i = y * this.w + x;
|
|
163
|
-
return { ch: this.ch[i]!, fg: this.fg[i]!, bg: this.bg[i]!, a: this.at[i]!, width: this.wd[i]! };
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/** a write over either half of a wide glyph turns its other half into a space */
|
|
167
|
-
private breakWide(i: number): void {
|
|
168
|
-
const w = this.wd[i];
|
|
169
|
-
if (w === 0 && i > 0) { this.ch[i - 1] = " "; this.wd[i - 1] = 1; }
|
|
170
|
-
else if (w === 2 && i + 1 < this.wd.length) { this.ch[i + 1] = " "; this.wd[i + 1] = 1; }
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private set(i: number, c: string, w: 1 | 2, fg: number, bg: number, a: number): void {
|
|
174
|
-
this.breakWide(i);
|
|
175
|
-
if (w === 2) this.breakWide(i + 1);
|
|
176
|
-
this.ch[i] = c; this.wd[i] = w; this.fg[i] = fg; if (bg >= 0) this.bg[i] = bg; this.at[i] = a;
|
|
177
|
-
if (w === 2) { this.ch[i + 1] = ""; this.wd[i + 1] = 0; this.fg[i + 1] = fg; if (bg >= 0) this.bg[i + 1] = bg; this.at[i + 1] = a; }
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/** the longest prefix of s that fits in w cells */
|
|
181
|
-
private head(s: string, w: number): string {
|
|
182
|
-
let out = "", used = 0;
|
|
183
|
-
for (const [g, cw] of glyphs(s, this.ambiguousAsWide)) {
|
|
184
|
-
if (used + cw > w) break;
|
|
185
|
-
out += g; used += cw;
|
|
186
|
-
}
|
|
187
|
-
return out;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/** write a string; returns the x after the last cell written. bg < 0 keeps the cell's background. */
|
|
191
|
-
put(x: number, y: number, str: string, st?: Style, maxW = Infinity): number {
|
|
192
|
-
if (y < 0 || y >= this.h || !str) return x;
|
|
193
|
-
const fg = st ? st.fg : -1, bg = st ? st.bg : -1, a = st ? st.a : 0;
|
|
194
|
-
let cx = x;
|
|
195
|
-
const end = Math.min(this.w, x + maxW);
|
|
196
|
-
for (const [g, cw] of glyphs(str.replace(CONTROL_RE, " "), this.ambiguousAsWide)) {
|
|
197
|
-
if (cx >= end) break;
|
|
198
|
-
if (cw === 2 && cx + 2 > end) break; // a wide glyph that does not fit is dropped, never half-drawn
|
|
199
|
-
if (cx >= 0) this.set(y * this.w + cx, g, cw, fg, bg, a);
|
|
200
|
-
cx += cw;
|
|
201
|
-
}
|
|
202
|
-
return cx;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/** write segments clipped to maxW; returns the x after the last cell */
|
|
206
|
-
text(x: number, y: number, segs: readonly Seg[], maxW = Infinity): number {
|
|
207
|
-
let cx = x;
|
|
208
|
-
const end = x + maxW;
|
|
209
|
-
for (const [s, st] of segs) {
|
|
210
|
-
if (cx >= end) break;
|
|
211
|
-
cx = this.put(cx, y, s, st, end - cx);
|
|
212
|
-
}
|
|
213
|
-
return cx;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/** clipped text with a trailing ellipsis when it does not fit (measured in cells) */
|
|
217
|
-
clip(x: number, y: number, str: string, st: Style | undefined, maxW: number): number {
|
|
218
|
-
if (maxW <= 0) return x;
|
|
219
|
-
if (strWidth(str, this.ambiguousAsWide) > maxW) str = maxW > 1 ? this.head(str, maxW - 1) + "…" : this.head(str, maxW);
|
|
220
|
-
return this.put(x, y, str, st, maxW);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
fill(x: number, y: number, w: number, h: number, ch: string, st?: Style): void {
|
|
224
|
-
const fg = st ? st.fg : -1, bg = st ? st.bg : -1, a = st ? st.a : 0;
|
|
225
|
-
let cp = ch.replace(CONTROL_RE, " ").codePointAt(0) ?? 0x20;
|
|
226
|
-
if (isZeroWidth(cp)) cp = 0x20; // a lone zero-width glyph has nothing to join (and a 0-cell step would never advance)
|
|
227
|
-
const g = String.fromCodePoint(cp), cw = charWidth(cp, this.ambiguousAsWide) || 1;
|
|
228
|
-
for (let yy = y; yy < y + h; yy++) {
|
|
229
|
-
if (yy < 0 || yy >= this.h) continue;
|
|
230
|
-
for (let xx = x; xx < x + w; xx += cw) {
|
|
231
|
-
if (xx < 0 || xx + cw > this.w || xx + cw > x + w) continue;
|
|
232
|
-
this.set(yy * this.w + xx, g, cw, fg, bg, a);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/** recolor a rectangle's background only */
|
|
238
|
-
tint(x: number, y: number, w: number, h: number, bg: number): void {
|
|
239
|
-
for (let yy = y; yy < y + h; yy++) {
|
|
240
|
-
if (yy < 0 || yy >= this.h) continue;
|
|
241
|
-
for (let xx = x; xx < x + w; xx++) {
|
|
242
|
-
if (xx < 0 || xx >= this.w) continue;
|
|
243
|
-
this.bg[yy * this.w + xx] = bg;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
hline(x: number, y: number, w: number, st?: Style, ch = "─"): void { for (let i = 0; i < w; i++) this.put(x + i, y, ch, st); }
|
|
249
|
-
vline(x: number, y: number, h: number, st?: Style, ch = "│"): void { for (let i = 0; i < h; i++) this.put(x, y + i, ch, st); }
|
|
250
|
-
|
|
251
|
-
/** rounded box; bgFill paints the interior first when given */
|
|
252
|
-
box(x: number, y: number, w: number, h: number, st?: Style, bgFill?: number): void {
|
|
253
|
-
if (bgFill != null) this.fill(x, y, w, h, " ", { fg: -1, bg: bgFill, a: 0 });
|
|
254
|
-
this.put(x, y, "╭", st); this.put(x + w - 1, y, "╮", st);
|
|
255
|
-
this.put(x, y + h - 1, "╰", st); this.put(x + w - 1, y + h - 1, "╯", st);
|
|
256
|
-
this.hline(x + 1, y, w - 2, st); this.hline(x + 1, y + h - 1, w - 2, st);
|
|
257
|
-
this.vline(x, y + 1, h - 2, st); this.vline(x + w - 1, y + 1, h - 2, st);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/** emit the difference to the previous flush: full paint (ESC[2J) on the first frame or after
|
|
261
|
-
* resize, otherwise only changed cells — a cursor move only where the run is discontiguous, an
|
|
262
|
-
* SGR only when the style changes, and never the bottom-right cell (terminals may scroll on it). */
|
|
263
|
-
flush(cursor?: Cursor | null): void {
|
|
264
|
-
const n = this.w * this.h;
|
|
265
|
-
let full = false;
|
|
266
|
-
if (!this.prev || this.prev.ch.length !== n) {
|
|
267
|
-
this.prev = { ch: new Array<string | null>(n).fill(null), fg: new Int32Array(n).fill(-2), bg: new Int32Array(n).fill(-2), at: new Uint8Array(n).fill(255) };
|
|
268
|
-
full = true;
|
|
269
|
-
}
|
|
270
|
-
const p = this.prev;
|
|
271
|
-
let out = full ? CSI + "2J" : "";
|
|
272
|
-
let cfg: number | null = null, cbg: number | null = null, cat: number | null = null, lx = -1, ly = -1;
|
|
273
|
-
const last = n - 1;
|
|
274
|
-
for (let y = 0; y < this.h; y++) {
|
|
275
|
-
for (let x = 0; x < this.w; x++) {
|
|
276
|
-
const i = y * this.w + x;
|
|
277
|
-
const wd = this.wd[i]!;
|
|
278
|
-
if (wd === 0) continue; // continuation half: painted together with its glyph
|
|
279
|
-
if (i + wd - 1 >= last) continue; // scroll guard: the last cell (or a glyph spilling into it) is never written
|
|
280
|
-
if (!full && this.ch[i] === p.ch[i] && this.fg[i] === p.fg[i] && this.bg[i] === p.bg[i] && this.at[i] === p.at[i]) continue;
|
|
281
|
-
if (!(ly === y && lx === x)) out += CSI + (y + 1) + ";" + (x + 1) + "H";
|
|
282
|
-
const fg = this.fg[i]!, bg = this.bg[i]!, at = this.at[i]!;
|
|
283
|
-
if (fg !== cfg || bg !== cbg || at !== cat) { out += sgr(fg, bg, at, this.truecolor); cfg = fg; cbg = bg; cat = at; }
|
|
284
|
-
out += this.ch[i]!;
|
|
285
|
-
lx = x + wd; ly = y;
|
|
286
|
-
p.ch[i] = this.ch[i]!; p.fg[i] = fg; p.bg[i] = bg; p.at[i] = at;
|
|
287
|
-
if (wd === 2) { p.ch[i + 1] = ""; p.fg[i + 1] = fg; p.bg[i + 1] = bg; p.at[i + 1] = at; }
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
out += cursor ? CSI + (cursor.y + 1) + ";" + (cursor.x + 1) + "H" + CSI + "?25h" : CSI + "?25l";
|
|
291
|
-
this.sink.write(out);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/** plain-text dump: one line per row, trailing whitespace removed, no escape bytes ever */
|
|
295
|
-
toText(): string {
|
|
296
|
-
const lines: string[] = [];
|
|
297
|
-
for (let y = 0; y < this.h; y++) lines.push(this.ch.slice(y * this.w, (y + 1) * this.w).join("").replace(/\s+$/, ""));
|
|
298
|
-
return lines.join("\n");
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/** html dump with colors (debug/screenshots) */
|
|
302
|
-
toHTML(font = "Cascadia Mono"): string {
|
|
303
|
-
let html = "";
|
|
304
|
-
for (let y = 0; y < this.h; y++) {
|
|
305
|
-
let row = "", run = "";
|
|
306
|
-
let cur: Style | null = null;
|
|
307
|
-
const flushRun = (): void => {
|
|
308
|
-
if (!run || !cur) return;
|
|
309
|
-
const s = cur;
|
|
310
|
-
row += `<span style="color:${s.fg >= 0 ? hex(s.fg) : "inherit"};background:${s.bg >= 0 ? hex(s.bg) : "transparent"};${s.a & ATTR.BOLD ? "font-weight:600;" : ""}${s.a & ATTR.ITALIC ? "font-style:italic;" : ""}${s.a & ATTR.STRIKE ? "text-decoration:line-through;" : ""}">${run.replace(/&/g, "&").replace(/</g, "<")}</span>`;
|
|
311
|
-
run = "";
|
|
312
|
-
};
|
|
313
|
-
for (let x = 0; x < this.w; x++) {
|
|
314
|
-
const i = y * this.w + x;
|
|
315
|
-
const s: Style = { fg: this.fg[i]!, bg: this.bg[i]!, a: this.at[i]! };
|
|
316
|
-
if (!cur || cur.fg !== s.fg || cur.bg !== s.bg || cur.a !== s.a) { flushRun(); cur = s; }
|
|
317
|
-
run += this.ch[i]!;
|
|
318
|
-
}
|
|
319
|
-
flushRun();
|
|
320
|
-
html += row + "\n";
|
|
321
|
-
}
|
|
322
|
-
return `<!doctype html><meta charset="utf-8"><body style="margin:0;background:#000"><pre style="margin:0;font:14px/1.25 '${font}',Consolas,monospace;display:inline-block">${html}</pre></body>`;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/** Scrollbar thumbs as grab zones (types.ts HitZone.onDrag). Each painter draws its bar from a
|
|
2
|
-
* handful of numbers — track x/y/h, content rows, viewport rows, offset (draw-messages.ts:338,
|
|
3
|
-
* draw-frame.ts:111, draw-code.ts:385). The same numbers rebuilt here give the thumb's rect; a drag
|
|
4
|
-
* slides the thumb by `dy` rows from where it was painted and maps that back onto an offset, so the
|
|
5
|
-
* thumb stays under the finger wherever it was grabbed. */
|
|
6
|
-
import { codeScrollTop, RAIL_W, rowCount } from "./draw-code.ts";
|
|
7
|
-
import { areas, messagesScroll } from "./draw-messages.ts";
|
|
8
|
-
import { inner } from "./draw-util.ts";
|
|
9
|
-
import { scrollbarGeom, thumbRect, type ScrollbarGeom } from "./scrollbar.ts";
|
|
10
|
-
import type { HitZone, Layout, Page, SextantState, Theme, TreeRow } from "./types.ts";
|
|
11
|
-
|
|
12
|
-
/** the content offset after sliding the thumb `dy` rows from where it was painted (clamped) */
|
|
13
|
-
export function slideOffset(g: ScrollbarGeom, dy: number, total: number, viewport: number): number {
|
|
14
|
-
const range = Math.max(0, total - viewport), track = g.trackH - g.thumbH;
|
|
15
|
-
if (track <= 0 || range === 0) return 0;
|
|
16
|
-
const top = Math.max(g.trackY, Math.min(g.trackY + track, g.thumbY + dy));
|
|
17
|
-
return Math.round((top - g.trackY) / track * range);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function thumbZone(g: ScrollbarGeom, total: number, viewport: number, set: (offset: number) => void): HitZone | null {
|
|
21
|
-
if (!g.visible) return null;
|
|
22
|
-
return { rect: thumbRect(g), onClick: () => {}, onDrag: (_y, dy) => set(slideOffset(g, dy, total, viewport)) };
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** Wheeling the messages up unsticks the view from the tail; once the person scrolls back down to the end
|
|
26
|
-
* (wheel, drag, keys) the view follows the tail again — otherwise a conversation that has been scrolled
|
|
27
|
-
* once never follows new text until pgdn/end. Called by the frame loop after the paint. */
|
|
28
|
-
export function followTailIfAtEnd(L: Layout, s: SextantState, theme: Theme, now: number): void {
|
|
29
|
-
if (s.stick) return;
|
|
30
|
-
const { max } = messagesScroll(L.messages, s, theme, now);
|
|
31
|
-
if (s.msgScroll >= max) { s.stick = true; s.msgScroll = max; }
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** one zone per visible scrollbar thumb: messages, the files tree (in its panel or paged into the
|
|
35
|
-
* main slot), and the code panel in a scrolling mode (file / diff / search; run and agents tail) */
|
|
36
|
-
export function scrollThumbHits(L: Layout, main: Page, s: SextantState, theme: Theme, now: number, rows: TreeRow[]): HitZone[] {
|
|
37
|
-
const out: HitZone[] = [];
|
|
38
|
-
{
|
|
39
|
-
const B = inner(L.messages);
|
|
40
|
-
const { msgH } = areas(B, s);
|
|
41
|
-
const { offset, max } = messagesScroll(L.messages, s, theme, now);
|
|
42
|
-
const total = max + msgH;
|
|
43
|
-
const z = thumbZone(scrollbarGeom(B.x + B.w - 1, B.y, msgH, total, msgH, offset), total, msgH,
|
|
44
|
-
(o) => { s.msgScroll = o; s.stick = o >= max; }); // dragged to the bottom = follow the tail again
|
|
45
|
-
if (z) out.push(z);
|
|
46
|
-
}
|
|
47
|
-
// the files painter re-clamps scroll around the cursor, so the cursor is pulled into the new window
|
|
48
|
-
const filesRect = L.files ?? (main === "files" ? L.code : null);
|
|
49
|
-
if (filesRect) {
|
|
50
|
-
const B = inner(filesRect);
|
|
51
|
-
const z = thumbZone(scrollbarGeom(B.x + B.w - 1, B.y, B.h, rows.length, B.h, s.files.scroll), rows.length, B.h,
|
|
52
|
-
(o) => { s.files.scroll = o; s.files.cursor = Math.max(o, Math.min(s.files.cursor, o + B.h - 1)); });
|
|
53
|
-
if (z) out.push(z);
|
|
54
|
-
}
|
|
55
|
-
const c = s.code;
|
|
56
|
-
if (main === "code" && (c.mode === "code" || c.mode === "diff" || c.mode === "search")) {
|
|
57
|
-
const B = inner(L.code);
|
|
58
|
-
if (B.w >= RAIL_W + 2) {
|
|
59
|
-
const total = rowCount(s, B.w - RAIL_W - 2), top = codeScrollTop(L.code, s);
|
|
60
|
-
const z = thumbZone(scrollbarGeom(B.x + B.w - RAIL_W - 1, B.y, B.h, total, B.h, top), total, B.h,
|
|
61
|
-
(o) => { c.scroll = o; });
|
|
62
|
-
if (z) out.push(z);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
return out;
|
|
66
|
-
}
|
package/src/sextant/scrollbar.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/** Sextant surface — shared one-column scrollbar painter.
|
|
2
|
-
* Pure: no I/O, no timers, no state mutation. All geometry is exported so a
|
|
3
|
-
* caller can hang a mouse hit-zone on the thumb rectangle. */
|
|
4
|
-
|
|
5
|
-
import type { Rect, ScreenLike, Theme } from "./types.ts";
|
|
6
|
-
import { st } from "./theme.ts";
|
|
7
|
-
|
|
8
|
-
/** Geometry for a vertical scrollbar track.
|
|
9
|
-
* When `visible` is false, no other fields are meaningful. */
|
|
10
|
-
export interface ScrollbarGeom {
|
|
11
|
-
/** column the bar occupies */
|
|
12
|
-
x: number;
|
|
13
|
-
/** first row of the track */
|
|
14
|
-
trackY: number;
|
|
15
|
-
/** number of rows in the track */
|
|
16
|
-
trackH: number;
|
|
17
|
-
/** first row of the thumb (absolute) */
|
|
18
|
-
thumbY: number;
|
|
19
|
-
/** number of rows the thumb spans (≥ 1 when visible) */
|
|
20
|
-
thumbH: number;
|
|
21
|
-
visible: boolean;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** Compute scrollbar geometry without drawing.
|
|
25
|
-
* @param x - column for the bar
|
|
26
|
-
* @param trackY - first row of the track
|
|
27
|
-
* @param trackH - track height (rows)
|
|
28
|
-
* @param total - total content rows
|
|
29
|
-
* @param viewport - visible rows (same unit as total)
|
|
30
|
-
* @param offset - first visible row (0-based)
|
|
31
|
-
*/
|
|
32
|
-
export function scrollbarGeom(
|
|
33
|
-
x: number,
|
|
34
|
-
trackY: number,
|
|
35
|
-
trackH: number,
|
|
36
|
-
total: number,
|
|
37
|
-
viewport: number,
|
|
38
|
-
offset: number,
|
|
39
|
-
): ScrollbarGeom {
|
|
40
|
-
const visible = total > viewport && trackH >= 2;
|
|
41
|
-
if (!visible) return { x, trackY, trackH, thumbY: trackY, thumbH: 0, visible: false };
|
|
42
|
-
const thumbH = Math.max(1, Math.round(trackH * viewport / total));
|
|
43
|
-
const scrollRange = Math.max(1, total - viewport);
|
|
44
|
-
const trackRange = Math.max(0, trackH - thumbH);
|
|
45
|
-
const rawThumbY = trackY + Math.round(trackRange * Math.max(0, offset) / scrollRange);
|
|
46
|
-
const thumbY = Math.min(rawThumbY, trackY + trackH - thumbH);
|
|
47
|
-
return { x, trackY, trackH, thumbY, thumbH, visible: true };
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** Paint the scrollbar described by `geom`.
|
|
51
|
-
* Track: thin `│` in theme.rule; thumb: `▌` in theme.dim. */
|
|
52
|
-
export function drawScrollbar(scr: ScreenLike, geom: ScrollbarGeom, theme: Theme): void {
|
|
53
|
-
if (!geom.visible) return;
|
|
54
|
-
const trackSt = st(theme.rule);
|
|
55
|
-
const thumbSt = st(theme.dim);
|
|
56
|
-
for (let i = 0; i < geom.trackH; i++) {
|
|
57
|
-
const y = geom.trackY + i;
|
|
58
|
-
const inThumb = y >= geom.thumbY && y < geom.thumbY + geom.thumbH;
|
|
59
|
-
scr.put(geom.x, y, inThumb ? "▌" : "│", inThumb ? thumbSt : trackSt);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Convenience: compute + draw in one call; returns the geometry (for hit-zone export). */
|
|
64
|
-
export function scrollbar(
|
|
65
|
-
scr: ScreenLike,
|
|
66
|
-
theme: Theme,
|
|
67
|
-
x: number,
|
|
68
|
-
trackY: number,
|
|
69
|
-
trackH: number,
|
|
70
|
-
total: number,
|
|
71
|
-
viewport: number,
|
|
72
|
-
offset: number,
|
|
73
|
-
): ScrollbarGeom {
|
|
74
|
-
const geom = scrollbarGeom(x, trackY, trackH, total, viewport, offset);
|
|
75
|
-
drawScrollbar(scr, geom, theme);
|
|
76
|
-
return geom;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** A Rect covering the thumb — useful for registering a mouse hit-zone. */
|
|
80
|
-
export function thumbRect(geom: ScrollbarGeom): Rect {
|
|
81
|
-
return { x: geom.x, y: geom.thumbY, w: 1, h: geom.thumbH };
|
|
82
|
-
}
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
/** Sextant bridge (port #44): pure helpers between rovecode's app/Renderer seam and the surface state —
|
|
2
|
-
* a user line → row (image chips split off), a replayed tool card → row, how many duplicate app
|
|
3
|
-
* notes a RunEvent triggers (the #41 reducer already produced the row), and the RunEvent / TaskInfo
|
|
4
|
-
* → rovecode forwarding table (#45's report: start/read/edit/write/remove/run/glob/plan/spawn/
|
|
5
|
-
* permission/fetch/crew/tinker on starts — every tool says its specific thing, a risky command gets
|
|
6
|
-
* the risk line — + observe over written content and edit newLines; grep's count, tool_fail/pass/fail + a fail-line
|
|
7
|
-
* reaction on tool ends; denied on a permission refusal; done/stopped/error at run_end; laneDone /
|
|
8
|
-
* laneFail from the task manager). Pure: `now` is a parameter, no I/O, no timers. */
|
|
9
|
-
|
|
10
|
-
import type { RunEvent } from "../core/types.ts";
|
|
11
|
-
import type { TaskInfo } from "../core/tasks.ts";
|
|
12
|
-
import type { Pet, PetEventData } from "./pet.ts";
|
|
13
|
-
import { baseName, describeCall, relPath } from "./tool-rows.ts";
|
|
14
|
-
import { splitAttached } from "./mentions.ts";
|
|
15
|
-
import type { MessageRow, ToolRow } from "./types.ts";
|
|
16
|
-
|
|
17
|
-
type UserRow = Extract<MessageRow, { kind: "user" }>;
|
|
18
|
-
const CHIP_RE = /\[image: ([^\]]*)\]/g;
|
|
19
|
-
const TEST_CMD = /\b(tests?|vitest|jest|pytest|mocha|spec)\b/i;
|
|
20
|
-
/** commands worth a second look before they run: recursive deletes, force pushes, history rewrites,
|
|
21
|
-
* world-writable modes, piping the network into a shell, dropping tables */
|
|
22
|
-
const RISKY_CMD = /\brm\s+(-[a-z]*r[a-z]*f|-[a-z]*f[a-z]*r)\b|--force\b|\bpush\s+-f\b|\breset\s+--hard\b|\bchmod\s+777\b|\bcurl\b[^|]*\|\s*(ba|z)?sh\b|\bdrop\s+(table|database)\b/i;
|
|
23
|
-
const RUN_TOOLS = new Set(["bash", "shell", "run"]);
|
|
24
|
-
const REMOVE_TOOLS = new Set(["remove", "rm", "delete", "unlink"]);
|
|
25
|
-
|
|
26
|
-
const rec = (v: unknown): Record<string, unknown> => (v && typeof v === "object" && !Array.isArray(v) ? (v as Record<string, unknown>) : {});
|
|
27
|
-
const str = (v: unknown): string => (typeof v === "string" ? v : "");
|
|
28
|
-
const oneLine = (s: string, max = 40): string => s.replace(/\s+/g, " ").trim().slice(0, max);
|
|
29
|
-
|
|
30
|
-
/** tui/attach.ts userTurnLine: the text, then ONE line of `[image: name]` chips (or chips alone) */
|
|
31
|
-
export function userRow(line: string, now: number): UserRow {
|
|
32
|
-
const lines = line.split("\n");
|
|
33
|
-
const last = lines[lines.length - 1] ?? "";
|
|
34
|
-
const chips = [...last.matchAll(CHIP_RE)].map((m) => m[1]!);
|
|
35
|
-
const chipLine = chips.length > 0 && last.replace(CHIP_RE, "").trim() === "";
|
|
36
|
-
// `@file` read blocks (mentions.ts) stay out of the panel: the typed text and one chip per file
|
|
37
|
-
const { text, files } = splitAttached((chipLine ? lines.slice(0, -1) : lines).join("\n"));
|
|
38
|
-
const row: UserRow = { kind: "user", text, at: now };
|
|
39
|
-
if (chipLine) row.images = chips;
|
|
40
|
-
if (files.length > 0) row.files = files;
|
|
41
|
-
return row;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** args for a replayed tool card: session-cmd replayTranscript hands the renderer a ≤120-char JSON
|
|
45
|
-
* slice — the whole object when it still parses, else the path/command/pattern/url/question/label
|
|
46
|
-
* fields recovered from the intact prefix (a truncated escape yields nothing for that key) */
|
|
47
|
-
export function argsFromPreview(preview: string): Record<string, unknown> {
|
|
48
|
-
try {
|
|
49
|
-
const v: unknown = JSON.parse(preview);
|
|
50
|
-
if (v && typeof v === "object" && !Array.isArray(v)) return v as Record<string, unknown>;
|
|
51
|
-
} catch { /* truncated — fall through */ }
|
|
52
|
-
const out: Record<string, unknown> = {};
|
|
53
|
-
for (const k of ["path", "command", "pattern", "url", "question", "label"]) {
|
|
54
|
-
const m = new RegExp(`"${k}":"((?:[^"\\\\]|\\\\.)*)"`).exec(preview);
|
|
55
|
-
if (!m) continue;
|
|
56
|
-
try { out[k] = JSON.parse(`"${m[1]}"`); } catch { /* unterminated escape */ }
|
|
57
|
-
}
|
|
58
|
-
return out;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** a replayed tool card (the renderer is NOT busy: session history) → a settled row; toolEnd fills ok/detail */
|
|
62
|
-
export function replayToolRow(callId: string, tool: string, argsPreview: string, cwd: string): ToolRow {
|
|
63
|
-
const d = describeCall(tool, argsFromPreview(argsPreview), cwd);
|
|
64
|
-
const row: ToolRow = { kind: "tool", callId, tool, verb: d.verb, label: d.label, running: false };
|
|
65
|
-
if (d.path) row.path = d.path;
|
|
66
|
-
if (d.verb === "edit" || d.verb === "write") { row.add = d.add; row.del = d.del; }
|
|
67
|
-
return row;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** how many addSystemNote calls app.ts makes for this event that duplicate a reducer row: the
|
|
71
|
-
* compaction note, "↪ steering applied", and the run_end error/warn line (none for `done`) — the
|
|
72
|
-
* renderer drops exactly that many, and only those */
|
|
73
|
-
export function duplicateNotes(ev: RunEvent): number {
|
|
74
|
-
if (ev.type === "compaction" || ev.type === "steer") return 1;
|
|
75
|
-
if (ev.type === "run_end") return ev.status === "done" ? 0 : 1;
|
|
76
|
-
return 0;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** what the renderer remembers per live call so the end event can find its tool/command */
|
|
80
|
-
export interface LiveCall { tool: string; cmd: string }
|
|
81
|
-
|
|
82
|
-
/** RunEvent → rovecode (see the header table) */
|
|
83
|
-
export function petOnEvent(pet: Pet, ev: RunEvent, calls: Map<string, LiveCall>, cwd: string, now: number): void {
|
|
84
|
-
switch (ev.type) {
|
|
85
|
-
case "run_start": pet.event("start", undefined, now); break;
|
|
86
|
-
case "tool_execution_start": {
|
|
87
|
-
const a = rec(ev.args), f = baseName(relPath(cwd, str(a.path))) || "file";
|
|
88
|
-
calls.set(ev.callId, { tool: ev.tool, cmd: str(a.command) || str(a.cmd) });
|
|
89
|
-
petOnStart(pet, ev.tool, a, f, now);
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
case "tool_execution_end": {
|
|
93
|
-
const c = calls.get(ev.callId);
|
|
94
|
-
calls.delete(ev.callId);
|
|
95
|
-
petOnEnd(pet, c, ev.ok, ev.output, now);
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
case "tool_call_failed":
|
|
99
|
-
calls.delete(ev.callId);
|
|
100
|
-
pet.event(ev.reason === "permission_denied" ? "denied" : "tool_fail", undefined, now);
|
|
101
|
-
break;
|
|
102
|
-
case "run_end":
|
|
103
|
-
calls.clear();
|
|
104
|
-
pet.event(ev.status === "done" ? "done" : ev.status === "error" ? "error" : "stopped", undefined, now);
|
|
105
|
-
break;
|
|
106
|
-
default: break;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/** the host of a URL for the fetch quip; a bare or broken URL keeps its first 30 chars */
|
|
111
|
-
const hostOf = (u: string): string => { try { return new URL(u).host || oneLine(u, 30); } catch { return oneLine(u, 30) || "the web"; } };
|
|
112
|
-
|
|
113
|
-
/** Every tool the agent has says something SPECIFIC — the file, the pattern, the host, the child,
|
|
114
|
-
* the thing being tinkered with — because a bubble that only says "working" is worse than silence.
|
|
115
|
-
* Kinds are the existing ones where they fit (a directory listing is a read, an ask is a permission,
|
|
116
|
-
* a search start is glob's line with the pattern); fetch / crew / tinker are the three acts that
|
|
117
|
-
* had none. Unknown tools (an MCP server's own, a future one) fall to tinker with their name. */
|
|
118
|
-
function petOnStart(pet: Pet, tool: string, a: Record<string, unknown>, f: string, now: number): void {
|
|
119
|
-
const data: PetEventData = { f };
|
|
120
|
-
if (tool === "read") pet.event("read", data, now);
|
|
121
|
-
else if (tool === "edit") {
|
|
122
|
-
pet.event("edit", data, now);
|
|
123
|
-
const lines = (Array.isArray(a.edits) ? a.edits : []).flatMap((e) => { const nl = rec(e).newLines; return Array.isArray(nl) ? nl.map(String) : []; });
|
|
124
|
-
if (lines.length) pet.observe(lines.join("\n"), "ins", now);
|
|
125
|
-
} else if (tool === "write") { pet.event("write", data, now); if (str(a.content)) pet.observe(str(a.content), "ins", now); }
|
|
126
|
-
else if (REMOVE_TOOLS.has(tool)) pet.event("remove", data, now);
|
|
127
|
-
else if (RUN_TOOLS.has(tool)) {
|
|
128
|
-
// a destructive-looking command gets the risk line instead of "thunder time" — keyed off the
|
|
129
|
-
// command text the agent asked for, never off an error message (the validator owns those)
|
|
130
|
-
const cmd = str(a.command) || str(a.cmd);
|
|
131
|
-
if (RISKY_CMD.test(cmd)) pet.react("risk", now); else pet.event("run", undefined, now);
|
|
132
|
-
}
|
|
133
|
-
else if (tool === "glob" || tool === "grep") pet.event("glob", { q: oneLine(str(a.pattern), 24) || "it" }, now);
|
|
134
|
-
else if (tool === "ls") pet.event("read", { f: (baseName(str(a.path)) || ".") + "/" }, now);
|
|
135
|
-
else if (tool === "web_fetch") pet.event("fetch", { f: hostOf(str(a.url)) }, now);
|
|
136
|
-
else if (tool === "todo_write") { const n = Array.isArray(a.todos) ? a.todos.length : 0; if (n) pet.event("plan", { n }, now); }
|
|
137
|
-
else if (tool === "todo_read") pet.event("read", { f: "the plan" }, now);
|
|
138
|
-
else if (tool === "ask_user") pet.event("permission", undefined, now);
|
|
139
|
-
else if (tool === "task") pet.event("spawn", { a: oneLine(str(a.label) || str(a.agent) || "a worker", 20) }, now);
|
|
140
|
-
else if (tool === "task_status") pet.event("crew", { a: str(a.action) === "list" ? "the crew" : oneLine(str(a.id), 20) || "the crew" }, now);
|
|
141
|
-
else pet.event("tinker", { f: tinkerTarget(tool, a) }, now);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** what the housekeeping tools are about, by name: `providers`, `skills`, `memory`, `notes`, `search/issues` */
|
|
145
|
-
function tinkerTarget(tool: string, a: Record<string, unknown>): string {
|
|
146
|
-
if (tool.startsWith("provider_")) return str(a.action) === "use" && str(a.selector) ? oneLine(str(a.selector), 24) : "providers";
|
|
147
|
-
if (tool === "skill_view") return oneLine(str(a.name) || str(a.skill), 24) || "a skill";
|
|
148
|
-
if (tool === "skills_list") return "the skills";
|
|
149
|
-
if (tool === "memory_edit") return "memory";
|
|
150
|
-
if (tool === "recall") return oneLine(str(a.query), 24) ? `notes on ${oneLine(str(a.query), 24)}` : "the notes";
|
|
151
|
-
if (tool === "eval_cell") return "a scratch cell";
|
|
152
|
-
if (tool === "mcp_call" || tool === "mcp_list") return [str(a.server), str(a.tool)].filter(Boolean).map((s) => oneLine(s, 16)).join(" ") || "mcp";
|
|
153
|
-
return oneLine(tool, 24);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function petOnEnd(pet: Pet, c: LiveCall | undefined, ok: boolean, output: string, now: number): void {
|
|
157
|
-
if (c && RUN_TOOLS.has(c.tool)) {
|
|
158
|
-
const lines = output.replace(/^exit=-?\d+\r?\n?/, "").split(/\r?\n/).filter((l) => l.trim());
|
|
159
|
-
const r = oneLine(lines[lines.length - 1] ?? "");
|
|
160
|
-
if (TEST_CMD.test(c.cmd)) pet.event(ok ? "pass" : "fail", { r }, now);
|
|
161
|
-
else if (!ok) pet.event("tool_fail", undefined, now);
|
|
162
|
-
if (lines.some((l) => /^\s*FAIL\b/.test(l))) pet.react("fail-line", now);
|
|
163
|
-
else if (ok && lines.some((l) => /^\s*PASS\b/.test(l))) pet.react("pass-line", now);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (!ok) { pet.event("tool_fail", undefined, now); return; }
|
|
167
|
-
if (c?.tool === "grep") pet.event("grep", { n: output.split(/\r?\n/).filter((l) => l.trim() && !l.startsWith("(")).length }, now);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/** TaskManager status transitions → laneDone / laneFail quips (queued/running/cancelled say nothing) */
|
|
171
|
-
export function petOnTask(pet: Pet, t: TaskInfo, now: number): void {
|
|
172
|
-
if (t.status === "done") pet.event("laneDone", { a: oneLine(t.label, 20), r: oneLine(t.summary ?? "done") }, now);
|
|
173
|
-
else if (t.status === "failed") pet.event("laneFail", { a: oneLine(t.label, 20), r: oneLine(t.error ?? "failed") }, now);
|
|
174
|
-
}
|