@phnx-labs/agents-cli 1.22.35 → 1.22.37
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 +666 -2
- package/README.md +75 -35
- package/dist/bin/agents +0 -0
- package/dist/bootstrap.d.ts +15 -0
- package/dist/bootstrap.js +1211 -0
- package/dist/commands/accounts.d.ts +4 -11
- package/dist/commands/accounts.js +159 -27
- package/dist/commands/attach.js +17 -4
- package/dist/commands/audit.d.ts +8 -8
- package/dist/commands/audit.js +57 -47
- package/dist/commands/browser.js +15 -11
- package/dist/commands/cloud.js +1 -1
- package/dist/commands/commands.js +0 -11
- package/dist/commands/computer-actions.js +33 -0
- package/dist/commands/computer-sessions-picker.d.ts +21 -0
- package/dist/commands/computer-sessions-picker.js +141 -0
- package/dist/commands/computer.d.ts +16 -0
- package/dist/commands/computer.js +37 -0
- package/dist/commands/config.d.ts +17 -0
- package/dist/commands/config.js +401 -0
- package/dist/commands/cp.d.ts +84 -0
- package/dist/commands/cp.js +231 -0
- package/dist/commands/daemon.js +243 -14
- package/dist/commands/detach-core.d.ts +1 -1
- package/dist/commands/detach-core.js +12 -2
- package/dist/commands/detach.js +1 -1
- package/dist/commands/doctor.js +64 -5
- package/dist/commands/events.d.ts +24 -12
- package/dist/commands/events.js +144 -28
- package/dist/commands/exec.js +85 -41
- package/dist/commands/feed.d.ts +1 -1
- package/dist/commands/feed.js +16 -8
- package/dist/commands/focus.d.ts +33 -1
- package/dist/commands/focus.js +177 -17
- package/dist/commands/funnel.d.ts +1 -1
- package/dist/commands/go.js +9 -8
- package/dist/commands/harness-wizard.d.ts +1 -0
- package/dist/commands/harness-wizard.js +18 -20
- package/dist/commands/harness.d.ts +2 -0
- package/dist/commands/harness.js +59 -26
- package/dist/commands/hooks.js +0 -11
- package/dist/commands/inspect.d.ts +94 -1
- package/dist/commands/inspect.js +866 -40
- package/dist/commands/lease.d.ts +4 -4
- package/dist/commands/lease.js +6 -6
- package/dist/commands/login.js +0 -13
- package/dist/commands/logs.d.ts +2 -2
- package/dist/commands/logs.js +2 -2
- package/dist/commands/mcp.js +7 -2
- package/dist/commands/memory.js +7 -2
- package/dist/commands/message.d.ts +1 -1
- package/dist/commands/message.js +37 -6
- package/dist/commands/models.js +4 -0
- package/dist/commands/monitors.d.ts +0 -1
- package/dist/commands/monitors.js +199 -16
- package/dist/commands/open.d.ts +18 -0
- package/dist/commands/open.js +57 -0
- package/dist/commands/packages.js +2 -107
- package/dist/commands/plugins.js +6 -3
- package/dist/commands/profiles.d.ts +1 -0
- package/dist/commands/profiles.js +16 -160
- package/dist/commands/projects.d.ts +28 -0
- package/dist/commands/projects.js +125 -5
- package/dist/commands/reconnect.js +9 -3
- package/dist/commands/repo.js +42 -1
- package/dist/commands/resource-view.d.ts +17 -0
- package/dist/commands/resource-view.js +36 -14
- package/dist/commands/resume.js +9 -2
- package/dist/commands/routines.d.ts +0 -2
- package/dist/commands/routines.js +473 -289
- package/dist/commands/secrets.js +52 -9
- package/dist/commands/sessions-export.d.ts +47 -0
- package/dist/commands/sessions-export.js +116 -6
- package/dist/commands/sessions-import.d.ts +17 -0
- package/dist/commands/sessions-import.js +114 -6
- package/dist/commands/sessions-migrate.d.ts +27 -0
- package/dist/commands/sessions-migrate.js +50 -9
- package/dist/commands/sessions-picker.js +23 -4
- package/dist/commands/sessions-resume.d.ts +5 -3
- package/dist/commands/sessions-resume.js +30 -8
- package/dist/commands/sessions-watch.d.ts +2 -0
- package/dist/commands/sessions-watch.js +53 -0
- package/dist/commands/sessions.d.ts +66 -3
- package/dist/commands/sessions.js +298 -47
- package/dist/commands/set.d.ts +1 -1
- package/dist/commands/set.js +2 -2
- package/dist/commands/setup-browser.js +2 -2
- package/dist/commands/setup-mine.js +0 -1
- package/dist/commands/setup-preferences.js +1 -1
- package/dist/commands/setup-share.js +34 -4
- package/dist/commands/setup.d.ts +5 -0
- package/dist/commands/setup.js +26 -0
- package/dist/commands/share.d.ts +67 -0
- package/dist/commands/share.js +275 -12
- package/dist/commands/skills.js +0 -11
- package/dist/commands/snapshot.js +1 -1
- package/dist/commands/ssh.d.ts +18 -0
- package/dist/commands/ssh.js +549 -210
- package/dist/commands/sync.d.ts +5 -0
- package/dist/commands/sync.js +212 -32
- package/dist/commands/teams.d.ts +13 -0
- package/dist/commands/teams.js +187 -30
- package/dist/commands/tickets.d.ts +2 -0
- package/dist/commands/tickets.js +43 -0
- package/dist/commands/update.js +2 -4
- package/dist/commands/usage.js +5 -3
- package/dist/commands/versions.js +11 -5
- package/dist/commands/view.js +15 -7
- package/dist/commands/webhook.d.ts +2 -2
- package/dist/commands/webhook.js +7 -7
- package/dist/index.d.ts +18 -2
- package/dist/index.js +53 -1264
- package/dist/lib/account-catalog.d.ts +18 -0
- package/dist/lib/account-catalog.js +38 -0
- package/dist/lib/account-provider-registry.d.ts +18 -0
- package/dist/lib/account-provider-registry.js +59 -0
- package/dist/lib/account-registry.d.ts +40 -0
- package/dist/lib/account-registry.js +239 -0
- package/dist/lib/account-schema.d.ts +44 -0
- package/dist/lib/account-schema.js +91 -0
- package/dist/lib/account-state-service.d.ts +21 -0
- package/dist/lib/account-state-service.js +60 -0
- package/dist/lib/activity.d.ts +1 -1
- package/dist/lib/activity.js +8 -1
- package/dist/lib/add-dir.d.ts +80 -0
- package/dist/lib/add-dir.js +241 -0
- package/dist/lib/agent-cli-commands.d.ts +11 -0
- package/dist/lib/agent-cli-commands.js +30 -0
- package/dist/lib/agents.js +44 -36
- package/dist/lib/answer-router.js +1 -1
- package/dist/lib/audit/log.d.ts +10 -27
- package/dist/lib/audit/log.js +20 -33
- package/dist/lib/auth-health.d.ts +9 -2
- package/dist/lib/auth-health.js +42 -9
- package/dist/lib/auto-pull-worker.js +7 -3
- package/dist/lib/auto-pull.d.ts +44 -3
- package/dist/lib/auto-pull.js +88 -5
- package/dist/lib/binary-shadow.d.ts +28 -0
- package/dist/lib/binary-shadow.js +121 -0
- package/dist/lib/brand.js +9 -3
- package/dist/lib/browser/ipc.d.ts +30 -0
- package/dist/lib/browser/ipc.js +81 -4
- package/dist/lib/browser/profiles.d.ts +3 -2
- package/dist/lib/browser/profiles.js +65 -22
- package/dist/lib/browser/service.d.ts +4 -0
- package/dist/lib/browser/service.js +30 -3
- package/dist/lib/browser/sessions-list.d.ts +22 -2
- package/dist/lib/browser/sessions-list.js +54 -6
- package/dist/lib/browser/stream.d.ts +2 -0
- package/dist/lib/browser/stream.js +1 -0
- package/dist/lib/browser/types.d.ts +19 -0
- package/dist/lib/byok-usage.d.ts +9 -2
- package/dist/lib/byok-usage.js +133 -31
- package/dist/lib/cli-entry.d.ts +11 -0
- package/dist/lib/cli-entry.js +46 -0
- package/dist/lib/cloud/host.d.ts +1 -1
- package/dist/lib/cloud/host.js +2 -2
- package/dist/lib/cloud/registry.js +1 -1
- package/dist/lib/cloud/types.d.ts +1 -1
- package/dist/lib/commands.d.ts +2 -0
- package/dist/lib/commands.js +2 -0
- package/dist/lib/computer/sessions-list.d.ts +150 -0
- package/dist/lib/computer/sessions-list.js +363 -0
- package/dist/lib/config-keys.d.ts +86 -0
- package/dist/lib/config-keys.js +193 -0
- package/dist/lib/config-machine-keys.d.ts +12 -0
- package/dist/lib/config-machine-keys.js +17 -0
- package/dist/lib/config-transfer.js +3 -4
- package/dist/lib/crabbox/cli.d.ts +2 -2
- package/dist/lib/crabbox/cli.js +3 -3
- package/dist/lib/daemon-health.d.ts +22 -0
- package/dist/lib/daemon-health.js +33 -3
- package/dist/lib/daemon-services.d.ts +50 -0
- package/dist/lib/daemon-services.js +147 -0
- package/dist/lib/daemon-ticks.d.ts +35 -66
- package/dist/lib/daemon-ticks.js +77 -159
- package/dist/lib/daemon.d.ts +72 -4
- package/dist/lib/daemon.js +792 -202
- package/dist/lib/deeplink/register.d.ts +49 -0
- package/dist/lib/deeplink/register.js +253 -0
- package/dist/lib/deeplink/url.d.ts +34 -0
- package/dist/lib/deeplink/url.js +78 -0
- package/dist/lib/device-config.d.ts +124 -29
- package/dist/lib/device-config.js +346 -141
- package/dist/lib/devices/config-migration.d.ts +42 -0
- package/dist/lib/devices/config-migration.js +203 -0
- package/dist/lib/devices/connect.js +14 -7
- package/dist/lib/devices/doctor-findings.d.ts +4 -1
- package/dist/lib/devices/doctor-findings.js +20 -1
- package/dist/lib/devices/harness-inventory.d.ts +11 -2
- package/dist/lib/devices/harness-inventory.js +0 -0
- package/dist/lib/devices/health.d.ts +1 -1
- package/dist/lib/devices/health.js +1 -1
- package/dist/lib/devices/pending.d.ts +22 -1
- package/dist/lib/devices/pending.js +67 -2
- package/dist/lib/devices/registry.d.ts +0 -25
- package/dist/lib/devices/registry.js +2 -83
- package/dist/lib/devices/resolve-profile.d.ts +20 -0
- package/dist/lib/devices/resolve-profile.js +44 -0
- package/dist/lib/devices/rollout-verify.d.ts +101 -0
- package/dist/lib/devices/rollout-verify.js +193 -0
- package/dist/lib/devices/ssh-config.js +10 -6
- package/dist/lib/event-families.d.ts +28 -0
- package/dist/lib/event-families.js +159 -0
- package/dist/lib/event-stream.d.ts +9 -1
- package/dist/lib/event-stream.js +26 -9
- package/dist/lib/events.d.ts +9 -1
- package/dist/lib/events.js +21 -6
- package/dist/lib/exec.d.ts +30 -0
- package/dist/lib/exec.js +219 -121
- package/dist/lib/feed-broadcast.d.ts +25 -0
- package/dist/lib/feed-broadcast.js +33 -0
- package/dist/lib/feed.d.ts +1 -1
- package/dist/lib/feed.js +12 -2
- package/dist/lib/fleet/capture.js +15 -0
- package/dist/lib/fleet/manifest.js +9 -0
- package/dist/lib/fleet/types.d.ts +9 -0
- package/dist/lib/fleet-status.js +10 -8
- package/dist/lib/git.d.ts +20 -6
- package/dist/lib/git.js +121 -17
- package/dist/lib/hosts/dispatch.d.ts +8 -3
- package/dist/lib/hosts/dispatch.js +29 -3
- package/dist/lib/hosts/logs.d.ts +2 -2
- package/dist/lib/hosts/logs.js +2 -2
- package/dist/lib/hosts/option.js +1 -1
- package/dist/lib/hosts/passthrough.d.ts +2 -3
- package/dist/lib/hosts/passthrough.js +10 -24
- package/dist/lib/hosts/progress.js +2 -2
- package/dist/lib/hosts/providers/devices.d.ts +3 -3
- package/dist/lib/hosts/providers/devices.js +18 -12
- package/dist/lib/hosts/ready.d.ts +5 -1
- package/dist/lib/hosts/ready.js +9 -3
- package/dist/lib/hosts/reconcile.d.ts +2 -2
- package/dist/lib/hosts/reconcile.js +2 -2
- package/dist/lib/hosts/registry.js +14 -9
- package/dist/lib/hosts/remote-cmd.js +1 -1
- package/dist/lib/hosts/remote-os.d.ts +9 -6
- package/dist/lib/hosts/remote-os.js +13 -6
- package/dist/lib/hosts/routing-flag.d.ts +23 -0
- package/dist/lib/hosts/routing-flag.js +41 -0
- package/dist/lib/hosts/run-target.js +1 -1
- package/dist/lib/hosts/session-index.js +1 -1
- package/dist/lib/hosts/tasks.d.ts +6 -6
- package/dist/lib/hosts/tasks.js +4 -4
- package/dist/lib/hosts/types.js +1 -2
- package/dist/lib/installations/resolve.js +2 -8
- package/dist/lib/isolation-boundary-report.js +0 -1
- package/dist/lib/linear-cache.d.ts +7 -0
- package/dist/lib/linear-cache.js +31 -4
- package/dist/lib/linear-project-counts.d.ts +1 -1
- package/dist/lib/linear-project-counts.js +2 -3
- package/dist/lib/linear-projects.js +1 -1
- package/dist/lib/loop.d.ts +2 -2
- package/dist/lib/loop.js +1 -1
- package/dist/lib/mailbox-target.d.ts +1 -1
- package/dist/lib/mailbox-target.js +1 -1
- package/dist/lib/manifest.js +7 -4
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/snapshot.d.ts +3 -2
- package/dist/lib/menubar/snapshot.js +6 -2
- package/dist/lib/migrate-fold.d.ts +33 -0
- package/dist/lib/migrate-fold.js +130 -0
- package/dist/lib/migrate.d.ts +34 -34
- package/dist/lib/migrate.js +106 -128
- package/dist/lib/model-tier-overrides.d.ts +1 -1
- package/dist/lib/model-tier-overrides.js +15 -2
- package/dist/lib/monitors/config.d.ts +17 -3
- package/dist/lib/monitors/config.js +52 -18
- package/dist/lib/monitors/engine.d.ts +32 -1
- package/dist/lib/monitors/engine.js +94 -11
- package/dist/lib/monitors/fingerprint.d.ts +46 -0
- package/dist/lib/monitors/fingerprint.js +100 -0
- package/dist/lib/monitors/remote.d.ts +47 -0
- package/dist/lib/monitors/remote.js +81 -0
- package/dist/lib/monitors/state.d.ts +39 -0
- package/dist/lib/monitors/state.js +56 -0
- package/dist/lib/onepassword.d.ts +17 -0
- package/dist/lib/onepassword.js +52 -22
- package/dist/lib/open-url.js +1 -1
- package/dist/lib/picker.d.ts +14 -2
- package/dist/lib/picker.js +35 -13
- package/dist/lib/placement.d.ts +1 -1
- package/dist/lib/placement.js +1 -1
- package/dist/lib/pr-land-detach.d.ts +32 -0
- package/dist/lib/pr-land-detach.js +79 -0
- package/dist/lib/profiles-presets.js +13 -0
- package/dist/lib/profiles.d.ts +2 -0
- package/dist/lib/profiles.js +44 -1
- package/dist/lib/project-focus.d.ts +1 -1
- package/dist/lib/project-focus.js +1 -1
- package/dist/lib/project-probe.d.ts +4 -1
- package/dist/lib/project-probe.js +5 -4
- package/dist/lib/project-resources.js +2 -18
- package/dist/lib/project-root.d.ts +16 -0
- package/dist/lib/project-root.js +20 -2
- package/dist/lib/projects.d.ts +20 -1
- package/dist/lib/projects.js +78 -1
- package/dist/lib/refresh-coordinator.d.ts +24 -0
- package/dist/lib/refresh-coordinator.js +52 -0
- package/dist/lib/registry.d.ts +2 -2
- package/dist/lib/registry.js +1 -1
- package/dist/lib/resource-aliases.d.ts +13 -0
- package/dist/lib/resource-aliases.js +26 -0
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.d.ts +16 -0
- package/dist/lib/resources.js +66 -10
- package/dist/lib/rotate.d.ts +3 -4
- package/dist/lib/rotate.js +4 -5
- package/dist/lib/routine-activation.d.ts +22 -2
- package/dist/lib/routine-activation.js +63 -16
- package/dist/lib/routine-context.d.ts +9 -2
- package/dist/lib/routine-context.js +21 -6
- package/dist/lib/routines-project.d.ts +58 -48
- package/dist/lib/routines-project.js +190 -159
- package/dist/lib/routines.d.ts +41 -6
- package/dist/lib/routines.js +92 -34
- package/dist/lib/run-defaults.d.ts +5 -0
- package/dist/lib/run-defaults.js +11 -1
- package/dist/lib/runner.d.ts +10 -8
- package/dist/lib/runner.js +122 -39
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/agent.d.ts +10 -3
- package/dist/lib/secrets/agent.js +43 -8
- package/dist/lib/secrets/bundles.d.ts +1 -0
- package/dist/lib/secrets/bundles.js +92 -80
- package/dist/lib/secrets/index.js +32 -9
- package/dist/lib/secrets/install-helper.d.ts +4 -4
- package/dist/lib/secrets/install-helper.js +4 -4
- package/dist/lib/secrets/push.d.ts +40 -6
- package/dist/lib/secrets/push.js +58 -11
- package/dist/lib/secrets/read-backoff.d.ts +1 -1
- package/dist/lib/secrets/read-backoff.js +1 -1
- package/dist/lib/secrets/remote.d.ts +24 -0
- package/dist/lib/secrets/remote.js +54 -4
- package/dist/lib/self-update.d.ts +108 -0
- package/dist/lib/self-update.js +276 -1
- package/dist/lib/session/active.d.ts +89 -5
- package/dist/lib/session/active.js +165 -10
- package/dist/lib/session/actor-sidecar.d.ts +1 -1
- package/dist/lib/session/actor-sidecar.js +2 -1
- package/dist/lib/session/db.d.ts +176 -2
- package/dist/lib/session/db.js +484 -17
- package/dist/lib/session/discover.js +27 -4
- package/dist/lib/session/hook-sessions.js +2 -2
- package/dist/lib/session/host-link.d.ts +2 -2
- package/dist/lib/session/host-link.js +2 -2
- package/dist/lib/session/pid-registry.d.ts +21 -0
- package/dist/lib/session/pid-registry.js +57 -0
- package/dist/lib/session/remote-active.js +15 -1
- package/dist/lib/session/remote.js +2 -2
- package/dist/lib/session/session-cache.d.ts +14 -7
- package/dist/lib/session/session-cache.js +51 -9
- package/dist/lib/session/state.d.ts +2 -2
- package/dist/lib/session/state.js +1 -1
- package/dist/lib/session/sync/config.d.ts +10 -10
- package/dist/lib/session/sync/config.js +10 -10
- package/dist/lib/session/sync/r2.d.ts +34 -0
- package/dist/lib/session/sync/r2.js +123 -0
- package/dist/lib/session/throughput.d.ts +1 -1
- package/dist/lib/session/throughput.js +1 -1
- package/dist/lib/session/types.d.ts +23 -1
- package/dist/lib/session/types.js +15 -0
- package/dist/lib/session/viewing-in.d.ts +1 -1
- package/dist/lib/session/viewing-in.js +1 -1
- package/dist/lib/session/watch.d.ts +101 -0
- package/dist/lib/session/watch.js +242 -0
- package/dist/lib/share/config.d.ts +4 -0
- package/dist/lib/share/config.js +1 -0
- package/dist/lib/share/provision.d.ts +38 -0
- package/dist/lib/share/provision.js +50 -0
- package/dist/lib/share/publish.d.ts +40 -1
- package/dist/lib/share/publish.js +116 -3
- package/dist/lib/share/worker-template.js +71 -6
- package/dist/lib/shims.d.ts +17 -3
- package/dist/lib/shims.js +98 -26
- package/dist/lib/signin-badge.js +3 -2
- package/dist/lib/skills.js +2 -0
- package/dist/lib/smart-launch.d.ts +8 -8
- package/dist/lib/smart-launch.js +80 -59
- package/dist/lib/ssh-exec.d.ts +1 -1
- package/dist/lib/ssh-exec.js +1 -1
- package/dist/lib/staleness/prune.d.ts +88 -0
- package/dist/lib/staleness/prune.js +69 -0
- package/dist/lib/staleness/registry.d.ts +1 -1
- package/dist/lib/staleness/writers/commands.js +34 -2
- package/dist/lib/staleness/writers/hooks.js +16 -0
- package/dist/lib/staleness/writers/kinds.d.ts +6 -0
- package/dist/lib/staleness/writers/skills.js +19 -0
- package/dist/lib/staleness/writers/subagents.d.ts +2 -3
- package/dist/lib/staleness/writers/subagents.js +0 -4
- package/dist/lib/staleness/writers/types.d.ts +32 -0
- package/dist/lib/startup/command-registry.d.ts +6 -12
- package/dist/lib/startup/command-registry.js +11 -31
- package/dist/lib/startup/dev-build.d.ts +10 -0
- package/dist/lib/startup/dev-build.js +13 -1
- package/dist/lib/startup/spellcheck.d.ts +18 -0
- package/dist/lib/startup/spellcheck.js +45 -0
- package/dist/lib/state.d.ts +36 -9
- package/dist/lib/state.js +96 -46
- package/dist/lib/subagents-registry.d.ts +0 -7
- package/dist/lib/subagents-registry.js +38 -65
- package/dist/lib/subagents.d.ts +0 -33
- package/dist/lib/subagents.js +0 -75
- package/dist/lib/sync-umbrella.js +1 -1
- package/dist/lib/teams/agents.d.ts +41 -1
- package/dist/lib/teams/agents.js +187 -9
- package/dist/lib/teams/api.d.ts +11 -1
- package/dist/lib/teams/api.js +11 -2
- package/dist/lib/teams/delivery.d.ts +41 -0
- package/dist/lib/teams/delivery.js +60 -0
- package/dist/lib/teams/registry.d.ts +14 -0
- package/dist/lib/teams/registry.js +51 -1
- package/dist/lib/teams/remoteWorktree.d.ts +19 -0
- package/dist/lib/teams/remoteWorktree.js +29 -0
- package/dist/lib/teams/scheduler.d.ts +1 -1
- package/dist/lib/teams/scheduler.js +1 -1
- package/dist/lib/teams/worktree.d.ts +24 -0
- package/dist/lib/teams/worktree.js +42 -0
- package/dist/lib/terminal/backends/vscodium-agent.d.ts +10 -1
- package/dist/lib/terminal/backends/vscodium-agent.js +16 -5
- package/dist/lib/terminal/engine.d.ts +4 -0
- package/dist/lib/terminal/engine.js +8 -2
- package/dist/lib/terminal/types.d.ts +21 -2
- package/dist/lib/testdata/refresh-coordinator-worker.d.ts +1 -0
- package/dist/lib/testdata/refresh-coordinator-worker.js +23 -0
- package/dist/lib/tickets/list.d.ts +53 -0
- package/dist/lib/tickets/list.js +153 -0
- package/dist/lib/tmux/orphan-reap.d.ts +320 -0
- package/dist/lib/tmux/orphan-reap.js +644 -0
- package/dist/lib/tmux/session.d.ts +68 -3
- package/dist/lib/tmux/session.js +95 -5
- package/dist/lib/triggers/handlers.d.ts +20 -0
- package/dist/lib/triggers/handlers.js +6 -1
- package/dist/lib/types.d.ts +46 -34
- package/dist/lib/usage-fleet.d.ts +32 -0
- package/dist/lib/usage-fleet.js +125 -0
- package/dist/lib/usage-refresh.d.ts +3 -3
- package/dist/lib/usage-refresh.js +19 -16
- package/dist/lib/usage.d.ts +51 -47
- package/dist/lib/usage.js +145 -153
- package/dist/lib/version-duplicates.js +2 -2
- package/dist/lib/versions.d.ts +56 -13
- package/dist/lib/versions.js +195 -45
- package/dist/lib/watchdog/log.d.ts +1 -1
- package/dist/lib/watchdog/log.js +3 -3
- package/dist/lib/watchdog/rotate.d.ts +6 -6
- package/dist/lib/watchdog/rotate.js +6 -6
- package/dist/lib/workflows.d.ts +1 -1
- package/dist/lib/yaml-io.d.ts +47 -0
- package/dist/lib/yaml-io.js +55 -0
- package/package.json +2 -1
- package/scripts/install-helper.js +2 -2
- package/scripts/postinstall.js +23 -20
- package/dist/commands/defaults.d.ts +0 -7
- package/dist/commands/defaults.js +0 -107
- package/dist/commands/export.d.ts +0 -11
- package/dist/commands/export.js +0 -215
- package/dist/commands/helper.d.ts +0 -12
- package/dist/commands/helper.js +0 -87
- package/dist/commands/hosts.d.ts +0 -11
- package/dist/commands/hosts.js +0 -330
- package/dist/commands/lock.d.ts +0 -12
- package/dist/commands/lock.js +0 -70
- package/dist/commands/pull.d.ts +0 -17
- package/dist/commands/pull.js +0 -39
- package/dist/commands/push.d.ts +0 -14
- package/dist/commands/push.js +0 -30
- package/dist/commands/wallet.d.ts +0 -20
- package/dist/commands/wallet.js +0 -216
- package/dist/commands/worktree.d.ts +0 -19
- package/dist/commands/worktree.js +0 -272
- package/dist/lib/account-labels.d.ts +0 -24
- package/dist/lib/account-labels.js +0 -72
- package/dist/lib/auto-dispatch-linear.d.ts +0 -18
- package/dist/lib/auto-dispatch-linear.js +0 -107
- package/dist/lib/auto-dispatch-provider.d.ts +0 -10
- package/dist/lib/auto-dispatch-provider.js +0 -30
- package/dist/lib/auto-dispatch.d.ts +0 -93
- package/dist/lib/auto-dispatch.js +0 -128
- package/dist/lib/export.d.ts +0 -72
- package/dist/lib/export.js +0 -269
- package/dist/lib/lock.d.ts +0 -93
- package/dist/lib/lock.js +0 -207
- package/dist/lib/wallet/index.d.ts +0 -78
- package/dist/lib/wallet/index.js +0 -253
|
@@ -14,14 +14,14 @@ import { spawn } from 'child_process';
|
|
|
14
14
|
import { Option } from 'commander';
|
|
15
15
|
import chalk from 'chalk';
|
|
16
16
|
import { truncate, padRight, humanDuration } from '../lib/format.js';
|
|
17
|
-
import { sanitizeForTerminal } from '../lib/redact.js';
|
|
17
|
+
import { sanitizeForTerminal, redactSecrets } from '../lib/redact.js';
|
|
18
18
|
import { resolveProjectKey } from '../lib/project-key.js';
|
|
19
19
|
import { listProjectDefs, resolveProjectNameForCwd } from '../lib/projects.js';
|
|
20
20
|
import ora from 'ora';
|
|
21
21
|
import { SESSION_AGENTS } from '../lib/session/types.js';
|
|
22
22
|
import { discoverArtifacts, readArtifact, resolveArtifact } from '../lib/session/artifacts.js';
|
|
23
23
|
import { looksLikePath, toComparablePath, homeDir, needsWindowsShell, composeWin32CommandLine } from '../lib/platform/index.js';
|
|
24
|
-
import { getActiveSessions } from '../lib/session/active.js';
|
|
24
|
+
import { getActiveSessions, sessionProcessIsLocal } from '../lib/session/active.js';
|
|
25
25
|
import { enumerateGhosttyTabs, assignGhosttyTabs } from '../lib/session/ghostty-tabs.js';
|
|
26
26
|
import { mapPanesToTargets, listClients } from '../lib/tmux/session.js';
|
|
27
27
|
import { resolveViewingIn, viewingInLabel } from '../lib/session/viewing-in.js';
|
|
@@ -29,10 +29,11 @@ import { machineId, normalizeHost } from '../lib/session/sync/config.js';
|
|
|
29
29
|
import { gatherRemoteActive, NO_FANOUT_ENV } from '../lib/session/remote-active.js';
|
|
30
30
|
import { loadFleetActiveSessions, loadLocalActiveSessions, } from '../lib/session/session-cache.js';
|
|
31
31
|
import { gatherRemoteList, gatherRemoteToolProgramCounts, gatherRemoteToolSearch, runOnPeer } from '../lib/session/remote-list.js';
|
|
32
|
+
import { gatherRemoteAgentsJson } from '../lib/remote-agents-json.js';
|
|
32
33
|
import { stringWidth, truncateToWidth, padToWidth, terminalWidth } from '../lib/session/width.js';
|
|
33
34
|
import { inferSessionState } from '../lib/session/state.js';
|
|
34
35
|
import { discoverSessions, queryIndexedSessions, countSessionsInScope, resolveSessionById, isCompleteSessionId, looksLikeSessionId, searchContentIndex, getSessionRoots, scopeToManaged } from '../lib/session/discover.js';
|
|
35
|
-
import { findSessionsById, querySessions, getSessionById } from '../lib/session/db.js';
|
|
36
|
+
import { findSessionsById, querySessions, getSessionById, readSessionContent, readArchivedSessionPreview } from '../lib/session/db.js';
|
|
36
37
|
import { filterTeamSessions, shouldShowTeamSessions, safeTeamText, groupSessionsByTeam, NO_TEAM_GROUP_KEY, } from '../lib/session/team-filter.js';
|
|
37
38
|
import { parseSession } from '../lib/session/parse.js';
|
|
38
39
|
import { runRemoteSessions, buildForwardedArgs, ensureWholeIndex } from '../lib/session/remote.js';
|
|
@@ -73,7 +74,10 @@ import { registerSessionsBackfillCommand } from './sessions-backfill.js';
|
|
|
73
74
|
import { registerSessionsStatsCommand } from './sessions-stats.js';
|
|
74
75
|
import { registerSessionsInsightsCommand } from './insights.js';
|
|
75
76
|
import { registerSessionsOptimizeCommand } from './sessions-optimize.js';
|
|
77
|
+
import { registerSessionsWatchCommand } from './sessions-watch.js';
|
|
76
78
|
import { runBrowserSessionsCommand } from './browser-sessions-picker.js';
|
|
79
|
+
import { runComputerSessionsCommand } from './computer-sessions-picker.js';
|
|
80
|
+
import { buildComputerSessionRows } from '../lib/computer/sessions-list.js';
|
|
77
81
|
import { countToolProgramOccurrences, parseToolProgramCountClause, readToolIndexCoverage, searchToolCalls, TOOL_QUERY_MAX_CLAUSE_BYTES, TOOL_QUERY_MAX_CLAUSES, TOOL_QUERY_MAX_RESULT_SESSIONS, serializeToolSearchEnvelope, toolSearchRemoteReceiveBudget, } from '../lib/session/tool-index.js';
|
|
78
82
|
const SESSION_AGENT_FILTER_HELP = `Filter by agent, e.g. claude, codex, claude@2.0.65`;
|
|
79
83
|
function collectQueryClause(value, previous) {
|
|
@@ -669,6 +673,29 @@ export function serializeActiveSessionsForJson(sessions) {
|
|
|
669
673
|
viewingIn: viewingInLabel(s) ?? null,
|
|
670
674
|
}));
|
|
671
675
|
}
|
|
676
|
+
/** Canonical JSON row consumed by resume pickers and other session UIs. */
|
|
677
|
+
export function serializeSessionPickerRows(sessions, liveSessions, self = machineId()) {
|
|
678
|
+
const liveById = new Map(liveSessions.filter((row) => row.sessionId).map((row) => [row.sessionId, row]));
|
|
679
|
+
return sessions.map((session) => {
|
|
680
|
+
const live = liveById.get(session.id);
|
|
681
|
+
const sourceDevice = live?.machine ?? session.machine ?? self;
|
|
682
|
+
const viewingIn = live ? viewingInLabel(live) ?? null : null;
|
|
683
|
+
const resumable = buildResumeCommand(session) !== null;
|
|
684
|
+
return {
|
|
685
|
+
...session,
|
|
686
|
+
state: live?.status ?? 'inactive',
|
|
687
|
+
resumable,
|
|
688
|
+
unwatched: !viewingIn,
|
|
689
|
+
viewingIn,
|
|
690
|
+
sourceDevice,
|
|
691
|
+
lastActivityMs: live?.lastActivityMs ?? Date.parse(session.lastActivity ?? session.timestamp),
|
|
692
|
+
pid: live?.pid ?? null,
|
|
693
|
+
recovery: resumable
|
|
694
|
+
? { command: 'agents', args: ['sessions', 'resume', session.id, '--device', sourceDevice], ...(session.cwd ? { cwd: session.cwd } : {}) }
|
|
695
|
+
: null,
|
|
696
|
+
};
|
|
697
|
+
});
|
|
698
|
+
}
|
|
672
699
|
/**
|
|
673
700
|
* Compact, colour-coded badges for the durable/awaiting signals. Text-only (no
|
|
674
701
|
* emoji, per repo convention): `plan` / `ask` / `perm` for why it's waiting,
|
|
@@ -984,7 +1011,7 @@ export function groupSessionsByMachine(sessions, localMachine) {
|
|
|
984
1011
|
* correlated, so they're all kept.
|
|
985
1012
|
*/
|
|
986
1013
|
export function dedupeByMachineSession(sessions) {
|
|
987
|
-
const seen = new
|
|
1014
|
+
const seen = new Map();
|
|
988
1015
|
const out = [];
|
|
989
1016
|
for (const s of sessions) {
|
|
990
1017
|
if (!s.sessionId) {
|
|
@@ -992,13 +1019,38 @@ export function dedupeByMachineSession(sessions) {
|
|
|
992
1019
|
continue;
|
|
993
1020
|
}
|
|
994
1021
|
const key = `${s.machine ?? ''}:${s.sessionId}`;
|
|
995
|
-
|
|
1022
|
+
const at = seen.get(key);
|
|
1023
|
+
if (at === undefined) {
|
|
1024
|
+
seen.set(key, out.length);
|
|
1025
|
+
out.push(s);
|
|
996
1026
|
continue;
|
|
997
|
-
|
|
998
|
-
|
|
1027
|
+
}
|
|
1028
|
+
// Both rows now describe the same session on the same machine, so the tie is
|
|
1029
|
+
// between the EXECUTING box's own row and the dispatcher's shim row for a
|
|
1030
|
+
// host-dispatched run (they only started colliding once foldExecutionMachine
|
|
1031
|
+
// attributed both to the executing host — RUSH-2479). The shim carries no
|
|
1032
|
+
// transcript and a `[host/<peer>]` placeholder label, so keeping it first
|
|
1033
|
+
// would strip a real preview off the merged fleet view. Prefer the row that
|
|
1034
|
+
// is not an offload shim; otherwise the first one still wins.
|
|
1035
|
+
if (out[at].offloadedFrom && !s.offloadedFrom)
|
|
1036
|
+
out[at] = s;
|
|
999
1037
|
}
|
|
1000
1038
|
return out;
|
|
1001
1039
|
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Narrow a gathered live set to the machines an explicit `--host`/`--device`
|
|
1042
|
+
* scope named. The gather picks which boxes to ASK; this asserts what the answer
|
|
1043
|
+
* may contain, and the two are not the same question: a host-dispatched run is
|
|
1044
|
+
* reported by the box that dispatched it while executing somewhere else, so
|
|
1045
|
+
* `--device <dispatcher>` used to list sessions that were not running there at
|
|
1046
|
+
* all (RUSH-2479). No scope → unchanged. Pure; exported for unit testing.
|
|
1047
|
+
*/
|
|
1048
|
+
export function filterActiveSessionsByHostScope(sessions, hosts, self) {
|
|
1049
|
+
if (!hosts || hosts.length === 0)
|
|
1050
|
+
return sessions;
|
|
1051
|
+
const wanted = new Set(hosts.map(hostToken));
|
|
1052
|
+
return sessions.filter((s) => wanted.has(s.machine ?? self));
|
|
1053
|
+
}
|
|
1002
1054
|
/**
|
|
1003
1055
|
* Order a merged listing so the local machine's sessions come first, then each
|
|
1004
1056
|
* remote machine as a contiguous block (more sessions first, then name), with
|
|
@@ -1090,6 +1142,41 @@ async function runRemoteSessionsJson(hosts) {
|
|
|
1090
1142
|
const { sessions } = await gatherRemoteList(forwarded, hosts);
|
|
1091
1143
|
process.stdout.write(serializeSessionsJson(sessions));
|
|
1092
1144
|
}
|
|
1145
|
+
/** Parse one peer's computer-run array without accepting banners or partial
|
|
1146
|
+
* JSON. The fan-out boundary supplies the machine name when an older peer row
|
|
1147
|
+
* omitted it. */
|
|
1148
|
+
export function parseRemoteComputerSessionRows(stdout, machine) {
|
|
1149
|
+
try {
|
|
1150
|
+
const value = JSON.parse(stdout);
|
|
1151
|
+
if (!Array.isArray(value))
|
|
1152
|
+
return { items: [], valid: false };
|
|
1153
|
+
const items = value
|
|
1154
|
+
.filter((row) => Boolean(row && typeof row === 'object' && !Array.isArray(row)))
|
|
1155
|
+
.map((row) => ({ ...row, machine: row.machine || machine }));
|
|
1156
|
+
return { items, valid: true };
|
|
1157
|
+
}
|
|
1158
|
+
catch {
|
|
1159
|
+
return { items: [], valid: false };
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
/** Collect computer history from named peers, or every automatic peer when
|
|
1163
|
+
* hosts is omitted. Every peer is forced to JSON and receives the recursion
|
|
1164
|
+
* guard through the shared fleet transport. */
|
|
1165
|
+
export async function gatherRemoteComputerSessionRows(hosts) {
|
|
1166
|
+
const hostSet = new Set(hosts ?? []);
|
|
1167
|
+
const forwarded = buildForwardedArgs(process.argv, hostSet);
|
|
1168
|
+
if (!forwarded.includes('--json'))
|
|
1169
|
+
forwarded.push('--json');
|
|
1170
|
+
if (!forwarded.includes('--no-interactive'))
|
|
1171
|
+
forwarded.push('--no-interactive');
|
|
1172
|
+
const result = await gatherRemoteAgentsJson({
|
|
1173
|
+
args: forwarded,
|
|
1174
|
+
noFanoutEnv: NO_FANOUT_ENV,
|
|
1175
|
+
hosts,
|
|
1176
|
+
parse: parseRemoteComputerSessionRows,
|
|
1177
|
+
});
|
|
1178
|
+
return result.items;
|
|
1179
|
+
}
|
|
1093
1180
|
/**
|
|
1094
1181
|
* `running N · idle N · waiting N · queued N · closed N · abandoned N · unknown N`
|
|
1095
1182
|
* for a bucket of sessions (zero buckets omitted). Same bucketing as the summary so
|
|
@@ -1351,7 +1438,15 @@ async function gatherActiveSessionsLive(opts = {}) {
|
|
|
1351
1438
|
merged = dedupeByMachineSession([...local, ...remote.sessions]);
|
|
1352
1439
|
}
|
|
1353
1440
|
}
|
|
1354
|
-
|
|
1441
|
+
// Asking a box is not the same as a session running there: a host-dispatched
|
|
1442
|
+
// run is reported by its dispatcher while executing on the peer. Scope on the
|
|
1443
|
+
// machine the session runs on so `--device X` never lists someone else's work
|
|
1444
|
+
// (RUSH-2479). Applied here, in the single gather, so the interactive browser
|
|
1445
|
+
// gets the same answer as `--active --json`.
|
|
1446
|
+
return {
|
|
1447
|
+
sessions: filterActiveSessionsByHostScope(merged, opts.hosts, self),
|
|
1448
|
+
remoteDeviceCount,
|
|
1449
|
+
};
|
|
1355
1450
|
}
|
|
1356
1451
|
/**
|
|
1357
1452
|
* Render the unified active-session view, grouped by machine. Scoping and the
|
|
@@ -1387,7 +1482,7 @@ async function renderActiveSessions(asJson, waitingOnly = false, opts = {}) {
|
|
|
1387
1482
|
// is how a consumer distinguishes a session someone is looking at from one
|
|
1388
1483
|
// running orphaned after its terminal died. tmux-only (no osascript) so the
|
|
1389
1484
|
// scriptable path stays cheap — see enrichTmuxLocators.
|
|
1390
|
-
await enrichTmuxLocators(sessions.filter(s =>
|
|
1485
|
+
await enrichTmuxLocators(sessions.filter(s => sessionProcessIsLocal(s, self)));
|
|
1391
1486
|
process.stdout.write(JSON.stringify(serializeActiveSessionsForJson(sessions), null, 2) + '\n');
|
|
1392
1487
|
if (waitingOnly && sessions.some(isAwaitingUser))
|
|
1393
1488
|
process.exitCode = 1;
|
|
@@ -1402,7 +1497,7 @@ async function renderActiveSessions(asJson, waitingOnly = false, opts = {}) {
|
|
|
1402
1497
|
// Enrich LOCAL sessions with jump locators (display-only, after the --json /
|
|
1403
1498
|
// --waiting gates so scriptable output stays osascript-free). Remote sessions
|
|
1404
1499
|
// keep their raw pane id — their tmux/Ghostty live on the other machine.
|
|
1405
|
-
await enrichLocalLocators(sessions.filter(s =>
|
|
1500
|
+
await enrichLocalLocators(sessions.filter(s => sessionProcessIsLocal(s, self)));
|
|
1406
1501
|
const grouped = groupSessionsByMachine(sessions, self);
|
|
1407
1502
|
let firstMachine = true;
|
|
1408
1503
|
for (const mg of grouped.machines) {
|
|
@@ -1944,9 +2039,15 @@ export async function renderSessionPreview(query, scope) {
|
|
|
1944
2039
|
}
|
|
1945
2040
|
}
|
|
1946
2041
|
if (outcome.kind === 'partial') {
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
2042
|
+
// RUSH-2492: an unreachable peer is a warning, not a hard failure. The
|
|
2043
|
+
// resolver already resolves an id found on the reachable fleet (SES-9a),
|
|
2044
|
+
// so reaching here means the session was not found on any device we COULD
|
|
2045
|
+
// reach — it may live on an unreachable peer, which we could not check.
|
|
2046
|
+
const offline = outcome.failedPeers;
|
|
2047
|
+
console.error(chalk.yellow(`Warning: ${offline.length} device(s) unreachable, not checked: ${offline.join(', ')}`));
|
|
2048
|
+
console.error(chalk.red(`No session matching "${query}" on any reachable device (${offline.length} unreachable, not checked).`));
|
|
2049
|
+
console.error(chalk.gray(' If it lives on an offline box, wake it (agents devices) or run there: agents ssh <device>'));
|
|
2050
|
+
process.exitCode = 1;
|
|
1950
2051
|
return;
|
|
1951
2052
|
}
|
|
1952
2053
|
if (outcome.kind === 'not-found') {
|
|
@@ -2722,7 +2823,14 @@ limitSource) {
|
|
|
2722
2823
|
const filtered = searchQuery
|
|
2723
2824
|
? resolveSessionQuery(sessions, searchQuery).matches
|
|
2724
2825
|
: sessions;
|
|
2725
|
-
|
|
2826
|
+
// JSON is the canonical picker contract: enrich the durable rows once
|
|
2827
|
+
// from the shared live cache so every consumer gets lifecycle/recovery
|
|
2828
|
+
// metadata without performing its own join or transcript scan.
|
|
2829
|
+
const live = await gatherActiveSessions({
|
|
2830
|
+
local: options.local === true || process.env[NO_FANOUT_ENV] === '1',
|
|
2831
|
+
hosts: options.host,
|
|
2832
|
+
});
|
|
2833
|
+
process.stdout.write(serializeSessionsJson(serializeSessionPickerRows(filtered, live.sessions)));
|
|
2726
2834
|
return;
|
|
2727
2835
|
}
|
|
2728
2836
|
// Cross-machine fan-out: unless --local (or we ARE a peer answering a
|
|
@@ -3351,10 +3459,79 @@ export async function renderSessionLog(session, mode = 'summary') {
|
|
|
3351
3459
|
export async function renderSessionLogJson(session) {
|
|
3352
3460
|
await renderSession(session, 'json', {});
|
|
3353
3461
|
}
|
|
3462
|
+
/**
|
|
3463
|
+
* Render a file-gone (archived) session from the local DB (RUSH-2436). The
|
|
3464
|
+
* transcript file is deleted, but the user turns survive in session_text and the
|
|
3465
|
+
* last-computed digest in session_preview_cache — serve those so `agents sessions
|
|
3466
|
+
* <id>` still shows the prompts instead of an empty metadata dump. User-turn text
|
|
3467
|
+
* is the durable content every harness stores; assistant text survives only as
|
|
3468
|
+
* the cached digest's `lastAssistant` snippet, shown when present.
|
|
3469
|
+
*/
|
|
3470
|
+
function renderArchivedSession(session, mode, options = {}) {
|
|
3471
|
+
// Redact by default, mirroring the live render path (render.ts renderConversationMarkdown):
|
|
3472
|
+
// session_text stores raw user text, so masking is render-time. `--no-redact`
|
|
3473
|
+
// opts out, same as the live path.
|
|
3474
|
+
const redact = (text) => options.redact !== false ? redactSecrets(text) : text;
|
|
3475
|
+
const content = redact((readSessionContent(session.id) ?? '').trim());
|
|
3476
|
+
const digestRaw = readArchivedSessionPreview(session.id);
|
|
3477
|
+
const digest = digestRaw
|
|
3478
|
+
? { ...digestRaw, lastAssistant: redact(digestRaw.lastAssistant ?? '') }
|
|
3479
|
+
: undefined;
|
|
3480
|
+
if (mode === 'json') {
|
|
3481
|
+
// Minimal machine shape for a file-gone session: the durable user content
|
|
3482
|
+
// plus the cached preview digest, tagged archived. Deliberately NOT the full
|
|
3483
|
+
// { session, events } contract — there are no events to parse. Redact the
|
|
3484
|
+
// first-message-excerpt meta fields (topic/label/plan) too, matching the live
|
|
3485
|
+
// single-session --json (render.ts redactJson), so `--json` masks them unless
|
|
3486
|
+
// --no-redact is passed.
|
|
3487
|
+
console.log(JSON.stringify({
|
|
3488
|
+
session: {
|
|
3489
|
+
...session,
|
|
3490
|
+
topic: session.topic != null ? redact(session.topic) : session.topic,
|
|
3491
|
+
label: session.label != null ? redact(session.label) : session.label,
|
|
3492
|
+
plan: session.plan != null ? redact(session.plan) : session.plan,
|
|
3493
|
+
archived: true,
|
|
3494
|
+
},
|
|
3495
|
+
archived: true,
|
|
3496
|
+
userContent: content,
|
|
3497
|
+
preview: digest ?? null,
|
|
3498
|
+
}, null, 2));
|
|
3499
|
+
return;
|
|
3500
|
+
}
|
|
3501
|
+
const agentColor = colorAgent(session.agent);
|
|
3502
|
+
const absTime = formatAbsoluteTime(session.timestamp);
|
|
3503
|
+
const title = session.label || session.topic;
|
|
3504
|
+
console.log('');
|
|
3505
|
+
if (title)
|
|
3506
|
+
console.log(chalk.bold.white(title));
|
|
3507
|
+
console.log(agentColor(session.agent) +
|
|
3508
|
+
(session.version ? chalk.yellow(` ${session.version}`) : '') +
|
|
3509
|
+
(session.project ? chalk.cyan(` ${session.project}`) : '') +
|
|
3510
|
+
chalk.gray(` ${absTime} (${formatRelativeTime(session.timestamp)})`) +
|
|
3511
|
+
(session.account ? chalk.gray(` · ${session.account}`) : ''));
|
|
3512
|
+
console.log(chalk.yellow('archived — transcript file removed; user turns served from the local DB'));
|
|
3513
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
3514
|
+
console.log(chalk.cyan('User:'));
|
|
3515
|
+
console.log(content);
|
|
3516
|
+
if (digest?.lastAssistant?.trim()) {
|
|
3517
|
+
console.log('');
|
|
3518
|
+
console.log(chalk.magenta('Last assistant:'));
|
|
3519
|
+
console.log(digest.lastAssistant.trim());
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3354
3522
|
async function renderSession(session, mode, filters, options = {}) {
|
|
3355
3523
|
// OpenCode stores sessions in SQLite; filePath is "db_path#session_id"
|
|
3356
3524
|
const realPath = session.filePath.split('#')[0];
|
|
3357
3525
|
if (!fs.existsSync(realPath)) {
|
|
3526
|
+
// The transcript file is gone, but the session's user turns are stored
|
|
3527
|
+
// durably in the local DB (session_text), so serve those instead of a bare
|
|
3528
|
+
// metadata dump (RUSH-2436). This is what makes an archived session still
|
|
3529
|
+
// render its prompts after `agents remove` / rm / a box reimage.
|
|
3530
|
+
const archivedContent = readSessionContent(session.id);
|
|
3531
|
+
if (archivedContent && archivedContent.trim() !== '') {
|
|
3532
|
+
renderArchivedSession(session, mode, options);
|
|
3533
|
+
return;
|
|
3534
|
+
}
|
|
3358
3535
|
console.log(chalk.yellow('Session transcript not available (file no longer exists).'));
|
|
3359
3536
|
console.log(chalk.gray(`Path: ${session.filePath}`));
|
|
3360
3537
|
if (session.version)
|
|
@@ -4265,8 +4442,15 @@ async function renderOneSession(query, mode, scope) {
|
|
|
4265
4442
|
if (looksLikeSessionId(query)) {
|
|
4266
4443
|
const outcome = await resolveSessionMetadataValue(query, scope);
|
|
4267
4444
|
if (outcome.kind === 'partial') {
|
|
4268
|
-
|
|
4269
|
-
|
|
4445
|
+
// RUSH-2492: an unreachable peer is a warning, not a hard failure. The
|
|
4446
|
+
// resolver already resolves an id found on the reachable fleet (SES-9a),
|
|
4447
|
+
// so reaching here means the session was not found on any device we
|
|
4448
|
+
// COULD reach — it may live on an unreachable peer we could not check.
|
|
4449
|
+
const offline = outcome.failedPeers;
|
|
4450
|
+
console.error(chalk.yellow(`Warning: ${offline.length} device(s) unreachable, not checked: ${offline.join(', ')}`));
|
|
4451
|
+
console.error(chalk.red(`No session matching "${query}" on any reachable device (${offline.length} unreachable, not checked).`));
|
|
4452
|
+
console.error(chalk.gray(' If it lives on an offline box, wake it (agents devices) or run there: agents ssh <device>'));
|
|
4453
|
+
process.exit(1);
|
|
4270
4454
|
}
|
|
4271
4455
|
// An index miss can be a transcript created since the last incremental
|
|
4272
4456
|
// scan, or a Claude history alias. Fall through to the established
|
|
@@ -4459,6 +4643,11 @@ const FULL_SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-
|
|
|
4459
4643
|
* the wrong session (whichever peer replied first). Labels therefore stay
|
|
4460
4644
|
* all-settle so a cross-machine label conflict surfaces as an ambiguity, and a
|
|
4461
4645
|
* short-id PREFIX stays all-settle for the same reason (RUSH-2203).
|
|
4646
|
+
*
|
|
4647
|
+
* This is about cancelling a sweep that is still IN FLIGHT, where a peer that
|
|
4648
|
+
* has not answered yet is still expected to. It is deliberately stricter than
|
|
4649
|
+
* `isUniqueEnoughSelector`, which decides what to do once the sweep is OVER and
|
|
4650
|
+
* a peer has definitively not answered — see SES-9a.
|
|
4462
4651
|
*/
|
|
4463
4652
|
export function isDefinitiveMatch(session, selector) {
|
|
4464
4653
|
return FULL_SESSION_ID_RE.test(selector) && session.id.toLowerCase() === selector.trim().toLowerCase();
|
|
@@ -4545,23 +4734,54 @@ export function toolSearchForwardedArgs(argv, hosts) {
|
|
|
4545
4734
|
args.push('--local');
|
|
4546
4735
|
return args;
|
|
4547
4736
|
}
|
|
4548
|
-
/**
|
|
4549
|
-
*
|
|
4550
|
-
*
|
|
4737
|
+
/** Width of the short id the CLI prints everywhere (`SessionMeta.shortId`):
|
|
4738
|
+
* 8 hex chars / 32 bits. A selector shorter than this is treated as a keyword,
|
|
4739
|
+
* not an identifier. */
|
|
4740
|
+
const SHORT_SESSION_ID_WIDTH = 8;
|
|
4741
|
+
/**
|
|
4742
|
+
* Whether a selector names ONE session precisely enough to resolve from the
|
|
4743
|
+
* reachable fleet alone when some peer did not answer (SES-9a).
|
|
4744
|
+
*
|
|
4745
|
+
* Deliberately stricter than `looksLikeSessionId`, which accepts any 6+ char
|
|
4746
|
+
* `[0-9a-f-]` run and so matches ordinary words (`facade`, `decade`, `beaded`).
|
|
4747
|
+
* Those are keywords a user typed as a search, not identifiers, and they must
|
|
4748
|
+
* keep waiting for every peer.
|
|
4749
|
+
*/
|
|
4750
|
+
export function isUniqueEnoughSelector(selector) {
|
|
4751
|
+
const trimmed = selector.trim();
|
|
4752
|
+
if (isCompleteSessionId(trimmed))
|
|
4753
|
+
return true;
|
|
4754
|
+
return /^[0-9a-f-]+$/i.test(trimmed)
|
|
4755
|
+
&& trimmed.replace(/-/g, '').length >= SHORT_SESSION_ID_WIDTH;
|
|
4756
|
+
}
|
|
4757
|
+
/** Resolution fails closed for keywords and labels when a peer did not answer.
|
|
4758
|
+
* An id-shaped selector at least `SHORT_SESSION_ID_WIDTH` hex chars wide (or a
|
|
4759
|
+
* complete id) resolves from a single reachable hit even when an unrelated
|
|
4760
|
+
* registered device is offline — see SES-9a for the accepted collision risk. */
|
|
4551
4761
|
export function metadataResolveOutcome(localMatches, remote, selector) {
|
|
4552
4762
|
// Every peer answered through --resolve-safe-v1, so its native-id row is
|
|
4553
4763
|
// already the result of resolving the original selector. Re-filtering by the
|
|
4554
4764
|
// selector would discard alias suffixes such as c1f3d813 because the native
|
|
4555
4765
|
// UUID intentionally has a different prefix.
|
|
4556
4766
|
const candidates = fleetCandidatesByQuery([...localMatches, ...remote.sessions], selector, true);
|
|
4557
|
-
//
|
|
4558
|
-
//
|
|
4559
|
-
//
|
|
4560
|
-
//
|
|
4561
|
-
//
|
|
4562
|
-
//
|
|
4563
|
-
//
|
|
4564
|
-
|
|
4767
|
+
// One hit on the REACHABLE fleet resolves a precise-enough id selector even
|
|
4768
|
+
// when a peer is offline (SES-9a). This is a deliberate, bounded trade, not a
|
|
4769
|
+
// claim that prefixes cannot collide — they can, which is why the `ambiguous`
|
|
4770
|
+
// branch below still exists for peers that DID answer:
|
|
4771
|
+
// - refusing costs 100% of lookups on any fleet with a permanently offline
|
|
4772
|
+
// device (9 of them here), to avoid a prefix collision that ALSO has to
|
|
4773
|
+
// land on the one box that did not answer. Rate depends on the id type:
|
|
4774
|
+
// a UUIDv4 short id is unique in practice, while a time-ordered
|
|
4775
|
+
// UUIDv7/ULID prefix is largely a timestamp and collides much more
|
|
4776
|
+
// readily (see deriveShortId in session/db.ts);
|
|
4777
|
+
// - `isUniqueEnoughSelector` keeps this off keyword-shaped queries, so a
|
|
4778
|
+
// 6-char word like `facade` or `decade` is not treated as an identifier.
|
|
4779
|
+
// A label stays fail-closed at any length: labels are free-form and collide by
|
|
4780
|
+
// design, so one hit there really is a guess.
|
|
4781
|
+
// (RUSH-2203's early-exit stays UUID-only — see isDefinitiveMatch — because
|
|
4782
|
+
// that cancels the sweep mid-flight, where a peer that has not answered YET is
|
|
4783
|
+
// still expected to answer. Here the sweep is already over.)
|
|
4784
|
+
if (isUniqueEnoughSelector(selector) && candidates.length === 1) {
|
|
4565
4785
|
return { kind: 'resolved', session: candidates[0].hits[0].session };
|
|
4566
4786
|
}
|
|
4567
4787
|
if (remote.unreachable.length > 0)
|
|
@@ -4610,8 +4830,11 @@ export async function resolveSessionMetadataValue(selector, scope = {}, deps = {
|
|
|
4610
4830
|
}
|
|
4611
4831
|
/** Resolve one selector to indexed metadata across the fleet without reading or
|
|
4612
4832
|
* rendering transcript events. A peer answering the parent sweep returns every
|
|
4613
|
-
* local candidate; the parent performs the one logical-session uniqueness gate.
|
|
4614
|
-
|
|
4833
|
+
* local candidate; the parent performs the one logical-session uniqueness gate.
|
|
4834
|
+
* Backs `agents sessions --resolve <selector> --json`. Exported (deps already
|
|
4835
|
+
* injectable) so tests can drive this real call site against a fake fan-out
|
|
4836
|
+
* instead of only the pure resolver it wraps. */
|
|
4837
|
+
export async function resolveSessionMetadata(selector, scope, deps = { gatherRemoteList }) {
|
|
4615
4838
|
const localMachine = machineId();
|
|
4616
4839
|
const includeLocal = !scope.hosts?.length || shouldIncludeLocal(scope.hosts, localMachine);
|
|
4617
4840
|
const indexed = includeLocal ? indexedRowsForSelector(selector, scope) : [];
|
|
@@ -4625,9 +4848,15 @@ async function resolveSessionMetadata(selector, scope, deps = { gatherRemoteList
|
|
|
4625
4848
|
}
|
|
4626
4849
|
const outcome = await resolveSessionMetadataValue(selector, scope, deps);
|
|
4627
4850
|
if (outcome.kind === 'partial') {
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4851
|
+
// RUSH-2492: an unreachable peer is a warning, not a hard failure. The
|
|
4852
|
+
// resolver already resolves an id found on the reachable fleet (SES-9a),
|
|
4853
|
+
// so reaching here means the session was not found on any device we
|
|
4854
|
+
// COULD reach — it may live on an unreachable peer we could not check.
|
|
4855
|
+
const offline = outcome.failedPeers;
|
|
4856
|
+
console.error(chalk.yellow(`Warning: ${offline.length} device(s) unreachable, not checked: ${offline.join(', ')}`));
|
|
4857
|
+
console.error(chalk.red(`No session matching "${selector}" on any reachable device (${offline.length} unreachable, not checked).`));
|
|
4858
|
+
console.error(chalk.gray(' If it lives on an offline box, wake it (agents devices) or run there: agents ssh <device>'));
|
|
4859
|
+
process.exit(1);
|
|
4631
4860
|
}
|
|
4632
4861
|
if (outcome.kind === 'not-found') {
|
|
4633
4862
|
console.error(chalk.red(`No session found matching: ${selector}`));
|
|
@@ -4766,6 +4995,7 @@ export function registerSessionsCommands(program) {
|
|
|
4766
4995
|
.option('--fleet', 'With --include tools: query every registered online compute device and merge compact matches')
|
|
4767
4996
|
.option('--count', 'With one program:<name> tool query: count static occurrences, containing calls, and sessions')
|
|
4768
4997
|
.option('--browser', 'List browser-profile captures (screenshots, PDFs, recordings, downloads) instead of agent transcripts — alias of `agents browser sessions`')
|
|
4998
|
+
.option('--computer', 'List computer-driving history, grouped by run, instead of agent transcripts — alias of `agents computer sessions`')
|
|
4769
4999
|
.option('--no-interactive', 'Print the listing instead of opening the interactive browser (default on a TTY for the bare listing and --active)')
|
|
4770
5000
|
.option('--print-cmd', 'Print the canonical `ag sessions …` command for the given flags and exit (the twin of the browser’s `y` hotkey)')
|
|
4771
5001
|
.option('--preview', 'With a session id/query: print a compact preview and exit (no pager)');
|
|
@@ -4789,17 +5019,17 @@ export function registerSessionsCommands(program) {
|
|
|
4789
5019
|
agents sessions --orphan
|
|
4790
5020
|
agents sessions --crashed
|
|
4791
5021
|
|
|
4792
|
-
# --- Session lifecycle
|
|
4793
|
-
#
|
|
4794
|
-
agents sessions
|
|
4795
|
-
#
|
|
4796
|
-
agents sessions
|
|
4797
|
-
#
|
|
4798
|
-
agents sessions
|
|
4799
|
-
# Headless → interactive in this terminal
|
|
4800
|
-
agents sessions attach a1b2c3d4
|
|
5022
|
+
# --- Session lifecycle ---
|
|
5023
|
+
# Get back into a session — attaches a live pane, or recovers an ended one
|
|
5024
|
+
agents sessions resume a1b2c3d4
|
|
5025
|
+
# Same, by the tmux name shown in: agents tmux ls
|
|
5026
|
+
agents sessions resume ag-claude-a1b2c3d4
|
|
5027
|
+
# Attach only — never fork a copy
|
|
5028
|
+
agents sessions resume a1b2c3d4 --attach-only
|
|
4801
5029
|
# Multi-select history and open each in a tab
|
|
4802
5030
|
agents sessions resume
|
|
5031
|
+
# The other direction: interactive → headless (keep working unattended)
|
|
5032
|
+
agents sessions detach a1b2c3d4
|
|
4803
5033
|
|
|
4804
5034
|
# The interactive list folds in other online machines automatically,
|
|
4805
5035
|
# labelled by host with this machine first. Stay local with --local:
|
|
@@ -4851,12 +5081,12 @@ export function registerSessionsCommands(program) {
|
|
|
4851
5081
|
agents sessions --all "deploy script" --host box-a --host box-b
|
|
4852
5082
|
`,
|
|
4853
5083
|
notes: `
|
|
4854
|
-
Session lifecycle
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
5084
|
+
Session lifecycle — ONE verb gets you back in, it detects the state:
|
|
5085
|
+
resume <id|alias> live pane -> attach; headless -> foreground; ended -> recover
|
|
5086
|
+
resume <id> --attach-only attach only; never fork a copy
|
|
5087
|
+
resume multi-select history -> open tabs
|
|
5088
|
+
detach <id> the other direction: interactive -> headless
|
|
5089
|
+
(retired, still working for one release: sessions attach, sessions go, reconnect)
|
|
4860
5090
|
- The interactive listing and every live-status flag fold in your other online machines automatically (live over SSH, no sync) — each row is labelled by host, this machine first. Use --local to skip the fan-out; single-id lookups stay local.
|
|
4861
5091
|
- --all is not a device flag: it widens historical directory and time filters. Fleet collection is already the default. A status flag (--working/--idle/--waiting/--orphan/--crashed/--closed/--abandoned/--queued/--unknown) implies --active; combine status flags for a union.
|
|
4862
5092
|
- --version <version> requires --agent and is equivalent to --agent <agent@version>.
|
|
@@ -4883,6 +5113,26 @@ export function registerSessionsCommands(program) {
|
|
|
4883
5113
|
await runBrowserSessionsCommand({ profile: query, json: options.json, interactive: options.interactive });
|
|
4884
5114
|
return;
|
|
4885
5115
|
}
|
|
5116
|
+
if (options.computer) {
|
|
5117
|
+
// Alias for `agents computer sessions`: a machine positional narrows to
|
|
5118
|
+
// one machine. `--no-interactive` carries through the same way.
|
|
5119
|
+
const limit = options.limit === undefined ? undefined : Number.parseInt(options.limit, 10);
|
|
5120
|
+
const deviceArgs = [...(options.device ?? []), ...(options.devices ?? [])];
|
|
5121
|
+
const allFleet = deviceArgs.some((host) => ['all', 'fleet'].includes(host.toLowerCase()));
|
|
5122
|
+
const hosts = [...(options.host ?? []), ...deviceArgs]
|
|
5123
|
+
.filter((host) => !['all', 'fleet'].includes(host.toLowerCase()));
|
|
5124
|
+
if (hosts.length > 0 || allFleet) {
|
|
5125
|
+
const remoteRows = await gatherRemoteComputerSessionRows(allFleet ? undefined : hosts);
|
|
5126
|
+
const rows = allFleet
|
|
5127
|
+
? [...buildComputerSessionRows({ machine: query }), ...remoteRows]
|
|
5128
|
+
: remoteRows;
|
|
5129
|
+
rows.sort((a, b) => b.endMs - a.endMs);
|
|
5130
|
+
await runComputerSessionsCommand({ rows, machine: query, limit, json: options.json, interactive: options.interactive });
|
|
5131
|
+
return;
|
|
5132
|
+
}
|
|
5133
|
+
await runComputerSessionsCommand({ machine: query, limit, json: options.json, interactive: options.interactive });
|
|
5134
|
+
return;
|
|
5135
|
+
}
|
|
4886
5136
|
await sessionsAction(query, options, command.getOptionValueSource('limit'));
|
|
4887
5137
|
});
|
|
4888
5138
|
const previewCmd = sessionsCmd
|
|
@@ -4943,6 +5193,7 @@ export function registerSessionsCommands(program) {
|
|
|
4943
5193
|
registerSessionsStatsCommand(sessionsCmd);
|
|
4944
5194
|
registerSessionsInsightsCommand(sessionsCmd);
|
|
4945
5195
|
registerSessionsOptimizeCommand(sessionsCmd);
|
|
5196
|
+
registerSessionsWatchCommand(sessionsCmd);
|
|
4946
5197
|
// Observe-umbrella alias (Phase 3): roster → sessions --active.
|
|
4947
5198
|
registerSessionsObserveAliases(program);
|
|
4948
5199
|
}
|
package/dist/commands/set.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `agents set claude@2.1.220 --model opus-5` pins the default model (and/or
|
|
5
5
|
* mode) that `agents run` uses for that agent version. It reads and writes the
|
|
6
|
-
* same store as `agents
|
|
6
|
+
* same store as `agents config set run.<agent@version>.*` (agents.yaml -> run.defaults), so the
|
|
7
7
|
* two stay consistent — `set` is just the short front door.
|
|
8
8
|
*
|
|
9
9
|
* agents set # list every configured default
|
package/dist/commands/set.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* `agents set claude@2.1.220 --model opus-5` pins the default model (and/or
|
|
5
5
|
* mode) that `agents run` uses for that agent version. It reads and writes the
|
|
6
|
-
* same store as `agents
|
|
6
|
+
* same store as `agents config set run.<agent@version>.*` (agents.yaml -> run.defaults), so the
|
|
7
7
|
* two stay consistent — `set` is just the short front door.
|
|
8
8
|
*
|
|
9
9
|
* agents set # list every configured default
|
|
@@ -72,7 +72,7 @@ export function registerSetCommand(program) {
|
|
|
72
72
|
notes: `
|
|
73
73
|
Selectors use <agent>@<version> or <agent>:<version>; * matches all versions.
|
|
74
74
|
Exact selectors override wildcard selectors field by field.
|
|
75
|
-
Writes the same store as 'agents
|
|
75
|
+
Writes the same store as 'agents config set run.<agent@version>.*'. Explicit flags on
|
|
76
76
|
'agents run' always win over configured defaults.
|
|
77
77
|
`,
|
|
78
78
|
});
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* the pinned browser or re-point the device default.
|
|
9
9
|
*/
|
|
10
10
|
import chalk from 'chalk';
|
|
11
|
-
import {
|
|
11
|
+
import { setConfigValue } from '../lib/device-config.js';
|
|
12
12
|
import { findFirstInstalledBrowser, listInstalledBrowsers } from '../lib/browser/chrome.js';
|
|
13
13
|
import { DEFAULT_BROWSER_PROFILE_NAME, createProfile, findFreeProfilePort, getConfiguredDefaultProfileName, getProfile, } from '../lib/browser/profiles.js';
|
|
14
14
|
import { DEFAULT_VIEWPORT } from '../lib/browser/devices.js';
|
|
@@ -113,7 +113,7 @@ async function maybeSetDeviceDefault(name, confirm) {
|
|
|
113
113
|
default: true,
|
|
114
114
|
});
|
|
115
115
|
if (set) {
|
|
116
|
-
|
|
116
|
+
setConfigValue('browser.profile', name);
|
|
117
117
|
console.log(chalk.dim(`Bare \`agents browser start\` will now use "${name}" on this machine.`));
|
|
118
118
|
}
|
|
119
119
|
}
|
|
@@ -25,7 +25,6 @@ const DISABLEABLE_FEATURES = [
|
|
|
25
25
|
{ name: 'secrets', hint: 'keychain-backed env bundles' },
|
|
26
26
|
{ name: 'routines', hint: 'run agents on a cron schedule' },
|
|
27
27
|
{ name: 'monitors', hint: 'event-triggered watchers' },
|
|
28
|
-
{ name: 'wallet', hint: 'payment cards' },
|
|
29
28
|
];
|
|
30
29
|
/**
|
|
31
30
|
* Interactive white-label setup. Returns true when a brand exists afterward,
|
|
@@ -67,7 +67,7 @@ export async function maybePickInteractiveHost() {
|
|
|
67
67
|
default: defaultInteractiveHostChoice(macs, self) ?? SKIP,
|
|
68
68
|
choices: [
|
|
69
69
|
...macs.map((n) => ({ name: n === self ? `${n} ${chalk.dim('(this machine)')}` : n, value: n })),
|
|
70
|
-
{ name: `Skip ${chalk.dim('— decide later: agents devices
|
|
70
|
+
{ name: `Skip ${chalk.dim('— decide later: agents devices config <name> interactive.host <name>')}`, value: SKIP },
|
|
71
71
|
],
|
|
72
72
|
});
|
|
73
73
|
if (picked === SKIP)
|