@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
package/dist/commands/feed.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ensureFeedPublishHook, listAskStats, listBlocks, recordNotified, buildD
|
|
|
3
3
|
import { ensureActivityLogHook, readRecentActivity, formatActivityLine, formatProgressUpdate, mergeActivityEvents, parseActivityPayload, } from '../lib/activity.js';
|
|
4
4
|
import { projectKeyFromCwd } from '../lib/project-key.js';
|
|
5
5
|
import { postFeedStatus } from '../lib/feed-post.js';
|
|
6
|
-
import { parseFeedPostLevel, planFeedBroadcast, runFeedBroadcast, effectiveBroadcastConfig, blockBroadcastContext, blockDeliveryFailure, } from '../lib/feed-broadcast.js';
|
|
6
|
+
import { parseFeedPostLevel, planFeedBroadcast, runFeedBroadcast, effectiveBroadcastConfig, withDesktopNotify, blockBroadcastContext, blockDeliveryFailure, } from '../lib/feed-broadcast.js';
|
|
7
7
|
import { getSessionById } from '../lib/session/db.js';
|
|
8
8
|
import { readMeta } from '../lib/state.js';
|
|
9
9
|
import { enrichBlocksFromSessions, groupBlocksByOutcome, isUnambiguousOutcomeAnswer, openBlocksForOutcome, stampBlockOutcomes, } from '../lib/feed-outcome.js';
|
|
@@ -33,6 +33,10 @@ Examples:
|
|
|
33
33
|
# Worth interrupting someone over - reaches sinks gated on minLevel: important:
|
|
34
34
|
agents feed post --title "npm token expired" "Cannot publish the release" --level important
|
|
35
35
|
|
|
36
|
+
# Also raise a local desktop banner on THIS machine (same notifier as run
|
|
37
|
+
# --notify), on top of any configured broadcast - useful when you are at the box:
|
|
38
|
+
agents feed post --title "Build green" "all checks passed" --notify
|
|
39
|
+
|
|
36
40
|
# Stuck: opens a needs-you block and always broadcasts at important:
|
|
37
41
|
agents feed post --title "Force-push denied" "git-guard blocked PR #1749" --blocked
|
|
38
42
|
agents feed post --title "Publish or wait?" "npm publish now or after review" --blocked --option publish --option wait
|
|
@@ -51,7 +55,7 @@ PRs) are not CLI flags - the ticket is joined from the session index at post
|
|
|
51
55
|
time. No em-dashes in title/body - they are scrubbed on the way out.
|
|
52
56
|
|
|
53
57
|
Configure where a post is mirrored under feed.broadcast in agents.yaml - see
|
|
54
|
-
docs/
|
|
58
|
+
docs/observability.md. A milestone is always recorded, but it does not text
|
|
55
59
|
the owner when the sink has minLevel: important. Add --level important for a
|
|
56
60
|
phone-worthy successful update. Use --blocked only when work cannot continue.
|
|
57
61
|
The owner destination comes from humans.yaml; do not duplicate it in agents.yaml.
|
|
@@ -331,6 +335,7 @@ export function registerFeedCommand(program) {
|
|
|
331
335
|
.option('--blocked', 'You are STUCK and need the user. Opens an answerable block and always broadcasts at important - do not also pass --level.')
|
|
332
336
|
.option('--option <label...>', 'With --blocked: an answer the user can pick; repeatable')
|
|
333
337
|
.option('--default <answer>', 'With --blocked: a safe default policy may apply if nobody answers in time')
|
|
338
|
+
.option('--notify', 'Also raise a local desktop banner on THIS machine (the same notifier as `run --notify`), on top of any configured broadcast. Fires at any level.')
|
|
334
339
|
.option('--json', 'Emit the written event as JSON')
|
|
335
340
|
.addHelpText('after', FEED_POST_HELP)
|
|
336
341
|
.action(async (textParts, opts, cmd) => {
|
|
@@ -345,6 +350,7 @@ export function registerFeedCommand(program) {
|
|
|
345
350
|
blocked: Boolean(opts?.blocked ?? cmd?.opts?.()?.blocked),
|
|
346
351
|
option: opts?.option ?? cmd?.opts?.()?.option,
|
|
347
352
|
default: opts?.default ?? cmd?.opts?.()?.default,
|
|
353
|
+
notify: Boolean(opts?.notify ?? cmd?.opts?.()?.notify),
|
|
348
354
|
json: Boolean(opts?.json ?? cmd?.opts?.()?.json ?? cmd?.parent?.opts?.()?.json),
|
|
349
355
|
};
|
|
350
356
|
try {
|
|
@@ -396,10 +402,10 @@ export function registerFeedCommand(program) {
|
|
|
396
402
|
agent: event.agent,
|
|
397
403
|
title: event.title,
|
|
398
404
|
body: event.detail,
|
|
399
|
-
}, meta);
|
|
405
|
+
}, meta, flags.notify);
|
|
400
406
|
}
|
|
401
407
|
else {
|
|
402
|
-
outcomes = await broadcastPostedEvent(event, level, meta);
|
|
408
|
+
outcomes = await broadcastPostedEvent(event, level, meta, flags.notify);
|
|
403
409
|
}
|
|
404
410
|
// Fail loud when a block reached nobody. This is computed BEFORE the
|
|
405
411
|
// --json early return: a machine caller is exactly the one that reads the
|
|
@@ -691,8 +697,10 @@ function registerFeedObserveAliases(program) {
|
|
|
691
697
|
* and the delivery are pinned to one config snapshot, and so this is testable
|
|
692
698
|
* against a real in-memory `Meta` without touching `~/.agents/agents.yaml`.
|
|
693
699
|
*/
|
|
694
|
-
async function broadcastPostedEvent(event, level, meta) {
|
|
695
|
-
|
|
700
|
+
async function broadcastPostedEvent(event, level, meta, notify = false) {
|
|
701
|
+
// `--notify` adds a local desktop banner on top of the configured sinks; it
|
|
702
|
+
// fires even for a milestone post that no configured sink would broadcast.
|
|
703
|
+
const config = withDesktopNotify(effectiveBroadcastConfig(meta.feed?.broadcast, level, meta), notify);
|
|
696
704
|
if (!config)
|
|
697
705
|
return [];
|
|
698
706
|
const ticket = getSessionById(event.sessionId)?.ticketId;
|
|
@@ -720,8 +728,8 @@ async function broadcastPostedEvent(event, level, meta) {
|
|
|
720
728
|
* `feed post`, while every `publishBlock` call wrote to the ledger and stopped
|
|
721
729
|
* there — so a "needs you" record was durable and invisible at the same time.
|
|
722
730
|
*/
|
|
723
|
-
async function broadcastBlock(block, extras, meta) {
|
|
724
|
-
const config = effectiveBroadcastConfig(meta.feed?.broadcast, 'important', meta);
|
|
731
|
+
async function broadcastBlock(block, extras, meta, notify = false) {
|
|
732
|
+
const config = withDesktopNotify(effectiveBroadcastConfig(meta.feed?.broadcast, 'important', meta), notify);
|
|
725
733
|
if (!config)
|
|
726
734
|
return [];
|
|
727
735
|
const ticket = getSessionById(block.sessionId)?.ticketId;
|
package/dist/commands/focus.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { Command } from 'commander';
|
|
16
16
|
import { probeAttachRail, type AttachRailLiveness, type UnreachableFallback } from './go.js';
|
|
17
|
-
import type
|
|
17
|
+
import { type ActiveSession } from '../lib/session/active.js';
|
|
18
18
|
import { type SessionMeta } from '../lib/session/types.js';
|
|
19
19
|
import { type LiveStatusFilter } from './sessions.js';
|
|
20
20
|
import { openSurfaces, type Backend } from '../lib/terminal/index.js';
|
|
@@ -74,6 +74,38 @@ export declare function selectFallback(attachOnly: boolean | undefined): Unreach
|
|
|
74
74
|
export declare function focusAction(id: string | undefined, opts: FocusOptions): Promise<void>;
|
|
75
75
|
/** A retained pane is not attachable merely because tmux can still display it. */
|
|
76
76
|
export declare function isAttachableLiveSession(session: ActiveSession): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Collapse rows that are the SAME logical session.
|
|
79
|
+
*
|
|
80
|
+
* A transcript syncs across the fleet, so one session appears once per machine
|
|
81
|
+
* holding a copy. SES-IF-2a: "Synced copies sharing the same full id MUST count
|
|
82
|
+
* as one logical session." `fleetCandidatesByQuery` already groups this way, but
|
|
83
|
+
* this path filtered raw rows instead — so `focus <full-uuid>` answered
|
|
84
|
+
* "is ambiguous (2 sessions). Use more of the id." with no longer id to give.
|
|
85
|
+
* Measured on zion: one of the two rows had no transcript at all
|
|
86
|
+
* ("Session transcript not available (file no longer exists). Path: ").
|
|
87
|
+
*/
|
|
88
|
+
export declare function dedupeSessionsByLogicalId(rows: SessionMeta[], self?: string): SessionMeta[];
|
|
89
|
+
export type TmuxAliasState = 'not-an-alias' | 'no-server' | 'absent' | 'dead' | 'live';
|
|
90
|
+
/** Shape of the tmux alias the CLI mints for an agent session: `ag-<agent>-<shortid>`.
|
|
91
|
+
* Delegates to the one canonical matcher beside the name parsers in active.ts. */
|
|
92
|
+
export declare function looksLikeTmuxAlias(selector: string): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Classify a selector against the live tmux server. Split from the attach so the
|
|
95
|
+
* decision is testable against a real tmux server without replacing the caller's
|
|
96
|
+
* shell (attaching is not something a test can undo).
|
|
97
|
+
*/
|
|
98
|
+
export declare function resolveTmuxAliasState(selector: string, socket?: string): Promise<TmuxAliasState>;
|
|
99
|
+
/**
|
|
100
|
+
* The session to focus once an id/identity selector has resolved across the
|
|
101
|
+
* fleet. Prefer the already-gathered candidate-pool row (it carries the live
|
|
102
|
+
* status collected for the picker), but fall back to the resolver's own metadata
|
|
103
|
+
* when the resolved session is not in the filtered pool — a peer-owned, older, or
|
|
104
|
+
* other-project session that the display filters excluded. Returning the resolved
|
|
105
|
+
* session there (instead of rejecting it) is what lets `focus <id>` reach a
|
|
106
|
+
* peer-owned session without `--device`, matching `resume`/`preview`.
|
|
107
|
+
*/
|
|
108
|
+
export declare function focusTargetForResolved(poolMatch: SessionMeta | undefined, resolved: SessionMeta): SessionMeta;
|
|
77
109
|
/** Focus one row selected by the shared session browser through the same
|
|
78
110
|
* attach/recover decision as `agents sessions focus <id>`. */
|
|
79
111
|
export declare function focusSelectedSession(meta: SessionMeta, active: ActiveSession | undefined, self: string): Promise<void>;
|
package/dist/commands/focus.js
CHANGED
|
@@ -16,6 +16,9 @@ import fs from 'node:fs';
|
|
|
16
16
|
import chalk from 'chalk';
|
|
17
17
|
import { confirm } from '@inquirer/prompts';
|
|
18
18
|
import { gatherLiveTargets, pickLiveTarget, pickLiveTargets, jumpTo, probeAttachRail, refuseFallback } from './go.js';
|
|
19
|
+
import { sessionProcessIsLocal, sessionProcessHost, shortIdFromName } from '../lib/session/active.js';
|
|
20
|
+
import { attachTmux, getDefaultSocketPath, hasSession, runTmux } from '../lib/tmux/index.js';
|
|
21
|
+
import { isAgentTmuxAlias } from '../lib/session/types.js';
|
|
19
22
|
import { buildSessionRecoveryCommand, filterSessionsByQuery, formatLiveStatusHeadline, formatPickerLabel, isRunningLiveSession, pickerColumnsFor, resumeSessionInPlace, resolveSessionMetadataValue, resolveSessionAgentName, requestedLiveStatuses, } from './sessions.js';
|
|
20
23
|
import { resolveBackend, CONFIRM_THRESHOLD } from './sessions-resume.js';
|
|
21
24
|
import { runOnPeer } from '../lib/session/remote-list.js';
|
|
@@ -69,7 +72,12 @@ function statusWord(status) {
|
|
|
69
72
|
}
|
|
70
73
|
export function registerFocusCommand(program) {
|
|
71
74
|
const cmd = program
|
|
72
|
-
.
|
|
75
|
+
// Hidden, but deliberately NOT warned. `sessions resume <id>` dispatches by
|
|
76
|
+
// spawning `agents sessions focus <id>` (buildSessionLifecycleArgs), so a
|
|
77
|
+
// deprecation notice here would print on every ordinary resume. focus is now
|
|
78
|
+
// the internal lifecycle dispatcher; `resume` is the surface. Do not add a
|
|
79
|
+
// console.warn here without first removing that delegation.
|
|
80
|
+
.command('focus', { hidden: true })
|
|
73
81
|
.argument('[selector]', 'Session id/prefix, agent@version, or topic/path search')
|
|
74
82
|
.option('--local', 'Only this machine (skip the cross-host sweep)')
|
|
75
83
|
.option('--attach-only', 'Attach only — never open a new tab / resume a copy (the old `go` behavior)')
|
|
@@ -134,6 +142,7 @@ export function registerFocusCommand(program) {
|
|
|
134
142
|
- space toggles a session, enter opens the selected set; a single check + enter opens just one.
|
|
135
143
|
- With no selector/filter, the picker shows the live fleet. An id focuses directly; agent@version and text selectors always show the preview picker.
|
|
136
144
|
- A living tmux pane is JOINED (a second client, no fork). Dead/missing panes recover on the origin device: exact healthy origin uses native resume; otherwise a healthy version of the same harness receives /continue <id>.
|
|
145
|
+
- An id/identity selector resolves across the whole reachable fleet on its own — you do NOT need --device to focus a session that lives on another box (same as resume/preview). --device only narrows the browsable picker and the agent/version resolution.
|
|
137
146
|
- --host/--device and the sessions-browser filters compose. latest/oldest resolve against each selected device's installed versions.
|
|
138
147
|
Lifecycle siblings (not synonyms):
|
|
139
148
|
focus attach if alive, otherwise recover (default "take me there")
|
|
@@ -159,7 +168,7 @@ export async function focusAction(id, opts) {
|
|
|
159
168
|
const local = !!opts.local && hosts.length === 0;
|
|
160
169
|
const fallback = selectFallback(opts.attachOnly);
|
|
161
170
|
const agentSelector = focusAgentSelector(id, opts);
|
|
162
|
-
|
|
171
|
+
let textSelector = id && !agentSelector ? id : undefined;
|
|
163
172
|
const filtered = !!id || hasFocusFilters(opts, statuses);
|
|
164
173
|
// Preserve the fast live multi-picker for an unqualified `focus`. Every
|
|
165
174
|
// selector/filter path below uses the sessions browser's shared candidate
|
|
@@ -200,14 +209,41 @@ export async function focusAction(id, opts) {
|
|
|
200
209
|
if (unreachable.length > 0) {
|
|
201
210
|
console.error(chalk.yellow(`Unavailable devices: ${unreachable.join(', ')}`));
|
|
202
211
|
}
|
|
203
|
-
|
|
204
|
-
|
|
212
|
+
const idSelector = textSelector && looksLikeIdSelector(textSelector) ? textSelector.toLowerCase() : undefined;
|
|
213
|
+
let exact = idSelector
|
|
214
|
+
? dedupeSessionsByLogicalId(sessions.filter((session) => session.id.toLowerCase().startsWith(idSelector)), self)
|
|
205
215
|
: [];
|
|
216
|
+
// A tmux alias naming a LIVE local session attaches directly. This must run
|
|
217
|
+
// before the metadata resolver: that resolver treats an unmatched alias as a
|
|
218
|
+
// keyword query, so `ag-kimi-632c1fbc` came back as 13 unrelated text hits
|
|
219
|
+
// while the pane was alive and attachable the whole time.
|
|
220
|
+
if (exact.length === 0 && textSelector && !hosts.length && await attachLiveTmuxAlias(textSelector))
|
|
221
|
+
return;
|
|
222
|
+
// Not live (or remote-scoped): an alias still carries the session's shortid,
|
|
223
|
+
// so resolve by THAT rather than handing the whole `ag-<agent>-<shortid>`
|
|
224
|
+
// string to the resolver — which treats an unmatched alias as a keyword
|
|
225
|
+
// query and answered `"ag-claude-dead5678" matches 200 sessions` for a pane
|
|
226
|
+
// whose process had simply exited. SES-41 requires an alias to resolve to one
|
|
227
|
+
// canonical session id.
|
|
228
|
+
if (textSelector && isAgentTmuxAlias(textSelector)) {
|
|
229
|
+
const short = shortIdFromName(textSelector);
|
|
230
|
+
if (short) {
|
|
231
|
+
textSelector = short;
|
|
232
|
+
exact = dedupeSessionsByLogicalId(sessions.filter((session) => session.id.toLowerCase().startsWith(short)), self);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
206
235
|
if (exact.length === 0 && textSelector && looksLikeIdentitySelector(textSelector)) {
|
|
207
236
|
const outcome = await resolveSessionMetadataValue(textSelector, { local, hosts });
|
|
208
237
|
if (outcome.kind === 'partial') {
|
|
209
|
-
|
|
210
|
-
|
|
238
|
+
// RUSH-2492: an unreachable peer is a warning, not a hard failure. The
|
|
239
|
+
// resolver already resolves an id found on the reachable fleet (SES-9a),
|
|
240
|
+
// so reaching here means the session was not found on any device we COULD
|
|
241
|
+
// reach — it may live on an unreachable peer, which we could not check.
|
|
242
|
+
const offline = outcome.failedPeers;
|
|
243
|
+
console.error(chalk.yellow(`Warning: ${offline.length} device(s) unreachable, not checked: ${offline.join(', ')}`));
|
|
244
|
+
console.error(chalk.red(`No session matching "${textSelector}" on any reachable device (${offline.length} unreachable, not checked).`));
|
|
245
|
+
console.error(chalk.gray(' If it lives on an offline box, wake it (agents devices) or run there: agents ssh <device>'));
|
|
246
|
+
process.exitCode = 1;
|
|
211
247
|
return;
|
|
212
248
|
}
|
|
213
249
|
if (outcome.kind === 'ambiguous') {
|
|
@@ -220,13 +256,17 @@ export async function focusAction(id, opts) {
|
|
|
220
256
|
process.exitCode = 1;
|
|
221
257
|
return;
|
|
222
258
|
}
|
|
259
|
+
// The fleet resolver is authoritative for an id/identity selector — the same
|
|
260
|
+
// one `resume`/`preview` use, and it already fanned out across the reachable
|
|
261
|
+
// fleet. Focus the session it found even when that session falls outside the
|
|
262
|
+
// candidate-pool DISPLAY filters (project scope, time window, device): those
|
|
263
|
+
// filters scope the browsable list, not an exact id lookup. Requiring the
|
|
264
|
+
// resolved row to ALSO be in the filtered pool is what made focusing a
|
|
265
|
+
// peer-owned (or older / other-project) session need `--device`. Prefer the
|
|
266
|
+
// pool's row when it carries the already-gathered live status, else fall back
|
|
267
|
+
// to the resolved metadata (focusResolvedSession hops to the owner from it).
|
|
223
268
|
const filteredMatch = sessions.find((session) => session.id === outcome.session.id);
|
|
224
|
-
|
|
225
|
-
console.error(chalk.red(`Session ${outcome.session.shortId} does not match the selected focus filters.`));
|
|
226
|
-
process.exitCode = 1;
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
exact = [filteredMatch];
|
|
269
|
+
exact = [focusTargetForResolved(filteredMatch, outcome.session)];
|
|
230
270
|
}
|
|
231
271
|
if (exact.length === 1) {
|
|
232
272
|
await focusResolvedSession(exact[0], liveById, self, fallback, opts.attachOnly === true);
|
|
@@ -299,7 +339,107 @@ function looksLikeIdSelector(selector) {
|
|
|
299
339
|
}
|
|
300
340
|
function looksLikeIdentitySelector(selector) {
|
|
301
341
|
return !!selector && (/^[0-9a-f][0-9a-f-]{5,}$/i.test(selector) ||
|
|
302
|
-
|
|
342
|
+
isAgentTmuxAlias(selector));
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Attach a live tmux session named exactly as the selector, without needing the
|
|
346
|
+
* session index to know anything about it.
|
|
347
|
+
*
|
|
348
|
+
* SES-41 requires a `ag-<agent>-<8hex>` tmux alias to resolve, but the alias's
|
|
349
|
+
* hex is the LAUNCH id, not the harness session id, and for a harness that
|
|
350
|
+
* writes no `state/sessions/<pid>.json` record there is no mapping back to a
|
|
351
|
+
* SessionMeta at all. Measured on yosemite-s0: `--resolve ag-kimi-632c1fbc`
|
|
352
|
+
* fell through to a keyword search and returned 13 unrelated rows, while the
|
|
353
|
+
* pane itself was alive (`%124`, `kimi-code`). The pane is the thing the user
|
|
354
|
+
* asked for, and its NAME is sufficient to attach it — so an unattributable
|
|
355
|
+
* session is still reachable instead of being a dead end that forces raw
|
|
356
|
+
* `tmux -S … attach`.
|
|
357
|
+
*
|
|
358
|
+
* Returns false when this is not an alias, the server/session is absent, or
|
|
359
|
+
* every pane is dead — the caller then continues to normal id resolution.
|
|
360
|
+
* SES-39's "re-read `pane_dead` immediately before attach" is honoured here:
|
|
361
|
+
* liveness is queried at attach time, not read from the roster.
|
|
362
|
+
*/
|
|
363
|
+
/**
|
|
364
|
+
* Rank two rows that are the same logical session, best first.
|
|
365
|
+
*
|
|
366
|
+
* Prefer the row that can actually be acted on: a real transcript over a
|
|
367
|
+
* phantom index entry (a purged copy indexes with an empty `filePath`), then
|
|
368
|
+
* this machine's copy over a peer mirror — resuming is machine-bound, so the
|
|
369
|
+
* local row is the one whose harness state exists here.
|
|
370
|
+
*/
|
|
371
|
+
function sessionRowRank(s, self) {
|
|
372
|
+
return (s.filePath ? 4 : 0) + (self && s.machine === self ? 2 : 0) + (s._remote ? 0 : 1);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Collapse rows that are the SAME logical session.
|
|
376
|
+
*
|
|
377
|
+
* A transcript syncs across the fleet, so one session appears once per machine
|
|
378
|
+
* holding a copy. SES-IF-2a: "Synced copies sharing the same full id MUST count
|
|
379
|
+
* as one logical session." `fleetCandidatesByQuery` already groups this way, but
|
|
380
|
+
* this path filtered raw rows instead — so `focus <full-uuid>` answered
|
|
381
|
+
* "is ambiguous (2 sessions). Use more of the id." with no longer id to give.
|
|
382
|
+
* Measured on zion: one of the two rows had no transcript at all
|
|
383
|
+
* ("Session transcript not available (file no longer exists). Path: ").
|
|
384
|
+
*/
|
|
385
|
+
export function dedupeSessionsByLogicalId(rows, self) {
|
|
386
|
+
const byId = new Map();
|
|
387
|
+
for (const row of rows) {
|
|
388
|
+
const key = row.id.toLowerCase();
|
|
389
|
+
const held = byId.get(key);
|
|
390
|
+
if (!held || sessionRowRank(row, self) > sessionRowRank(held, self))
|
|
391
|
+
byId.set(key, row);
|
|
392
|
+
}
|
|
393
|
+
return [...byId.values()];
|
|
394
|
+
}
|
|
395
|
+
/** Shape of the tmux alias the CLI mints for an agent session: `ag-<agent>-<shortid>`.
|
|
396
|
+
* Delegates to the one canonical matcher beside the name parsers in active.ts. */
|
|
397
|
+
export function looksLikeTmuxAlias(selector) {
|
|
398
|
+
return isAgentTmuxAlias(selector);
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Classify a selector against the live tmux server. Split from the attach so the
|
|
402
|
+
* decision is testable against a real tmux server without replacing the caller's
|
|
403
|
+
* shell (attaching is not something a test can undo).
|
|
404
|
+
*/
|
|
405
|
+
export async function resolveTmuxAliasState(selector, socket) {
|
|
406
|
+
if (!looksLikeTmuxAlias(selector))
|
|
407
|
+
return 'not-an-alias';
|
|
408
|
+
const sock = socket ?? getDefaultSocketPath();
|
|
409
|
+
if (!fs.existsSync(sock))
|
|
410
|
+
return 'no-server';
|
|
411
|
+
if (!(await hasSession(selector, sock).catch(() => false)))
|
|
412
|
+
return 'absent';
|
|
413
|
+
const panes = await runTmux({
|
|
414
|
+
socket: sock,
|
|
415
|
+
args: ['list-panes', '-t', `=${selector}`, '-F', '#{pane_dead}'],
|
|
416
|
+
}).catch(() => undefined);
|
|
417
|
+
const states = (panes?.stdout ?? '').split('\n').map(s => s.trim()).filter(Boolean);
|
|
418
|
+
return states.some(d => d === '0') ? 'live' : 'dead';
|
|
419
|
+
}
|
|
420
|
+
async function attachLiveTmuxAlias(selector) {
|
|
421
|
+
const socket = getDefaultSocketPath();
|
|
422
|
+
if (await resolveTmuxAliasState(selector, socket) !== 'live')
|
|
423
|
+
return false;
|
|
424
|
+
if (!process.stdout.isTTY) {
|
|
425
|
+
console.error(chalk.red(`"${selector}" is a live tmux session, but attaching needs a TTY.`));
|
|
426
|
+
console.error(chalk.gray(` Run it from a terminal, or: agents tmux attach ${selector}`));
|
|
427
|
+
process.exitCode = 1;
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
// Already inside a tmux client on this socket — which is the normal state for
|
|
431
|
+
// an interactive agent session here — MOVE that client instead of nesting a
|
|
432
|
+
// second one. jumpTo (go.ts) does the same; attaching from inside tmux
|
|
433
|
+
// otherwise stacks clients rather than taking you to the session.
|
|
434
|
+
if (process.env.TMUX) {
|
|
435
|
+
await runTmux({ socket, args: ['switch-client', '-t', `=${selector}`], throwOnError: false }).catch(() => { });
|
|
436
|
+
console.log(chalk.gray(`Switched this tmux client to ${selector}.`));
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
console.log(chalk.gray(`Attaching ${selector} — Ctrl-b d to detach.`));
|
|
440
|
+
const code = await attachTmux({ socket, args: ['attach-session', '-t', `=${selector}`] });
|
|
441
|
+
process.exitCode = code;
|
|
442
|
+
return true;
|
|
303
443
|
}
|
|
304
444
|
function hasFocusFilters(opts, statuses) {
|
|
305
445
|
return statuses.length > 0 || !!(opts.active || opts.local || opts.host?.length || opts.device?.length || focusOptionAgent(opts) ||
|
|
@@ -347,6 +487,18 @@ async function pickFocusCandidates(sessions, liveById, initialSearch) {
|
|
|
347
487
|
throw err;
|
|
348
488
|
}
|
|
349
489
|
}
|
|
490
|
+
/**
|
|
491
|
+
* The session to focus once an id/identity selector has resolved across the
|
|
492
|
+
* fleet. Prefer the already-gathered candidate-pool row (it carries the live
|
|
493
|
+
* status collected for the picker), but fall back to the resolver's own metadata
|
|
494
|
+
* when the resolved session is not in the filtered pool — a peer-owned, older, or
|
|
495
|
+
* other-project session that the display filters excluded. Returning the resolved
|
|
496
|
+
* session there (instead of rejecting it) is what lets `focus <id>` reach a
|
|
497
|
+
* peer-owned session without `--device`, matching `resume`/`preview`.
|
|
498
|
+
*/
|
|
499
|
+
export function focusTargetForResolved(poolMatch, resolved) {
|
|
500
|
+
return poolMatch ?? resolved;
|
|
501
|
+
}
|
|
350
502
|
async function focusResolvedSession(meta, liveById, self, fallback, attachOnly) {
|
|
351
503
|
const active = liveById.get(meta.id);
|
|
352
504
|
if (active && isAttachableLiveSession(active)) {
|
|
@@ -358,7 +510,7 @@ async function focusResolvedSession(meta, liveById, self, fallback, attachOnly)
|
|
|
358
510
|
process.exitCode = 1;
|
|
359
511
|
return;
|
|
360
512
|
}
|
|
361
|
-
const remote = meta
|
|
513
|
+
const remote = sessionProcessHost(meta, self);
|
|
362
514
|
if (remote) {
|
|
363
515
|
console.log(chalk.gray(`Recovering ${meta.shortId} on ${remote}…`));
|
|
364
516
|
const rc = await runOnPeer(sessionRecoveryRunArgs(meta), remote, { tty: true });
|
|
@@ -427,7 +579,7 @@ export function tmuxAttachScript(mux) {
|
|
|
427
579
|
* and the tests stay decoupled from `discoverSessions`).
|
|
428
580
|
*/
|
|
429
581
|
export function planFocusSurface(s, self, resumeCommandFor, rail = { state: 'alive' }) {
|
|
430
|
-
const remote = s
|
|
582
|
+
const remote = sessionProcessHost(s, self);
|
|
431
583
|
const mux = s.provenance?.mux;
|
|
432
584
|
const sid = shortId(s);
|
|
433
585
|
// Join rail = tmux only (local or remote over SSH). A new tab attaching the live
|
|
@@ -483,7 +635,7 @@ export async function openFocusTabs(targets, self, deps = {}) {
|
|
|
483
635
|
const resumeCommandFor = (s) => {
|
|
484
636
|
if (deps.attachOnly)
|
|
485
637
|
return null;
|
|
486
|
-
const remote =
|
|
638
|
+
const remote = !sessionProcessIsLocal(s, self);
|
|
487
639
|
return buildSessionRecoveryCommand(metaFor(s), remote);
|
|
488
640
|
};
|
|
489
641
|
const planned = await Promise.all(targets.map(async (s) => {
|
|
@@ -518,7 +670,15 @@ export async function openFocusTabs(targets, self, deps = {}) {
|
|
|
518
670
|
return;
|
|
519
671
|
}
|
|
520
672
|
console.log(chalk.gray(`Opening ${openable.length} session${openable.length === 1 ? '' : 's'} in ${backend} (tabs)…`));
|
|
521
|
-
|
|
673
|
+
// Pass agent + sessionId so the vscodium-agent backend can stamp the tab
|
|
674
|
+
// chip without sniffing the local process tree (remote attach has no agent
|
|
675
|
+
// binary on this box — #2478).
|
|
676
|
+
const results = await open(openable.map((p) => ({
|
|
677
|
+
cwd: cwdFor(p.s, byId),
|
|
678
|
+
command: p.plan.command,
|
|
679
|
+
agent: p.s.kind || undefined,
|
|
680
|
+
sessionId: p.s.sessionId || undefined,
|
|
681
|
+
})), { backend, packing: 'tabs' });
|
|
522
682
|
let opened = 0;
|
|
523
683
|
results.forEach((r, i) => {
|
|
524
684
|
const p = openable[i];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `agents funnel` — thin Tailscale Funnel wrapper for webhook ingress nodes.
|
|
2
|
+
* `agents daemon funnel` — thin Tailscale Funnel wrapper for webhook ingress nodes.
|
|
3
3
|
*/
|
|
4
4
|
import type { Command } from 'commander';
|
|
5
5
|
export declare function registerFunnelCommand(program: Command): void;
|
package/dist/commands/go.js
CHANGED
|
@@ -17,7 +17,7 @@ import chalk from 'chalk';
|
|
|
17
17
|
import path from 'path';
|
|
18
18
|
import { execFile } from 'child_process';
|
|
19
19
|
import { promisify } from 'util';
|
|
20
|
-
import { getActiveSessions, findSessionFileForKind } from '../lib/session/active.js';
|
|
20
|
+
import { getActiveSessions, findSessionFileForKind, sessionProcessIsLocal, sessionProcessHost } from '../lib/session/active.js';
|
|
21
21
|
import { gatherRemoteActive } from '../lib/session/remote-active.js';
|
|
22
22
|
import { discoverSessions } from '../lib/session/discover.js';
|
|
23
23
|
import { deriveShortId } from '../lib/session/short-id.js';
|
|
@@ -35,12 +35,13 @@ import { enumerateGhosttyTabs, assignGhosttyTabs } from '../lib/session/ghostty-
|
|
|
35
35
|
const execFileAsync = promisify(execFile);
|
|
36
36
|
export function registerGoCommand(program) {
|
|
37
37
|
program
|
|
38
|
-
.command('go')
|
|
38
|
+
.command('go', { hidden: true })
|
|
39
39
|
.argument('[id]', 'Short/full session id to jump to; omit for an interactive picker')
|
|
40
40
|
.option('--local', 'Only this machine (skip the cross-host sweep)')
|
|
41
|
-
.description('Deprecated
|
|
41
|
+
.description('Deprecated — use `agents sessions resume --attach-only` instead.')
|
|
42
42
|
.action(async (id, opts) => {
|
|
43
|
-
console.
|
|
43
|
+
console.warn(chalk.yellow('`agents sessions go` is deprecated — use `agents sessions resume --attach-only` instead:'));
|
|
44
|
+
console.warn(chalk.gray(` agents sessions resume ${id ?? '<id>'} --attach-only`));
|
|
44
45
|
await focusAction(id, { local: opts.local, attachOnly: true });
|
|
45
46
|
});
|
|
46
47
|
}
|
|
@@ -163,7 +164,7 @@ export async function buildLivePool(activeById, self) {
|
|
|
163
164
|
return mergeLocalFirst(pool, self);
|
|
164
165
|
}
|
|
165
166
|
function synthMeta(s, self) {
|
|
166
|
-
const remote =
|
|
167
|
+
const remote = !sessionProcessIsLocal(s, self);
|
|
167
168
|
// For a local session, locate the real transcript on disk so the picker's
|
|
168
169
|
// buildPreview parses it directly (rich Prompt/Changes/Tools/Last response) —
|
|
169
170
|
// independent of the sessions DB. Remote transcripts live on the peer, so leave
|
|
@@ -191,7 +192,7 @@ function shortId(s) {
|
|
|
191
192
|
* `jumpTo` below: remote-tmux, then local-tmux, then ghostty, then refuse.
|
|
192
193
|
*/
|
|
193
194
|
export function describeWhere(s, self) {
|
|
194
|
-
const remote = s
|
|
195
|
+
const remote = sessionProcessHost(s, self);
|
|
195
196
|
const mux = s.provenance?.mux;
|
|
196
197
|
if (mux?.kind === 'tmux' && mux.pane) {
|
|
197
198
|
// When the renderer has resolved the current viewer, fold it into the label
|
|
@@ -216,7 +217,7 @@ export async function probeAttachRail(s, self) {
|
|
|
216
217
|
const mux = s.provenance?.mux;
|
|
217
218
|
if (mux?.kind !== 'tmux' || !mux.pane)
|
|
218
219
|
return { state: 'missing' };
|
|
219
|
-
const remote = s
|
|
220
|
+
const remote = sessionProcessHost(s, self);
|
|
220
221
|
if (!remote) {
|
|
221
222
|
const pane = await paneExitStatus(mux.pane, mux.socket ?? getDefaultSocketPath());
|
|
222
223
|
if (!pane.found)
|
|
@@ -253,7 +254,7 @@ export async function refuseFallback(s, remote) {
|
|
|
253
254
|
process.exitCode = 1;
|
|
254
255
|
}
|
|
255
256
|
export async function jumpTo(s, self, fallback = refuseFallback) {
|
|
256
|
-
const remote = s
|
|
257
|
+
const remote = sessionProcessHost(s, self);
|
|
257
258
|
const mux = s.provenance?.mux;
|
|
258
259
|
// Path C: remote tmux — ssh in and attach, resolving the pane's session on the remote.
|
|
259
260
|
if (remote) {
|
|
@@ -31,6 +31,7 @@ import { baseUrlEnvKeyForHost, authEnvKeyForHost, modelEnvKeyForHost, validatePr
|
|
|
31
31
|
import { listPresets, getPreset } from '../lib/profiles-presets.js';
|
|
32
32
|
import { listBundles } from '../lib/secrets/bundles.js';
|
|
33
33
|
import { AGENTS, ALL_AGENT_IDS, isSelfUpdatingAgent, resolveAgentName } from '../lib/agents.js';
|
|
34
|
+
import { readAccountRegistry } from '../lib/account-registry.js';
|
|
34
35
|
/**
|
|
35
36
|
* Resolver-sourced editability, the scaffold default behind the RUSH-2222 seam.
|
|
36
37
|
* Every field is read from the same maps the run-time resolver uses
|
|
@@ -248,10 +249,17 @@ export function createSteps() {
|
|
|
248
249
|
},
|
|
249
250
|
},
|
|
250
251
|
{
|
|
251
|
-
id: '
|
|
252
|
-
decide: (d) => (d.authProvider && d.
|
|
252
|
+
id: 'account',
|
|
253
|
+
decide: (d) => (d.authProvider && d.account === undefined ? 'run' : 'skip'),
|
|
253
254
|
async run(io, d) {
|
|
254
|
-
|
|
255
|
+
const accounts = Object.values(readAccountRegistry().accounts).filter(account => account.provider === d.authProvider);
|
|
256
|
+
if (accounts.length === 0) {
|
|
257
|
+
throw new Error(`No '${d.authProvider}' account exists. Add one first with 'agents accounts add <name> --provider ${d.authProvider} --auth api-key'.`);
|
|
258
|
+
}
|
|
259
|
+
d.account = await io.select({
|
|
260
|
+
message: 'Account',
|
|
261
|
+
choices: accounts.map(account => ({ name: account.name, value: account.name })),
|
|
262
|
+
});
|
|
255
263
|
},
|
|
256
264
|
},
|
|
257
265
|
connectionTestStep(),
|
|
@@ -302,29 +310,19 @@ export function editSteps(original) {
|
|
|
302
310
|
},
|
|
303
311
|
},
|
|
304
312
|
{
|
|
305
|
-
id: '
|
|
313
|
+
id: 'account',
|
|
306
314
|
decide: () => (cap.auth ? 'run' : { disabled: `host '${host}' manages its own login — no auth to edit` }),
|
|
307
315
|
async run(io, d, hooks) {
|
|
308
316
|
if (!editableFor(hooks).auth)
|
|
309
317
|
return;
|
|
310
|
-
const
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
{ name: '
|
|
314
|
-
|
|
315
|
-
if (bundles.length > 0)
|
|
316
|
-
choices.push({ name: 'Copy a key from an agents secrets bundle', value: FROM_SECRETS });
|
|
317
|
-
const choice = await io.select({ message: 'Auth', choices });
|
|
318
|
+
const accounts = Object.values(readAccountRegistry().accounts);
|
|
319
|
+
const choice = await io.select({
|
|
320
|
+
message: 'Account',
|
|
321
|
+
choices: [{ name: 'Leave account unchanged', value: KEEP }, ...accounts.map(account => ({ name: `${account.name} (${account.provider})`, value: account.name }))],
|
|
322
|
+
});
|
|
318
323
|
if (choice === KEEP)
|
|
319
324
|
return;
|
|
320
|
-
|
|
321
|
-
message: 'Provider',
|
|
322
|
-
default: original.provider,
|
|
323
|
-
validate: (v) => (v.trim() ? true : 'Provider is required'),
|
|
324
|
-
});
|
|
325
|
-
d.authProvider = provider;
|
|
326
|
-
if (choice === FROM_SECRETS)
|
|
327
|
-
await askKeySource(io, d, provider);
|
|
325
|
+
d.account = choice;
|
|
328
326
|
},
|
|
329
327
|
},
|
|
330
328
|
{
|
|
@@ -25,6 +25,7 @@ export interface ForkOptions {
|
|
|
25
25
|
model?: string;
|
|
26
26
|
baseUrl?: string;
|
|
27
27
|
authProvider?: string;
|
|
28
|
+
account?: string;
|
|
28
29
|
version?: string;
|
|
29
30
|
description?: string;
|
|
30
31
|
/** `<bundle>` or `<bundle>:<key>` — see {@link applyFromSecrets} in ./profiles.js. */
|
|
@@ -37,6 +38,7 @@ export interface EditOptions {
|
|
|
37
38
|
model?: string;
|
|
38
39
|
baseUrl?: string;
|
|
39
40
|
authProvider?: string;
|
|
41
|
+
account?: string;
|
|
40
42
|
/** Empty string ('') unpins the host CLI version. */
|
|
41
43
|
version?: string;
|
|
42
44
|
description?: string;
|