@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
|
@@ -1,31 +1,43 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Device/user config keys — typed read/write over the
|
|
2
|
+
* Device/user config keys — typed read/write over the central agents.yaml store.
|
|
3
3
|
*
|
|
4
4
|
* One registry (`CONFIG_KEYS`) maps each CLI dotted name to where it lives:
|
|
5
|
-
* - user scope
|
|
6
|
-
*
|
|
7
|
-
* - device scope
|
|
8
|
-
*
|
|
5
|
+
* - user scope → central `~/.agents/agents.yaml` under `config:` (syncs
|
|
6
|
+
* fleet-wide via `agents repo push/pull`)
|
|
7
|
+
* - device scope → split by `visibility`, which asks WHO READS IT:
|
|
8
|
+
* · `shared` → central `fleet.devices.<name>.config`, because a PEER
|
|
9
|
+
* reads it (the ssh keys and platform to dial the box,
|
|
10
|
+
* agents.max-concurrent for placement, auto-launch and
|
|
11
|
+
* notes for fleet views). Names and non-secret values only
|
|
12
|
+
* (a secrets-bundle NAME is fine; a credential never is).
|
|
13
|
+
* · `machine` → the owning box's own doc, never the shared file, because
|
|
14
|
+
* nothing off-box reads it (browser.profile,
|
|
15
|
+
* browser.remote-control, scheduler.enabled,
|
|
16
|
+
* daemon.enabled).
|
|
9
17
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* target a peer (`--device`-style).
|
|
18
|
+
* That split exists because "central for everything" put 13 machines on one
|
|
19
|
+
* tracked path and they stopped being able to pull. `browser.remote-control` is
|
|
20
|
+
* also a consent flag — syncing one box's opt-in to the rest was a security bug,
|
|
21
|
+
* not just churn.
|
|
15
22
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
23
|
+
* The device registry (`~/.agents/.history/devices/registry.json`) stays the
|
|
24
|
+
* DISCOVERY cache (address, tailscale snapshot, reachability); the profile
|
|
25
|
+
* fields config can override (ssh.*, platform, user) are overlaid onto it at
|
|
26
|
+
* read time by `lib/devices/resolve-profile.ts`.
|
|
19
27
|
*
|
|
20
|
-
*
|
|
28
|
+
* Legacy stores (per-device `devices/<host>/agents.yaml` config and
|
|
29
|
+
* `.history/devices/auto-launch.json`) are folded into the central block once
|
|
30
|
+
* by `lib/devices/config-migration.ts`, invoked on the first read/write in a
|
|
31
|
+
* process — after migration there is ONE read path, no fallback branches.
|
|
32
|
+
*
|
|
33
|
+
* Unset always means today's behavior (the documented default).
|
|
21
34
|
*/
|
|
22
|
-
import
|
|
23
|
-
import * as path from 'path';
|
|
24
|
-
import * as yaml from 'yaml';
|
|
25
|
-
import { META_HEADER, getUserAgentsDir, readMeta, updateMeta } from './state.js';
|
|
26
|
-
import { atomicWriteFileSync } from './fs-atomic.js';
|
|
35
|
+
import { readMeta, updateMeta } from './state.js';
|
|
27
36
|
import { machineId } from './machine-id.js';
|
|
28
37
|
import { assertValidDeviceName } from './devices/registry.js';
|
|
38
|
+
import { fleetDevicesMapForWrite, migrateDeviceConfigToCentral } from './devices/config-migration.js';
|
|
39
|
+
const DEVICE_PLATFORMS = ['windows', 'linux', 'macos', 'unknown'];
|
|
40
|
+
const SSH_AUTH_METHODS = ['key', 'password'];
|
|
29
41
|
export const CONFIG_KEYS = [
|
|
30
42
|
{
|
|
31
43
|
name: 'interactive.host',
|
|
@@ -43,35 +55,56 @@ export const CONFIG_KEYS = [
|
|
|
43
55
|
}
|
|
44
56
|
},
|
|
45
57
|
},
|
|
58
|
+
{
|
|
59
|
+
name: 'usage.primary-host',
|
|
60
|
+
yamlKey: 'usagePrimaryHost',
|
|
61
|
+
scope: 'user',
|
|
62
|
+
type: 'string',
|
|
63
|
+
description: 'Device whose usage snapshots are authoritative for fleet-wide usage reporting.',
|
|
64
|
+
validate: (v) => {
|
|
65
|
+
try {
|
|
66
|
+
assertValidDeviceName(v);
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
return err?.message ?? String(err);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
},
|
|
46
74
|
{
|
|
47
75
|
name: 'browser.profile',
|
|
48
76
|
yamlKey: 'defaultBrowserProfile',
|
|
49
77
|
scope: 'device',
|
|
78
|
+
visibility: 'machine',
|
|
50
79
|
type: 'string',
|
|
51
|
-
field: 'defaultBrowserProfile',
|
|
52
80
|
description: 'Browser profile `agents browser start` resolves to without --profile (set via `agents browser profiles set-default`).',
|
|
53
81
|
},
|
|
54
82
|
{
|
|
55
83
|
name: 'agents.max-concurrent',
|
|
56
84
|
yamlKey: 'maxAgents',
|
|
57
85
|
scope: 'device',
|
|
86
|
+
visibility: 'shared',
|
|
58
87
|
type: 'int',
|
|
59
88
|
description: 'Cap on concurrent agents on this device. What counts toward it depends on the consumer: ' +
|
|
60
|
-
'
|
|
89
|
+
'AGI EXT auto-launch counts device-wide running agents; teams placement counts the team’s own roster on the device.',
|
|
61
90
|
validate: (v) => (v >= 1 ? null : 'agents.max-concurrent must be >= 1.'),
|
|
62
91
|
},
|
|
63
92
|
{
|
|
64
93
|
name: 'scheduler.enabled',
|
|
65
94
|
yamlKey: 'schedulerEnabled',
|
|
66
95
|
scope: 'device',
|
|
96
|
+
visibility: 'machine',
|
|
67
97
|
type: 'bool',
|
|
98
|
+
defaultValue: true,
|
|
68
99
|
description: 'Whether the routines scheduler (daemon) may fire on this device.',
|
|
69
100
|
},
|
|
70
101
|
{
|
|
71
102
|
name: 'daemon.enabled',
|
|
72
103
|
yamlKey: 'daemonEnabled',
|
|
73
104
|
scope: 'device',
|
|
105
|
+
visibility: 'machine',
|
|
74
106
|
type: 'bool',
|
|
107
|
+
defaultValue: true,
|
|
75
108
|
description: 'Whether the daemon may run on this device at all (secrets broker, browser IPC, watchdog, and the ' +
|
|
76
109
|
'routines scheduler). Disabling is the top-level kill switch: nothing auto-starts the daemon while it ' +
|
|
77
110
|
'is set, including `routines add`/`routines start`/`routines catchup`/webhook triggers. ' +
|
|
@@ -81,14 +114,18 @@ export const CONFIG_KEYS = [
|
|
|
81
114
|
name: 'watchdog.enabled',
|
|
82
115
|
yamlKey: 'watchdogEnabled',
|
|
83
116
|
scope: 'device',
|
|
117
|
+
visibility: 'shared',
|
|
84
118
|
type: 'bool',
|
|
119
|
+
defaultValue: false,
|
|
85
120
|
description: 'Whether the daemon runs the watchdog pass on this device.',
|
|
86
121
|
},
|
|
87
122
|
{
|
|
88
123
|
name: 'browser.remote-control',
|
|
89
124
|
yamlKey: 'browserRemoteControl',
|
|
90
125
|
scope: 'device',
|
|
126
|
+
visibility: 'machine',
|
|
91
127
|
type: 'bool',
|
|
128
|
+
defaultValue: false,
|
|
92
129
|
description: "Whether other fleet machines may drive THIS device's browser over `browser --host <this-device>`. " +
|
|
93
130
|
'Default off — a fleet-remote drive is refused until the owner runs `agents browser remote-control on`.',
|
|
94
131
|
},
|
|
@@ -96,8 +133,81 @@ export const CONFIG_KEYS = [
|
|
|
96
133
|
name: 'notes',
|
|
97
134
|
yamlKey: 'notes',
|
|
98
135
|
scope: 'device',
|
|
136
|
+
visibility: 'shared',
|
|
99
137
|
type: 'string-list',
|
|
100
|
-
description: 'Free-form operator notes about this device (one entry per `agents devices
|
|
138
|
+
description: 'Free-form operator notes about this device (one entry per `agents devices config <name> notes <text>`).',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: 'ssh.user',
|
|
142
|
+
yamlKey: 'sshUser',
|
|
143
|
+
scope: 'device',
|
|
144
|
+
visibility: 'shared',
|
|
145
|
+
type: 'string',
|
|
146
|
+
description: 'SSH login user for the device — overrides the registry profile’s user at dial time.',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: 'ssh.auth',
|
|
150
|
+
yamlKey: 'sshAuth',
|
|
151
|
+
scope: 'device',
|
|
152
|
+
visibility: 'shared',
|
|
153
|
+
type: 'string',
|
|
154
|
+
description: 'SSH auth method: `key` (ssh agent / on-disk keys) or `password` (pulled from a secrets bundle).',
|
|
155
|
+
validate: (v) => SSH_AUTH_METHODS.includes(v)
|
|
156
|
+
? null
|
|
157
|
+
: `ssh.auth must be one of ${SSH_AUTH_METHODS.join(' | ')}.`,
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: 'ssh.bundle',
|
|
161
|
+
yamlKey: 'sshBundle',
|
|
162
|
+
scope: 'device',
|
|
163
|
+
visibility: 'shared',
|
|
164
|
+
type: 'string',
|
|
165
|
+
description: 'Secrets bundle holding the SSH password (for ssh.auth=password). A bundle NAME — never a secret value.',
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'ssh.bundle-key',
|
|
169
|
+
yamlKey: 'sshBundleKey',
|
|
170
|
+
scope: 'device',
|
|
171
|
+
visibility: 'shared',
|
|
172
|
+
type: 'string',
|
|
173
|
+
description: "Key within the bundle whose value is the password (default 'password').",
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: 'ssh.identity-file',
|
|
177
|
+
yamlKey: 'sshIdentityFile',
|
|
178
|
+
scope: 'device',
|
|
179
|
+
visibility: 'shared',
|
|
180
|
+
type: 'string',
|
|
181
|
+
description: 'Explicit private-key path for key auth (passed to OpenSSH with IdentitiesOnly=yes).',
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: 'platform',
|
|
185
|
+
yamlKey: 'platform',
|
|
186
|
+
scope: 'device',
|
|
187
|
+
visibility: 'shared',
|
|
188
|
+
type: 'string',
|
|
189
|
+
description: 'OS family of the device — picks PowerShell vs POSIX on the remote end. Overrides the discovered platform.',
|
|
190
|
+
validate: (v) => DEVICE_PLATFORMS.includes(v)
|
|
191
|
+
? null
|
|
192
|
+
: `platform must be one of ${DEVICE_PLATFORMS.join(' | ')}.`,
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: 'auto-launch.enabled',
|
|
196
|
+
yamlKey: 'autoLaunchEnabled',
|
|
197
|
+
scope: 'device',
|
|
198
|
+
visibility: 'shared',
|
|
199
|
+
type: 'bool',
|
|
200
|
+
defaultValue: true,
|
|
201
|
+
description: 'Whether AGI EXT auto-launch may pick this device (default on).',
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'auto-launch.preferred',
|
|
205
|
+
yamlKey: 'autoLaunchPreferred',
|
|
206
|
+
scope: 'device',
|
|
207
|
+
visibility: 'shared',
|
|
208
|
+
type: 'bool',
|
|
209
|
+
defaultValue: false,
|
|
210
|
+
description: 'Boost this device in AGI EXT auto-launch ranking (default off).',
|
|
101
211
|
},
|
|
102
212
|
];
|
|
103
213
|
/** Look up a key spec by CLI dotted name, or throw listing the known keys. */
|
|
@@ -136,159 +246,254 @@ function assertValidValue(spec, value) {
|
|
|
136
246
|
if (err)
|
|
137
247
|
throw new Error(`Invalid value for '${spec.name}': ${err}`);
|
|
138
248
|
}
|
|
139
|
-
// ───
|
|
140
|
-
|
|
141
|
-
function deviceDocPath(device) {
|
|
142
|
-
return path.join(getUserAgentsDir(), 'devices', device, 'agents.yaml');
|
|
143
|
-
}
|
|
249
|
+
// ─── Migration hook ───────────────────────────────────────────────────────────
|
|
250
|
+
let migrationDone = false;
|
|
144
251
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
252
|
+
* Fold the legacy per-device config stores into the central block, once per
|
|
253
|
+
* process. A failure is loud but non-fatal — config reads must keep working,
|
|
254
|
+
* and the next process retries the fold. Honors AGENTS_SKIP_MIGRATION=1, the
|
|
255
|
+
* same gate bootstrap's runMigration uses (tests pin it so a fork never folds
|
|
256
|
+
* the developer's real ~/.agents as a side effect).
|
|
257
|
+
*
|
|
258
|
+
* Call this ONLY from a lifecycle entry point (daemon boot, `runMigration`).
|
|
259
|
+
* It must never hang off a config read or write: `~/.agents/agents.yaml` is a
|
|
260
|
+
* tracked file shared by every machine in the fleet, so a migration on the read
|
|
261
|
+
* path means an ordinary `agents config get` can dirty the shared file. That is
|
|
262
|
+
* what left yosemite-s0 unable to pull — 13 machines each rewriting one tracked
|
|
263
|
+
* path, on nearly every command.
|
|
150
264
|
*/
|
|
151
|
-
function
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
raw = fs.readFileSync(p, 'utf-8');
|
|
156
|
-
}
|
|
157
|
-
catch (err) {
|
|
158
|
-
if (err && err.code === 'ENOENT')
|
|
159
|
-
return null;
|
|
160
|
-
throw err;
|
|
161
|
-
}
|
|
162
|
-
const corrupted = (detail) => new Error(`Device config corrupted at ${p}: ${detail}. Inspect and restore from backup.`);
|
|
163
|
-
let parsed;
|
|
265
|
+
export function ensureDeviceConfigMigrated() {
|
|
266
|
+
if (migrationDone || process.env.AGENTS_SKIP_MIGRATION === '1')
|
|
267
|
+
return;
|
|
164
268
|
try {
|
|
165
|
-
|
|
269
|
+
migrateDeviceConfigToCentral();
|
|
270
|
+
migrationDone = true;
|
|
166
271
|
}
|
|
167
272
|
catch (err) {
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
if (parsed === null || parsed === undefined)
|
|
171
|
-
return {};
|
|
172
|
-
if (typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
173
|
-
throw corrupted(`expected a YAML map, got ${Array.isArray(parsed) ? 'a list' : JSON.stringify(parsed)}`);
|
|
273
|
+
console.error(`device config migration failed (${err?.message ?? err}); a later run retries`);
|
|
174
274
|
}
|
|
175
|
-
return parsed;
|
|
176
|
-
}
|
|
177
|
-
/** Write a device doc in place (atomic). Only ever holds device-local fields. */
|
|
178
|
-
function writeDeviceDoc(device, doc) {
|
|
179
|
-
const p = deviceDocPath(device);
|
|
180
|
-
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
181
|
-
const body = Object.keys(doc).length > 0 ? doc : { agents: {} };
|
|
182
|
-
atomicWriteFileSync(p, META_HEADER + yaml.stringify(body));
|
|
183
275
|
}
|
|
184
276
|
// ─── Reads ────────────────────────────────────────────────────────────────────
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
277
|
+
/**
|
|
278
|
+
* The raw device-scope config block for `device` from the central
|
|
279
|
+
* `fleet.devices.<name>.config` map ({} when unset). This is the single read
|
|
280
|
+
* path post-migration — the profile resolver (`lib/devices/resolve-profile.ts`)
|
|
281
|
+
* goes through here. Deliberately does NOT auto-trigger the migration: it
|
|
282
|
+
* serves the hot dial/render paths, and the keys it resolves (ssh.*, platform)
|
|
283
|
+
* are new — they never existed in the legacy stores. Keys with legacy data are
|
|
284
|
+
* read through the public API below, which triggers the fold.
|
|
285
|
+
*/
|
|
286
|
+
export function readDeviceConfigValues(device) {
|
|
287
|
+
const devices = readMeta().fleet?.devices;
|
|
288
|
+
if (!devices || devices === 'all')
|
|
289
|
+
return {};
|
|
290
|
+
const config = devices[device]?.config;
|
|
291
|
+
return config && typeof config === 'object' && !Array.isArray(config) ? config : {};
|
|
292
|
+
}
|
|
293
|
+
/** The device a targeted read/write applies to (default: this machine). */
|
|
294
|
+
function targetDevice(opts) {
|
|
295
|
+
return opts?.device ?? machineId();
|
|
196
296
|
}
|
|
197
|
-
/**
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
|
|
201
|
-
|
|
297
|
+
/**
|
|
298
|
+
* A machine-visibility key is only ever readable for THIS box, because it lives
|
|
299
|
+
* in this box's own gitignored doc. Asking for a peer's value is a mistake with a
|
|
300
|
+
* concrete fix, so say so rather than silently returning this machine's answer
|
|
301
|
+
* for another machine — that would make `agents devices config <peer>
|
|
302
|
+
* browser.remote-control` look like it reported the peer's consent state.
|
|
303
|
+
*/
|
|
304
|
+
function assertLocalTarget(spec, device) {
|
|
305
|
+
if (spec.scope !== 'device' || spec.visibility !== 'machine')
|
|
306
|
+
return;
|
|
307
|
+
if (device === machineId())
|
|
308
|
+
return;
|
|
309
|
+
throw new Error(`${spec.name} is machine-local, so it can only be read or set on the device itself.\n` +
|
|
310
|
+
`Run it on ${device}, e.g.: agents ssh ${device} 'agents config ${spec.name} <value>'`);
|
|
202
311
|
}
|
|
203
312
|
/** Get one config key's value and the layer that set it. */
|
|
204
313
|
export function getConfigValue(name, opts) {
|
|
205
314
|
const spec = configKeySpec(name);
|
|
206
|
-
if (spec.scope === '
|
|
207
|
-
const
|
|
208
|
-
return
|
|
315
|
+
if (spec.scope === 'user') {
|
|
316
|
+
const value = readMeta().config?.[spec.yamlKey];
|
|
317
|
+
return { spec, value, layer: value !== undefined ? 'user' : undefined };
|
|
318
|
+
}
|
|
319
|
+
const device = targetDevice(opts);
|
|
320
|
+
assertLocalTarget(spec, device);
|
|
321
|
+
if (spec.visibility === 'machine') {
|
|
322
|
+
// This machine's own doc, never the synced file. Fall back to the central
|
|
323
|
+
// block so a value written by an older CLI is still honored until the
|
|
324
|
+
// operator prunes it (the migration is additive and leaves it in place).
|
|
325
|
+
const local = readMeta().deviceConfig?.[spec.yamlKey];
|
|
326
|
+
const value = local !== undefined ? local : readDeviceConfigValues(device)[spec.yamlKey];
|
|
327
|
+
return { spec, value, layer: value !== undefined ? 'device' : undefined };
|
|
209
328
|
}
|
|
210
|
-
|
|
329
|
+
const value = readDeviceConfigValues(device)[spec.yamlKey];
|
|
330
|
+
return { spec, value, layer: value !== undefined ? 'device' : undefined };
|
|
211
331
|
}
|
|
212
|
-
/**
|
|
332
|
+
/**
|
|
333
|
+
* List every known key with its value and the layer that set it.
|
|
334
|
+
*
|
|
335
|
+
* Listing a PEER omits its machine-local keys rather than throwing. Their values
|
|
336
|
+
* live in that box's own doc and are genuinely unknowable from here, but a bulk
|
|
337
|
+
* listing must not hard-fail because one key in the registry is unreadable —
|
|
338
|
+
* `agents devices config <peer>` should still show everything it CAN resolve.
|
|
339
|
+
* Asking for such a key by name still errors, with the `agents ssh` fix named.
|
|
340
|
+
*/
|
|
213
341
|
export function listConfig(opts) {
|
|
214
|
-
|
|
342
|
+
const isPeer = targetDevice(opts) !== machineId();
|
|
343
|
+
const visible = isPeer
|
|
344
|
+
? CONFIG_KEYS.filter((spec) => spec.scope !== 'device' || spec.visibility !== 'machine')
|
|
345
|
+
: CONFIG_KEYS;
|
|
346
|
+
return visible.map((spec) => getConfigValue(spec.name, opts));
|
|
347
|
+
}
|
|
348
|
+
/** List user-scope config keys with their values. Used to show inherited settings
|
|
349
|
+
* in per-device views without implying those keys are device-local. */
|
|
350
|
+
export function listUserConfig() {
|
|
351
|
+
return CONFIG_KEYS.filter((spec) => spec.scope === 'user').map((spec) => getConfigValue(spec.name));
|
|
352
|
+
}
|
|
353
|
+
/** Resolve the explicit usage host, falling back to the user's interactive host. */
|
|
354
|
+
export function resolveUsagePrimaryHost() {
|
|
355
|
+
return getConfigValue('usage.primary-host').value
|
|
356
|
+
?? getConfigValue('interactive.host').value
|
|
357
|
+
?? null;
|
|
215
358
|
}
|
|
216
359
|
// ─── Writes ───────────────────────────────────────────────────────────────────
|
|
217
|
-
function
|
|
360
|
+
function setInCentralBlock(device, spec, value) {
|
|
218
361
|
updateMeta((m) => {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return { ...m, config: { ...m.config, [spec.yamlKey]: value } };
|
|
224
|
-
}
|
|
225
|
-
return { ...m, deviceConfig: { ...m.deviceConfig, [spec.yamlKey]: value } };
|
|
362
|
+
const devices = fleetDevicesMapForWrite(m.fleet);
|
|
363
|
+
const prev = devices[device] ?? {};
|
|
364
|
+
devices[device] = { ...prev, config: { ...prev.config, [spec.yamlKey]: value } };
|
|
365
|
+
return { ...m, fleet: { ...m.fleet, devices } };
|
|
226
366
|
});
|
|
227
367
|
}
|
|
228
|
-
function
|
|
368
|
+
function unsetInCentralBlock(device, spec) {
|
|
229
369
|
updateMeta((m) => {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
370
|
+
const stored = m.fleet?.devices;
|
|
371
|
+
if (!stored || stored === 'all')
|
|
372
|
+
return m; // nothing stored — unset is a no-op (never upgrade 'all' for one)
|
|
373
|
+
const prev = stored[device];
|
|
374
|
+
if (!prev?.config || !(spec.yamlKey in prev.config))
|
|
375
|
+
return m; // key not present — no write needed
|
|
376
|
+
const config = { ...prev.config };
|
|
377
|
+
delete config[spec.yamlKey];
|
|
378
|
+
const override = { ...prev };
|
|
379
|
+
if (Object.keys(config).length > 0)
|
|
380
|
+
override.config = config;
|
|
381
|
+
else
|
|
382
|
+
delete override.config;
|
|
383
|
+
const devices = { ...stored };
|
|
384
|
+
if (Object.keys(override).length > 0)
|
|
385
|
+
devices[device] = override;
|
|
386
|
+
else
|
|
387
|
+
delete devices[device];
|
|
388
|
+
const fleet = { ...m.fleet, devices };
|
|
389
|
+
// Drop the fleet block entirely when the unset emptied a block that holds
|
|
390
|
+
// nothing else — don't leave a vestigial `fleet: {devices: {}}` behind.
|
|
391
|
+
if (Object.keys(devices).length === 0 && !fleet.defaults && !fleet.secrets && !fleet.routines) {
|
|
392
|
+
const { fleet: _, ...rest } = m;
|
|
393
|
+
void _;
|
|
233
394
|
return rest;
|
|
234
395
|
}
|
|
235
|
-
|
|
236
|
-
if (!block || !(spec.yamlKey in block))
|
|
237
|
-
return m;
|
|
238
|
-
const next = { ...block };
|
|
239
|
-
delete next[spec.yamlKey];
|
|
240
|
-
const cleaned = Object.keys(next).length > 0 ? next : undefined;
|
|
241
|
-
return spec.scope === 'user' ? { ...m, config: cleaned } : { ...m, deviceConfig: cleaned };
|
|
396
|
+
return { ...m, fleet };
|
|
242
397
|
});
|
|
243
398
|
}
|
|
244
|
-
function setInDeviceDoc(device, spec, value) {
|
|
245
|
-
const doc = readDeviceDoc(device) ?? {};
|
|
246
|
-
if (spec.field === 'defaultBrowserProfile') {
|
|
247
|
-
doc.defaultBrowserProfile = value;
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
doc.config = { ...doc.config, [spec.yamlKey]: value };
|
|
251
|
-
}
|
|
252
|
-
writeDeviceDoc(device, doc);
|
|
253
|
-
}
|
|
254
|
-
function unsetInDeviceDoc(device, spec) {
|
|
255
|
-
const doc = readDeviceDoc(device);
|
|
256
|
-
if (!doc)
|
|
257
|
-
return; // nothing stored — unset is a no-op
|
|
258
|
-
if (spec.field === 'defaultBrowserProfile') {
|
|
259
|
-
delete doc.defaultBrowserProfile;
|
|
260
|
-
}
|
|
261
|
-
else if (doc.config && spec.yamlKey in doc.config) {
|
|
262
|
-
delete doc.config[spec.yamlKey];
|
|
263
|
-
if (Object.keys(doc.config).length === 0)
|
|
264
|
-
delete doc.config;
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
267
|
-
return; // key not present — no write needed
|
|
268
|
-
}
|
|
269
|
-
writeDeviceDoc(device, doc);
|
|
270
|
-
}
|
|
271
399
|
/** Set a config key (validated). Device-scope keys target this machine unless `opts.device` names a peer. */
|
|
272
400
|
export function setConfigValue(name, value, opts) {
|
|
273
401
|
const spec = configKeySpec(name);
|
|
274
402
|
assertValidValue(spec, value);
|
|
275
|
-
if (spec.scope === '
|
|
276
|
-
|
|
403
|
+
if (spec.scope === 'user') {
|
|
404
|
+
updateMeta((m) => ({ ...m, config: { ...m.config, [spec.yamlKey]: value } }));
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const device = targetDevice(opts);
|
|
408
|
+
assertLocalTarget(spec, device);
|
|
409
|
+
if (spec.visibility === 'machine') {
|
|
410
|
+
updateMeta((m) => ({ ...m, deviceConfig: { ...m.deviceConfig, [spec.yamlKey]: value } }));
|
|
277
411
|
return;
|
|
278
412
|
}
|
|
279
|
-
|
|
413
|
+
setInCentralBlock(device, spec, value);
|
|
280
414
|
}
|
|
281
415
|
/** Unset a config key — restores default behavior. No-op when already unset. */
|
|
282
416
|
export function unsetConfigValue(name, opts) {
|
|
283
417
|
const spec = configKeySpec(name);
|
|
284
|
-
if (spec.scope === '
|
|
285
|
-
|
|
418
|
+
if (spec.scope === 'user') {
|
|
419
|
+
updateMeta((m) => {
|
|
420
|
+
if (!m.config || !(spec.yamlKey in m.config))
|
|
421
|
+
return m;
|
|
422
|
+
const next = { ...m.config };
|
|
423
|
+
delete next[spec.yamlKey];
|
|
424
|
+
return { ...m, config: Object.keys(next).length > 0 ? next : undefined };
|
|
425
|
+
});
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const device = targetDevice(opts);
|
|
429
|
+
assertLocalTarget(spec, device);
|
|
430
|
+
if (spec.visibility === 'machine') {
|
|
431
|
+
updateMeta((m) => {
|
|
432
|
+
if (!m.deviceConfig || !(spec.yamlKey in m.deviceConfig))
|
|
433
|
+
return m;
|
|
434
|
+
const next = { ...m.deviceConfig };
|
|
435
|
+
delete next[spec.yamlKey];
|
|
436
|
+
return { ...m, deviceConfig: Object.keys(next).length > 0 ? next : undefined };
|
|
437
|
+
});
|
|
438
|
+
// Also clear any copy an older CLI left centrally, so the unset is not
|
|
439
|
+
// shadowed by the fallback read above.
|
|
440
|
+
unsetInCentralBlock(device, spec);
|
|
286
441
|
return;
|
|
287
442
|
}
|
|
288
|
-
|
|
443
|
+
unsetInCentralBlock(device, spec);
|
|
444
|
+
}
|
|
445
|
+
/** True if the device is enabled for auto-launch. Unset defaults to true. */
|
|
446
|
+
export function isAutoLaunchEnabled(name) {
|
|
447
|
+
assertValidDeviceName(name);
|
|
448
|
+
return getConfigValue('auto-launch.enabled', { device: name }).value !== false;
|
|
449
|
+
}
|
|
450
|
+
/** Set whether a device is enabled for auto-launch. Setting the default
|
|
451
|
+
* (enabled) removes the key to keep the block minimal. */
|
|
452
|
+
export function setAutoLaunchEnabled(name, enabled) {
|
|
453
|
+
assertValidDeviceName(name);
|
|
454
|
+
if (enabled)
|
|
455
|
+
unsetConfigValue('auto-launch.enabled', { device: name });
|
|
456
|
+
else
|
|
457
|
+
setConfigValue('auto-launch.enabled', false, { device: name });
|
|
458
|
+
}
|
|
459
|
+
/** True if the device is preferred for auto-launch ranking. */
|
|
460
|
+
export function isAutoLaunchPreferred(name) {
|
|
461
|
+
assertValidDeviceName(name);
|
|
462
|
+
return getConfigValue('auto-launch.preferred', { device: name }).value === true;
|
|
463
|
+
}
|
|
464
|
+
/** Set whether a device is preferred for auto-launch. Setting the default
|
|
465
|
+
* (not preferred) removes the key to keep the block minimal. */
|
|
466
|
+
export function setAutoLaunchPreferred(name, preferred) {
|
|
467
|
+
assertValidDeviceName(name);
|
|
468
|
+
if (preferred)
|
|
469
|
+
setConfigValue('auto-launch.preferred', true, { device: name });
|
|
470
|
+
else
|
|
471
|
+
unsetConfigValue('auto-launch.preferred', { device: name });
|
|
472
|
+
}
|
|
473
|
+
/** Every device's auto-launch flags, keyed by device name (set flags only) —
|
|
474
|
+
* the shape the ext's launch ranking consumes. */
|
|
475
|
+
export function loadAutoLaunchPreferences() {
|
|
476
|
+
ensureDeviceConfigMigrated();
|
|
477
|
+
const devices = readMeta().fleet?.devices;
|
|
478
|
+
const out = {};
|
|
479
|
+
if (!devices || devices === 'all')
|
|
480
|
+
return out;
|
|
481
|
+
for (const [name, override] of Object.entries(devices)) {
|
|
482
|
+
const config = override?.config;
|
|
483
|
+
if (!config)
|
|
484
|
+
continue;
|
|
485
|
+
const pref = {};
|
|
486
|
+
if (config.autoLaunchEnabled === false)
|
|
487
|
+
pref.enabled = false;
|
|
488
|
+
if (config.autoLaunchPreferred === true)
|
|
489
|
+
pref.preferred = true;
|
|
490
|
+
if (pref.enabled !== undefined || pref.preferred !== undefined)
|
|
491
|
+
out[name] = pref;
|
|
492
|
+
}
|
|
493
|
+
return out;
|
|
289
494
|
}
|
|
290
495
|
// ─── Consumers' helpers ───────────────────────────────────────────────────────
|
|
291
|
-
/** True unless this machine's
|
|
496
|
+
/** True unless this machine's config disables the routines scheduler. */
|
|
292
497
|
export function isSchedulerEnabled() {
|
|
293
498
|
return getConfigValue('scheduler.enabled').value !== false;
|
|
294
499
|
}
|
|
@@ -301,10 +506,10 @@ export function isSchedulerEnabled() {
|
|
|
301
506
|
export function assertSchedulerEnabled() {
|
|
302
507
|
if (isSchedulerEnabled())
|
|
303
508
|
return;
|
|
304
|
-
throw new Error(`The routines scheduler is disabled on this device (scheduler.enabled=false in ~/.agents/devices
|
|
305
|
-
`Re-enable with: agents devices
|
|
509
|
+
throw new Error(`The routines scheduler is disabled on this device (scheduler.enabled=false in ~/.agents/agents.yaml fleet.devices.${machineId()}.config). ` +
|
|
510
|
+
`Re-enable with: agents devices config ${machineId()} scheduler.enabled on`);
|
|
306
511
|
}
|
|
307
|
-
/** True unless this machine's
|
|
512
|
+
/** True unless this machine's config disables the daemon outright (top-level kill switch). */
|
|
308
513
|
export function isDaemonEnabled() {
|
|
309
514
|
return getConfigValue('daemon.enabled').value !== false;
|
|
310
515
|
}
|
|
@@ -318,12 +523,12 @@ export function isDaemonEnabled() {
|
|
|
318
523
|
export function assertDaemonEnabled() {
|
|
319
524
|
if (isDaemonEnabled())
|
|
320
525
|
return;
|
|
321
|
-
throw new Error(`The daemon is disabled on this device (daemon.enabled=false in ~/.agents/devices
|
|
526
|
+
throw new Error(`The daemon is disabled on this device (daemon.enabled=false in ~/.agents/agents.yaml fleet.devices.${machineId()}.config). ` +
|
|
322
527
|
`Re-enable with: agents daemon enable`);
|
|
323
528
|
}
|
|
324
529
|
/**
|
|
325
|
-
* Read the `agents.max-concurrent` cap for each named device from
|
|
326
|
-
*
|
|
530
|
+
* Read the `agents.max-concurrent` cap for each named device from the central
|
|
531
|
+
* config block (no SSH). Devices without a cap are omitted — uncapped is the
|
|
327
532
|
* default. Used as an input to host ranking (teams placement, Factory
|
|
328
533
|
* auto-launch), never as a remote probe.
|
|
329
534
|
*/
|