@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/lease.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `agents lease` — manage the disposable cloud boxes used by `agents run --lease`.
|
|
2
|
+
* `agents devices lease` — manage the disposable cloud boxes used by `agents run --lease`.
|
|
3
3
|
*
|
|
4
|
-
* Today: `agents lease gc`, which stops expired + idle "orphan" boxes that are
|
|
4
|
+
* Today: `agents devices lease gc`, which stops expired + idle "orphan" boxes that are
|
|
5
5
|
* holding a provider's server quota (the cause of the `server_limit` 403 a new
|
|
6
6
|
* lease hits). Reaping is conservative: only boxes whose lease has expired AND
|
|
7
7
|
* that have been untouched for a safety window are eligible (see `isReapSafe`),
|
|
@@ -25,7 +25,7 @@ export declare function boxStatus(box: CrabboxBox): string;
|
|
|
25
25
|
* freshest box (an untouched `lastTouchedAt` sorts last).
|
|
26
26
|
*/
|
|
27
27
|
export declare function reusableBoxes(boxes: CrabboxBox[], nowSecs: number): CrabboxBox[];
|
|
28
|
-
/** One aligned row for the reuse picker / `agents lease list`. */
|
|
28
|
+
/** One aligned row for the reuse picker / `agents devices lease list`. */
|
|
29
29
|
export declare function formatBoxRow(box: CrabboxBox, nowSecs: number): string;
|
|
30
30
|
/** Validate a Hetzner token against the live API. Exported for unit tests (fetch injectable). */
|
|
31
31
|
export declare function validateHetznerToken(token: string, fetchImpl?: typeof fetch): Promise<'valid' | 'invalid' | 'unreachable'>;
|
|
@@ -39,4 +39,4 @@ export declare function validateHetznerToken(token: string, fetchImpl?: typeof f
|
|
|
39
39
|
export declare function runLeaseSetup(opts?: {
|
|
40
40
|
provider?: string;
|
|
41
41
|
}): Promise<boolean>;
|
|
42
|
-
export declare function registerLeaseCommand(
|
|
42
|
+
export declare function registerLeaseCommand(devicesCommand: Command): void;
|
package/dist/commands/lease.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `agents lease` — manage the disposable cloud boxes used by `agents run --lease`.
|
|
2
|
+
* `agents devices lease` — manage the disposable cloud boxes used by `agents run --lease`.
|
|
3
3
|
*
|
|
4
|
-
* Today: `agents lease gc`, which stops expired + idle "orphan" boxes that are
|
|
4
|
+
* Today: `agents devices lease gc`, which stops expired + idle "orphan" boxes that are
|
|
5
5
|
* holding a provider's server quota (the cause of the `server_limit` 403 a new
|
|
6
6
|
* lease hits). Reaping is conservative: only boxes whose lease has expired AND
|
|
7
7
|
* that have been untouched for a safety window are eligible (see `isReapSafe`),
|
|
@@ -64,7 +64,7 @@ export function reusableBoxes(boxes, nowSecs) {
|
|
|
64
64
|
.filter((b) => b.ready && (b.expiresAt === null || b.expiresAt > nowSecs))
|
|
65
65
|
.sort((a, b) => (b.lastTouchedAt ?? 0) - (a.lastTouchedAt ?? 0));
|
|
66
66
|
}
|
|
67
|
-
/** One aligned row for the reuse picker / `agents lease list`. */
|
|
67
|
+
/** One aligned row for the reuse picker / `agents devices lease list`. */
|
|
68
68
|
export function formatBoxRow(box, nowSecs) {
|
|
69
69
|
const slug = box.slug.padEnd(16);
|
|
70
70
|
const cls = (box.class ?? '?').padEnd(10);
|
|
@@ -201,8 +201,8 @@ export async function runLeaseSetup(opts = {}) {
|
|
|
201
201
|
throw e;
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
|
-
export function registerLeaseCommand(
|
|
205
|
-
const lease =
|
|
204
|
+
export function registerLeaseCommand(devicesCommand) {
|
|
205
|
+
const lease = devicesCommand
|
|
206
206
|
.command('lease')
|
|
207
207
|
.description('Manage the disposable cloud boxes used by `agents run --lease`.');
|
|
208
208
|
lease
|
|
@@ -241,7 +241,7 @@ export function registerLeaseCommand(program) {
|
|
|
241
241
|
console.log(chalk.bold(`Warm boxes (${boxes.length})`));
|
|
242
242
|
for (const b of boxes)
|
|
243
243
|
console.log(' ' + formatBoxRow(b, nowSecs));
|
|
244
|
-
console.log(chalk.gray(' Reuse: agents run <agent> "…" --box <slug> · Stop: agents lease stop <slug>'));
|
|
244
|
+
console.log(chalk.gray(' Reuse: agents run <agent> "…" --box <slug> · Stop: agents devices lease stop <slug>'));
|
|
245
245
|
});
|
|
246
246
|
lease
|
|
247
247
|
.command('stop <slug>')
|
package/dist/commands/login.js
CHANGED
|
@@ -107,17 +107,4 @@ export function registerLoginCommands(program) {
|
|
|
107
107
|
clearVaultKey();
|
|
108
108
|
console.log(chalk.green('Logged out. Synced secrets are locked.'));
|
|
109
109
|
});
|
|
110
|
-
program
|
|
111
|
-
.command('whoami')
|
|
112
|
-
.description('Show synced-secrets login status')
|
|
113
|
-
.action(() => {
|
|
114
|
-
const session = getVaultSession();
|
|
115
|
-
if (!session.loggedIn) {
|
|
116
|
-
console.log(chalk.yellow('Not logged in.'));
|
|
117
|
-
console.log(chalk.gray(`File: ${vaultPath()}${vaultExists() ? '' : ' (not created)'}`));
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
console.log(chalk.green(`Logged in (${formatRemaining(session.expiresAt)} remaining).`));
|
|
121
|
-
console.log(chalk.gray(`File: ${vaultPath()}`));
|
|
122
|
-
});
|
|
123
110
|
}
|
package/dist/commands/logs.d.ts
CHANGED
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
* id, `--host`/`--agent`/`--version` filter a merged candidate list; one match is
|
|
18
18
|
* shown, several open the fuzzy picker (or, non-TTY, print the list).
|
|
19
19
|
*
|
|
20
|
-
* Additive: `agents
|
|
21
|
-
* the same underlying helpers (showHostTaskLog / streamSessionTail).
|
|
20
|
+
* Additive: `agents devices ps`/`stop` and `agents sessions tail` are unchanged and
|
|
21
|
+
* share the same underlying helpers (showHostTaskLog / streamSessionTail).
|
|
22
22
|
*/
|
|
23
23
|
import type { Command } from 'commander';
|
|
24
24
|
/** Register the top-level `agents logs` command. */
|
package/dist/commands/logs.js
CHANGED
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
* id, `--host`/`--agent`/`--version` filter a merged candidate list; one match is
|
|
18
18
|
* shown, several open the fuzzy picker (or, non-TTY, print the list).
|
|
19
19
|
*
|
|
20
|
-
* Additive: `agents
|
|
21
|
-
* the same underlying helpers (showHostTaskLog / streamSessionTail).
|
|
20
|
+
* Additive: `agents devices ps`/`stop` and `agents sessions tail` are unchanged and
|
|
21
|
+
* share the same underlying helpers (showHostTaskLog / streamSessionTail).
|
|
22
22
|
*/
|
|
23
23
|
import chalk from 'chalk';
|
|
24
24
|
import { discoverSessions, resolveSessionById } from '../lib/session/discover.js';
|
package/dist/commands/mcp.js
CHANGED
|
@@ -564,9 +564,11 @@ Examples:
|
|
|
564
564
|
}
|
|
565
565
|
console.log();
|
|
566
566
|
});
|
|
567
|
+
// Deprecated: superseded by `agents sync --mcp`. Kept as a warned, functional
|
|
568
|
+
// alias so old muscle-memory and scripts don't break.
|
|
567
569
|
mcpCmd
|
|
568
|
-
.command('register [name]')
|
|
569
|
-
.description('
|
|
570
|
+
.command('register [name]', { hidden: true })
|
|
571
|
+
.description('Deprecated — use `agents sync --mcp` instead.')
|
|
570
572
|
.option('-a, --agents <list>', 'Override manifest targets: claude, codex@0.116.0')
|
|
571
573
|
.option('-y, --yes', 'Auto-install any missing agent versions without prompting')
|
|
572
574
|
.addHelpText('after', `
|
|
@@ -581,6 +583,9 @@ Examples:
|
|
|
581
583
|
agents mcp register --agents codex@0.116.0
|
|
582
584
|
`)
|
|
583
585
|
.action(async (name, options) => {
|
|
586
|
+
console.warn(chalk.yellow('`agents mcp register` is deprecated — use `agents sync --mcp` instead:'));
|
|
587
|
+
console.warn(chalk.gray(' all servers: agents sync --mcp'));
|
|
588
|
+
console.warn(chalk.gray(' specific server: agents sync --mcp <name>'));
|
|
584
589
|
const localPath = getUserAgentsDir();
|
|
585
590
|
const manifest = readManifest(localPath);
|
|
586
591
|
if (!manifest?.mcp) {
|
package/dist/commands/memory.js
CHANGED
|
@@ -111,11 +111,16 @@ export function registerMemoryCommands(program) {
|
|
|
111
111
|
console.log(chalk.dim(`# ${fact.name} [${fact.layer}] ${fact.path}`));
|
|
112
112
|
console.log(fs.readFileSync(fact.path, 'utf-8'));
|
|
113
113
|
});
|
|
114
|
+
// Deprecated: superseded by `agents sync --memory`. Kept as a warned, functional
|
|
115
|
+
// alias so old muscle-memory and scripts don't break.
|
|
114
116
|
memoryCmd
|
|
115
|
-
.command('sync [agent]')
|
|
116
|
-
.description('
|
|
117
|
+
.command('sync [agent]', { hidden: true })
|
|
118
|
+
.description('Deprecated — use `agents sync --memory` instead.')
|
|
117
119
|
.option('-a, --agent <agent>', 'Limit to one agent (or agent@version)')
|
|
118
120
|
.action(async (agentArg, options) => {
|
|
121
|
+
console.warn(chalk.yellow('`agents memory sync` is deprecated — use `agents sync --memory` instead:'));
|
|
122
|
+
console.warn(chalk.gray(' all agents: agents sync --memory'));
|
|
123
|
+
console.warn(chalk.gray(' one agent: agents sync --memory <agent>'));
|
|
119
124
|
ensureUserMemoryDir();
|
|
120
125
|
const input = agentArg || options.agent;
|
|
121
126
|
if (input) {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* written on the host that actually owns the agent. A caller who doesn't already
|
|
13
13
|
* know the host (a detached `agents run --device <h> --no-follow` dispatch) is
|
|
14
14
|
* still resolved automatically: a `target` matching no local/cloud session falls
|
|
15
|
-
* through to the `~/.agents/.cache/hosts/` records `agents
|
|
15
|
+
* through to the `~/.agents/.cache/hosts/` records `agents devices ps` reads
|
|
16
16
|
* (RUSH-2366 follow-up — see decideHostTaskRoute in lib/mailbox-target.ts), and
|
|
17
17
|
* the message is rerouted there.
|
|
18
18
|
*
|
package/dist/commands/message.js
CHANGED
|
@@ -2,7 +2,7 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { spawn } from 'child_process';
|
|
3
3
|
import { die } from '../lib/format.js';
|
|
4
4
|
import { parseDuration } from '../lib/hooks/cache.js';
|
|
5
|
-
import { getActiveSessions } from '../lib/session/active.js';
|
|
5
|
+
import { getActiveSessions, isSessionIdLiveOnProcessTable } from '../lib/session/active.js';
|
|
6
6
|
import { getTaskById, updateTaskStatus } from '../lib/cloud/store.js';
|
|
7
7
|
import { resolveProvider } from '../lib/cloud/registry.js';
|
|
8
8
|
import { mailboxDir, enqueue } from '../lib/mailbox.js';
|
|
@@ -119,7 +119,7 @@ async function deliverViaResume(route, mailboxId) {
|
|
|
119
119
|
* dispatch (RUSH-2366 follow-up). `getActiveSessions()` never sees these: the
|
|
120
120
|
* live process is on the dispatch's host, not this machine, so the local
|
|
121
121
|
* session resolver in `resolveMessageTarget` reports "no running agent" even
|
|
122
|
-
* while `agents
|
|
122
|
+
* while `agents devices ps` shows the same dispatch running with a live remote
|
|
123
123
|
* pid — the only recovery was kill-and-redispatch, losing all context.
|
|
124
124
|
*
|
|
125
125
|
* Re-spawns `agents message <remoteRef> <text> --host <host>` through
|
|
@@ -251,11 +251,42 @@ export function registerMessageCommand(program) {
|
|
|
251
251
|
return;
|
|
252
252
|
}
|
|
253
253
|
case 'none': {
|
|
254
|
+
// RUSH-2384: a live local process can still advertise `--session-id
|
|
255
|
+
// <target>` in its argv when getActiveSessions lost the row (empty
|
|
256
|
+
// by-pid registry, teams status flap, fold into a parent). Mailbox
|
|
257
|
+
// delivery only needs the id — prove liveness from the process table
|
|
258
|
+
// before giving up, so a mid-run agent is never unreachable while
|
|
259
|
+
// its pid is alive.
|
|
260
|
+
if (await isSessionIdLiveOnProcessTable(target)) {
|
|
261
|
+
try {
|
|
262
|
+
const block = findOpenBlockForMailbox(target);
|
|
263
|
+
const route = resolveAnswerRoute({
|
|
264
|
+
mailboxId: target,
|
|
265
|
+
answer: text,
|
|
266
|
+
block,
|
|
267
|
+
session: null,
|
|
268
|
+
});
|
|
269
|
+
if (route.kind === 'refuse')
|
|
270
|
+
die(route.reason);
|
|
271
|
+
claimBlockAnswer(block, opts);
|
|
272
|
+
if (route.kind === 'mailbox') {
|
|
273
|
+
await deliverViaMailbox(target, text, block, { from: opts.from, ttlSeconds });
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
die(`Live process carries --session-id ${target} but needs a ${route.kind} rail ` +
|
|
277
|
+
`that is unavailable without an active-session row. Retry after the session ` +
|
|
278
|
+
`reappears in \`agents sessions --active\`, or inject into its terminal directly.`);
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
die(err.message);
|
|
282
|
+
}
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
254
285
|
// Not a local/cloud session — check whether it's a detached
|
|
255
286
|
// `--device ... --no-follow` dispatch, which `getActiveSessions()`
|
|
256
287
|
// never sees (its live process is on another host). Same records
|
|
257
|
-
// `agents
|
|
258
|
-
// Heal first, exactly as `
|
|
288
|
+
// `agents devices ps` reads, so the two commands never disagree.
|
|
289
|
+
// Heal first, exactly as `agents devices stop`/`agents devices ps` do: a detached
|
|
259
290
|
// dispatch record never self-updates, so a finished run is still
|
|
260
291
|
// stamped `status:'running'` on disk. Without this we'd route a dead
|
|
261
292
|
// task through an SSH reroute that can only fail, instead of
|
|
@@ -269,9 +300,9 @@ export function registerMessageCommand(program) {
|
|
|
269
300
|
if (hostRoute.kind === 'finished') {
|
|
270
301
|
die(`Task '${target}' on host '${hostRoute.host}' already ${hostRoute.status}` +
|
|
271
302
|
(hostRoute.exitCode !== undefined ? ` (exit ${hostRoute.exitCode})` : '') +
|
|
272
|
-
`. Nothing to message. View its output: \`agents
|
|
303
|
+
`. Nothing to message. View its output: \`agents logs ${target}\`.`);
|
|
273
304
|
}
|
|
274
|
-
die(`No running agent or cloud task matches "${target}". List targets with \`agents sessions --active\` or \`agents
|
|
305
|
+
die(`No running agent or cloud task matches "${target}". List targets with \`agents sessions --active\` or \`agents devices ps\`.`);
|
|
275
306
|
}
|
|
276
307
|
}
|
|
277
308
|
});
|
package/dist/commands/models.js
CHANGED
|
@@ -77,6 +77,7 @@ export function registerModelsCommand(program) {
|
|
|
77
77
|
});
|
|
78
78
|
// Override subcommands. These WRITE agents.yaml so the user never hand-edits it;
|
|
79
79
|
// resolution is exact `<agent>@<version>` over `<agent>` over the auto guess.
|
|
80
|
+
const tierDeprecation = chalk.yellow('Deprecation: `agents models tier` is replaced by `agents config set run.<agent@version>.tier.<tier>`.');
|
|
80
81
|
const tier = models
|
|
81
82
|
.command('tier')
|
|
82
83
|
.description('Override which model a cost tier resolves to (per harness, or per agent@version).');
|
|
@@ -85,6 +86,7 @@ export function registerModelsCommand(program) {
|
|
|
85
86
|
.description('Pin a tier to a model. selector: <agent> or <agent>@<version> (e.g. kimi, kimi@0.19.2).')
|
|
86
87
|
.action((selector, tierName, model) => {
|
|
87
88
|
try {
|
|
89
|
+
console.warn(tierDeprecation);
|
|
88
90
|
const entry = setTierOverride(selector, tierName, model);
|
|
89
91
|
console.log(chalk.green(`✓ ${entry.selector} ${chalk.cyan(tierName.toLowerCase())} → ${chalk.bold(model)}`));
|
|
90
92
|
}
|
|
@@ -98,6 +100,7 @@ export function registerModelsCommand(program) {
|
|
|
98
100
|
.description('Clear one tier (or all tiers) back to the auto guess.')
|
|
99
101
|
.action((selector, tierName) => {
|
|
100
102
|
try {
|
|
103
|
+
console.warn(tierDeprecation);
|
|
101
104
|
const changed = clearTierOverride(selector, tierName);
|
|
102
105
|
console.log(changed ? chalk.green(`✓ cleared ${selector}${tierName ? ` ${tierName}` : ''}`) : chalk.gray('nothing to clear'));
|
|
103
106
|
}
|
|
@@ -110,6 +113,7 @@ export function registerModelsCommand(program) {
|
|
|
110
113
|
.command('list')
|
|
111
114
|
.description('List all configured tier overrides.')
|
|
112
115
|
.action(() => {
|
|
116
|
+
console.warn(tierDeprecation);
|
|
113
117
|
const entries = listTierOverrides();
|
|
114
118
|
if (entries.length === 0) {
|
|
115
119
|
console.log(chalk.gray('No tier overrides — every tier uses the auto guess. Set one with `agents models tier set`.'));
|
|
@@ -12,9 +12,12 @@ import * as fs from 'fs';
|
|
|
12
12
|
import * as path from 'path';
|
|
13
13
|
import * as yaml from 'yaml';
|
|
14
14
|
import { isDaemonRunning, signalDaemonReload, startDaemon, } from '../lib/daemon.js';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
15
|
+
import { findDuplicateMonitor, monitorFingerprint } from '../lib/monitors/fingerprint.js';
|
|
16
|
+
import { gatherFleetMonitors, NO_MONITOR_FANOUT_ENV } from '../lib/monitors/remote.js';
|
|
17
|
+
import { listMonitors, readMonitor, writeMonitor, deleteMonitor, setMonitorEnabled, getMonitorPath, validateMonitor, monitorRunsOnThisDevice, parseInterval, } from '../lib/monitors/config.js';
|
|
18
|
+
import { formatRelativeTime } from '../lib/session/relative-time.js';
|
|
19
|
+
import { evaluateMonitorOnce, POLL_SOURCE_TYPES } from '../lib/monitors/engine.js';
|
|
20
|
+
import { listFires, readState, readLiveness } from '../lib/monitors/state.js';
|
|
18
21
|
import { listRuns, getLatestRun, getRunDir } from '../lib/routines.js';
|
|
19
22
|
import { getMonitorsDir } from '../lib/state.js';
|
|
20
23
|
import { IS_WINDOWS } from '../lib/platform/index.js';
|
|
@@ -72,6 +75,54 @@ function ownerLabel(monitor) {
|
|
|
72
75
|
return monitor.devices.join(',');
|
|
73
76
|
return 'all';
|
|
74
77
|
}
|
|
78
|
+
/** A monitor's evaluation cadence in ms (falls back to the engine default). */
|
|
79
|
+
function monitorIntervalMs(monitor) {
|
|
80
|
+
if (monitor.source.interval)
|
|
81
|
+
return parseInterval(monitor.source.interval) ?? 60_000;
|
|
82
|
+
return 60_000;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* True when an enabled, locally-owned monitor's last poll is far enough past its
|
|
86
|
+
* interval that the engine has plainly stopped checking it (dead engine, swallowed
|
|
87
|
+
* start failure, never picked up). Tolerates a few missed ticks before flagging.
|
|
88
|
+
*/
|
|
89
|
+
function isStalled(monitor, liveness) {
|
|
90
|
+
if (!monitor.enabled || !monitorRunsOnThisDevice(monitor))
|
|
91
|
+
return false;
|
|
92
|
+
if (!liveness)
|
|
93
|
+
return false; // "never polled" is its own state, handled separately
|
|
94
|
+
const staleAfter = Math.max(monitorIntervalMs(monitor) * 3, 90_000);
|
|
95
|
+
return Date.now() - new Date(liveness.lastCheckedAt).getTime() > staleAfter;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The human liveness line for a monitor. This is the RUSH-2485 fix: it makes
|
|
99
|
+
* "the engine has never touched this" (`never polled`) visibly distinct from
|
|
100
|
+
* "polling steadily, condition just isn't matching" (`checked Nx`), from a real
|
|
101
|
+
* fire, and from a stalled engine.
|
|
102
|
+
*/
|
|
103
|
+
function livenessLabel(monitor, state, liveness) {
|
|
104
|
+
const here = monitorRunsOnThisDevice(monitor);
|
|
105
|
+
if (!monitor.enabled)
|
|
106
|
+
return chalk.gray('paused');
|
|
107
|
+
if (!here) {
|
|
108
|
+
// Not owned by this box — this daemon never checks it, so there's no local
|
|
109
|
+
// liveness to report; fall back to fire history if the owner synced it.
|
|
110
|
+
return state?.lastFiredAt ? chalk.gray(`fired ${formatRelativeTime(state.lastFiredAt)}`) : chalk.gray('owned elsewhere');
|
|
111
|
+
}
|
|
112
|
+
if (!liveness)
|
|
113
|
+
return chalk.yellow('never polled');
|
|
114
|
+
if (isStalled(monitor, liveness)) {
|
|
115
|
+
return chalk.red(`STALLED — last poll ${formatRelativeTime(liveness.lastCheckedAt)}`);
|
|
116
|
+
}
|
|
117
|
+
const checkedAgo = formatRelativeTime(liveness.lastCheckedAt);
|
|
118
|
+
if (liveness.lastError) {
|
|
119
|
+
return chalk.red(`checked ${liveness.checkCount}x · error: ${liveness.lastError.replace(/\s+/g, ' ').slice(0, 60)}`);
|
|
120
|
+
}
|
|
121
|
+
if (state?.lastFiredAt) {
|
|
122
|
+
return chalk.green(`fired ${formatRelativeTime(state.lastFiredAt)}`) + chalk.gray(` · checked ${liveness.checkCount}x`);
|
|
123
|
+
}
|
|
124
|
+
return chalk.gray(`checked ${liveness.checkCount}x · last ${checkedAgo} · no match yet`);
|
|
125
|
+
}
|
|
75
126
|
/** Start or reload the background daemon so a newly-added monitor is watched. */
|
|
76
127
|
function ensureDaemonRunning() {
|
|
77
128
|
if (isDaemonRunning()) {
|
|
@@ -88,6 +139,37 @@ function ensureDaemonRunning() {
|
|
|
88
139
|
stderrLine(chalk.yellow('Could not start the daemon. Start it manually with: agents routines start'));
|
|
89
140
|
}
|
|
90
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Assert the postcondition of `add`: the engine actually picked the monitor up.
|
|
144
|
+
* Config acceptance is not enough — RUSH-2485 was a monitor that added cleanly,
|
|
145
|
+
* listed as `on`, and never polled. A poll-model monitor owned by and enabled on
|
|
146
|
+
* this box should show a liveness heartbeat within a couple of engine ticks; wait
|
|
147
|
+
* for it and report the real outcome instead of reporting success on write. A
|
|
148
|
+
* miss is a warning, not a hard failure — a freshly-started daemon may still be
|
|
149
|
+
* booting — but it is surfaced so a dead engine can never masquerade as healthy.
|
|
150
|
+
*/
|
|
151
|
+
async function assertEnginePickup(monitor) {
|
|
152
|
+
const pollSource = POLL_SOURCE_TYPES.has(monitor.source.type);
|
|
153
|
+
if (!monitor.enabled || !monitorRunsOnThisDevice(monitor) || !pollSource)
|
|
154
|
+
return; // nothing to assert here
|
|
155
|
+
const before = readLiveness(monitor.name);
|
|
156
|
+
const baseline = before?.checkCount ?? 0;
|
|
157
|
+
const deadline = Date.now() + 12_000; // a couple of 5s ticks, plus daemon-boot slack
|
|
158
|
+
stderrLine(chalk.gray(' waiting for the engine to poll it…'));
|
|
159
|
+
while (Date.now() < deadline) {
|
|
160
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
161
|
+
const now = readLiveness(monitor.name);
|
|
162
|
+
if (now && now.checkCount > baseline) {
|
|
163
|
+
console.log(chalk.green(` engine picked it up — first poll ${formatRelativeTime(now.lastCheckedAt)}`));
|
|
164
|
+
if (now.lastError) {
|
|
165
|
+
stderrLine(chalk.yellow(` note: that poll errored — ${now.lastError.replace(/\s+/g, ' ').slice(0, 80)}`));
|
|
166
|
+
}
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
stderrLine(chalk.yellow(` the engine has not polled '${monitor.name}' yet.`));
|
|
171
|
+
stderrLine(chalk.yellow(` confirm the daemon is running (agents routines status) and re-check with: agents monitors view ${monitor.name}`));
|
|
172
|
+
}
|
|
91
173
|
/** Validate a single device name against the registered fleet; exit on miss. */
|
|
92
174
|
async function validateDevice(name) {
|
|
93
175
|
const normalized = normalizeHost(name.trim());
|
|
@@ -242,6 +324,58 @@ async function pickMonitor(message, alternatives = []) {
|
|
|
242
324
|
}
|
|
243
325
|
}
|
|
244
326
|
/** Register the `agents monitors` command tree. */
|
|
327
|
+
/**
|
|
328
|
+
* Refuse a monitor that duplicates one already in play — same NAME (which
|
|
329
|
+
* `writeMonitor` would silently overwrite) or same BEHAVIOR under any name, on
|
|
330
|
+
* this box or any other. Exits the process on a refusal.
|
|
331
|
+
*
|
|
332
|
+
* Shared by BOTH `add` paths. The file path (`add ./watcher.yml`) returns early
|
|
333
|
+
* and used to skip the guard entirely, so a duplicate could be walked straight
|
|
334
|
+
* in through a YAML file — the one input an agent is most likely to generate.
|
|
335
|
+
*/
|
|
336
|
+
async function guardAgainstDuplicateMonitor(config, force) {
|
|
337
|
+
if (force)
|
|
338
|
+
return;
|
|
339
|
+
const existing = listMonitors();
|
|
340
|
+
const sameName = existing.find((m) => m.name === config.name);
|
|
341
|
+
if (sameName) {
|
|
342
|
+
stderrLine(chalk.red(`Monitor '${config.name}' already exists — adding would overwrite it.`));
|
|
343
|
+
stderrLine(chalk.gray(` Inspect it: agents monitors view ${config.name}`));
|
|
344
|
+
stderrLine(chalk.gray(` Replace it: agents monitors add ${config.name} ... --force`));
|
|
345
|
+
process.exit(1);
|
|
346
|
+
}
|
|
347
|
+
const duplicate = findDuplicateMonitor(config, existing);
|
|
348
|
+
if (duplicate) {
|
|
349
|
+
stderrLine(chalk.red(`Monitor '${duplicate}' already watches this exact source and fires the same action.`));
|
|
350
|
+
stderrLine(chalk.gray(' Adding it again would fire the same trigger twice.'));
|
|
351
|
+
stderrLine(chalk.gray(` Inspect it: agents monitors view ${duplicate}`));
|
|
352
|
+
stderrLine(chalk.gray(` Add anyway: agents monitors add ${config.name} ... --force`));
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
// The case a local check cannot see: another agent, on another box, already
|
|
356
|
+
// watching this same work item with these same arguments. One work item, two
|
|
357
|
+
// triggers. Identity is the arguments, so the claim has to be fleet-wide —
|
|
358
|
+
// different arguments (another PR) are not a clash and still pass.
|
|
359
|
+
if (process.env[NO_MONITOR_FANOUT_ENV])
|
|
360
|
+
return;
|
|
361
|
+
const fleet = await gatherFleetMonitors();
|
|
362
|
+
const mine = monitorFingerprint(config);
|
|
363
|
+
const clash = fleet.monitors.find((r) => monitorFingerprint(r.monitor) === mine);
|
|
364
|
+
if (clash) {
|
|
365
|
+
stderrLine(chalk.red(`Monitor '${clash.monitor.name}' on ${chalk.bold(clash.machine)} already watches this exact source and fires the same action.`));
|
|
366
|
+
stderrLine(chalk.gray(' Two boxes watching one work item is a double trigger.'));
|
|
367
|
+
stderrLine(chalk.gray(` Inspect it: agents ssh ${clash.machine} 'agents monitors view ${clash.monitor.name}'`));
|
|
368
|
+
stderrLine(chalk.gray(` Add anyway: agents monitors add ${config.name} ... --force`));
|
|
369
|
+
process.exit(1);
|
|
370
|
+
}
|
|
371
|
+
// Never treat "could not ask" as "no duplicate".
|
|
372
|
+
if (fleet.discoveryFailed) {
|
|
373
|
+
stderrLine(chalk.yellow(' Note: could not reach the device registry — the fleet was not checked for duplicates.'));
|
|
374
|
+
}
|
|
375
|
+
else if (fleet.skipped.length > 0) {
|
|
376
|
+
stderrLine(chalk.yellow(` Note: could not check ${fleet.skipped.join(', ')} — a duplicate there would not have been caught.`));
|
|
377
|
+
}
|
|
378
|
+
}
|
|
245
379
|
export function registerMonitorsCommands(program) {
|
|
246
380
|
const monitorsCmd = program
|
|
247
381
|
.command('monitors')
|
|
@@ -315,11 +449,12 @@ export function registerMonitorsCommands(program) {
|
|
|
315
449
|
.option('--notify [channel]', 'Notify the owner (notify.owner); [channel] overrides the owner channel')
|
|
316
450
|
.option('--webhook-out <url>', 'POST the event to this URL')
|
|
317
451
|
// PLACEMENT / hygiene
|
|
318
|
-
.option('--device <name>', 'OWNER (not body placement) — the single machine that evaluates + fires (exactly-once). See docs/
|
|
452
|
+
.option('--device <name>', 'OWNER (not body placement) — the single machine that evaluates + fires (exactly-once). See docs/concepts.md#placement.')
|
|
319
453
|
.option('--devices <list>', 'Allowlist (comma-separated): each device fires independently')
|
|
320
454
|
.option('--run-on <host>', 'BODY placement — execute the ACTION on this machine over SSH (same idea as run --where device:<host>)')
|
|
321
455
|
.option('--rate-limit <spec>', 'Auto-pause if it fires more than N/<interval> (e.g. 5/1m)')
|
|
322
456
|
.option('--disabled', 'Create the monitor paused (enable later with resume)')
|
|
457
|
+
.option('--force', 'Overwrite a same-named monitor, or add one that duplicates an existing watcher')
|
|
323
458
|
.action(async (nameOrPath, options) => {
|
|
324
459
|
// File mode: a single arg pointing at an existing .yml with no source flags.
|
|
325
460
|
const hasSourceFlag = Boolean(options.watch || options.poll || options.pollHttp || options.on || options.ws || options.watchFile || options.watchDevice);
|
|
@@ -342,9 +477,11 @@ export function registerMonitorsCommands(program) {
|
|
|
342
477
|
stderrLine(chalk.red(` - ${err}`));
|
|
343
478
|
process.exit(1);
|
|
344
479
|
}
|
|
480
|
+
await guardAgainstDuplicateMonitor(config, options.force === true);
|
|
345
481
|
writeMonitor(config);
|
|
346
482
|
console.log(chalk.green(`Monitor '${name}' added`));
|
|
347
483
|
ensureDaemonRunning();
|
|
484
|
+
await assertEnginePickup(config);
|
|
348
485
|
return;
|
|
349
486
|
}
|
|
350
487
|
if (!nameOrPath) {
|
|
@@ -413,10 +550,12 @@ export function registerMonitorsCommands(program) {
|
|
|
413
550
|
if (condition.mode === 'match' && condition.match && /^(issued|success|ok|pass(ed)?|done|ready)$/i.test(condition.match)) {
|
|
414
551
|
stderrLine(chalk.yellow(` Note: --match '${condition.match}' only fires on success — it stays silent if the source breaks or never matches.`));
|
|
415
552
|
}
|
|
553
|
+
await guardAgainstDuplicateMonitor(config, options.force === true);
|
|
416
554
|
writeMonitor(config);
|
|
417
555
|
console.log(chalk.green(`Monitor '${nameOrPath}' added`));
|
|
418
556
|
console.log(chalk.gray(` ${sourceLabel(source)} → [${condition.mode}] → ${actionLabel(action)} · owner: ${ownerLabel(config)}`));
|
|
419
557
|
ensureDaemonRunning();
|
|
558
|
+
await assertEnginePickup(config);
|
|
420
559
|
});
|
|
421
560
|
// ─── list ────────────────────────────────────────────────────────────────────
|
|
422
561
|
monitorsCmd
|
|
@@ -428,16 +567,28 @@ export function registerMonitorsCommands(program) {
|
|
|
428
567
|
if (options.json) {
|
|
429
568
|
const payload = monitors.map((m) => {
|
|
430
569
|
const state = readState(m.name);
|
|
570
|
+
const liveness = readLiveness(m.name);
|
|
431
571
|
return {
|
|
432
572
|
name: m.name,
|
|
433
573
|
enabled: m.enabled,
|
|
434
574
|
source: m.source,
|
|
435
575
|
condition: m.condition,
|
|
436
|
-
action
|
|
576
|
+
// Full action, not just `type`: the cross-machine duplicate guard
|
|
577
|
+
// fingerprints source+condition+action, so a type-only action made
|
|
578
|
+
// every `--run` monitor unmatchable and the fleet check inert for
|
|
579
|
+
// exactly the case it exists for. `source` already ships whole.
|
|
580
|
+
action: m.action,
|
|
437
581
|
owner: ownerLabel(m),
|
|
438
582
|
runsHere: monitorRunsOnThisDevice(m),
|
|
439
583
|
lastSeenAt: state?.lastSeenAt ?? null,
|
|
440
584
|
lastFiredAt: state?.lastFiredAt ?? null,
|
|
585
|
+
// Liveness heartbeat (RUSH-2485): distinguishes never-polled from
|
|
586
|
+
// polling-not-matching from a stalled engine.
|
|
587
|
+
lastCheckedAt: liveness?.lastCheckedAt ?? null,
|
|
588
|
+
checkCount: liveness?.checkCount ?? 0,
|
|
589
|
+
lastError: liveness?.lastError ?? null,
|
|
590
|
+
consecutiveErrors: liveness?.consecutiveErrors ?? 0,
|
|
591
|
+
stalled: isStalled(m, liveness),
|
|
441
592
|
};
|
|
442
593
|
});
|
|
443
594
|
stdoutJson(payload);
|
|
@@ -451,12 +602,12 @@ export function registerMonitorsCommands(program) {
|
|
|
451
602
|
console.log(chalk.bold('Monitors\n'));
|
|
452
603
|
for (const m of monitors) {
|
|
453
604
|
const state = readState(m.name);
|
|
605
|
+
const liveness = readLiveness(m.name);
|
|
454
606
|
const enabled = m.enabled ? chalk.green('on') : chalk.gray('off');
|
|
455
607
|
const here = monitorRunsOnThisDevice(m);
|
|
456
608
|
const owner = here ? ownerLabel(m) : chalk.gray(ownerLabel(m));
|
|
457
|
-
const lastFired = state?.lastFiredAt ? `fired ${state.lastFiredAt}` : chalk.gray('never fired');
|
|
458
609
|
console.log(` ${chalk.cyan(m.name.padEnd(22))} ${enabled.padEnd(3)} ${sourceLabel(m.source)}`);
|
|
459
|
-
console.log(` ${' '.repeat(22)} ${chalk.gray(`[${m.condition.mode}]`)} → ${actionLabel(m.action)} ${chalk.gray(`owner: ${owner}`)} ${
|
|
610
|
+
console.log(` ${' '.repeat(22)} ${chalk.gray(`[${m.condition.mode}]`)} → ${actionLabel(m.action)} ${chalk.gray(`owner: ${owner}`)} ${livenessLabel(m, state, liveness)}`);
|
|
460
611
|
}
|
|
461
612
|
console.log();
|
|
462
613
|
});
|
|
@@ -477,6 +628,7 @@ export function registerMonitorsCommands(program) {
|
|
|
477
628
|
process.exit(1);
|
|
478
629
|
}
|
|
479
630
|
const state = readState(name);
|
|
631
|
+
const liveness = readLiveness(name);
|
|
480
632
|
const recentFires = listFires(name).slice(-5);
|
|
481
633
|
if (options.json) {
|
|
482
634
|
stdoutJson({
|
|
@@ -485,14 +637,30 @@ export function registerMonitorsCommands(program) {
|
|
|
485
637
|
owner: ownerLabel(monitor),
|
|
486
638
|
runsHere: monitorRunsOnThisDevice(monitor),
|
|
487
639
|
state,
|
|
640
|
+
liveness,
|
|
641
|
+
stalled: isStalled(monitor, liveness),
|
|
488
642
|
recentFires,
|
|
489
643
|
});
|
|
490
644
|
return;
|
|
491
645
|
}
|
|
492
646
|
console.log(chalk.bold(`Monitor: ${name}\n`));
|
|
493
647
|
console.log(yaml.stringify(monitor));
|
|
648
|
+
// Liveness first (RUSH-2485): the heartbeat is the answer to "is this thing
|
|
649
|
+
// actually running?" — it renders even when the monitor has never fired.
|
|
650
|
+
console.log(chalk.bold('Liveness'));
|
|
651
|
+
console.log(` ${livenessLabel(monitor, state, liveness)}`);
|
|
652
|
+
if (liveness) {
|
|
653
|
+
console.log(chalk.gray(` last checked: ${liveness.lastCheckedAt} (${formatRelativeTime(liveness.lastCheckedAt)})`));
|
|
654
|
+
console.log(chalk.gray(` checks: ${liveness.checkCount}`));
|
|
655
|
+
if (liveness.lastError) {
|
|
656
|
+
console.log(chalk.red(` last error: ${liveness.lastError.replace(/\s+/g, ' ').slice(0, 200)} (${liveness.consecutiveErrors} in a row)`));
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
else if (monitor.enabled && monitorRunsOnThisDevice(monitor)) {
|
|
660
|
+
console.log(chalk.yellow(' The engine has not polled this monitor yet. If this persists, the daemon may not have picked it up — check: agents routines status'));
|
|
661
|
+
}
|
|
494
662
|
if (state) {
|
|
495
|
-
console.log(chalk.bold('
|
|
663
|
+
console.log(chalk.bold('\nWatched state'));
|
|
496
664
|
console.log(chalk.gray(` last seen: ${state.lastSeenAt}`));
|
|
497
665
|
if (state.lastFiredAt)
|
|
498
666
|
console.log(chalk.gray(` last fired: ${state.lastFiredAt}`));
|
|
@@ -566,19 +734,29 @@ export function registerMonitorsCommands(program) {
|
|
|
566
734
|
if (!name)
|
|
567
735
|
return;
|
|
568
736
|
}
|
|
737
|
+
// getMonitorPath is user-layer only: edits always land in the user dir,
|
|
738
|
+
// never the pull-only system mirror. Editing a system built-in (no user
|
|
739
|
+
// copy yet) materializes one, prefilled with the built-in's own config.
|
|
569
740
|
let monitorPath = getMonitorPath(name);
|
|
570
741
|
if (!monitorPath) {
|
|
571
742
|
const dir = getMonitorsDir();
|
|
572
743
|
fs.mkdirSync(dir, { recursive: true });
|
|
573
744
|
monitorPath = safeJoin(dir, `${name}.yml`);
|
|
574
|
-
const
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
745
|
+
const builtIn = readMonitor(name);
|
|
746
|
+
if (builtIn) {
|
|
747
|
+
fs.writeFileSync(monitorPath, yaml.stringify(builtIn), 'utf-8');
|
|
748
|
+
console.log(chalk.gray(`Editing a copy of built-in monitor '${name}' in your user dir: ${monitorPath}`));
|
|
749
|
+
}
|
|
750
|
+
else {
|
|
751
|
+
const template = yaml.stringify({
|
|
752
|
+
name,
|
|
753
|
+
source: { type: 'poll', command: 'echo hello', interval: '1m' },
|
|
754
|
+
condition: { mode: 'on-change' },
|
|
755
|
+
action: { type: 'notify' },
|
|
756
|
+
});
|
|
757
|
+
fs.writeFileSync(monitorPath, template, 'utf-8');
|
|
758
|
+
console.log(chalk.gray(`Created new monitor file: ${monitorPath}`));
|
|
759
|
+
}
|
|
582
760
|
}
|
|
583
761
|
const editor = process.env.EDITOR || process.env.VISUAL || (IS_WINDOWS ? 'notepad' : 'vi');
|
|
584
762
|
const parts = editor.split(/\s+/).filter(Boolean);
|
|
@@ -772,6 +950,11 @@ export function registerMonitorsCommands(program) {
|
|
|
772
950
|
stderrLine(chalk.gray('Daemon reloaded'));
|
|
773
951
|
}
|
|
774
952
|
}
|
|
953
|
+
else if (readMonitor(name)) {
|
|
954
|
+
// Resolvable but not in the user dir: a pull-only system built-in.
|
|
955
|
+
stderrLine(chalk.red(`Monitor '${name}' is a built-in and can't be removed; pause it with: agents monitors pause ${name}`));
|
|
956
|
+
process.exit(1);
|
|
957
|
+
}
|
|
775
958
|
else {
|
|
776
959
|
stderrLine(chalk.red(`Monitor '${name}' not found`));
|
|
777
960
|
process.exit(1);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agents open` — resolve an `agents://` deep link, and manage the OS handler
|
|
3
|
+
* that routes such links here.
|
|
4
|
+
*
|
|
5
|
+
* agents open agents://session/<id> resume that session in a terminal
|
|
6
|
+
* agents open register register the agents:// scheme with the OS
|
|
7
|
+
* agents open unregister remove the handler
|
|
8
|
+
* agents open status report whether the handler is registered
|
|
9
|
+
*
|
|
10
|
+
* A rendered artifact (plan/report) embeds `agents://session/<id>` in its
|
|
11
|
+
* provenance line; clicking it hands the URL to the OS, which invokes
|
|
12
|
+
* `agents open <url>`. This command parses it (lib/deeplink/url.ts) and hands the
|
|
13
|
+
* session id to the existing resume dispatcher, which resolves the owning host
|
|
14
|
+
* and opens the terminal with the cursor in the input bar. The id is passed as
|
|
15
|
+
* argv, never interpolated into a shell.
|
|
16
|
+
*/
|
|
17
|
+
import type { Command } from 'commander';
|
|
18
|
+
export declare function registerOpenCommand(program: Command): void;
|