@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
package/dist/commands/ssh.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* (offline → fail fast instead of a 2-minute hang), platform-aware exec
|
|
8
8
|
* (PowerShell on Windows), and password-from-bundle auth via an askpass shim.
|
|
9
9
|
* Rendering the registry to an ssh_config include also lets plain ssh / scp /
|
|
10
|
-
* rsync / `agents sessions --
|
|
10
|
+
* rsync / `agents sessions --device` resolve the same logical names.
|
|
11
11
|
*/
|
|
12
12
|
import { spawnSync } from 'child_process';
|
|
13
13
|
import * as fs from 'fs';
|
|
@@ -31,6 +31,7 @@ import { defaultPickerChecked, localLoginUser, planDeviceReconciliation, runDevi
|
|
|
31
31
|
import { resolveDeviceTarget, splitUserHost } from '../lib/devices/resolve-target.js';
|
|
32
32
|
import { deriveMirroredCwd } from '../lib/project-root.js';
|
|
33
33
|
import { clearPendingSentinel } from '../lib/devices/pending.js';
|
|
34
|
+
import { getDeviceDiscoveryStatus, setDeviceDiscoveryStatus } from '../lib/devices/discovery-policy.js';
|
|
34
35
|
import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
|
|
35
36
|
import { hostNameFor, renderSshConfig } from '../lib/devices/ssh-config.js';
|
|
36
37
|
import { ASKPASS_BUNDLE_ENV, ASKPASS_KEY_ENV, buildSshInvocation, deviceIdentityArgs, fleetDialTarget, writeAskpassShim, } from '../lib/devices/connect.js';
|
|
@@ -54,14 +55,16 @@ import { ALL_AGENT_IDS } from '../lib/agents.js';
|
|
|
54
55
|
import { collectLocalHarnessInventory, groupByAccount, renderAccountsMatrix, renderHarnessMatrix, } from '../lib/devices/harness-inventory.js';
|
|
55
56
|
import { crabboxList, crabboxFind, crabboxSshArgv } from '../lib/crabbox/cli.js';
|
|
56
57
|
import { boxAddress, boxStatus, fmtIdleShort, fmtExpiresShort, registerLeaseCommand } from './lease.js';
|
|
58
|
+
import { registerSnapshotCommand } from './snapshot.js';
|
|
57
59
|
import { authCellColor, formatCheckedAge, isDeadVerdict, readAuthHealthCache, summarizeHostAuth, summarizeVerdicts, verdictColor, verdictLabel, writeFleetAuthRows, } from '../lib/auth-health.js';
|
|
58
60
|
import { runFleetLogin } from '../lib/fleet/remote-login.js';
|
|
59
|
-
import { getConfigValue, listConfig, setConfigValue, unsetConfigValue, configKeySpec } from '../lib/device-config.js';
|
|
61
|
+
import { getConfigValue, listConfig, setConfigValue, unsetConfigValue, configKeySpec, autoPoolMode, configuredDeviceRole, listConfiguredDeviceRoles, setConfiguredDeviceRole, } from '../lib/device-config.js';
|
|
62
|
+
import { filterAutoPool, listWorkerDevices } from '../lib/devices/pool.js';
|
|
60
63
|
import { registerCommandGroups, setHelpSections } from '../lib/help.js';
|
|
61
64
|
/** One-line summary of a device for `list`. `isSelf` marks the machine this
|
|
62
65
|
* command is running on so it stands out from the rest of the tailnet.
|
|
63
66
|
* `isInteractive` marks the configured interactive host (`devices config <name> interactive.host`). */
|
|
64
|
-
function deviceSummary(d, isSelf = false, stats, isInteractive = false) {
|
|
67
|
+
function deviceSummary(d, isSelf = false, stats, isInteractive = false, roles) {
|
|
65
68
|
d = resolveDeviceProfile(d);
|
|
66
69
|
const addr = hostNameFor(d) ?? chalk.gray('no address');
|
|
67
70
|
// Prefer a fresh live verdict (this run's probe, else the written-back
|
|
@@ -77,7 +80,22 @@ function deviceSummary(d, isSelf = false, stats, isInteractive = false) {
|
|
|
77
80
|
const name = isSelf ? chalk.bold.cyan(d.name.padEnd(16)) : chalk.bold(d.name.padEnd(16));
|
|
78
81
|
const here = isSelf ? chalk.cyan(' ← this machine') : '';
|
|
79
82
|
const interactive = isInteractive ? chalk.yellow(' ★ interactive') : '';
|
|
80
|
-
|
|
83
|
+
// `roles` defaults to a single-device roster so a fleet-wide `role` default
|
|
84
|
+
// still reaches this device even when it has no per-device doc of its own.
|
|
85
|
+
const role = roleTag(d.name, roles ?? listConfiguredDeviceRoles([d.name]));
|
|
86
|
+
return `${marker}${name} ${String(d.platform).padEnd(8)} ${(d.user ? d.user + '@' : '') + addr} ${online}${reach}${here}${interactive}${role}`;
|
|
87
|
+
}
|
|
88
|
+
/** The fleet-wide role mark, rendered for a device row. Empty when unmarked —
|
|
89
|
+
* an unmarked device is the common case and must not add a column of noise. */
|
|
90
|
+
function roleTag(name, roles) {
|
|
91
|
+
const role = roles[name];
|
|
92
|
+
if (!role)
|
|
93
|
+
return '';
|
|
94
|
+
if (role === 'worker')
|
|
95
|
+
return chalk.green(' worker');
|
|
96
|
+
if (role === 'personal')
|
|
97
|
+
return chalk.yellow(' personal');
|
|
98
|
+
return chalk.gray(' control');
|
|
81
99
|
}
|
|
82
100
|
const HEADROOM_BADGE = {
|
|
83
101
|
idle: chalk.green('○ idle'),
|
|
@@ -105,8 +123,11 @@ function pctCell(v, width) {
|
|
|
105
123
|
* capacity summary is appended whenever stats were gathered.
|
|
106
124
|
*/
|
|
107
125
|
function renderDeviceTable(reg, names, self, statsMap, full = false, interactiveHost) {
|
|
108
|
-
if (!statsMap)
|
|
109
|
-
|
|
126
|
+
if (!statsMap) {
|
|
127
|
+
const roles = listConfiguredDeviceRoles(names);
|
|
128
|
+
return names.map((n) => deviceSummary(reg[n], n === self, undefined, n === interactiveHost, roles));
|
|
129
|
+
}
|
|
130
|
+
const deviceRoles = listConfiguredDeviceRoles(names);
|
|
110
131
|
const lines = [];
|
|
111
132
|
const head = ' ' +
|
|
112
133
|
chalk.gray('device'.padEnd(16)) +
|
|
@@ -149,7 +170,7 @@ function renderDeviceTable(reg, names, self, statsMap, full = false, interactive
|
|
|
149
170
|
const badge = HEADROOM_BADGE[headroom(stats)];
|
|
150
171
|
const here = isSelf ? chalk.cyan(' ← this machine') : '';
|
|
151
172
|
const interactive = name === interactiveHost ? chalk.yellow(' ★ interactive') : '';
|
|
152
|
-
lines.push(`${marker}${label}${plat} ${cores}${load}${mem}${freeTotal} ${badge}${relay}${here}${interactive}`);
|
|
173
|
+
lines.push(`${marker}${label}${plat} ${cores}${load}${mem}${freeTotal} ${badge}${relay}${here}${interactive}${roleTag(name, deviceRoles)}`);
|
|
153
174
|
}
|
|
154
175
|
// Fleet capacity summary — total cores + how much RAM is free right now.
|
|
155
176
|
const cap = fleetCapacity(statsMap.values());
|
|
@@ -304,13 +325,16 @@ async function runInteractiveDeviceSync() {
|
|
|
304
325
|
for (const name of plan.toRegister) {
|
|
305
326
|
const input = withDefaultUser(nodeToDeviceInput(byName.get(name)), reg[name]?.user, localUser);
|
|
306
327
|
await upsertDevice(name, input);
|
|
328
|
+
setDeviceDiscoveryStatus(name, 'approved');
|
|
307
329
|
}
|
|
308
330
|
for (const name of plan.toUnignore)
|
|
309
331
|
await removeIgnored(name);
|
|
310
332
|
for (const name of plan.toRemove)
|
|
311
333
|
await removeDevice(name);
|
|
312
|
-
for (const name of plan.toIgnore)
|
|
334
|
+
for (const name of plan.toIgnore) {
|
|
313
335
|
await addIgnored(name);
|
|
336
|
+
setDeviceDiscoveryStatus(name, 'ignored');
|
|
337
|
+
}
|
|
314
338
|
const parts = [
|
|
315
339
|
chalk.green(`${plan.toRegister.length} registered`),
|
|
316
340
|
plan.toRemove.length ? chalk.yellow(`${plan.toRemove.length} removed`) : null,
|
|
@@ -420,11 +444,14 @@ async function probeRemoteHealth(target) {
|
|
|
420
444
|
inventory: parsed.fleet,
|
|
421
445
|
};
|
|
422
446
|
}
|
|
423
|
-
/**
|
|
447
|
+
/** Device-layer config only (not fleet defaults), keyed by the canonical YAML key. */
|
|
424
448
|
function deviceConfigJson(name) {
|
|
425
449
|
const config = {};
|
|
426
450
|
for (const entry of listConfig({ device: name })) {
|
|
427
|
-
|
|
451
|
+
// The device's OWN layer only — a fleet-default value is not this
|
|
452
|
+
// device's setting (the effective profile fields already carry the
|
|
453
|
+
// merged view via resolveDeviceProfile).
|
|
454
|
+
if (entry.source !== 'device')
|
|
428
455
|
continue;
|
|
429
456
|
config[entry.spec.yamlKey] = entry.value;
|
|
430
457
|
}
|
|
@@ -967,9 +994,10 @@ function registerDevicesCommands(program) {
|
|
|
967
994
|
notes: '`agents fleet` is an alias for `agents devices` — same subcommands.',
|
|
968
995
|
});
|
|
969
996
|
registerLeaseCommand(devicesCmd);
|
|
997
|
+
registerSnapshotCommand(devicesCmd);
|
|
970
998
|
registerCommandGroups(devicesCmd, [
|
|
971
999
|
{ title: 'Discover & register', names: ['sync', 'register', 'add', 'ignore', 'unignore', 'rm'] },
|
|
972
|
-
{ title: 'Inspect', names: ['list', 'show', 'status', 'ping', 'harnesses', 'accounts'] },
|
|
1000
|
+
{ title: 'Inspect', names: ['list', 'show', 'status', 'ping', 'harnesses', 'accounts', 'snapshot'] },
|
|
973
1001
|
{ title: 'Disposable devices', names: ['lease'] },
|
|
974
1002
|
{ title: 'Configure a device', names: ['config', 'render'] },
|
|
975
1003
|
{ title: 'Fleet operations', names: ['update', 'run', 'login', 'pair-ios', 'capture', 'apply'] },
|
|
@@ -986,6 +1014,8 @@ function registerDevicesCommands(program) {
|
|
|
986
1014
|
const spinner = ora('Reading tailscale status...').start();
|
|
987
1015
|
try {
|
|
988
1016
|
const res = await runDeviceSync();
|
|
1017
|
+
for (const name of res.syncedNames)
|
|
1018
|
+
setDeviceDiscoveryStatus(name, 'approved');
|
|
989
1019
|
const extra = res.pending.length ? chalk.gray(` (${res.pending.length} new)`) : '';
|
|
990
1020
|
spinner.succeed(`Synced ${res.synced} device${res.synced === 1 ? '' : 's'} from Tailscale${extra}`);
|
|
991
1021
|
}
|
|
@@ -1001,7 +1031,7 @@ function registerDevicesCommands(program) {
|
|
|
1001
1031
|
registerFleetApplyAlias(devicesCmd);
|
|
1002
1032
|
devicesCmd
|
|
1003
1033
|
.command('register <name>')
|
|
1004
|
-
.description('Register a discovered
|
|
1034
|
+
.description('Register a discovered node and sync the approval through agents.yaml fleet.discovery.')
|
|
1005
1035
|
.action(async (name) => {
|
|
1006
1036
|
try {
|
|
1007
1037
|
const nodes = parseTailscaleStatus(tailscaleStatusJson());
|
|
@@ -1012,6 +1042,7 @@ function registerDevicesCommands(program) {
|
|
|
1012
1042
|
}
|
|
1013
1043
|
await removeIgnored(name); // a re-registered node is no longer dismissed
|
|
1014
1044
|
const d = await upsertDevice(name, nodeToDeviceInput(node));
|
|
1045
|
+
setDeviceDiscoveryStatus(name, 'approved');
|
|
1015
1046
|
clearPendingSentinel(name); // drop the notification immediately
|
|
1016
1047
|
console.log(chalk.green(`Registered '${name}'`) + chalk.gray(` (${d.platform})`));
|
|
1017
1048
|
}
|
|
@@ -1022,11 +1053,12 @@ function registerDevicesCommands(program) {
|
|
|
1022
1053
|
});
|
|
1023
1054
|
devicesCmd
|
|
1024
1055
|
.command('ignore <name>')
|
|
1025
|
-
.description('Dismiss a node
|
|
1056
|
+
.description('Dismiss a node and sync the decision through agents.yaml fleet.discovery (also removes it locally).')
|
|
1026
1057
|
.action(async (name) => {
|
|
1027
1058
|
try {
|
|
1028
1059
|
await removeDevice(name);
|
|
1029
1060
|
await addIgnored(name);
|
|
1061
|
+
setDeviceDiscoveryStatus(name, 'ignored');
|
|
1030
1062
|
clearPendingSentinel(name); // drop the notification immediately
|
|
1031
1063
|
console.log(chalk.green(`Ignored '${name}'`) + chalk.gray(" — it won't be suggested again. Undo with `agents devices unignore`."));
|
|
1032
1064
|
}
|
|
@@ -1039,11 +1071,13 @@ function registerDevicesCommands(program) {
|
|
|
1039
1071
|
.command('unignore <name>')
|
|
1040
1072
|
.description('Undo `ignore`: allow a node to be discovered and registered again.')
|
|
1041
1073
|
.action(async (name) => {
|
|
1074
|
+
const portableWasIgnored = getDeviceDiscoveryStatus(name) === 'ignored';
|
|
1042
1075
|
const ok = await removeIgnored(name);
|
|
1043
|
-
if (!ok) {
|
|
1076
|
+
if (!ok && !portableWasIgnored) {
|
|
1044
1077
|
console.error(chalk.gray(`'${name}' was not ignored.`));
|
|
1045
1078
|
return;
|
|
1046
1079
|
}
|
|
1080
|
+
setDeviceDiscoveryStatus(name, undefined);
|
|
1047
1081
|
console.log(chalk.green(`No longer ignoring '${name}'`) + chalk.gray(' — run `agents devices sync` to register it.'));
|
|
1048
1082
|
});
|
|
1049
1083
|
// ─── devices config (unified settings surface) ────────────────────────────
|
|
@@ -1079,18 +1113,39 @@ function registerDevicesCommands(program) {
|
|
|
1079
1113
|
};
|
|
1080
1114
|
/** The device-scope config entries for `name` (what the config surface edits). */
|
|
1081
1115
|
const deviceConfigEntries = (name) => listConfig({ device: name }).filter((e) => e.spec.scope === 'device');
|
|
1116
|
+
/** Render one entry's effective value with its layer tag. */
|
|
1117
|
+
const entryValueText = (e) => {
|
|
1118
|
+
if (e.source === 'default')
|
|
1119
|
+
return chalk.gray('— (default)');
|
|
1120
|
+
const tag = e.source === 'fleet' ? chalk.yellow(' (fleet default)') : e.source === 'user' ? chalk.gray(' (user scope)') : '';
|
|
1121
|
+
return chalk.cyan(JSON.stringify(e.value)) + tag;
|
|
1122
|
+
};
|
|
1082
1123
|
/** Print the full resolved config for a device (bare invocation, non-menu). */
|
|
1083
1124
|
const printDevicesConfig = (name, json) => {
|
|
1084
1125
|
const entries = deviceConfigEntries(name);
|
|
1085
1126
|
if (json) {
|
|
1086
1127
|
const config = {};
|
|
1087
1128
|
for (const e of entries)
|
|
1088
|
-
|
|
1089
|
-
config[e.spec.name] = e.value;
|
|
1129
|
+
config[e.spec.name] = { value: e.value ?? null, source: e.source };
|
|
1090
1130
|
writeJson({ device: name, config });
|
|
1091
1131
|
return;
|
|
1092
1132
|
}
|
|
1093
1133
|
console.log(chalk.bold(`Config for '${name}'`));
|
|
1134
|
+
for (const e of entries) {
|
|
1135
|
+
console.log(` ${e.spec.name.padEnd(24)} ${entryValueText(e)}${chalk.gray(` ${e.spec.description}`)}`);
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
/** Print the fleet-wide defaults layer (`config --fleet`, bare). */
|
|
1139
|
+
const printFleetConfig = (json) => {
|
|
1140
|
+
const entries = listConfig({ fleet: true }).filter((e) => e.spec.scope === 'device');
|
|
1141
|
+
if (json) {
|
|
1142
|
+
const config = {};
|
|
1143
|
+
for (const e of entries)
|
|
1144
|
+
config[e.spec.name] = { value: e.value ?? null, source: e.source };
|
|
1145
|
+
writeJson({ fleet: true, config });
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
console.log(chalk.bold('Fleet-wide config defaults') + chalk.gray(' (every device inherits these unless it overrides the key)'));
|
|
1094
1149
|
for (const e of entries) {
|
|
1095
1150
|
const value = e.value === undefined ? chalk.gray('— (default)') : chalk.cyan(JSON.stringify(e.value));
|
|
1096
1151
|
console.log(` ${e.spec.name.padEnd(24)} ${value}${chalk.gray(` ${e.spec.description}`)}`);
|
|
@@ -1099,11 +1154,60 @@ function registerDevicesCommands(program) {
|
|
|
1099
1154
|
/**
|
|
1100
1155
|
* The `devices config` engine — shared by the config command's action and
|
|
1101
1156
|
* every tombstone. `quiet` performs the write with no output (a tombstone
|
|
1102
|
-
* that prints its own legacy shape).
|
|
1103
|
-
*
|
|
1157
|
+
* that prints its own legacy shape). `fleet` targets the fleet-wide defaults
|
|
1158
|
+
* layer instead of a device (`name` is then unused). Throws on a bad
|
|
1159
|
+
* key/value; callers map that to exit 1.
|
|
1104
1160
|
*/
|
|
1105
1161
|
const runDevicesConfig = async (name, key, valueParts, opts) => {
|
|
1106
1162
|
const spec = key ? configKeySpec(key) : undefined; // unknown key → throw listing the valid keys
|
|
1163
|
+
// ── Fleet-defaults layer (`--fleet`): no device involved.
|
|
1164
|
+
if (opts.fleet) {
|
|
1165
|
+
if (spec && spec.scope === 'user') {
|
|
1166
|
+
throw new Error(`Config key '${spec.name}' is user-scope (already fleet-wide) — --fleet does not apply.`);
|
|
1167
|
+
}
|
|
1168
|
+
if (opts.unset) {
|
|
1169
|
+
if (!spec)
|
|
1170
|
+
throw new Error('--unset needs a key: agents devices config --fleet <key> --unset');
|
|
1171
|
+
unsetConfigValue(spec.name, { fleet: true });
|
|
1172
|
+
if (opts.quiet)
|
|
1173
|
+
return;
|
|
1174
|
+
if (opts.json)
|
|
1175
|
+
writeJson({ fleet: true, key: spec.name, value: null, source: 'default' });
|
|
1176
|
+
else
|
|
1177
|
+
console.log(chalk.green(`Unset ${spec.name}`) + chalk.gray(' in the fleet defaults.'));
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
if (spec && valueParts.length > 0) {
|
|
1181
|
+
let value;
|
|
1182
|
+
if (spec.type === 'string-list') {
|
|
1183
|
+
const existing = getConfigValue(spec.name, { fleet: true }).value ?? [];
|
|
1184
|
+
value = [...existing, valueParts.join(' ')];
|
|
1185
|
+
}
|
|
1186
|
+
else {
|
|
1187
|
+
value = parseConfigValueInput(spec, valueParts.join(' '));
|
|
1188
|
+
}
|
|
1189
|
+
setConfigValue(spec.name, value, { fleet: true });
|
|
1190
|
+
if (opts.quiet)
|
|
1191
|
+
return;
|
|
1192
|
+
if (opts.json)
|
|
1193
|
+
writeJson({ fleet: true, key: spec.name, value, source: 'fleet' });
|
|
1194
|
+
else
|
|
1195
|
+
console.log(chalk.green(`Set ${spec.name} = ${JSON.stringify(value)}`) + chalk.gray(' as the fleet-wide default.'));
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
if (spec) {
|
|
1199
|
+
const entry = getConfigValue(spec.name, { fleet: true });
|
|
1200
|
+
if (opts.quiet)
|
|
1201
|
+
return;
|
|
1202
|
+
if (opts.json)
|
|
1203
|
+
writeJson({ fleet: true, key: spec.name, value: entry.value ?? null, source: entry.source });
|
|
1204
|
+
else
|
|
1205
|
+
console.log(` ${spec.name.padEnd(24)} ${entryValueText(entry)}${chalk.gray(` ${spec.description}`)}`);
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
printFleetConfig(Boolean(opts.json));
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1107
1211
|
// User-scope keys (interactive.host) are stored centrally — the device name
|
|
1108
1212
|
// is syntax only, so an unregistered name is not an error for them.
|
|
1109
1213
|
if (!spec || spec.scope === 'device')
|
|
@@ -1115,9 +1219,9 @@ function registerDevicesCommands(program) {
|
|
|
1115
1219
|
if (opts.quiet)
|
|
1116
1220
|
return;
|
|
1117
1221
|
if (opts.json)
|
|
1118
|
-
writeJson({ device: name, key: spec.name, value: null });
|
|
1222
|
+
writeJson({ device: name, key: spec.name, value: null, source: 'default' });
|
|
1119
1223
|
else
|
|
1120
|
-
console.log(chalk.green(`Unset ${spec.name}`) + chalk.gray(` on '${name}' — back to the default.`));
|
|
1224
|
+
console.log(chalk.green(`Unset ${spec.name}`) + chalk.gray(` on '${name}' — falls back to the fleet default / built-in behavior.`));
|
|
1121
1225
|
return;
|
|
1122
1226
|
}
|
|
1123
1227
|
if (spec && valueParts.length > 0) {
|
|
@@ -1134,7 +1238,7 @@ function registerDevicesCommands(program) {
|
|
|
1134
1238
|
if (opts.quiet)
|
|
1135
1239
|
return;
|
|
1136
1240
|
if (opts.json)
|
|
1137
|
-
writeJson({ device: name, key: spec.name, value });
|
|
1241
|
+
writeJson({ device: name, key: spec.name, value, source: 'device' });
|
|
1138
1242
|
else
|
|
1139
1243
|
console.log(chalk.green(`Set ${spec.name} = ${JSON.stringify(value)}`) + chalk.gray(` on '${name}'.`));
|
|
1140
1244
|
return;
|
|
@@ -1144,13 +1248,10 @@ function registerDevicesCommands(program) {
|
|
|
1144
1248
|
if (opts.quiet)
|
|
1145
1249
|
return;
|
|
1146
1250
|
if (opts.json) {
|
|
1147
|
-
writeJson({ device: name, key: spec.name, value: entry.value ?? null });
|
|
1148
|
-
}
|
|
1149
|
-
else if (entry.value === undefined) {
|
|
1150
|
-
console.log(` ${spec.name.padEnd(24)} ${chalk.gray('— (default)')}${chalk.gray(` ${spec.description}`)}`);
|
|
1251
|
+
writeJson({ device: name, key: spec.name, value: entry.value ?? null, source: entry.source });
|
|
1151
1252
|
}
|
|
1152
1253
|
else {
|
|
1153
|
-
console.log(` ${spec.name.padEnd(24)} ${
|
|
1254
|
+
console.log(` ${spec.name.padEnd(24)} ${entryValueText(entry)}${chalk.gray(` ${spec.description}`)}`);
|
|
1154
1255
|
}
|
|
1155
1256
|
return;
|
|
1156
1257
|
}
|
|
@@ -1161,7 +1262,96 @@ function registerDevicesCommands(program) {
|
|
|
1161
1262
|
}
|
|
1162
1263
|
await runDevicesConfigMenu(name);
|
|
1163
1264
|
};
|
|
1164
|
-
/**
|
|
1265
|
+
/**
|
|
1266
|
+
* The `devices role` engine — read or write the fleet-wide role mark, and say
|
|
1267
|
+
* what it does to automatic placement.
|
|
1268
|
+
*
|
|
1269
|
+
* A role written here lands in that device's tracked per-device doc
|
|
1270
|
+
* (`devices/<name>/agents.yaml` `config.role`) and syncs with repo
|
|
1271
|
+
* push/pull. The vocabulary is deliberately `worker | personal` only: a
|
|
1272
|
+
* paired cockpit's `control` role lives in the per-machine device registry,
|
|
1273
|
+
* is written by `agents devices pair-ios`, and is what the existing
|
|
1274
|
+
* dial-exclusion filters (`isControlDevice`) read. Accepting `control` here
|
|
1275
|
+
* too would promise a fleet-wide dial exclusion this key cannot deliver —
|
|
1276
|
+
* those filters read each box's own registry, so the mark would only hold
|
|
1277
|
+
* on the machine that ran the command.
|
|
1278
|
+
*/
|
|
1279
|
+
const runDevicesRole = async (name, role, opts) => {
|
|
1280
|
+
if (!name) {
|
|
1281
|
+
if (role)
|
|
1282
|
+
throw new Error('Name a device: agents devices role <name> <worker|personal>');
|
|
1283
|
+
const reg = await loadDevices();
|
|
1284
|
+
// The full registered roster, not just online — a fleet-wide `role`
|
|
1285
|
+
// default must reach a registered device even when it has no per-device
|
|
1286
|
+
// doc of its own, or it silently falls out of the worker allowlist.
|
|
1287
|
+
const roles = listConfiguredDeviceRoles(Object.keys(reg));
|
|
1288
|
+
const mode = autoPoolMode();
|
|
1289
|
+
const online = Object.entries(reg)
|
|
1290
|
+
.filter(([, d]) => d?.tailscale?.online !== false)
|
|
1291
|
+
.map(([n]) => n);
|
|
1292
|
+
const pool = filterAutoPool(online, { mode, roles });
|
|
1293
|
+
if (opts.json) {
|
|
1294
|
+
writeJson({ mode, roles, autoPool: pool });
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
const marked = Object.entries(roles);
|
|
1298
|
+
if (marked.length === 0) {
|
|
1299
|
+
console.log(chalk.gray('No device is marked. `--device auto` considers every online device.'));
|
|
1300
|
+
}
|
|
1301
|
+
else {
|
|
1302
|
+
for (const [device, r] of marked) {
|
|
1303
|
+
const tint = r === 'worker' ? chalk.green : r === 'personal' ? chalk.yellow : chalk.gray;
|
|
1304
|
+
console.log(` ${device.padEnd(20)} ${tint(r)}`);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
console.log();
|
|
1308
|
+
console.log(chalk.bold('--device auto picks from: ') + (pool.length > 0 ? pool.join(', ') : chalk.red('nothing — no eligible device')));
|
|
1309
|
+
if (mode === 'all')
|
|
1310
|
+
console.log(chalk.gray('auto.pool=all — worker marks are ignored (a personal device is still excluded).'));
|
|
1311
|
+
return;
|
|
1312
|
+
}
|
|
1313
|
+
await mustGetDevice(name);
|
|
1314
|
+
if (opts.clear || role === 'none') {
|
|
1315
|
+
setConfiguredDeviceRole(name, undefined);
|
|
1316
|
+
if (opts.json)
|
|
1317
|
+
writeJson({ device: name, role: null });
|
|
1318
|
+
else
|
|
1319
|
+
console.log(chalk.green(`Cleared the role on '${name}'.`));
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
if (!role) {
|
|
1323
|
+
const current = configuredDeviceRole(name);
|
|
1324
|
+
if (opts.json)
|
|
1325
|
+
writeJson({ device: name, role: current ?? null });
|
|
1326
|
+
else
|
|
1327
|
+
console.log(` ${name.padEnd(20)} ${current ? chalk.cyan(current) : chalk.gray('— (unmarked)')}`);
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
// configuredDeviceRole's key spec validates the value; a bad one throws with
|
|
1331
|
+
// the accepted list, which the command's catch turns into exit 1.
|
|
1332
|
+
setConfiguredDeviceRole(name, role);
|
|
1333
|
+
// Full registered roster, mirroring the bare-listing branch above — a
|
|
1334
|
+
// fleet-wide `role` default must reach a doc-less registered device here
|
|
1335
|
+
// too, or `autoPoolWorkers` under-reports the allowlist right after this
|
|
1336
|
+
// write changed it.
|
|
1337
|
+
const roles = listConfiguredDeviceRoles(Object.keys(await loadDevices()));
|
|
1338
|
+
if (opts.json) {
|
|
1339
|
+
writeJson({ device: name, role, autoPoolWorkers: listWorkerDevices({ roles }) });
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
console.log(chalk.green(`Marked '${name}' role=${role}.`));
|
|
1343
|
+
const workers = listWorkerDevices({ roles });
|
|
1344
|
+
if (workers.length > 0) {
|
|
1345
|
+
console.log(chalk.gray(`\`--device auto\` now picks only from: ${workers.join(', ')}`));
|
|
1346
|
+
}
|
|
1347
|
+
else {
|
|
1348
|
+
console.log(chalk.gray('No device is marked worker, so `--device auto` still considers every online device.'));
|
|
1349
|
+
}
|
|
1350
|
+
console.log(chalk.gray('Sync it to the fleet with `agents repo push`.'));
|
|
1351
|
+
};
|
|
1352
|
+
/** The interactive settings menu: pick a key, edit it, repeat. TTY-only.
|
|
1353
|
+
* Shows EFFECTIVE values (with a fleet tag when inherited); edits always
|
|
1354
|
+
* write the device layer. */
|
|
1165
1355
|
const runDevicesConfigMenu = async (name) => {
|
|
1166
1356
|
const { select, input, confirm } = await import('@inquirer/prompts');
|
|
1167
1357
|
const DONE = '__done__';
|
|
@@ -1169,12 +1359,12 @@ function registerDevicesCommands(program) {
|
|
|
1169
1359
|
for (;;) {
|
|
1170
1360
|
const entries = deviceConfigEntries(name);
|
|
1171
1361
|
const picked = await select({
|
|
1172
|
-
message: `Config for '${name}' — pick a key to edit:`,
|
|
1362
|
+
message: `Config for '${name}' — pick a key to edit (writes the device layer):`,
|
|
1173
1363
|
pageSize: Math.min(entries.length + 1, 20),
|
|
1174
1364
|
choices: [
|
|
1175
1365
|
...entries.map((e) => {
|
|
1176
|
-
const value = e.
|
|
1177
|
-
?
|
|
1366
|
+
const value = e.source !== 'default'
|
|
1367
|
+
? entryValueText(e)
|
|
1178
1368
|
: chalk.gray(e.spec.defaultValue !== undefined
|
|
1179
1369
|
? `default: ${JSON.stringify(e.spec.defaultValue)}`
|
|
1180
1370
|
: 'unset (default)');
|
|
@@ -1224,14 +1414,25 @@ function registerDevicesCommands(program) {
|
|
|
1224
1414
|
}
|
|
1225
1415
|
};
|
|
1226
1416
|
const configCmd = devicesCmd
|
|
1227
|
-
.command('config
|
|
1417
|
+
.command('config [name] [key] [value...]')
|
|
1228
1418
|
.description('Get, set, or unset a device’s settings (scheduler, agent cap, ssh overrides, auto-launch, notes). ' +
|
|
1229
1419
|
'Bare opens an interactive settings menu (TTY) or prints the resolved config (piped). ' +
|
|
1230
|
-
'
|
|
1231
|
-
|
|
1232
|
-
.option('--
|
|
1420
|
+
'Per-device values live in the tracked devices/<name>/agents.yaml config: block; --fleet targets the ' +
|
|
1421
|
+
'fleet-wide defaults (central fleet.defaults.config) every device inherits unless it overrides the key.')
|
|
1422
|
+
.option('--fleet', 'target the fleet-wide defaults layer instead of a device (first positional is the key)')
|
|
1423
|
+
.option('--unset', 'reset the key at that layer (a device key then inherits the fleet default)')
|
|
1424
|
+
.option('--json', 'output machine-readable JSON (each key carries its source: device | fleet | default)')
|
|
1233
1425
|
.action(async (name, key, valueParts, opts) => {
|
|
1234
1426
|
try {
|
|
1427
|
+
if (opts.fleet) {
|
|
1428
|
+
// Positionals shift left: the first one is the key, the rest the value.
|
|
1429
|
+
const fleetValue = [key, ...(valueParts ?? [])].filter((v) => v !== undefined);
|
|
1430
|
+
await runDevicesConfig(undefined, name, fleetValue, opts);
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
if (!name) {
|
|
1434
|
+
throw new Error('Missing device name. Usage: agents devices config <name> [key] [value] — or --fleet <key> <value> for the fleet-wide defaults.');
|
|
1435
|
+
}
|
|
1235
1436
|
await runDevicesConfig(name, key, valueParts ?? [], opts);
|
|
1236
1437
|
}
|
|
1237
1438
|
catch (err) {
|
|
@@ -1242,38 +1443,97 @@ function registerDevicesCommands(program) {
|
|
|
1242
1443
|
setHelpSections(configCmd, {
|
|
1243
1444
|
examples: `
|
|
1244
1445
|
agents devices config mac-mini # settings menu (TTY) / print config (piped)
|
|
1245
|
-
agents devices config mac-mini agents.max-concurrent 4 # cap concurrent agents
|
|
1446
|
+
agents devices config mac-mini agents.max-concurrent 4 # cap concurrent agents on mac-mini
|
|
1246
1447
|
agents devices config mac-mini scheduler.enabled off # no routines firing there
|
|
1247
|
-
agents devices config mac-mini scheduler.enabled # read
|
|
1248
|
-
agents devices config mac-mini scheduler.enabled --unset #
|
|
1448
|
+
agents devices config mac-mini scheduler.enabled # read the effective value back
|
|
1449
|
+
agents devices config mac-mini scheduler.enabled --unset # inherit the fleet default again
|
|
1450
|
+
agents devices config --fleet scheduler.enabled off # fleet-wide default (all devices)
|
|
1451
|
+
agents devices config --fleet agents.max-concurrent 2 # every box caps at 2 unless it overrides
|
|
1452
|
+
agents devices config --fleet # print the fleet defaults layer
|
|
1249
1453
|
agents devices config mac-mini notes "runs the releases" # append an operator note
|
|
1250
1454
|
agents devices config win-mini ssh.auth password # password auth…
|
|
1251
1455
|
agents devices config win-mini ssh.bundle muqsit # …from this secrets bundle
|
|
1252
1456
|
agents devices config worker ssh.identity-file ~/.ssh/worker_ed25519
|
|
1457
|
+
agents devices config mac-mini role worker # same as \`agents devices role mac-mini worker\`
|
|
1253
1458
|
agents devices config mac-mini auto-launch.enabled off # exclude from AGI EXT auto-launch
|
|
1254
1459
|
agents devices config mac-mini auto-launch.preferred on # boost in auto-launch ranking
|
|
1255
1460
|
agents devices config zion interactive.host zion # user scope: where agents show YOU artifacts
|
|
1256
|
-
agents devices config mac-mini --json # machine-readable
|
|
1461
|
+
agents devices config mac-mini --json # machine-readable, per-key source
|
|
1257
1462
|
`,
|
|
1258
1463
|
notes: `
|
|
1259
|
-
Keys:
|
|
1260
|
-
|
|
1261
|
-
|
|
1464
|
+
Keys: role (worker|personal), see 'agents devices role',
|
|
1465
|
+
agents.max-concurrent, scheduler.enabled, daemon.enabled,
|
|
1466
|
+
watchdog.enabled, tmux.enabled, browser.remote-control,
|
|
1467
|
+
browser.task-idle-minutes, browser.profile,
|
|
1468
|
+
notes, ssh.user, ssh.auth (key|password), ssh.bundle, ssh.bundle-key,
|
|
1262
1469
|
ssh.identity-file, platform (windows|linux|macos|unknown),
|
|
1263
1470
|
auto-launch.enabled, auto-launch.preferred — plus the user-scope
|
|
1264
1471
|
interactive.host (stored centrally; the device name is syntax only).
|
|
1265
1472
|
|
|
1473
|
+
Three layers, read in order — built-in default < fleet default
|
|
1474
|
+
(--fleet, central fleet.defaults.config) < per-device value
|
|
1475
|
+
(devices/<name>/agents.yaml config:). Both files are tracked and sync
|
|
1476
|
+
with 'agents repo push/pull'; per-device files are conflict-free because
|
|
1477
|
+
each machine writes only its own folder. --unset removes the value at
|
|
1478
|
+
the targeted layer, so a device key falls back to the fleet default.
|
|
1479
|
+
|
|
1266
1480
|
Booleans take on/off (or true/false). 'notes' appends one entry per
|
|
1267
|
-
invocation.
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1481
|
+
invocation. ssh.* / platform / user overlay the discovered registry
|
|
1482
|
+
profile at dial time. scheduler.enabled / daemon.enabled take effect
|
|
1483
|
+
when the daemon reloads or restarts on that device. Machine-local keys
|
|
1484
|
+
(scheduler.enabled, daemon.enabled, tmux.enabled, browser.remote-control,
|
|
1485
|
+
browser.task-idle-minutes, browser.profile) can only be read or set on
|
|
1486
|
+
the device itself; --fleet still writes a fleet-wide default those boxes
|
|
1487
|
+
inherit until they override.
|
|
1272
1488
|
|
|
1273
1489
|
The retired subcommands still work and forward here: configure, note,
|
|
1274
1490
|
set, set-interactive, enable, disable, prefer, unprefer.
|
|
1275
1491
|
`,
|
|
1276
1492
|
});
|
|
1493
|
+
const roleCmd = devicesCmd
|
|
1494
|
+
.command('role [name] [role]')
|
|
1495
|
+
.description('Show or set what a device is for: worker (agents run here) or personal (you sit here — never picked automatically). ' +
|
|
1496
|
+
'Marking any device worker makes `--device auto` an allowlist over the marked workers.')
|
|
1497
|
+
.option('--clear', 'remove the mark, returning the device to unmarked')
|
|
1498
|
+
.option('--json', 'output machine-readable JSON')
|
|
1499
|
+
.action(async (name, role, opts) => {
|
|
1500
|
+
try {
|
|
1501
|
+
await runDevicesRole(name, role, opts);
|
|
1502
|
+
}
|
|
1503
|
+
catch (err) {
|
|
1504
|
+
console.error(chalk.red(err.message));
|
|
1505
|
+
process.exit(1);
|
|
1506
|
+
}
|
|
1507
|
+
});
|
|
1508
|
+
setHelpSections(roleCmd, {
|
|
1509
|
+
examples: `
|
|
1510
|
+
agents devices role # who is marked what, and what --device auto would pick
|
|
1511
|
+
agents devices role yosemite-s0 worker # agents spin up here
|
|
1512
|
+
agents devices role yosemite-s1 worker # …and here; auto now rotates over these two only
|
|
1513
|
+
agents devices role zion personal # your laptop — keep automatic placement off it
|
|
1514
|
+
agents devices role yosemite-s0 --clear # unmark
|
|
1515
|
+
agents devices role --json # machine-readable
|
|
1516
|
+
`,
|
|
1517
|
+
notes: `
|
|
1518
|
+
Roles live in that device's tracked per-device doc
|
|
1519
|
+
(devices/<name>/agents.yaml config.role) and travel with
|
|
1520
|
+
'agents repo push/pull', so a mark set on one box is the whole fleet's
|
|
1521
|
+
answer.
|
|
1522
|
+
|
|
1523
|
+
Effect on '--device auto' (agents run, teams, agents ssh auto, and the AGI
|
|
1524
|
+
EXT launch commands, which all resolve placement through the CLI):
|
|
1525
|
+
no device marked -> every online device, as before
|
|
1526
|
+
any worker marked -> ONLY the marked workers
|
|
1527
|
+
personal -> never picked, under either state
|
|
1528
|
+
|
|
1529
|
+
Turn the allowlist off with 'agents config set auto.pool all'; a personal
|
|
1530
|
+
box stays excluded, since that is what the mark is for.
|
|
1531
|
+
|
|
1532
|
+
A paired iPhone/iPad cockpit is a separate role: 'agents devices pair-ios'
|
|
1533
|
+
marks it control in that box's device registry, and the fleet never dials
|
|
1534
|
+
it — including for placement. This command does not set that role.
|
|
1535
|
+
`,
|
|
1536
|
+
});
|
|
1277
1537
|
/** Deprecation notice for a retired subcommand — STDERR only, so a --json consumer's stdout stays parseable. */
|
|
1278
1538
|
const configTombstoneNotice = (retired, replacement) => {
|
|
1279
1539
|
console.error(chalk.yellow(`Deprecated: "agents devices ${retired}" is now "agents devices ${replacement}". Running that for you.\n`));
|
|
@@ -1493,12 +1753,19 @@ function registerDevicesCommands(program) {
|
|
|
1493
1753
|
await writeReachability(collectReachabilityWriteBacks(reg, statsMap)).catch(() => { });
|
|
1494
1754
|
}
|
|
1495
1755
|
if (opts.json) {
|
|
1756
|
+
const jsonRoles = listConfiguredDeviceRoles(names);
|
|
1757
|
+
const autoPool = new Set(filterAutoPool(names, { roles: jsonRoles }));
|
|
1496
1758
|
process.stdout.write(JSON.stringify(names.map((name) => {
|
|
1497
1759
|
const config = deviceConfigJson(name);
|
|
1498
1760
|
const health = statsMap?.get(name);
|
|
1499
1761
|
return {
|
|
1500
1762
|
...resolveDeviceProfile(reg[name]),
|
|
1501
1763
|
interactive: name === interactiveHost,
|
|
1764
|
+
// Roles as machine-readable fields: `role` is what the operator
|
|
1765
|
+
// marked (absent when unmarked), `autoPool` is the answer that
|
|
1766
|
+
// matters to a caller — may `--device auto` pick this box.
|
|
1767
|
+
...(jsonRoles[name] ? { role: jsonRoles[name] } : {}),
|
|
1768
|
+
autoPool: autoPool.has(name),
|
|
1502
1769
|
...(config ? { config } : {}),
|
|
1503
1770
|
...(health ? { health: { ...health, headroom: headroom(health) } } : {}),
|
|
1504
1771
|
};
|
|
@@ -1669,6 +1936,7 @@ email) into a single row. Use \`agents devices harnesses\` for the per-install v
|
|
|
1669
1936
|
user,
|
|
1670
1937
|
address: { via: 'manual', dnsName: isIp ? undefined : host, ip: isIp ? host : undefined },
|
|
1671
1938
|
});
|
|
1939
|
+
setDeviceDiscoveryStatus(name, 'approved');
|
|
1672
1940
|
console.log(chalk.green(`Added device '${name}'`) + chalk.gray(` (${d.platform}, ${user ? user + '@' : ''}${host})`));
|
|
1673
1941
|
}
|
|
1674
1942
|
catch (err) {
|
|
@@ -1740,6 +2008,7 @@ email) into a single row. Use \`agents devices harnesses\` for the per-install v
|
|
|
1740
2008
|
const existing = await getDevice(name);
|
|
1741
2009
|
if (existing) {
|
|
1742
2010
|
await upsertDevice(name, { role: 'control' });
|
|
2011
|
+
setDeviceDiscoveryStatus(name, 'approved');
|
|
1743
2012
|
marked = true;
|
|
1744
2013
|
}
|
|
1745
2014
|
else {
|
|
@@ -1774,6 +2043,7 @@ email) into a single row. Use \`agents devices harnesses\` for the per-install v
|
|
|
1774
2043
|
console.error(chalk.red(`Unknown device '${name}'.`));
|
|
1775
2044
|
process.exit(1);
|
|
1776
2045
|
}
|
|
2046
|
+
setDeviceDiscoveryStatus(name, undefined);
|
|
1777
2047
|
console.log(chalk.green(`Removed device '${name}'`));
|
|
1778
2048
|
});
|
|
1779
2049
|
devicesCmd
|
|
@@ -1949,7 +2219,7 @@ is refused with a clear message instead of self-dialing.
|
|
|
1949
2219
|
An interactive login with no command mirrors the home-relative directory you
|
|
1950
2220
|
launched from — 'agents ssh yosemite-s0' from ~/src/app lands in ~/src/app on
|
|
1951
2221
|
the target when it exists, else the remote home. Same portable-cwd rule as
|
|
1952
|
-
'agents run --
|
|
2222
|
+
'agents run --device'. Passing a command keeps the remote home.
|
|
1953
2223
|
`)
|
|
1954
2224
|
.action(async (name, cmd) => {
|
|
1955
2225
|
// Hidden askpass bridge: ssh execs the shim, which re-invokes us here.
|
|
@@ -2012,7 +2282,7 @@ the target when it exists, else the remote home. Same portable-cwd rule as
|
|
|
2012
2282
|
const pinned = addr ? isHostPinned(addr) : false;
|
|
2013
2283
|
// Interactive login (no cmd): mirror the caller's project directory on
|
|
2014
2284
|
// the target when the same home-relative checkout exists there, matching
|
|
2015
|
-
// `agents run --
|
|
2285
|
+
// `agents run --device` (deriveMirroredCwd). Best-effort — a missing dir
|
|
2016
2286
|
// falls back to the remote home. An explicit `cmd` keeps its cwd (RUSH-2412).
|
|
2017
2287
|
const mirrorCwd = cmd.length === 0 ? deriveMirroredCwd(process.cwd()) : undefined;
|
|
2018
2288
|
const { args, env } = buildSshInvocation(device, cmd, shim, { pinned }, { interactiveCwd: mirrorCwd });
|
|
@@ -14,7 +14,7 @@ import { homeDir } from '../lib/platform/index.js';
|
|
|
14
14
|
import { capableAgents } from '../lib/capabilities.js';
|
|
15
15
|
import { cloneRepo } from '../lib/git.js';
|
|
16
16
|
import { discoverSubagentsFromRepo, installSubagentCentrally, listInstalledSubagents, getInstalledSubagent, listSubagentsForAgent, iterSubagentsCapableVersions, removeSubagentFromVersion, } from '../lib/subagents.js';
|
|
17
|
-
import { listInstalledVersions, syncResourcesToVersion, getGlobalDefault, getVersionHomePath, promptAgentVersionSelection, } from '../lib/versions.js';
|
|
17
|
+
import { listInstalledVersions, syncResourcesToVersion, getGlobalDefault, getVersionHomePath, promptAgentVersionSelection, } from '../lib/installations/versions.js';
|
|
18
18
|
import { getSubagentsDir, recordVersionResources } from '../lib/state.js';
|
|
19
19
|
import { requireDestructiveArg, promptRemovalTargets, parseCommaSeparatedList, resolveAgentTargetsAutoInstalling, } from './utils.js';
|
|
20
20
|
import { showResourceList, buildTargetsSection, } from './resource-view.js';
|