@phnx-labs/agents-cli 1.22.38 → 1.22.40
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 +302 -0
- package/README.md +111 -70
- package/dist/bin/agents +0 -0
- package/dist/bootstrap.js +46 -27
- package/dist/browser.js +2 -2
- package/dist/cli/command-registry.d.ts +135 -0
- package/dist/cli/command-registry.js +260 -0
- package/dist/commands/accounts.d.ts +20 -0
- package/dist/commands/accounts.js +186 -25
- package/dist/commands/apply.d.ts +3 -3
- package/dist/commands/apply.js +20 -63
- package/dist/commands/browser.js +206 -94
- package/dist/commands/budget.d.ts +7 -6
- package/dist/commands/budget.js +8 -7
- package/dist/commands/cloud.js +17 -20
- package/dist/commands/commands.js +1 -1
- package/dist/commands/computer-actions.d.ts +1 -35
- package/dist/commands/computer-actions.js +13 -181
- package/dist/commands/computer.d.ts +28 -3
- package/dist/commands/computer.js +93 -65
- package/dist/commands/config.js +47 -4
- package/dist/commands/cost.d.ts +2 -1
- package/dist/commands/cost.js +7 -6
- package/dist/commands/daemon.js +151 -4
- package/dist/commands/detach.js +1 -1
- package/dist/commands/doctor.js +19 -11
- package/dist/commands/events.js +1 -1
- package/dist/commands/exec.d.ts +2 -50
- package/dist/commands/exec.js +161 -216
- package/dist/commands/factory.js +1 -1
- package/dist/commands/feed.d.ts +2 -2
- package/dist/commands/feed.js +9 -12
- package/dist/commands/fleet-capture.js +25 -27
- package/dist/commands/focus.d.ts +2 -3
- package/dist/commands/focus.js +34 -9
- package/dist/commands/go.js +15 -5
- package/dist/commands/harness.d.ts +3 -3
- package/dist/commands/harness.js +53 -5
- package/dist/commands/hooks.js +1 -1
- package/dist/commands/import.js +2 -2
- package/dist/commands/insights.d.ts +5 -5
- package/dist/commands/insights.js +15 -9
- package/dist/commands/inspect.d.ts +2 -3
- package/dist/commands/inspect.js +4 -16
- package/dist/commands/logs.d.ts +2 -2
- package/dist/commands/logs.js +9 -9
- package/dist/commands/mcp.js +2 -2
- package/dist/commands/memory.js +1 -1
- package/dist/commands/message.d.ts +1 -1
- package/dist/commands/message.js +7 -7
- package/dist/commands/mine.d.ts +11 -8
- package/dist/commands/mine.js +11 -10
- package/dist/commands/models.js +1 -1
- package/dist/commands/modes.js +1 -1
- package/dist/commands/monitors.js +23 -6
- package/dist/commands/output.d.ts +7 -6
- package/dist/commands/output.js +11 -10
- package/dist/commands/packages.js +4 -4
- package/dist/commands/perf.js +1 -1
- package/dist/commands/permissions.js +49 -32
- package/dist/commands/plugins.d.ts +1 -1
- package/dist/commands/plugins.js +3 -3
- package/dist/commands/profiles.d.ts +6 -9
- package/dist/commands/profiles.js +8 -321
- package/dist/commands/projects.d.ts +9 -0
- package/dist/commands/projects.js +140 -8
- package/dist/commands/prune.js +5 -13
- package/dist/commands/refresh-rules.js +1 -1
- package/dist/commands/repo.d.ts +5 -7
- package/dist/commands/repo.js +34 -18
- package/dist/commands/resource-view.js +4 -0
- package/dist/commands/resume.d.ts +11 -7
- package/dist/commands/resume.js +82 -98
- package/dist/commands/route.d.ts +12 -0
- package/dist/commands/route.js +261 -0
- package/dist/commands/routines.d.ts +2 -3
- package/dist/commands/routines.js +120 -145
- package/dist/commands/rules.js +1 -1
- package/dist/commands/run-account-picker.d.ts +1 -1
- package/dist/commands/run-account-picker.js +2 -2
- package/dist/commands/run-broadcast.d.ts +21 -0
- package/dist/commands/run-broadcast.js +89 -0
- package/dist/commands/run-cloud.js +1 -1
- package/dist/commands/secrets-vault.d.ts +10 -0
- package/dist/commands/{login.js → secrets-vault.js} +34 -14
- package/dist/commands/secrets.d.ts +4 -4
- package/dist/commands/secrets.js +72 -63
- package/dist/commands/sessions-backfill.js +1 -1
- package/dist/commands/sessions-browser.d.ts +1 -1
- package/dist/commands/sessions-browser.js +9 -5
- package/dist/commands/sessions-export.js +2 -2
- package/dist/commands/sessions-inject.js +4 -5
- package/dist/commands/sessions-migrate.js +16 -27
- package/dist/commands/sessions-picker.d.ts +13 -0
- package/dist/commands/sessions-picker.js +182 -8
- package/dist/commands/sessions-resume.d.ts +7 -3
- package/dist/commands/sessions-resume.js +81 -33
- package/dist/commands/sessions-stats.js +2 -2
- package/dist/commands/sessions.d.ts +75 -68
- package/dist/commands/sessions.js +142 -180
- package/dist/commands/setup-computer.js +1 -1
- package/dist/commands/setup-fleet.js +3 -0
- package/dist/commands/setup-mine.d.ts +7 -3
- package/dist/commands/setup-mine.js +13 -8
- package/dist/commands/setup-secrets.js +2 -2
- package/dist/commands/setup-watchdog.js +2 -2
- package/dist/commands/setup.js +7 -2
- package/dist/commands/share.d.ts +65 -0
- package/dist/commands/share.js +253 -20
- package/dist/commands/skills.js +3 -3
- package/dist/commands/snapshot.d.ts +2 -2
- package/dist/commands/snapshot.js +9 -9
- package/dist/commands/ssh.d.ts +1 -1
- package/dist/commands/ssh.js +318 -48
- package/dist/commands/subagents.js +1 -1
- package/dist/commands/sync.js +24 -9
- package/dist/commands/teams.d.ts +2 -2
- package/dist/commands/teams.js +9 -18
- package/dist/commands/tmux.js +5 -1
- package/dist/commands/trash.js +1 -1
- package/dist/commands/usage.d.ts +1 -1
- package/dist/commands/usage.js +2 -2
- package/dist/commands/utils.d.ts +4 -14
- package/dist/commands/utils.js +6 -27
- package/dist/commands/versions.js +2 -2
- package/dist/commands/view.d.ts +9 -77
- package/dist/commands/view.js +23 -8
- package/dist/commands/watchdog.js +1 -1
- package/dist/commands/webhook.js +11 -25
- package/dist/commands/workflows.js +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/account-capabilities.d.ts +39 -0
- package/dist/lib/account-capabilities.js +59 -0
- package/dist/lib/account-catalog.js +1 -1
- package/dist/lib/account-registry.d.ts +66 -0
- package/dist/lib/account-registry.js +151 -5
- package/dist/lib/{rotate.d.ts → accounting/rotate.d.ts} +4 -4
- package/dist/lib/{rotate.js → accounting/rotate.js} +8 -8
- package/dist/lib/{usage.d.ts → accounting/usage.d.ts} +4 -4
- package/dist/lib/{usage.js → accounting/usage.js} +11 -11
- package/dist/lib/agent-spec/provider.js +1 -1
- package/dist/lib/agents.d.ts +72 -4
- package/dist/lib/agents.js +231 -199
- package/dist/lib/answer-router.d.ts +2 -2
- package/dist/lib/ask-classifier.d.ts +1 -1
- package/dist/lib/ask-classifier.js +1 -1
- package/dist/lib/audit/log.js +1 -1
- package/dist/lib/auth-health.d.ts +1 -1
- package/dist/lib/auth-health.js +2 -2
- package/dist/lib/brand.js +1 -1
- package/dist/lib/browser/caller-identity.d.ts +28 -0
- package/dist/lib/browser/caller-identity.js +156 -0
- package/dist/lib/browser/cdp.js +1 -1
- package/dist/lib/browser/drivers/ssh.d.ts +1 -1
- package/dist/lib/browser/drivers/ssh.js +2 -2
- package/dist/lib/browser/hygiene.d.ts +10 -2
- package/dist/lib/browser/hygiene.js +7 -4
- package/dist/lib/browser/ipc.d.ts +22 -2
- package/dist/lib/browser/ipc.js +185 -21
- package/dist/lib/browser/profiles.d.ts +67 -3
- package/dist/lib/browser/profiles.js +129 -7
- package/dist/lib/browser/remote-control.d.ts +2 -2
- package/dist/lib/browser/remote-control.js +3 -3
- package/dist/lib/browser/runtime-state.d.ts +79 -0
- package/dist/lib/browser/runtime-state.js +119 -1
- package/dist/lib/browser/service.d.ts +113 -1
- package/dist/lib/browser/service.js +454 -40
- package/dist/lib/browser/sessions-list.d.ts +2 -1
- package/dist/lib/browser/sessions-list.js +4 -13
- package/dist/lib/browser/types.d.ts +18 -0
- package/dist/lib/budget/config.js +1 -1
- package/dist/lib/budget/ledger.js +1 -1
- package/dist/lib/byok-usage.js +1 -1
- package/dist/lib/capabilities.js +3 -15
- package/dist/lib/catchup.d.ts +1 -1
- package/dist/lib/catchup.js +1 -1
- package/dist/lib/cloud/dispatch.js +1 -1
- package/dist/lib/cloud/host.d.ts +3 -3
- package/dist/lib/cloud/host.js +5 -5
- package/dist/lib/cloud/rush.d.ts +9 -21
- package/dist/lib/cloud/rush.js +33 -120
- package/dist/lib/cloud/types.d.ts +2 -2
- package/dist/lib/commands.js +3 -13
- package/dist/lib/computer/actions.d.ts +36 -0
- package/dist/lib/computer/actions.js +162 -0
- package/dist/lib/computer/dispatch.d.ts +2 -2
- package/dist/lib/computer/dispatch.js +2 -2
- package/dist/lib/computer/sessions-list.d.ts +3 -3
- package/dist/lib/computer/sessions-list.js +2 -2
- package/dist/lib/config-keys.d.ts +12 -3
- package/dist/lib/config-keys.js +29 -6
- package/dist/lib/config-machine-keys.d.ts +4 -2
- package/dist/lib/config-machine-keys.js +6 -2
- package/dist/lib/crabbox/lease.js +9 -1
- package/dist/lib/crabbox/runtimes.d.ts +32 -7
- package/dist/lib/crabbox/runtimes.js +72 -30
- package/dist/lib/{daemon.d.ts → daemon/daemon.d.ts} +59 -1
- package/dist/lib/{daemon.js → daemon/daemon.js} +237 -49
- package/dist/lib/daemon-services.d.ts +1 -1
- package/dist/lib/daemon-services.js +5 -0
- package/dist/lib/daemon-ticks.d.ts +25 -0
- package/dist/lib/daemon-ticks.js +31 -1
- package/dist/lib/daemon-webhooks.d.ts +102 -0
- package/dist/lib/daemon-webhooks.js +210 -0
- package/dist/lib/device-config.d.ts +116 -72
- package/dist/lib/device-config.js +366 -132
- package/dist/lib/devices/config-migration.d.ts +29 -34
- package/dist/lib/devices/config-migration.js +209 -130
- package/dist/lib/devices/connect.d.ts +2 -2
- package/dist/lib/devices/connect.js +2 -2
- package/dist/lib/devices/discovery-policy.d.ts +30 -0
- package/dist/lib/devices/discovery-policy.js +101 -0
- package/dist/lib/devices/fleet-inventory.js +8 -3
- package/dist/lib/devices/harness-inventory.d.ts +1 -1
- package/dist/lib/devices/harness-inventory.js +12 -3
- package/dist/lib/devices/known-hosts.js +1 -1
- package/dist/lib/devices/pool.d.ts +61 -0
- package/dist/lib/devices/pool.js +83 -0
- package/dist/lib/devices/registry.d.ts +1 -1
- package/dist/lib/devices/registry.js +1 -1
- package/dist/lib/devices/resolve-profile.d.ts +2 -2
- package/dist/lib/devices/resolve-profile.js +2 -2
- package/dist/lib/devices/resolve-target.d.ts +1 -1
- package/dist/lib/devices/resolve-target.js +4 -4
- package/dist/lib/devices/self-host.d.ts +1 -1
- package/dist/lib/devices/self-host.js +3 -3
- package/dist/lib/devices/ssh-config.d.ts +1 -1
- package/dist/lib/devices/stats-cache.js +1 -1
- package/dist/lib/devices/sync.d.ts +3 -1
- package/dist/lib/devices/sync.js +3 -3
- package/dist/lib/doctor-diff.js +4 -4
- package/dist/lib/drift-sync.js +2 -2
- package/dist/lib/drift.js +2 -2
- package/dist/lib/event-families.d.ts +1 -1
- package/dist/lib/event-stream.d.ts +1 -1
- package/dist/lib/event-stream.js +2 -2
- package/dist/lib/events-ingest.js +2 -2
- package/dist/lib/exec.d.ts +8 -5
- package/dist/lib/exec.js +19 -13
- package/dist/lib/factory/snapshot.d.ts +1 -1
- package/dist/lib/factory/snapshot.js +1 -1
- package/dist/lib/{activity.d.ts → feed/activity.d.ts} +1 -1
- package/dist/lib/{activity.js → feed/activity.js} +7 -7
- package/dist/lib/{events.d.ts → feed/events.d.ts} +2 -2
- package/dist/lib/{events.js → feed/events.js} +5 -5
- package/dist/lib/{feed.js → feed/feed.js} +4 -4
- package/dist/lib/feed-outcome.d.ts +1 -1
- package/dist/lib/feed-policy.d.ts +1 -1
- package/dist/lib/feed-policy.js +1 -1
- package/dist/lib/feed-post.d.ts +1 -1
- package/dist/lib/feed-post.js +1 -1
- package/dist/lib/feed-ranking.d.ts +1 -1
- package/dist/lib/fleet/apply.d.ts +0 -6
- package/dist/lib/fleet/apply.js +18 -45
- package/dist/lib/fleet/auth-sync.d.ts +16 -35
- package/dist/lib/fleet/auth-sync.js +16 -75
- package/dist/lib/fleet/capture.js +8 -6
- package/dist/lib/fleet/manifest.js +23 -11
- package/dist/lib/fleet/types.d.ts +19 -7
- package/dist/lib/fleet-cache.d.ts +1 -1
- package/dist/lib/fleet-cache.js +1 -1
- package/dist/lib/format.d.ts +19 -0
- package/dist/lib/format.js +44 -1
- package/dist/lib/friction-heuristics.d.ts +1 -1
- package/dist/lib/git.d.ts +24 -1
- package/dist/lib/git.js +82 -38
- package/dist/lib/heal.js +3 -3
- package/dist/lib/hooks.d.ts +18 -0
- package/dist/lib/hooks.js +113 -1
- package/dist/lib/hosts/credentials.d.ts +30 -10
- package/dist/lib/hosts/credentials.js +38 -26
- package/dist/lib/hosts/dispatch.d.ts +3 -3
- package/dist/lib/hosts/dispatch.js +3 -3
- package/dist/lib/hosts/option.d.ts +3 -3
- package/dist/lib/hosts/option.js +7 -8
- package/dist/lib/hosts/passthrough.d.ts +17 -17
- package/dist/lib/hosts/passthrough.js +67 -50
- package/dist/lib/hosts/providers/devices.d.ts +1 -1
- package/dist/lib/hosts/providers/devices.js +1 -1
- package/dist/lib/hosts/reconcile.d.ts +1 -1
- package/dist/lib/hosts/reconcile.js +1 -1
- package/dist/lib/hosts/reconnect.d.ts +1 -1
- package/dist/lib/hosts/reconnect.js +2 -2
- package/dist/lib/hosts/registry.d.ts +5 -5
- package/dist/lib/hosts/registry.js +5 -5
- package/dist/lib/hosts/remote-cmd.d.ts +10 -10
- package/dist/lib/hosts/remote-cmd.js +25 -18
- package/dist/lib/hosts/remote-os.d.ts +4 -4
- package/dist/lib/hosts/remote-os.js +4 -4
- package/dist/lib/hosts/remote-session-id.d.ts +2 -2
- package/dist/lib/hosts/remote-session-id.js +2 -2
- package/dist/lib/hosts/routing-flag.d.ts +3 -3
- package/dist/lib/hosts/routing-flag.js +4 -5
- package/dist/lib/hosts/run-target.d.ts +4 -4
- package/dist/lib/hosts/run-target.js +4 -4
- package/dist/lib/hosts/session-index.d.ts +2 -2
- package/dist/lib/hosts/session-index.js +1 -1
- package/dist/lib/hosts/session-marker.d.ts +1 -1
- package/dist/lib/hosts/session-marker.js +1 -1
- package/dist/lib/hosts/types.d.ts +2 -2
- package/dist/lib/hosts/types.js +2 -2
- package/dist/lib/import.js +1 -1
- package/dist/lib/{migrate.d.ts → installations/migrate.d.ts} +49 -1
- package/dist/lib/{migrate.js → installations/migrate.js} +265 -38
- package/dist/lib/installations/resolve.js +1 -1
- package/dist/lib/installations/strategies.js +1 -1
- package/dist/lib/installations/update.js +2 -2
- package/dist/lib/{versions.d.ts → installations/versions.d.ts} +12 -3
- package/dist/lib/{versions.js → installations/versions.js} +51 -31
- package/dist/lib/isolation-boundary-report.js +1 -1
- package/dist/lib/linear-projects.d.ts +28 -0
- package/dist/lib/linear-projects.js +30 -0
- package/dist/lib/loop.js +1 -1
- package/dist/lib/mailbox-gc.js +1 -1
- package/dist/lib/mailbox.js +1 -1
- package/dist/lib/mcp-registry.d.ts +62 -0
- package/dist/lib/mcp-registry.js +177 -0
- package/dist/lib/mcp.d.ts +5 -0
- package/dist/lib/mcp.js +124 -307
- 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/install-menubar.d.ts +7 -0
- package/dist/lib/menubar/install-menubar.js +24 -6
- package/dist/lib/menubar/snapshot.d.ts +7 -0
- package/dist/lib/menubar/snapshot.js +8 -6
- package/dist/lib/models.js +1 -1
- package/dist/lib/monitors/config.d.ts +12 -0
- package/dist/lib/monitors/config.js +3 -0
- package/dist/lib/monitors/dispatch.js +26 -5
- package/dist/lib/monitors/engine.js +10 -0
- package/dist/lib/monitors/sources/webhook.d.ts +1 -1
- package/dist/lib/monitors/state.d.ts +42 -0
- package/dist/lib/monitors/state.js +30 -0
- package/dist/lib/notify.d.ts +1 -1
- package/dist/lib/observe-aliases.d.ts +2 -2
- package/dist/lib/observe-aliases.js +2 -11
- package/dist/lib/output/git-output.js +2 -2
- package/dist/lib/overdue.d.ts +1 -1
- package/dist/lib/overdue.js +1 -1
- package/dist/lib/permissions-registry.d.ts +65 -0
- package/dist/lib/permissions-registry.js +599 -0
- package/dist/lib/permissions.d.ts +24 -13
- package/dist/lib/permissions.js +52 -271
- package/dist/lib/picker.d.ts +16 -0
- package/dist/lib/picker.js +33 -3
- package/dist/lib/placement.d.ts +1 -1
- package/dist/lib/placement.js +4 -4
- package/dist/lib/platform/paths.d.ts +8 -0
- package/dist/lib/platform/paths.js +11 -0
- package/dist/lib/platform/posixpath.js +3 -3
- package/dist/lib/{plugin-marketplace.d.ts → plugins/plugin-marketplace.d.ts} +1 -1
- package/dist/lib/{plugin-marketplace.js → plugins/plugin-marketplace.js} +2 -2
- package/dist/lib/{plugins.d.ts → plugins/plugins.d.ts} +1 -1
- package/dist/lib/{plugins.js → plugins/plugins.js} +7 -7
- package/dist/lib/{skills.d.ts → plugins/skills.d.ts} +1 -1
- package/dist/lib/{skills.js → plugins/skills.js} +7 -7
- package/dist/lib/pricing/cost.d.ts +1 -1
- package/dist/lib/pricing/cost.js +1 -1
- package/dist/lib/profiles-presets.d.ts +1 -1
- package/dist/lib/profiles-presets.js +1 -1
- package/dist/lib/profiles.js +2 -2
- package/dist/lib/project-import.js +4 -1
- package/dist/lib/project-launch.d.ts +1 -1
- package/dist/lib/project-launch.js +3 -3
- package/dist/lib/project-pull.d.ts +128 -0
- package/dist/lib/project-pull.js +384 -0
- package/dist/lib/project-root.d.ts +2 -2
- package/dist/lib/project-root.js +2 -2
- package/dist/lib/project-status.js +1 -1
- package/dist/lib/projects.d.ts +23 -0
- package/dist/lib/projects.js +29 -6
- package/dist/lib/refresh.d.ts +12 -1
- package/dist/lib/refresh.js +16 -9
- package/dist/lib/registry.d.ts +9 -2
- package/dist/lib/registry.js +11 -4
- package/dist/lib/resources.d.ts +2 -2
- package/dist/lib/resources.js +2 -2
- package/dist/lib/routers.d.ts +81 -0
- package/dist/lib/routers.js +153 -0
- package/dist/lib/routine-context.d.ts +1 -0
- package/dist/lib/routine-context.js +7 -2
- package/dist/lib/routine-notify-owner.d.ts +1 -1
- package/dist/lib/routine-notify.d.ts +1 -1
- package/dist/lib/routine-notify.js +1 -1
- package/dist/lib/routine-process-cleanup.d.ts +1 -1
- package/dist/lib/routine-readiness.d.ts +1 -1
- package/dist/lib/routine-readiness.js +11 -4
- package/dist/lib/routines-placement.d.ts +12 -2
- package/dist/lib/routines-placement.js +20 -3
- package/dist/lib/routines-project.d.ts +1 -1
- package/dist/lib/routines-project.js +1 -1
- package/dist/lib/rules/compile.d.ts +1 -0
- package/dist/lib/rules/compile.js +10 -2
- package/dist/lib/rules/rules.js +1 -1
- package/dist/lib/run-notify.js +1 -1
- package/dist/lib/runner.d.ts +80 -2
- package/dist/lib/runner.js +241 -62
- package/dist/lib/sandbox.d.ts +1 -1
- package/dist/lib/scheduler.d.ts +1 -1
- package/dist/lib/scheduler.js +1 -1
- package/dist/lib/{routines.d.ts → scheduling/routines.d.ts} +54 -9
- package/dist/lib/{routines.js → scheduling/routines.js} +173 -14
- 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.js +2 -2
- package/dist/lib/secrets/audit.js +1 -1
- package/dist/lib/secrets/bundles.d.ts +3 -3
- package/dist/lib/secrets/bundles.js +7 -7
- package/dist/lib/secrets/index.js +1 -1
- package/dist/lib/secrets/list-filter.d.ts +1 -1
- package/dist/lib/secrets/list-filter.js +2 -2
- package/dist/lib/secrets/push.d.ts +1 -1
- package/dist/lib/secrets/push.js +10 -12
- package/dist/lib/secrets/remote.d.ts +12 -10
- package/dist/lib/secrets/remote.js +21 -14
- package/dist/lib/secrets/vault.js +2 -2
- package/dist/lib/self-heal/checks/shadowing.js +1 -1
- package/dist/lib/self-heal/checks/shims.js +1 -1
- package/dist/lib/self-update.d.ts +39 -4
- package/dist/lib/self-update.js +78 -25
- package/dist/lib/serve/control.d.ts +1 -1
- package/dist/lib/serve/control.js +4 -4
- package/dist/lib/serve/data.d.ts +1 -1
- package/dist/lib/serve/data.js +1 -1
- package/dist/lib/serve/stream.js +1 -1
- package/dist/lib/service-manifest.d.ts +29 -0
- package/dist/lib/service-manifest.js +80 -0
- package/dist/lib/session/active.d.ts +59 -7
- package/dist/lib/session/active.js +158 -17
- package/dist/lib/session/bash-command.js +1 -1
- package/dist/lib/session/claude-accounts.d.ts +1 -1
- package/dist/lib/session/claude-accounts.js +1 -1
- package/dist/lib/session/db.d.ts +10 -2
- package/dist/lib/session/db.js +25 -6
- package/dist/lib/session/discover.d.ts +77 -0
- package/dist/lib/session/discover.js +130 -25
- package/dist/lib/session/fork.js +1 -1
- package/dist/lib/session/inject.d.ts +1 -1
- package/dist/lib/session/insights.d.ts +1 -1
- package/dist/lib/session/insights.js +1 -1
- package/dist/lib/session/live-metadata.d.ts +15 -0
- package/dist/lib/session/live-metadata.js +76 -0
- package/dist/lib/session/migrate-targets.d.ts +1 -1
- package/dist/lib/session/recovery.d.ts +1 -1
- package/dist/lib/session/recovery.js +2 -2
- package/dist/lib/session/remote-active.d.ts +10 -1
- package/dist/lib/session/remote-active.js +8 -3
- package/dist/lib/session/remote-bundle.d.ts +1 -1
- package/dist/lib/session/remote-bundle.js +2 -2
- package/dist/lib/session/remote-list.d.ts +15 -4
- package/dist/lib/session/remote-list.js +40 -3
- package/dist/lib/session/remote.d.ts +5 -5
- package/dist/lib/session/remote.js +13 -17
- package/dist/lib/session/resume-command.d.ts +3 -2
- package/dist/lib/session/resume-command.js +4 -3
- package/dist/lib/session/resume-owner.d.ts +3 -3
- package/dist/lib/session/resume-owner.js +3 -3
- package/dist/lib/session/session-cache.d.ts +12 -0
- package/dist/lib/session/session-cache.js +2 -0
- package/dist/lib/session/shell-programs.js +1 -1
- package/dist/lib/session/state.js +5 -5
- package/dist/lib/session/team-filter.d.ts +1 -1
- package/dist/lib/session/team-filter.js +1 -1
- package/dist/lib/session/types.d.ts +3 -3
- package/dist/lib/session/width.d.ts +2 -2
- package/dist/lib/session/width.js +2 -2
- package/dist/lib/share/delete.d.ts +21 -0
- package/dist/lib/share/delete.js +42 -0
- package/dist/lib/share/publish.d.ts +82 -0
- package/dist/lib/share/publish.js +170 -18
- package/dist/lib/share/worker-template.js +172 -9
- package/dist/lib/shims.js +35 -7
- package/dist/lib/smart-launch.d.ts +36 -6
- package/dist/lib/smart-launch.js +65 -8
- package/dist/lib/snapshot.d.ts +4 -4
- package/dist/lib/snapshot.js +2 -2
- package/dist/lib/ssh-exec.d.ts +1 -1
- package/dist/lib/ssh-exec.js +2 -2
- package/dist/lib/ssh-tunnel.d.ts +10 -10
- package/dist/lib/ssh-tunnel.js +12 -12
- package/dist/lib/staleness/checkers/hooks.d.ts +1 -1
- package/dist/lib/staleness/checkers/hooks.js +1 -1
- package/dist/lib/staleness/detectors/permissions.js +0 -23
- package/dist/lib/staleness/detectors/plugins.js +1 -1
- package/dist/lib/staleness/fingerprint.js +1 -1
- package/dist/lib/staleness/layers.d.ts +1 -1
- package/dist/lib/staleness/layers.js +1 -1
- package/dist/lib/staleness/writers/mcp.js +3 -1
- package/dist/lib/staleness/writers/plugins.js +1 -1
- package/dist/lib/staleness/writers/types.d.ts +8 -0
- package/dist/lib/startup/command-registry.d.ts +5 -147
- package/dist/lib/startup/command-registry.js +38 -303
- package/dist/lib/startup/dev-build.d.ts +0 -21
- package/dist/lib/startup/dev-build.js +29 -8
- package/dist/lib/state.d.ts +19 -1
- package/dist/lib/state.js +120 -51
- package/dist/lib/subagents.js +1 -1
- package/dist/lib/sync-status.js +1 -1
- package/dist/lib/sync-umbrella.d.ts +6 -1
- package/dist/lib/sync-umbrella.js +9 -4
- package/dist/lib/teams/agents.js +2 -2
- package/dist/lib/teams/registry.js +1 -1
- package/dist/lib/terminal/backends/vscodium-agent.js +1 -1
- package/dist/lib/terminal/engine.js +1 -1
- package/dist/lib/terminal/index.d.ts +4 -0
- package/dist/lib/terminal/index.js +3 -0
- package/dist/lib/terminal/inject.d.ts +2 -2
- package/dist/lib/terminal/inject.js +2 -2
- package/dist/lib/terminal/transport.js +1 -1
- package/dist/lib/tmux/index.d.ts +1 -1
- package/dist/lib/tmux/index.js +1 -1
- package/dist/lib/tmux/session.d.ts +21 -5
- package/dist/lib/tmux/session.js +76 -22
- package/dist/lib/triggers/handlers.d.ts +1 -1
- package/dist/lib/triggers/handlers.js +2 -2
- package/dist/lib/triggers/webhook.d.ts +36 -2
- package/dist/lib/triggers/webhook.js +97 -42
- package/dist/lib/types.d.ts +18 -6
- package/dist/lib/usage-fleet.d.ts +1 -1
- package/dist/lib/usage-fleet.js +1 -1
- package/dist/lib/usage-refresh.d.ts +1 -1
- package/dist/lib/usage-refresh.js +3 -3
- package/dist/lib/version-duplicates.js +2 -2
- package/dist/lib/view-types.d.ts +56 -0
- package/dist/lib/view-types.js +1 -0
- package/dist/lib/watchdog/rotate.d.ts +2 -2
- package/dist/lib/watchdog/rotate.js +3 -3
- package/dist/lib/watchdog/runner.d.ts +2 -3
- package/dist/lib/watchdog/runner.js +3 -4
- package/dist/lib/workflows.js +1 -1
- package/package.json +2 -1
- package/scripts/postinstall.js +2 -2
- package/dist/commands/bench.d.ts +0 -2
- package/dist/commands/bench.js +0 -101
- package/dist/commands/cp.d.ts +0 -84
- package/dist/commands/cp.js +0 -231
- package/dist/commands/login.d.ts +0 -2
- package/dist/lib/resources/commands.d.ts +0 -46
- package/dist/lib/resources/commands.js +0 -211
- package/dist/lib/resources/hooks.d.ts +0 -16
- package/dist/lib/resources/hooks.js +0 -153
- package/dist/lib/resources/mcp.d.ts +0 -34
- package/dist/lib/resources/mcp.js +0 -250
- package/dist/lib/resources/memory.d.ts +0 -15
- package/dist/lib/resources/memory.js +0 -46
- package/dist/lib/resources/permissions.d.ts +0 -13
- package/dist/lib/resources/permissions.js +0 -202
- package/dist/lib/resources/rules.d.ts +0 -46
- package/dist/lib/resources/rules.js +0 -179
- package/dist/lib/resources/skills.d.ts +0 -37
- package/dist/lib/resources/skills.js +0 -247
- package/dist/lib/resources/subagents.d.ts +0 -46
- package/dist/lib/resources/subagents.js +0 -202
- /package/dist/lib/{feed.d.ts → feed/feed.d.ts} +0 -0
|
@@ -1,43 +1,49 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Device/user config keys — typed read/write over the
|
|
2
|
+
* Device/user config keys — typed read/write over the three-layer 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
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* browser.remote-control, scheduler.enabled,
|
|
16
|
-
* daemon.enabled).
|
|
5
|
+
* - user scope → central `~/.agents/agents.yaml` under `config:` (syncs
|
|
6
|
+
* fleet-wide via `agents repo push/pull`)
|
|
7
|
+
* - device scope → the per-device TRACKED doc
|
|
8
|
+
* `~/.agents/devices/<name>/agents.yaml` under `config:` —
|
|
9
|
+
* conflict-free by construction (each machine writes only
|
|
10
|
+
* its own folder, and the churny auto-written pins no longer
|
|
11
|
+
* share the file)
|
|
12
|
+
* - fleet layer → central `~/.agents/agents.yaml` under
|
|
13
|
+
* `fleet.defaults.config` — fleet-wide defaults written by
|
|
14
|
+
* `agents devices config --fleet <key> <value>`
|
|
17
15
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* not just churn.
|
|
16
|
+
* Read order for a device-scope key: built-in default < fleet.defaults.config
|
|
17
|
+
* < per-device config:. Names and non-secret values only (a secrets-bundle
|
|
18
|
+
* NAME is fine; a credential never is).
|
|
22
19
|
*
|
|
23
20
|
* The device registry (`~/.agents/.history/devices/registry.json`) stays the
|
|
24
21
|
* DISCOVERY cache (address, tailscale snapshot, reachability); the profile
|
|
25
22
|
* fields config can override (ssh.*, platform, user) are overlaid onto it at
|
|
26
23
|
* read time by `lib/devices/resolve-profile.ts`.
|
|
27
24
|
*
|
|
28
|
-
* Legacy stores (
|
|
29
|
-
*
|
|
30
|
-
* by `lib/devices/config-migration.ts`, invoked on the first
|
|
31
|
-
* process — after migration there is ONE read path
|
|
25
|
+
* Legacy stores (central `fleet.devices.<name>.config`, legacy auto-launch.json,
|
|
26
|
+
* doc-level defaultBrowserProfile, pins in tracked docs) are folded into this
|
|
27
|
+
* layout once by `lib/devices/config-migration.ts`, invoked on the first
|
|
28
|
+
* read/write in a process — after migration there is ONE read path per layer,
|
|
29
|
+
* no fallback branches.
|
|
32
30
|
*
|
|
33
31
|
* Unset always means today's behavior (the documented default).
|
|
34
32
|
*/
|
|
35
|
-
import
|
|
33
|
+
import * as fs from 'fs';
|
|
34
|
+
import * as path from 'path';
|
|
35
|
+
import * as yaml from 'yaml';
|
|
36
|
+
import { META_HEADER, getUserAgentsDir, readMeta, updateMeta, withMetaLock } from './state.js';
|
|
37
|
+
import { atomicWriteFileSync } from './fs-atomic.js';
|
|
36
38
|
import { machineId } from './machine-id.js';
|
|
37
39
|
import { assertValidDeviceName } from './devices/registry.js';
|
|
38
|
-
import {
|
|
40
|
+
import { migrateDeviceConfigStores } from './devices/config-migration.js';
|
|
39
41
|
const DEVICE_PLATFORMS = ['windows', 'linux', 'macos', 'unknown'];
|
|
40
42
|
const SSH_AUTH_METHODS = ['key', 'password'];
|
|
43
|
+
/** Roles a device can be marked with — see the `role` key below. */
|
|
44
|
+
const DEVICE_ROLES = ['worker', 'personal'];
|
|
45
|
+
/** Which devices automatic placement may pick — see the `auto.pool` key below. */
|
|
46
|
+
const AUTO_POOL_MODES = ['workers', 'all'];
|
|
41
47
|
export const CONFIG_KEYS = [
|
|
42
48
|
{
|
|
43
49
|
name: 'interactive.host',
|
|
@@ -71,6 +77,19 @@ export const CONFIG_KEYS = [
|
|
|
71
77
|
}
|
|
72
78
|
},
|
|
73
79
|
},
|
|
80
|
+
{
|
|
81
|
+
name: 'auto.pool',
|
|
82
|
+
yamlKey: 'autoPool',
|
|
83
|
+
scope: 'user',
|
|
84
|
+
type: 'string',
|
|
85
|
+
description: "Which devices automatic placement (`--device auto`) may pick: 'workers' (default — only devices marked role=worker, " +
|
|
86
|
+
"once at least one is marked) or 'all' (every online device, ignoring worker marks). A device marked personal is " +
|
|
87
|
+
'never picked automatically under either mode.',
|
|
88
|
+
defaultValue: 'workers',
|
|
89
|
+
validate: (v) => AUTO_POOL_MODES.includes(v)
|
|
90
|
+
? null
|
|
91
|
+
: `auto.pool must be one of ${AUTO_POOL_MODES.join(' | ')}.`,
|
|
92
|
+
},
|
|
74
93
|
{
|
|
75
94
|
name: 'browser.profile',
|
|
76
95
|
yamlKey: 'defaultBrowserProfile',
|
|
@@ -119,6 +138,18 @@ export const CONFIG_KEYS = [
|
|
|
119
138
|
defaultValue: false,
|
|
120
139
|
description: 'Whether the daemon runs the watchdog pass on this device.',
|
|
121
140
|
},
|
|
141
|
+
{
|
|
142
|
+
name: 'tmux.enabled',
|
|
143
|
+
yamlKey: 'tmuxEnabled',
|
|
144
|
+
scope: 'device',
|
|
145
|
+
visibility: 'machine',
|
|
146
|
+
type: 'bool',
|
|
147
|
+
defaultValue: true,
|
|
148
|
+
description: 'Whether an interactive `agents run` on this device is wrapped in the shared-socket tmux session. ' +
|
|
149
|
+
'On gives every agent an addressable pane (`agents sessions --active` tells co-located agents apart, ' +
|
|
150
|
+
'`agents focus` re-attaches without forking). Off spawns the agent directly on this box — the durable ' +
|
|
151
|
+
'form of `--no-tmux`, for a machine whose tmux is broken or unwanted.',
|
|
152
|
+
},
|
|
122
153
|
{
|
|
123
154
|
name: 'browser.remote-control',
|
|
124
155
|
yamlKey: 'browserRemoteControl',
|
|
@@ -126,9 +157,22 @@ export const CONFIG_KEYS = [
|
|
|
126
157
|
visibility: 'machine',
|
|
127
158
|
type: 'bool',
|
|
128
159
|
defaultValue: false,
|
|
129
|
-
description: "Whether other fleet machines may drive THIS device's browser over `browser --
|
|
160
|
+
description: "Whether other fleet machines may drive THIS device's browser over `browser --device <this-device>`. " +
|
|
130
161
|
'Default off — a fleet-remote drive is refused until the owner runs `agents browser remote-control on`.',
|
|
131
162
|
},
|
|
163
|
+
{
|
|
164
|
+
name: 'browser.task-idle-minutes',
|
|
165
|
+
yamlKey: 'browserTaskIdleMinutes',
|
|
166
|
+
scope: 'device',
|
|
167
|
+
visibility: 'machine',
|
|
168
|
+
type: 'int',
|
|
169
|
+
defaultValue: 30,
|
|
170
|
+
description: 'Minutes a browser task may sit with no IPC action (navigate, click, type, screenshot, …) before the daemon\'s ' +
|
|
171
|
+
'abandoned-task reaper closes its tabs and marks it done (RUSH-2622). 0 disables idle reaping — the reaper still ' +
|
|
172
|
+
"closes a task whose owning agent session has exited, whatever this is set to. Read only on THIS box's own " +
|
|
173
|
+
'reaper tick and `agents browser gc`, so it never applies to a peer.',
|
|
174
|
+
validate: (v) => v >= 0 ? null : 'browser.task-idle-minutes must be >= 0 (0 disables idle reaping).',
|
|
175
|
+
},
|
|
132
176
|
{
|
|
133
177
|
name: 'notes',
|
|
134
178
|
yamlKey: 'notes',
|
|
@@ -191,6 +235,20 @@ export const CONFIG_KEYS = [
|
|
|
191
235
|
? null
|
|
192
236
|
: `platform must be one of ${DEVICE_PLATFORMS.join(' | ')}.`,
|
|
193
237
|
},
|
|
238
|
+
{
|
|
239
|
+
name: 'role',
|
|
240
|
+
yamlKey: 'role',
|
|
241
|
+
scope: 'device',
|
|
242
|
+
visibility: 'shared',
|
|
243
|
+
type: 'string',
|
|
244
|
+
description: "What this device is for, fleet-wide: 'worker' (a box agents run on) or 'personal' (a machine you sit at — never " +
|
|
245
|
+
'picked automatically). Marking ANY device worker turns automatic placement into an allowlist: `--device auto` then ' +
|
|
246
|
+
'picks only from the marked workers. (A paired iPhone/iPad cockpit is marked control by `agents devices pair-ios` ' +
|
|
247
|
+
'and is excluded from placement by that role, not this key.)',
|
|
248
|
+
validate: (v) => DEVICE_ROLES.includes(v)
|
|
249
|
+
? null
|
|
250
|
+
: `role must be one of ${DEVICE_ROLES.join(' | ')}.`,
|
|
251
|
+
},
|
|
194
252
|
{
|
|
195
253
|
name: 'auto-launch.enabled',
|
|
196
254
|
yamlKey: 'autoLaunchEnabled',
|
|
@@ -249,57 +307,106 @@ function assertValidValue(spec, value) {
|
|
|
249
307
|
// ─── Migration hook ───────────────────────────────────────────────────────────
|
|
250
308
|
let migrationDone = false;
|
|
251
309
|
/**
|
|
252
|
-
* Fold the legacy
|
|
310
|
+
* Fold the legacy config/pins stores into the current layout, once per
|
|
253
311
|
* process. A failure is loud but non-fatal — config reads must keep working,
|
|
254
312
|
* and the next process retries the fold. Honors AGENTS_SKIP_MIGRATION=1, the
|
|
255
313
|
* same gate bootstrap's runMigration uses (tests pin it so a fork never folds
|
|
256
314
|
* 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.
|
|
264
315
|
*/
|
|
265
316
|
export function ensureDeviceConfigMigrated() {
|
|
266
317
|
if (migrationDone || process.env.AGENTS_SKIP_MIGRATION === '1')
|
|
267
318
|
return;
|
|
268
319
|
try {
|
|
269
|
-
|
|
320
|
+
migrateDeviceConfigStores();
|
|
270
321
|
migrationDone = true;
|
|
271
322
|
}
|
|
272
323
|
catch (err) {
|
|
273
324
|
console.error(`device config migration failed (${err?.message ?? err}); a later run retries`);
|
|
274
325
|
}
|
|
275
326
|
}
|
|
276
|
-
// ───
|
|
327
|
+
// ─── Layer reads ──────────────────────────────────────────────────────────────
|
|
328
|
+
/** Path to a device's tracked operator doc (`devices/<name>/agents.yaml`). */
|
|
329
|
+
function deviceDocPath(device) {
|
|
330
|
+
return path.join(getUserAgentsDir(), 'devices', device, 'agents.yaml');
|
|
331
|
+
}
|
|
277
332
|
/**
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
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.
|
|
333
|
+
* Read a device's doc. Returns null when the file does not exist. A malformed
|
|
334
|
+
* file is a hard error — silently returning null would let the next write wipe
|
|
335
|
+
* the device's routines/config (same contract as routine-activation's reader).
|
|
285
336
|
*/
|
|
286
|
-
|
|
287
|
-
const
|
|
288
|
-
|
|
337
|
+
function readDeviceDoc(device) {
|
|
338
|
+
const p = deviceDocPath(device);
|
|
339
|
+
let raw;
|
|
340
|
+
try {
|
|
341
|
+
raw = fs.readFileSync(p, 'utf-8');
|
|
342
|
+
}
|
|
343
|
+
catch (err) {
|
|
344
|
+
if (err && err.code === 'ENOENT')
|
|
345
|
+
return null;
|
|
346
|
+
throw err;
|
|
347
|
+
}
|
|
348
|
+
const corrupted = (detail) => new Error(`Device config corrupted at ${p}: ${detail}. Inspect and restore from backup.`);
|
|
349
|
+
let parsed;
|
|
350
|
+
try {
|
|
351
|
+
parsed = yaml.parse(raw);
|
|
352
|
+
}
|
|
353
|
+
catch (err) {
|
|
354
|
+
throw corrupted(err?.message ?? String(err));
|
|
355
|
+
}
|
|
356
|
+
if (parsed === null || parsed === undefined)
|
|
289
357
|
return {};
|
|
290
|
-
|
|
358
|
+
if (typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
359
|
+
throw corrupted(`expected a YAML map, got ${Array.isArray(parsed) ? 'a list' : JSON.stringify(parsed)}`);
|
|
360
|
+
}
|
|
361
|
+
const doc = parsed;
|
|
362
|
+
if (doc.config !== undefined && (typeof doc.config !== 'object' || doc.config === null || Array.isArray(doc.config))) {
|
|
363
|
+
throw corrupted('config: must be a mapping');
|
|
364
|
+
}
|
|
365
|
+
return doc;
|
|
366
|
+
}
|
|
367
|
+
/** Write a device doc (atomic), preserving keys this module does not own
|
|
368
|
+
* (`routines:`). A doc left empty is removed instead of leaving an empty
|
|
369
|
+
* tracked file behind. */
|
|
370
|
+
function writeDeviceDoc(device, doc) {
|
|
371
|
+
const p = deviceDocPath(device);
|
|
372
|
+
if (Object.keys(doc).length === 0) {
|
|
373
|
+
try {
|
|
374
|
+
fs.rmSync(p, { force: true });
|
|
375
|
+
fs.rmdirSync(path.dirname(p));
|
|
376
|
+
}
|
|
377
|
+
catch { /* dir not empty, or the file was already gone */ }
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
381
|
+
atomicWriteFileSync(p, META_HEADER + yaml.stringify(doc));
|
|
382
|
+
}
|
|
383
|
+
/** The fleet-defaults config layer (central `fleet.defaults.config`; {} when unset). */
|
|
384
|
+
export function readFleetConfigDefaults() {
|
|
385
|
+
const config = readMeta().fleet?.defaults?.config;
|
|
291
386
|
return config && typeof config === 'object' && !Array.isArray(config) ? config : {};
|
|
292
387
|
}
|
|
388
|
+
/** The device layer only: the doc's `config:` block ({} when unset). */
|
|
389
|
+
function readDeviceDocConfig(device) {
|
|
390
|
+
return readDeviceDoc(device)?.config ?? {};
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* The effective device-scope config block for `device`: fleet.defaults.config
|
|
394
|
+
* overlaid with the per-device doc's config:. This is the single read path
|
|
395
|
+
* post-migration — the profile resolver (`lib/devices/resolve-profile.ts`)
|
|
396
|
+
* goes through here. Deliberately does NOT auto-trigger the migration: it
|
|
397
|
+
* serves the hot dial/render paths. Sync and cheap (small local files).
|
|
398
|
+
*/
|
|
399
|
+
export function readDeviceConfigValues(device) {
|
|
400
|
+
return { ...readFleetConfigDefaults(), ...readDeviceDocConfig(device) };
|
|
401
|
+
}
|
|
293
402
|
/** The device a targeted read/write applies to (default: this machine). */
|
|
294
403
|
function targetDevice(opts) {
|
|
295
404
|
return opts?.device ?? machineId();
|
|
296
405
|
}
|
|
297
406
|
/**
|
|
298
|
-
* A machine-visibility key is only ever readable for THIS box
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
* for another machine — that would make `agents devices config <peer>
|
|
302
|
-
* browser.remote-control` look like it reported the peer's consent state.
|
|
407
|
+
* A machine-visibility key is only ever readable for THIS box. Asking for a
|
|
408
|
+
* peer's value is a mistake with a concrete fix, so say so rather than
|
|
409
|
+
* silently returning this machine's answer for another machine.
|
|
303
410
|
*/
|
|
304
411
|
function assertLocalTarget(spec, device) {
|
|
305
412
|
if (spec.scope !== 'device' || spec.visibility !== 'machine')
|
|
@@ -307,39 +414,39 @@ function assertLocalTarget(spec, device) {
|
|
|
307
414
|
if (device === machineId())
|
|
308
415
|
return;
|
|
309
416
|
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>'`);
|
|
417
|
+
`Run it on ${device}, e.g.: agents ssh ${device} 'agents devices config ${device} ${spec.name} <value>'`);
|
|
311
418
|
}
|
|
312
|
-
/** Get one config key's value and the layer that set it. */
|
|
419
|
+
/** Get one config key's effective value and the layer that set it. */
|
|
313
420
|
export function getConfigValue(name, opts) {
|
|
421
|
+
ensureDeviceConfigMigrated();
|
|
314
422
|
const spec = configKeySpec(name);
|
|
315
423
|
if (spec.scope === 'user') {
|
|
316
424
|
const value = readMeta().config?.[spec.yamlKey];
|
|
317
|
-
return { spec, value,
|
|
425
|
+
return { spec, value, source: value !== undefined ? 'user' : 'default' };
|
|
426
|
+
}
|
|
427
|
+
if (opts?.fleet) {
|
|
428
|
+
const value = readFleetConfigDefaults()[spec.yamlKey];
|
|
429
|
+
return { spec, value, source: value !== undefined ? 'fleet' : 'default' };
|
|
318
430
|
}
|
|
319
431
|
const device = targetDevice(opts);
|
|
320
432
|
assertLocalTarget(spec, device);
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
329
|
-
const value = readDeviceConfigValues(device)[spec.yamlKey];
|
|
330
|
-
return { spec, value, layer: value !== undefined ? 'device' : undefined };
|
|
433
|
+
const docConfig = readDeviceDocConfig(device);
|
|
434
|
+
if (spec.yamlKey in docConfig)
|
|
435
|
+
return { spec, value: docConfig[spec.yamlKey], source: 'device' };
|
|
436
|
+
const fleetConfig = readFleetConfigDefaults();
|
|
437
|
+
if (spec.yamlKey in fleetConfig)
|
|
438
|
+
return { spec, value: fleetConfig[spec.yamlKey], source: 'fleet' };
|
|
439
|
+
return { spec, value: undefined, source: 'default' };
|
|
331
440
|
}
|
|
332
441
|
/**
|
|
333
|
-
* List every known key with its value and the layer that set it.
|
|
442
|
+
* List every known key with its effective value and the layer that set it.
|
|
334
443
|
*
|
|
335
|
-
* Listing a PEER omits its machine-local keys rather than throwing
|
|
336
|
-
* live
|
|
337
|
-
*
|
|
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.
|
|
444
|
+
* Listing a PEER omits its machine-local keys rather than throwing — those
|
|
445
|
+
* values live on that box and are unknowable from here, but a bulk listing
|
|
446
|
+
* must not hard-fail. Asking for such a key by name still errors.
|
|
340
447
|
*/
|
|
341
448
|
export function listConfig(opts) {
|
|
342
|
-
const isPeer = targetDevice(opts) !== machineId();
|
|
449
|
+
const isPeer = !opts?.fleet && targetDevice(opts) !== machineId();
|
|
343
450
|
const visible = isPeer
|
|
344
451
|
? CONFIG_KEYS.filter((spec) => spec.scope !== 'device' || spec.visibility !== 'machine')
|
|
345
452
|
: CONFIG_KEYS;
|
|
@@ -357,38 +464,42 @@ export function resolveUsagePrimaryHost() {
|
|
|
357
464
|
?? null;
|
|
358
465
|
}
|
|
359
466
|
// ─── Writes ───────────────────────────────────────────────────────────────────
|
|
360
|
-
|
|
467
|
+
/** The fleet manifest for a defaults write: `devices` materializes as an
|
|
468
|
+
* explicit empty map (NOT 'all') so `agents apply` targets nothing until the
|
|
469
|
+
* operator declares a roster. */
|
|
470
|
+
function fleetForDefaultsWrite(fleet) {
|
|
471
|
+
return { ...fleet, devices: fleet && fleet.devices !== undefined ? fleet.devices : {} };
|
|
472
|
+
}
|
|
473
|
+
function setInFleetDefaults(spec, value) {
|
|
361
474
|
updateMeta((m) => {
|
|
362
|
-
const
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
return { ...m, fleet: { ...m.fleet, devices } };
|
|
475
|
+
const fleet = fleetForDefaultsWrite(m.fleet);
|
|
476
|
+
const defaults = { ...fleet.defaults, config: { ...fleet.defaults?.config, [spec.yamlKey]: value } };
|
|
477
|
+
return { ...m, fleet: { ...fleet, defaults } };
|
|
366
478
|
});
|
|
367
479
|
}
|
|
368
|
-
function
|
|
480
|
+
function unsetInFleetDefaults(spec) {
|
|
369
481
|
updateMeta((m) => {
|
|
370
|
-
const stored = m.fleet?.
|
|
371
|
-
if (!stored ||
|
|
372
|
-
return m; // nothing stored —
|
|
373
|
-
const
|
|
374
|
-
if (!prev?.config || !(spec.yamlKey in prev.config))
|
|
375
|
-
return m; // key not present — no write needed
|
|
376
|
-
const config = { ...prev.config };
|
|
482
|
+
const stored = m.fleet?.defaults?.config;
|
|
483
|
+
if (!stored || !(spec.yamlKey in stored))
|
|
484
|
+
return m; // nothing stored — no-op
|
|
485
|
+
const config = { ...stored };
|
|
377
486
|
delete config[spec.yamlKey];
|
|
378
|
-
const
|
|
487
|
+
const defaults = { ...m.fleet.defaults };
|
|
379
488
|
if (Object.keys(config).length > 0)
|
|
380
|
-
|
|
489
|
+
defaults.config = config;
|
|
381
490
|
else
|
|
382
|
-
delete
|
|
383
|
-
const
|
|
384
|
-
if (Object.keys(
|
|
385
|
-
|
|
491
|
+
delete defaults.config;
|
|
492
|
+
const fleet = { ...m.fleet, devices: m.fleet.devices };
|
|
493
|
+
if (Object.keys(defaults).length > 0)
|
|
494
|
+
fleet.defaults = defaults;
|
|
386
495
|
else
|
|
387
|
-
delete
|
|
388
|
-
const fleet = { ...m.fleet, devices };
|
|
496
|
+
delete fleet.defaults;
|
|
389
497
|
// Drop the fleet block entirely when the unset emptied a block that holds
|
|
390
498
|
// nothing else — don't leave a vestigial `fleet: {devices: {}}` behind.
|
|
391
|
-
|
|
499
|
+
const devicesEmpty = fleet.devices == null || fleet.devices === 'all'
|
|
500
|
+
? false
|
|
501
|
+
: Object.keys(fleet.devices).length === 0;
|
|
502
|
+
if (devicesEmpty && !fleet.defaults && !fleet.secrets && !fleet.routines) {
|
|
392
503
|
const { fleet: _, ...rest } = m;
|
|
393
504
|
void _;
|
|
394
505
|
return rest;
|
|
@@ -396,26 +507,65 @@ function unsetInCentralBlock(device, spec) {
|
|
|
396
507
|
return { ...m, fleet };
|
|
397
508
|
});
|
|
398
509
|
}
|
|
399
|
-
|
|
510
|
+
function setInDeviceDoc(device, spec, value) {
|
|
511
|
+
// The doc is shared with writeMetaUnlocked (which owns routines:) — the
|
|
512
|
+
// read-modify-write runs under the meta lock so the two writers can't lose
|
|
513
|
+
// each other's update across processes.
|
|
514
|
+
withMetaLock(() => {
|
|
515
|
+
const doc = readDeviceDoc(device) ?? {};
|
|
516
|
+
doc.config = { ...doc.config, [spec.yamlKey]: value };
|
|
517
|
+
writeDeviceDoc(device, doc);
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
function unsetInDeviceDoc(device, spec) {
|
|
521
|
+
withMetaLock(() => {
|
|
522
|
+
const doc = readDeviceDoc(device);
|
|
523
|
+
if (!doc)
|
|
524
|
+
return; // nothing stored — unset is a no-op
|
|
525
|
+
const config = doc.config;
|
|
526
|
+
if (!config || !(spec.yamlKey in config))
|
|
527
|
+
return; // key not present — no write needed
|
|
528
|
+
delete config[spec.yamlKey];
|
|
529
|
+
if (Object.keys(config).length > 0)
|
|
530
|
+
doc.config = config;
|
|
531
|
+
else
|
|
532
|
+
delete doc.config;
|
|
533
|
+
writeDeviceDoc(device, doc);
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Set a config key (validated). Device-scope keys target this machine unless
|
|
538
|
+
* `opts.device` names a peer; `opts.fleet` writes the fleet-wide defaults layer
|
|
539
|
+
* instead. User-scope keys reject `fleet` (they are already fleet-wide).
|
|
540
|
+
*/
|
|
400
541
|
export function setConfigValue(name, value, opts) {
|
|
542
|
+
ensureDeviceConfigMigrated();
|
|
401
543
|
const spec = configKeySpec(name);
|
|
402
544
|
assertValidValue(spec, value);
|
|
403
545
|
if (spec.scope === 'user') {
|
|
546
|
+
if (opts?.fleet) {
|
|
547
|
+
throw new Error(`Config key '${spec.name}' is user-scope (already fleet-wide) — --fleet does not apply.`);
|
|
548
|
+
}
|
|
404
549
|
updateMeta((m) => ({ ...m, config: { ...m.config, [spec.yamlKey]: value } }));
|
|
405
550
|
return;
|
|
406
551
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
if (spec.visibility === 'machine') {
|
|
410
|
-
updateMeta((m) => ({ ...m, deviceConfig: { ...m.deviceConfig, [spec.yamlKey]: value } }));
|
|
552
|
+
if (opts?.fleet) {
|
|
553
|
+
setInFleetDefaults(spec, value);
|
|
411
554
|
return;
|
|
412
555
|
}
|
|
413
|
-
|
|
556
|
+
const device = targetDevice(opts);
|
|
557
|
+
assertLocalTarget(spec, device);
|
|
558
|
+
setInDeviceDoc(device, spec, value);
|
|
414
559
|
}
|
|
415
|
-
/** Unset a config key — restores
|
|
560
|
+
/** Unset a config key — restores the next layer down (fleet default, then the
|
|
561
|
+
* built-in default). No-op when already unset at that layer. */
|
|
416
562
|
export function unsetConfigValue(name, opts) {
|
|
563
|
+
ensureDeviceConfigMigrated();
|
|
417
564
|
const spec = configKeySpec(name);
|
|
418
565
|
if (spec.scope === 'user') {
|
|
566
|
+
if (opts?.fleet) {
|
|
567
|
+
throw new Error(`Config key '${spec.name}' is user-scope (already fleet-wide) — --fleet does not apply.`);
|
|
568
|
+
}
|
|
419
569
|
updateMeta((m) => {
|
|
420
570
|
if (!m.config || !(spec.yamlKey in m.config))
|
|
421
571
|
return m;
|
|
@@ -425,22 +575,69 @@ export function unsetConfigValue(name, opts) {
|
|
|
425
575
|
});
|
|
426
576
|
return;
|
|
427
577
|
}
|
|
578
|
+
if (opts?.fleet) {
|
|
579
|
+
unsetInFleetDefaults(spec);
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
428
582
|
const device = targetDevice(opts);
|
|
429
583
|
assertLocalTarget(spec, device);
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
584
|
+
unsetInDeviceDoc(device, spec);
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* The role marked on one device, or undefined when the operator never marked it.
|
|
588
|
+
*
|
|
589
|
+
* Undefined is meaningful and is NOT the same as `worker`: an unmarked device is
|
|
590
|
+
* eligible for automatic placement only while no device anywhere carries an
|
|
591
|
+
* explicit `worker` mark (see {@link listConfiguredDeviceRoles}).
|
|
592
|
+
*/
|
|
593
|
+
export function configuredDeviceRole(name) {
|
|
594
|
+
assertValidDeviceName(name);
|
|
595
|
+
return getConfigValue('role', { device: name }).value;
|
|
596
|
+
}
|
|
597
|
+
/** Mark a device's role fleet-wide; `undefined` clears the mark. */
|
|
598
|
+
export function setConfiguredDeviceRole(name, role) {
|
|
599
|
+
assertValidDeviceName(name);
|
|
600
|
+
if (role === undefined)
|
|
601
|
+
unsetConfigValue('role', { device: name });
|
|
602
|
+
else
|
|
603
|
+
setConfigValue('role', role, { device: name });
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Every device with an effective role, keyed by device name. Layers like every
|
|
607
|
+
* other device-scope key: the fleet default (central fleet.defaults.config)
|
|
608
|
+
* applies fleet-wide and the per-device doc wins on conflict. `roster` (the
|
|
609
|
+
* registered device names) lets a fleet default reach devices that have no doc
|
|
610
|
+
* of their own; without it only devices with docs are considered — so a
|
|
611
|
+
* fleet-wide `role` default would silently miss a doc-less device and drop it
|
|
612
|
+
* from the worker allowlist. Mirrors {@link loadAutoLaunchPreferences}.
|
|
613
|
+
*/
|
|
614
|
+
export function listConfiguredDeviceRoles(roster) {
|
|
615
|
+
ensureDeviceConfigMigrated();
|
|
616
|
+
const out = {};
|
|
617
|
+
const fleetRole = readFleetConfigDefaults().role;
|
|
618
|
+
const names = new Set(roster ?? []);
|
|
619
|
+
if (!roster) {
|
|
620
|
+
const devicesRoot = path.join(getUserAgentsDir(), 'devices');
|
|
621
|
+
try {
|
|
622
|
+
for (const entry of fs.readdirSync(devicesRoot, { withFileTypes: true })) {
|
|
623
|
+
if (entry.isDirectory())
|
|
624
|
+
names.add(entry.name);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
catch { /* no devices/ tree — roster stays empty */ }
|
|
442
628
|
}
|
|
443
|
-
|
|
629
|
+
for (const name of names) {
|
|
630
|
+
const role = readDeviceDocConfig(name).role ?? fleetRole;
|
|
631
|
+
if (typeof role === 'string' && DEVICE_ROLES.includes(role)) {
|
|
632
|
+
out[name] = role;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
return out;
|
|
636
|
+
}
|
|
637
|
+
/** The configured automatic-placement pool mode. Unset means `workers`. */
|
|
638
|
+
export function autoPoolMode() {
|
|
639
|
+
const value = getConfigValue('auto.pool').value;
|
|
640
|
+
return value === 'all' ? 'all' : 'workers';
|
|
444
641
|
}
|
|
445
642
|
/** True if the device is enabled for auto-launch. Unset defaults to true. */
|
|
446
643
|
export function isAutoLaunchEnabled(name) {
|
|
@@ -448,7 +645,7 @@ export function isAutoLaunchEnabled(name) {
|
|
|
448
645
|
return getConfigValue('auto-launch.enabled', { device: name }).value !== false;
|
|
449
646
|
}
|
|
450
647
|
/** Set whether a device is enabled for auto-launch. Setting the default
|
|
451
|
-
* (enabled) removes the key to keep the
|
|
648
|
+
* (enabled) removes the key to keep the doc minimal. */
|
|
452
649
|
export function setAutoLaunchEnabled(name, enabled) {
|
|
453
650
|
assertValidDeviceName(name);
|
|
454
651
|
if (enabled)
|
|
@@ -462,7 +659,7 @@ export function isAutoLaunchPreferred(name) {
|
|
|
462
659
|
return getConfigValue('auto-launch.preferred', { device: name }).value === true;
|
|
463
660
|
}
|
|
464
661
|
/** Set whether a device is preferred for auto-launch. Setting the default
|
|
465
|
-
* (not preferred) removes the key to keep the
|
|
662
|
+
* (not preferred) removes the key to keep the doc minimal. */
|
|
466
663
|
export function setAutoLaunchPreferred(name, preferred) {
|
|
467
664
|
assertValidDeviceName(name);
|
|
468
665
|
if (preferred)
|
|
@@ -470,22 +667,37 @@ export function setAutoLaunchPreferred(name, preferred) {
|
|
|
470
667
|
else
|
|
471
668
|
unsetConfigValue('auto-launch.preferred', { device: name });
|
|
472
669
|
}
|
|
473
|
-
/**
|
|
474
|
-
*
|
|
475
|
-
|
|
670
|
+
/**
|
|
671
|
+
* Every device's effective auto-launch flags, keyed by device name — the shape
|
|
672
|
+
* the menu-bar snapshot consumes. Layers like every other device-scope key: the
|
|
673
|
+
* fleet default (central fleet.defaults.config) applies fleet-wide and the
|
|
674
|
+
* per-device doc wins on conflict. `roster` (the registered device names) lets
|
|
675
|
+
* a fleet default reach devices that have no doc of their own; without it only
|
|
676
|
+
* devices with docs are listed.
|
|
677
|
+
*/
|
|
678
|
+
export function loadAutoLaunchPreferences(roster) {
|
|
476
679
|
ensureDeviceConfigMigrated();
|
|
477
|
-
const
|
|
680
|
+
const fleet = readFleetConfigDefaults();
|
|
681
|
+
const names = new Set(roster ?? []);
|
|
682
|
+
if (!roster) {
|
|
683
|
+
const devicesRoot = path.join(getUserAgentsDir(), 'devices');
|
|
684
|
+
try {
|
|
685
|
+
for (const entry of fs.readdirSync(devicesRoot, { withFileTypes: true })) {
|
|
686
|
+
if (entry.isDirectory())
|
|
687
|
+
names.add(entry.name);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
catch { /* no devices/ tree — roster stays empty */ }
|
|
691
|
+
}
|
|
478
692
|
const out = {};
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
const
|
|
483
|
-
if (!config)
|
|
484
|
-
continue;
|
|
693
|
+
for (const name of names) {
|
|
694
|
+
const doc = readDeviceDocConfig(name);
|
|
695
|
+
const enabled = (doc.autoLaunchEnabled ?? fleet.autoLaunchEnabled);
|
|
696
|
+
const preferred = (doc.autoLaunchPreferred ?? fleet.autoLaunchPreferred);
|
|
485
697
|
const pref = {};
|
|
486
|
-
if (
|
|
698
|
+
if (enabled === false)
|
|
487
699
|
pref.enabled = false;
|
|
488
|
-
if (
|
|
700
|
+
if (preferred === true)
|
|
489
701
|
pref.preferred = true;
|
|
490
702
|
if (pref.enabled !== undefined || pref.preferred !== undefined)
|
|
491
703
|
out[name] = pref;
|
|
@@ -506,9 +718,20 @@ export function isSchedulerEnabled() {
|
|
|
506
718
|
export function assertSchedulerEnabled() {
|
|
507
719
|
if (isSchedulerEnabled())
|
|
508
720
|
return;
|
|
509
|
-
throw new Error(`The routines scheduler is disabled on this device (scheduler.enabled=false in ~/.agents/
|
|
721
|
+
throw new Error(`The routines scheduler is disabled on this device (scheduler.enabled=false in ~/.agents/devices/${machineId()}/agents.yaml). ` +
|
|
510
722
|
`Re-enable with: agents devices config ${machineId()} scheduler.enabled on`);
|
|
511
723
|
}
|
|
724
|
+
/**
|
|
725
|
+
* True unless this machine's config turns off the managed tmux wrap for
|
|
726
|
+
* interactive `agents run` launches (`tmux.enabled=false`).
|
|
727
|
+
*
|
|
728
|
+
* Read as one of the guards in `shouldWrapInTmux` (lib/exec.ts) — the durable,
|
|
729
|
+
* per-machine form of `--no-tmux` / `AGENTS_NO_TMUX=1`, for a box whose tmux is
|
|
730
|
+
* broken or unwanted. Unset means today's behavior: wrap.
|
|
731
|
+
*/
|
|
732
|
+
export function isTmuxEnabled() {
|
|
733
|
+
return getConfigValue('tmux.enabled').value !== false;
|
|
734
|
+
}
|
|
512
735
|
/** True unless this machine's config disables the daemon outright (top-level kill switch). */
|
|
513
736
|
export function isDaemonEnabled() {
|
|
514
737
|
return getConfigValue('daemon.enabled').value !== false;
|
|
@@ -523,14 +746,25 @@ export function isDaemonEnabled() {
|
|
|
523
746
|
export function assertDaemonEnabled() {
|
|
524
747
|
if (isDaemonEnabled())
|
|
525
748
|
return;
|
|
526
|
-
throw new Error(`The daemon is disabled on this device (daemon.enabled=false in ~/.agents/
|
|
749
|
+
throw new Error(`The daemon is disabled on this device (daemon.enabled=false in ~/.agents/devices/${machineId()}/agents.yaml). ` +
|
|
527
750
|
`Re-enable with: agents daemon enable`);
|
|
528
751
|
}
|
|
529
752
|
/**
|
|
530
|
-
*
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
*
|
|
753
|
+
* Idle window (ms) the browser-task reaper (`browser/hygiene.ts`) uses on THIS
|
|
754
|
+
* machine, or `null` when idle reaping is off (`browser.task-idle-minutes=0`)
|
|
755
|
+
* — session-dead reaping is unaffected either way. Unset means the default 30
|
|
756
|
+
* minutes. Read by the daemon's periodic tick and, as the fallback when a
|
|
757
|
+
* caller omits `--idle-minutes`, by the `gc` IPC action.
|
|
758
|
+
*/
|
|
759
|
+
export function resolveBrowserTaskIdleMs() {
|
|
760
|
+
const minutes = getConfigValue('browser.task-idle-minutes').value ?? 30;
|
|
761
|
+
return minutes === 0 ? null : minutes * 60_000;
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Read the effective `agents.max-concurrent` cap for each named device (fleet
|
|
765
|
+
* defaults layered under the per-device doc; no SSH). Devices without a cap
|
|
766
|
+
* are omitted — uncapped is the default. Used as an input to host ranking
|
|
767
|
+
* (teams placement, AGI EXT auto-launch), never as a remote probe.
|
|
534
768
|
*/
|
|
535
769
|
export function readMaxConcurrentCaps(devices) {
|
|
536
770
|
const caps = {};
|