@phnx-labs/agents-cli 1.22.34 → 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 +672 -2
- package/README.md +82 -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 +85 -0
- package/dist/commands/share.js +379 -8
- 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/codex-policy.d.ts +9 -1
- package/dist/lib/codex-policy.js +17 -2
- 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 +220 -122
- 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-key.d.ts +17 -0
- package/dist/lib/project-key.js +26 -0
- 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/delete.d.ts +93 -0
- package/dist/lib/share/delete.js +127 -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 +136 -27
- 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 +14 -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
|
@@ -77,13 +77,66 @@ export declare function hasSession(name: string, socket?: string): Promise<boole
|
|
|
77
77
|
* `replace` or `attachExisting` is set.
|
|
78
78
|
*/
|
|
79
79
|
export declare function createSession(opts: CreateSessionOptions): Promise<SessionMeta>;
|
|
80
|
-
/**
|
|
81
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Kill one named session. Idempotent — killing a non-existent session is a no-op.
|
|
82
|
+
*
|
|
83
|
+
* Destroying the tmux session only SIGHUPs each pane's FOREGROUND process group,
|
|
84
|
+
* so a helper the agent put in its own process group (an MCP server, a harness
|
|
85
|
+
* background daemon) survives and reparents to init. `reapOrphans` therefore
|
|
86
|
+
* defaults ON: the session's leftover helpers are terminated with it rather than
|
|
87
|
+
* waiting for the daemon's next sweep (RUSH-2521). {@link reapDeadTmuxPanes}
|
|
88
|
+
* passes `false` because it sweeps every session's leftovers in one pass instead
|
|
89
|
+
* of re-snapshotting the process table per session.
|
|
90
|
+
*/
|
|
91
|
+
export declare function killSession(name: string, socket?: string, opts?: {
|
|
92
|
+
reapOrphans?: boolean;
|
|
93
|
+
}): Promise<boolean>;
|
|
82
94
|
/**
|
|
83
95
|
* Kill every session on the shared server AND the server itself, then prune
|
|
84
96
|
* meta files. Wipes the socket so the next `new` starts from a clean slate.
|
|
85
97
|
*/
|
|
86
98
|
export declare function killAll(socket?: string): Promise<number>;
|
|
99
|
+
/** Result returned by {@link reapDeadTmuxPanes}. */
|
|
100
|
+
export interface ReapDeadPanesResult {
|
|
101
|
+
/** Number of tmux sessions killed. */
|
|
102
|
+
reaped: number;
|
|
103
|
+
/** Names of reaped sessions. */
|
|
104
|
+
sessions: string[];
|
|
105
|
+
/** Human-readable lines describing each reap, for log output. */
|
|
106
|
+
details: string[];
|
|
107
|
+
/** Orphaned helper processes terminated (MCP servers, harness background daemons). */
|
|
108
|
+
processes: number;
|
|
109
|
+
/** One human-readable line per terminated helper process. */
|
|
110
|
+
processDetails: string[];
|
|
111
|
+
/** Non-fatal observations worth logging — e.g. a tier-1 sweep skipped this tick because a tmux query failed. */
|
|
112
|
+
warnings: string[];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Kill every tmux session whose panes are ALL dead (`pane_dead=1`), and
|
|
116
|
+
* terminate the helper processes whose owning agent has exited.
|
|
117
|
+
*
|
|
118
|
+
* Dead panes accumulate because `remain-on-exit on` is intentionally set
|
|
119
|
+
* per-pane so the harness can inspect exit status. Without a periodic sweep
|
|
120
|
+
* they pile up indefinitely — e.g. 48 of 127 sessions dead on yosemite-s0
|
|
121
|
+
* (RUSH-2501).
|
|
122
|
+
*
|
|
123
|
+
* Killing the pane is not enough on its own: it SIGHUPs only the pane's
|
|
124
|
+
* FOREGROUND process group, so an MCP server or harness background daemon that
|
|
125
|
+
* moved itself out of that group survives the session that spawned it and keeps
|
|
126
|
+
* its memory forever (RUSH-2521). The process sweep runs FIRST, while the dead
|
|
127
|
+
* sessions still exist, so every leftover is attributed to a named session
|
|
128
|
+
* rather than to a session tmux has already forgotten.
|
|
129
|
+
*
|
|
130
|
+
* Safety invariant: a session with ANY live pane (`pane_dead=0`) is never
|
|
131
|
+
* touched, and neither are the processes belonging to a session whose agent is
|
|
132
|
+
* still running or that has a client attached.
|
|
133
|
+
*
|
|
134
|
+
* `dryRun` reports both halves without killing anything.
|
|
135
|
+
*/
|
|
136
|
+
export declare function reapDeadTmuxPanes(socket?: string, opts?: {
|
|
137
|
+
dryRun?: boolean;
|
|
138
|
+
pids?: number[];
|
|
139
|
+
}): Promise<ReapDeadPanesResult>;
|
|
87
140
|
/**
|
|
88
141
|
* Map every pane id (`%N`) on a socket to its `session:window.pane` attach
|
|
89
142
|
* target, in one batched `tmux list-panes -a` call. `%116 -> main:2.0` is a
|
|
@@ -179,6 +232,18 @@ export declare const AGENT_HOOK_SCHEMA = 5;
|
|
|
179
232
|
export declare function agentPaneDiedHook(sessionName: string, agentPane: string): string;
|
|
180
233
|
/** Stamp a session's hook-schema marker to the current version. */
|
|
181
234
|
export declare function markSessionHookSchema(name: string, socket?: string): Promise<void>;
|
|
235
|
+
/**
|
|
236
|
+
* The outcome of {@link prepareSessionForResume}. `attach` carries the pane it
|
|
237
|
+
* positively resolved so the caller can read that pane's exit status back after
|
|
238
|
+
* its attach client returns — without that, a resume-attach has no handle to ask
|
|
239
|
+
* tmux what happened and can only assume success (EXEC-23b).
|
|
240
|
+
*/
|
|
241
|
+
export type ResumePreparation = {
|
|
242
|
+
decision: 'attach';
|
|
243
|
+
pane: string;
|
|
244
|
+
} | {
|
|
245
|
+
decision: 'create';
|
|
246
|
+
};
|
|
182
247
|
/**
|
|
183
248
|
* Decide whether a native resume may attach an existing managed tmux session.
|
|
184
249
|
* Only a positively resolved, living agent pane is reusable. Metadata-less
|
|
@@ -186,7 +251,7 @@ export declare function markSessionHookSchema(name: string, socket?: string): Pr
|
|
|
186
251
|
* tmux before the decision; a dead or unreadable session is reaped so the
|
|
187
252
|
* caller can create a fresh wrapper for the resumed harness.
|
|
188
253
|
*/
|
|
189
|
-
export declare function prepareSessionForResume(name: string, socket?: string): Promise<
|
|
254
|
+
export declare function prepareSessionForResume(name: string, socket?: string): Promise<ResumePreparation>;
|
|
190
255
|
/**
|
|
191
256
|
* Retrofit the current guarded `pane-died` hook onto every managed `agents run`
|
|
192
257
|
* session whose hook predates AGENT_HOOK_SCHEMA. Idempotent and NON-DESTRUCTIVE:
|
package/dist/lib/tmux/session.js
CHANGED
|
@@ -117,8 +117,18 @@ export async function createSession(opts) {
|
|
|
117
117
|
writeSessionMeta(meta);
|
|
118
118
|
return meta;
|
|
119
119
|
}
|
|
120
|
-
/**
|
|
121
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Kill one named session. Idempotent — killing a non-existent session is a no-op.
|
|
122
|
+
*
|
|
123
|
+
* Destroying the tmux session only SIGHUPs each pane's FOREGROUND process group,
|
|
124
|
+
* so a helper the agent put in its own process group (an MCP server, a harness
|
|
125
|
+
* background daemon) survives and reparents to init. `reapOrphans` therefore
|
|
126
|
+
* defaults ON: the session's leftover helpers are terminated with it rather than
|
|
127
|
+
* waiting for the daemon's next sweep (RUSH-2521). {@link reapDeadTmuxPanes}
|
|
128
|
+
* passes `false` because it sweeps every session's leftovers in one pass instead
|
|
129
|
+
* of re-snapshotting the process table per session.
|
|
130
|
+
*/
|
|
131
|
+
export async function killSession(name, socket, opts = {}) {
|
|
122
132
|
assertValidSessionName(name);
|
|
123
133
|
const sock = socket ?? getDefaultSocketPath();
|
|
124
134
|
const existed = await hasSession(name, sock);
|
|
@@ -137,6 +147,10 @@ export async function killSession(name, socket) {
|
|
|
137
147
|
throw err;
|
|
138
148
|
}
|
|
139
149
|
}
|
|
150
|
+
if (opts.reapOrphans !== false) {
|
|
151
|
+
const { reapProcessesForTmuxSession } = await import('./orphan-reap.js');
|
|
152
|
+
await reapProcessesForTmuxSession(name, sock).catch(() => ({ killed: 0, details: [], candidates: [], warnings: [] }));
|
|
153
|
+
}
|
|
140
154
|
removeSessionMeta(name);
|
|
141
155
|
return true;
|
|
142
156
|
}
|
|
@@ -172,6 +186,82 @@ export async function killAll(socket) {
|
|
|
172
186
|
catch { /* may not exist */ }
|
|
173
187
|
return count;
|
|
174
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Kill every tmux session whose panes are ALL dead (`pane_dead=1`), and
|
|
191
|
+
* terminate the helper processes whose owning agent has exited.
|
|
192
|
+
*
|
|
193
|
+
* Dead panes accumulate because `remain-on-exit on` is intentionally set
|
|
194
|
+
* per-pane so the harness can inspect exit status. Without a periodic sweep
|
|
195
|
+
* they pile up indefinitely — e.g. 48 of 127 sessions dead on yosemite-s0
|
|
196
|
+
* (RUSH-2501).
|
|
197
|
+
*
|
|
198
|
+
* Killing the pane is not enough on its own: it SIGHUPs only the pane's
|
|
199
|
+
* FOREGROUND process group, so an MCP server or harness background daemon that
|
|
200
|
+
* moved itself out of that group survives the session that spawned it and keeps
|
|
201
|
+
* its memory forever (RUSH-2521). The process sweep runs FIRST, while the dead
|
|
202
|
+
* sessions still exist, so every leftover is attributed to a named session
|
|
203
|
+
* rather than to a session tmux has already forgotten.
|
|
204
|
+
*
|
|
205
|
+
* Safety invariant: a session with ANY live pane (`pane_dead=0`) is never
|
|
206
|
+
* touched, and neither are the processes belonging to a session whose agent is
|
|
207
|
+
* still running or that has a client attached.
|
|
208
|
+
*
|
|
209
|
+
* `dryRun` reports both halves without killing anything.
|
|
210
|
+
*/
|
|
211
|
+
export async function reapDeadTmuxPanes(socket, opts = {}) {
|
|
212
|
+
const sock = socket ?? getDefaultSocketPath();
|
|
213
|
+
const result = { reaped: 0, sessions: [], details: [], processes: 0, processDetails: [], warnings: [] };
|
|
214
|
+
// The process sweep runs even with no server on this socket: a torn-down
|
|
215
|
+
// server (`killAll` unlinks the socket) is the strongest orphan signal there
|
|
216
|
+
// is, and skipping it here would strand exactly those leftovers forever.
|
|
217
|
+
// `opts.pids` is a test-only process-table scope (see `readAgentProcesses`)
|
|
218
|
+
// — production callers never set it.
|
|
219
|
+
const { reapOrphanAgentProcesses } = await import('./orphan-reap.js');
|
|
220
|
+
const orphans = await reapOrphanAgentProcesses({ socket: sock, dryRun: opts.dryRun, pids: opts.pids });
|
|
221
|
+
result.warnings = orphans.warnings;
|
|
222
|
+
result.processes = opts.dryRun ? orphans.candidates.length : orphans.killed;
|
|
223
|
+
result.processDetails = orphans.details;
|
|
224
|
+
if (!fs.existsSync(sock))
|
|
225
|
+
return result;
|
|
226
|
+
const res = await runTmux({
|
|
227
|
+
socket: sock,
|
|
228
|
+
args: ['list-panes', '-a', '-F', '#{pane_id}\t#{session_name}\t#{pane_dead}'],
|
|
229
|
+
throwOnError: false,
|
|
230
|
+
});
|
|
231
|
+
// Nonzero exit means no server or no sessions — nothing to reap.
|
|
232
|
+
if (res.code !== 0)
|
|
233
|
+
return result;
|
|
234
|
+
// Group dead-flags by session name.
|
|
235
|
+
const sessionFlags = new Map();
|
|
236
|
+
for (const raw of res.stdout.split('\n')) {
|
|
237
|
+
const parts = raw.trim().split('\t');
|
|
238
|
+
const name = parts[1];
|
|
239
|
+
if (!name)
|
|
240
|
+
continue;
|
|
241
|
+
const dead = parts[2]?.trim() === '1';
|
|
242
|
+
if (!sessionFlags.has(name))
|
|
243
|
+
sessionFlags.set(name, []);
|
|
244
|
+
sessionFlags.get(name).push(dead);
|
|
245
|
+
}
|
|
246
|
+
// Kill only sessions where every pane is dead.
|
|
247
|
+
for (const [name, flags] of sessionFlags) {
|
|
248
|
+
if (flags.length === 0 || !flags.every(d => d))
|
|
249
|
+
continue;
|
|
250
|
+
try {
|
|
251
|
+
// The one process-table sweep above already collected this session's
|
|
252
|
+
// leftovers; a per-session reap here would re-snapshot `ps` N times.
|
|
253
|
+
if (!opts.dryRun)
|
|
254
|
+
await killSession(name, sock, { reapOrphans: false });
|
|
255
|
+
result.reaped++;
|
|
256
|
+
result.sessions.push(name);
|
|
257
|
+
result.details.push(`${name} (${flags.length} dead pane${flags.length === 1 ? '' : 's'})`);
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// Best-effort: session may already be gone by the time we hit it.
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
175
265
|
/**
|
|
176
266
|
* Map every pane id (`%N`) on a socket to its `session:window.pane` attach
|
|
177
267
|
* target, in one batched `tmux list-panes -a` call. `%116 -> main:2.0` is a
|
|
@@ -369,7 +459,7 @@ async function lowestPaneId(name, socket) {
|
|
|
369
459
|
export async function prepareSessionForResume(name, socket) {
|
|
370
460
|
const sock = socket ?? getDefaultSocketPath();
|
|
371
461
|
if (!(await hasSession(name, sock)))
|
|
372
|
-
return 'create';
|
|
462
|
+
return { decision: 'create' };
|
|
373
463
|
const recordedPane = readSessionMeta(name)?.pane;
|
|
374
464
|
const recordedState = recordedPane ? await paneExitStatus(recordedPane, sock) : undefined;
|
|
375
465
|
const pane = recordedPane && recordedState?.found
|
|
@@ -377,9 +467,9 @@ export async function prepareSessionForResume(name, socket) {
|
|
|
377
467
|
: await lowestPaneId(name, sock);
|
|
378
468
|
const state = pane ? await paneExitStatus(pane, sock) : undefined;
|
|
379
469
|
if (pane && state?.found && !state.dead)
|
|
380
|
-
return 'attach';
|
|
470
|
+
return { decision: 'attach', pane };
|
|
381
471
|
await killSession(name, sock);
|
|
382
|
-
return 'create';
|
|
472
|
+
return { decision: 'create' };
|
|
383
473
|
}
|
|
384
474
|
/**
|
|
385
475
|
* Retrofit the current guarded `pane-died` hook onto every managed `agents run`
|
|
@@ -28,6 +28,26 @@ export interface WebhookHandler {
|
|
|
28
28
|
* to one platform. Omitted runs locally.
|
|
29
29
|
*/
|
|
30
30
|
host?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Named project (`agents projects`) whose base directory the dispatched
|
|
33
|
+
* agent/workflow run lands in — the execution anchor, mirroring a routine's
|
|
34
|
+
* `project`. Without it an agent handler runs at the target's `$HOME` with no
|
|
35
|
+
* repo checkout to edit. Applies to `run.agent`/`run.workflow` and the
|
|
36
|
+
* `routine:` delegate; ignored by `run.command` (put a `cd` in the command).
|
|
37
|
+
*/
|
|
38
|
+
project?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Portable execution directory for the dispatched run. A relative value
|
|
41
|
+
* resolves under `project` when set, otherwise the target's `$HOME`. Mirrors
|
|
42
|
+
* a routine's `cwd`.
|
|
43
|
+
*/
|
|
44
|
+
cwd?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Permission mode for a dispatched agent/workflow run. Defaults to `auto`
|
|
47
|
+
* (write with the classifier). Set `skip`/`full` for fully unattended edits,
|
|
48
|
+
* or `plan` for a read-only run.
|
|
49
|
+
*/
|
|
50
|
+
mode?: JobConfig['mode'];
|
|
31
51
|
run?: {
|
|
32
52
|
agent?: AgentId;
|
|
33
53
|
workflow?: string;
|
|
@@ -341,7 +341,7 @@ async function executeHandlerAction(handler, webhook, context, opts) {
|
|
|
341
341
|
if (handler.run?.agent || handler.run?.workflow) {
|
|
342
342
|
const config = {
|
|
343
343
|
name: handler.name,
|
|
344
|
-
mode: 'auto',
|
|
344
|
+
mode: handler.mode ?? 'auto',
|
|
345
345
|
effort: 'auto',
|
|
346
346
|
timeout: '10m',
|
|
347
347
|
enabled: true,
|
|
@@ -349,6 +349,8 @@ async function executeHandlerAction(handler, webhook, context, opts) {
|
|
|
349
349
|
...(handler.run.agent ? { agent: handler.run.agent } : { workflow: handler.run.workflow }),
|
|
350
350
|
...(handler.devices ? { devices: handler.devices } : {}),
|
|
351
351
|
...(handler.run.env ? { env: handler.run.env } : {}),
|
|
352
|
+
...(handler.project ? { project: handler.project } : {}),
|
|
353
|
+
...(handler.cwd ? { cwd: handler.cwd } : {}),
|
|
352
354
|
...(hostFields.host ? { host: hostFields.host } : {}),
|
|
353
355
|
...(hostFields.hostStrategy ? { hostStrategy: hostFields.hostStrategy } : {}),
|
|
354
356
|
};
|
|
@@ -373,6 +375,9 @@ async function executeHandlerAction(handler, webhook, context, opts) {
|
|
|
373
375
|
...routine,
|
|
374
376
|
prompt: substituteWebhookPrompt(routine.prompt, context),
|
|
375
377
|
...(handler.devices ? { devices: handler.devices } : {}),
|
|
378
|
+
...(handler.project ? { project: handler.project } : {}),
|
|
379
|
+
...(handler.cwd ? { cwd: handler.cwd } : {}),
|
|
380
|
+
...(handler.mode ? { mode: handler.mode } : {}),
|
|
376
381
|
...(hostFields.host ? { host: hostFields.host } : {}),
|
|
377
382
|
...(hostFields.hostStrategy ? { hostStrategy: hostFields.hostStrategy } : {}),
|
|
378
383
|
};
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -381,6 +381,8 @@ export interface SkillMetadata {
|
|
|
381
381
|
version?: string;
|
|
382
382
|
license?: string;
|
|
383
383
|
keywords?: string[];
|
|
384
|
+
/** Alternate names this skill also resolves under (frontmatter `aliases:`). */
|
|
385
|
+
aliases?: string[];
|
|
384
386
|
}
|
|
385
387
|
/** Record of how a skill was installed into an agent version. */
|
|
386
388
|
export interface SkillInstallation {
|
|
@@ -487,9 +489,9 @@ export interface SkillEntry {
|
|
|
487
489
|
/** Registry-specific trust signal (e.g. 'builtin', 'trusted', 'community'). */
|
|
488
490
|
trustLevel?: string;
|
|
489
491
|
/**
|
|
490
|
-
* Lowercase hex sha256 of the skill's SKILL.md, as recorded by
|
|
491
|
-
*
|
|
492
|
-
*
|
|
492
|
+
* Lowercase hex sha256 of the skill's SKILL.md, as recorded by the registry
|
|
493
|
+
* index. When present, install verifies the cloned SKILL.md against it and
|
|
494
|
+
* aborts on mismatch.
|
|
493
495
|
*/
|
|
494
496
|
sha256?: string;
|
|
495
497
|
}
|
|
@@ -785,6 +787,10 @@ export interface ActorConfig {
|
|
|
785
787
|
}
|
|
786
788
|
/** Top-level structure of ~/.agents/.system/agents.yaml -- the CLI's persistent state. */
|
|
787
789
|
export interface Meta {
|
|
790
|
+
/** Preferred provider account per harness. Explicit --account wins. */
|
|
791
|
+
accounts?: {
|
|
792
|
+
defaults?: Partial<Record<AgentId, string>>;
|
|
793
|
+
};
|
|
788
794
|
agents?: Partial<Record<AgentId, string>>;
|
|
789
795
|
/**
|
|
790
796
|
* Per-agent preferred ISOLATED version — which copy a bare `agents run <agent>`
|
|
@@ -863,7 +869,7 @@ export interface Meta {
|
|
|
863
869
|
* operator's config rather than an integration compiled into this CLI. When
|
|
864
870
|
* this is unset/empty, an important-level post falls back to `notify.owner`
|
|
865
871
|
* implicitly (RUSH-2123) — see lib/feed-broadcast.ts and
|
|
866
|
-
* docs/
|
|
872
|
+
* docs/observability.md.
|
|
867
873
|
*/
|
|
868
874
|
feed?: {
|
|
869
875
|
broadcast?: FeedBroadcastConfig;
|
|
@@ -931,31 +937,28 @@ export interface Meta {
|
|
|
931
937
|
*/
|
|
932
938
|
browser?: Record<string, BrowserProfileConfig>;
|
|
933
939
|
/**
|
|
934
|
-
*
|
|
935
|
-
*
|
|
936
|
-
*
|
|
937
|
-
*
|
|
938
|
-
*
|
|
939
|
-
*
|
|
940
|
-
*
|
|
940
|
+
* Machine-local browser profiles — written to `config:`-adjacent
|
|
941
|
+
* `browser:` in `~/.agents/devices/<machine>/agents.yaml`, never the synced
|
|
942
|
+
* file.
|
|
943
|
+
*
|
|
944
|
+
* The auto-detected `default` profile lives here because it is inherently
|
|
945
|
+
* machine-specific: it carries an absolute `binary:` path and a port chosen by
|
|
946
|
+
* scanning THIS machine. Sharing it fleet-wide meant a macOS box wrote
|
|
947
|
+
* `/Applications/...`, a Linux box found it unlaunchable and rewrote
|
|
948
|
+
* `/usr/bin/chromium-browser`, and the two flipped the tracked agents.yaml back
|
|
949
|
+
* and forth on every `agents browser start` — the single largest source of
|
|
950
|
+
* churn on that file. User-created named profiles stay central and still sync.
|
|
941
951
|
*/
|
|
942
|
-
|
|
952
|
+
deviceBrowser?: Record<string, BrowserProfileConfig>;
|
|
943
953
|
/**
|
|
944
954
|
* User-scope config block (`config:` in central agents.yaml). Holds the
|
|
945
955
|
* user-scope keys from the device-config registry (`lib/device-config.ts`) —
|
|
946
|
-
*
|
|
947
|
-
*
|
|
956
|
+
* currently `interactiveHost` and `usagePrimaryHost`. Syncs fleet-wide via
|
|
957
|
+
* `agents repo push/pull`.
|
|
958
|
+
* Device-scope keys live under `fleet.devices.<name>.config` instead (see
|
|
959
|
+
* {@link Meta.fleet}).
|
|
948
960
|
*/
|
|
949
961
|
config?: Record<string, unknown>;
|
|
950
|
-
/**
|
|
951
|
-
* Device-scope config block, carried in memory under a distinct field so it
|
|
952
|
-
* can never leak into the central (synced) agents.yaml: `writeMetaUnlocked`
|
|
953
|
-
* routes it to `~/.agents/devices/<machine>/agents.yaml` under the `config:`
|
|
954
|
-
* key (mirroring how `defaultBrowserProfile` is routed), and
|
|
955
|
-
* `overlayMachineLocal` reads it back. Holds the device-scope keys from the
|
|
956
|
-
* device-config registry (`maxAgents`, `schedulerEnabled`, `notes`). Per-machine by design — unset = today's behavior.
|
|
957
|
-
*/
|
|
958
|
-
deviceConfig?: Record<string, unknown>;
|
|
959
962
|
/**
|
|
960
963
|
* Routine names enabled on this machine. In memory this stays distinct from
|
|
961
964
|
* portable user config; state.ts writes it as top-level `routines:` in
|
|
@@ -964,7 +967,19 @@ export interface Meta {
|
|
|
964
967
|
*/
|
|
965
968
|
deviceRoutines?: string[];
|
|
966
969
|
/**
|
|
967
|
-
*
|
|
970
|
+
* Machine-local operator config — the device-scope keys whose `visibility` is
|
|
971
|
+
* `machine` (see lib/device-config.ts). state.ts writes it as `config:` inside
|
|
972
|
+
* `~/.agents/devices/<machine>/agents.yaml`, which is gitignored, so it never
|
|
973
|
+
* reaches the fleet-shared agents.yaml.
|
|
974
|
+
*
|
|
975
|
+
* These are the keys nothing off-box reads. Keeping them out of the shared file
|
|
976
|
+
* is both a churn fix (13 machines were writing one tracked path) and a
|
|
977
|
+
* security one: `browser.remote-control` gates whether OTHER machines may drive
|
|
978
|
+
* this box's browser, so syncing one box's opt-in to the rest was wrong.
|
|
979
|
+
*/
|
|
980
|
+
deviceConfig?: Record<string, unknown>;
|
|
981
|
+
/**
|
|
982
|
+
* Agent-host registry keyed by host name (the `--host`/`--device` dispatch overlay). Portable user
|
|
968
983
|
* config synced with `agents repo push/pull`. For `ssh-config` hosts this is
|
|
969
984
|
* just an overlay (caps/os) — the connection details stay in ~/.ssh/config and
|
|
970
985
|
* are never copied. `inline` hosts carry their own address/user.
|
|
@@ -974,6 +989,9 @@ export interface Meta {
|
|
|
974
989
|
* Declarative fleet profile (`agents apply` / `ag apply`). Additive to the
|
|
975
990
|
* schema — project `agents:` version-pins are untouched. Declares which agents
|
|
976
991
|
* every device should have, which config to sync, and how login propagates.
|
|
992
|
+
* `fleet.devices.<name>.config` is also the central store for per-device
|
|
993
|
+
* operator config (`agents devices config <name>`) — the device-scope keys of
|
|
994
|
+
* the `lib/device-config.ts` registry.
|
|
977
995
|
* Full shape in `lib/fleet/types.ts` (FleetManifest).
|
|
978
996
|
*/
|
|
979
997
|
fleet?: import('./fleet/types.js').FleetManifest;
|
|
@@ -988,6 +1006,10 @@ export interface Meta {
|
|
|
988
1006
|
domain?: string;
|
|
989
1007
|
/** Cloudflare Web Analytics token injected into published HTML pages. */
|
|
990
1008
|
analyticsToken?: string;
|
|
1009
|
+
/** sha256 of the Worker script deployed at the last provision/update, so
|
|
1010
|
+
* `agents share status` can tell current vs outdated vs unknown (a config
|
|
1011
|
+
* from before this field existed has no hash — always "unknown"). */
|
|
1012
|
+
templateHash?: string;
|
|
991
1013
|
};
|
|
992
1014
|
/**
|
|
993
1015
|
* Owner/channel notification config for `agents send` / `agents notify`.
|
|
@@ -1004,16 +1026,6 @@ export interface Meta {
|
|
|
1004
1026
|
};
|
|
1005
1027
|
transports?: Record<string, string>;
|
|
1006
1028
|
};
|
|
1007
|
-
/**
|
|
1008
|
-
* Routines daemon settings. `projects` is the allowlist of project roots
|
|
1009
|
-
* whose `.agents/routines/*.yml` may be synced into `~/.agents/routines/`
|
|
1010
|
-
* and fired by the daemon — never auto-discovered from a cloned public
|
|
1011
|
-
* repo without an explicit opt-in (`agents routines enable-project`).
|
|
1012
|
-
* Paths are stored absolute (or home-relative `~/…`).
|
|
1013
|
-
*/
|
|
1014
|
-
routines?: {
|
|
1015
|
-
projects?: string[];
|
|
1016
|
-
};
|
|
1017
1029
|
}
|
|
1018
1030
|
/** A single delivery channel entry in humans.yaml. */
|
|
1019
1031
|
export interface HumanChannel {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type HeadroomEntry } from './usage-refresh.js';
|
|
2
|
+
import { type UsageWindow } from './usage.js';
|
|
3
|
+
export declare const USAGE_FLEET_VERSION = 1;
|
|
4
|
+
export declare const USAGE_FLEET_FILE = ".usage-fleet.json";
|
|
5
|
+
export interface UsageFleetWindow {
|
|
6
|
+
key: UsageWindow['key'];
|
|
7
|
+
label: string;
|
|
8
|
+
shortLabel: string;
|
|
9
|
+
usedPercent: number;
|
|
10
|
+
resetsAt: string | null;
|
|
11
|
+
windowMinutes: number | null;
|
|
12
|
+
}
|
|
13
|
+
export interface UsageFleetSnapshot {
|
|
14
|
+
capturedAt: string | null;
|
|
15
|
+
plan: string | null;
|
|
16
|
+
windows: UsageFleetWindow[];
|
|
17
|
+
}
|
|
18
|
+
export interface UsageFleetExport {
|
|
19
|
+
version: 1;
|
|
20
|
+
publishedAt: number;
|
|
21
|
+
usage: Record<string, UsageFleetSnapshot>;
|
|
22
|
+
headroom: Record<string, HeadroomEntry>;
|
|
23
|
+
}
|
|
24
|
+
/** Publisher/subscriber role selection, kept pure for the daemon gate test. */
|
|
25
|
+
export declare function usageRefreshRole(primaryHost: string | undefined, self: string): 'publisher' | 'subscriber';
|
|
26
|
+
export declare function setUsageFleetExportPathForTest(value: string | null): string | null;
|
|
27
|
+
/** Build and persist the primary's safe cache envelope. */
|
|
28
|
+
export declare function exportUsageFleet(now?: number): UsageFleetExport;
|
|
29
|
+
/** Merge a primary-host envelope into the subscriber's existing caches. */
|
|
30
|
+
export declare function importUsageFleet(value: unknown): UsageFleetExport;
|
|
31
|
+
/** Fetch the primary's published envelope over the registered device SSH path. */
|
|
32
|
+
export declare function importUsageFleetFromHost(host: string): Promise<UsageFleetExport>;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-free usage replication from the configured primary host.
|
|
3
|
+
*
|
|
4
|
+
* The publisher writes only the already-derived usage windows and routing
|
|
5
|
+
* headroom. Credentials, OAuth material, and provider responses never enter
|
|
6
|
+
* this envelope. Subscribers fetch that file over the existing SSH trust path
|
|
7
|
+
* and merge it into their local caches.
|
|
8
|
+
*/
|
|
9
|
+
import { spawn } from 'node:child_process';
|
|
10
|
+
import * as path from 'node:path';
|
|
11
|
+
import { buildSshInvocation, writeAskpassShim } from './devices/connect.js';
|
|
12
|
+
import { loadDevices } from './devices/registry.js';
|
|
13
|
+
import { atomicWriteFileSync } from './fs-atomic.js';
|
|
14
|
+
import { getCacheDir } from './state.js';
|
|
15
|
+
import { readHeadroomCache, writeHeadroomEntries, } from './usage-refresh.js';
|
|
16
|
+
import { readClaudeUsageCache, writeClaudeUsageCache, } from './usage.js';
|
|
17
|
+
export const USAGE_FLEET_VERSION = 1;
|
|
18
|
+
export const USAGE_FLEET_FILE = '.usage-fleet.json';
|
|
19
|
+
/** Publisher/subscriber role selection, kept pure for the daemon gate test. */
|
|
20
|
+
export function usageRefreshRole(primaryHost, self) {
|
|
21
|
+
return primaryHost && primaryHost !== self ? 'subscriber' : 'publisher';
|
|
22
|
+
}
|
|
23
|
+
let exportPathOverride = null;
|
|
24
|
+
export function setUsageFleetExportPathForTest(value) {
|
|
25
|
+
const previous = exportPathOverride;
|
|
26
|
+
exportPathOverride = value;
|
|
27
|
+
return previous;
|
|
28
|
+
}
|
|
29
|
+
function exportPath() {
|
|
30
|
+
return exportPathOverride ?? path.join(getCacheDir(), USAGE_FLEET_FILE);
|
|
31
|
+
}
|
|
32
|
+
function safeSnapshot(snapshot) {
|
|
33
|
+
return {
|
|
34
|
+
capturedAt: snapshot.capturedAt?.toISOString() ?? null,
|
|
35
|
+
plan: snapshot.plan ?? null,
|
|
36
|
+
windows: snapshot.windows.map((window) => ({
|
|
37
|
+
key: window.key,
|
|
38
|
+
label: window.label,
|
|
39
|
+
shortLabel: window.shortLabel,
|
|
40
|
+
usedPercent: window.usedPercent,
|
|
41
|
+
resetsAt: window.resetsAt?.toISOString() ?? null,
|
|
42
|
+
windowMinutes: window.windowMinutes,
|
|
43
|
+
})),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function liveSnapshot(snapshot) {
|
|
47
|
+
return {
|
|
48
|
+
source: 'last_seen',
|
|
49
|
+
sourceLabel: 'primary host cache',
|
|
50
|
+
capturedAt: snapshot.capturedAt ? new Date(snapshot.capturedAt) : null,
|
|
51
|
+
plan: snapshot.plan,
|
|
52
|
+
windows: snapshot.windows.map((window) => ({
|
|
53
|
+
...window,
|
|
54
|
+
resetsAt: window.resetsAt ? new Date(window.resetsAt) : null,
|
|
55
|
+
})),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** Build and persist the primary's safe cache envelope. */
|
|
59
|
+
export function exportUsageFleet(now = Date.now()) {
|
|
60
|
+
const headroom = readHeadroomCache();
|
|
61
|
+
const usage = {};
|
|
62
|
+
for (const usageKey of Object.keys(headroom)) {
|
|
63
|
+
const snapshot = readClaudeUsageCache(usageKey);
|
|
64
|
+
if (snapshot)
|
|
65
|
+
usage[usageKey] = safeSnapshot(snapshot);
|
|
66
|
+
}
|
|
67
|
+
const payload = {
|
|
68
|
+
version: USAGE_FLEET_VERSION,
|
|
69
|
+
publishedAt: now,
|
|
70
|
+
usage,
|
|
71
|
+
headroom,
|
|
72
|
+
};
|
|
73
|
+
atomicWriteFileSync(exportPath(), JSON.stringify(payload, null, 2), 'utf-8');
|
|
74
|
+
return payload;
|
|
75
|
+
}
|
|
76
|
+
function isUsageFleetExport(value) {
|
|
77
|
+
if (!value || typeof value !== 'object')
|
|
78
|
+
return false;
|
|
79
|
+
const payload = value;
|
|
80
|
+
return payload.version === USAGE_FLEET_VERSION
|
|
81
|
+
&& typeof payload.publishedAt === 'number'
|
|
82
|
+
&& !!payload.usage && typeof payload.usage === 'object'
|
|
83
|
+
&& !!payload.headroom && typeof payload.headroom === 'object';
|
|
84
|
+
}
|
|
85
|
+
/** Merge a primary-host envelope into the subscriber's existing caches. */
|
|
86
|
+
export function importUsageFleet(value) {
|
|
87
|
+
if (!isUsageFleetExport(value))
|
|
88
|
+
throw new Error('usage fleet export has an unsupported shape');
|
|
89
|
+
for (const [usageKey, snapshot] of Object.entries(value.usage)) {
|
|
90
|
+
writeClaudeUsageCache(usageKey, liveSnapshot(snapshot));
|
|
91
|
+
}
|
|
92
|
+
writeHeadroomEntries(value.headroom);
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
/** Fetch the primary's published envelope over the registered device SSH path. */
|
|
96
|
+
export async function importUsageFleetFromHost(host) {
|
|
97
|
+
const device = (await loadDevices())[host];
|
|
98
|
+
if (!device)
|
|
99
|
+
throw new Error(`usage primary host '${host}' is not a registered device`);
|
|
100
|
+
const remoteRead = device.shell === 'powershell'
|
|
101
|
+
? ['Get-Content', '-Raw', '(Join-Path $HOME \'.agents/.cache/.usage-fleet.json\')']
|
|
102
|
+
: ['cat', '"$HOME/.agents/.cache/.usage-fleet.json"'];
|
|
103
|
+
const { args, env } = buildSshInvocation(device, remoteRead, writeAskpassShim(), {}, { agentOnly: true });
|
|
104
|
+
const raw = await new Promise((resolve, reject) => {
|
|
105
|
+
const child = spawn('ssh', args, {
|
|
106
|
+
env: { ...process.env, ...env },
|
|
107
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
108
|
+
windowsHide: true,
|
|
109
|
+
});
|
|
110
|
+
let stdout = '';
|
|
111
|
+
let stderr = '';
|
|
112
|
+
child.stdout.setEncoding('utf-8');
|
|
113
|
+
child.stderr.setEncoding('utf-8');
|
|
114
|
+
child.stdout.on('data', (chunk) => { stdout += chunk; });
|
|
115
|
+
child.stderr.on('data', (chunk) => { stderr += chunk; });
|
|
116
|
+
child.on('error', reject);
|
|
117
|
+
child.on('close', (code) => {
|
|
118
|
+
if (code === 0)
|
|
119
|
+
resolve(stdout);
|
|
120
|
+
else
|
|
121
|
+
reject(new Error(`usage primary host '${host}' export failed: ${stderr.trim() || `ssh exited ${code}`}`));
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
return importUsageFleet(JSON.parse(raw));
|
|
125
|
+
}
|
|
@@ -72,7 +72,7 @@ export declare function shouldRefreshAccount(entry: HeadroomEntry | null | undef
|
|
|
72
72
|
* projection, and record this call for the hourly cap.
|
|
73
73
|
*/
|
|
74
74
|
export declare function nextHeadroomEntry(prev: HeadroomEntry | null | undefined, snapshot: UsageSnapshot | null, now: number): HeadroomEntry;
|
|
75
|
-
/** An account whose credentials live on
|
|
75
|
+
/** An account whose credentials live on the publisher host. */
|
|
76
76
|
export interface LocalUsageAccount {
|
|
77
77
|
usageKey: string;
|
|
78
78
|
agentId: AgentId;
|
|
@@ -80,12 +80,12 @@ export interface LocalUsageAccount {
|
|
|
80
80
|
fetch: () => Promise<UsageInfo>;
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
|
-
* Enumerate the
|
|
83
|
+
* Enumerate the usage accounts whose credentials live on THIS host — one
|
|
84
84
|
* per unique usage key, deduped to the most-recently-active version (the same
|
|
85
85
|
* canonicalization `getUsageInfoByIdentity` uses). Each carries a closure that
|
|
86
86
|
* live-fetches its usage. This is the daemon's `listAccounts`; because it only
|
|
87
87
|
* ever lists local, signed-in accounts, each host is the sole writer for its own
|
|
88
|
-
* accounts' caches
|
|
88
|
+
* accounts' caches. `runUsageRefreshTick` calls this only on the fleet publisher.
|
|
89
89
|
*/
|
|
90
90
|
export declare function buildLocalUsageAccounts(): Promise<LocalUsageAccount[]>;
|
|
91
91
|
/** Injectable side effects, so `runUsageRefresh` is drivable without the daemon. */
|