@phnx-labs/agents-cli 1.22.39 → 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 +294 -0
- package/README.md +111 -70
- package/dist/bin/agents +0 -0
- package/dist/bootstrap.js +45 -26
- 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 +16 -3
- 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 +160 -215
- 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 +186 -64
- 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 +2 -1
- package/dist/lib/config-keys.js +8 -4
- package/dist/lib/config-machine-keys.d.ts +4 -2
- package/dist/lib/config-machine-keys.js +5 -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 +85 -75
- package/dist/lib/device-config.js +279 -141
- 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 +10 -5
- package/dist/lib/devices/pool.js +5 -7
- 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 +4 -4
- package/dist/lib/exec.js +11 -11
- 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} +13 -1
- package/dist/lib/{migrate.js → installations/migrate.js} +160 -40
- 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 +4 -4
- package/dist/lib/smart-launch.js +6 -4
- 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,42 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* One-time migration
|
|
3
|
-
* central `fleet.devices.<name>.config` block of `~/.agents/agents.yaml`.
|
|
2
|
+
* One-time migration to the current device-config + pins layout:
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* (a) central `fleet.devices.<name>.config` (the short-lived #2458 store)
|
|
5
|
+
* folds into each per-device doc's `config:` block — central wins
|
|
6
|
+
* (newest intent) — and is stripped from central;
|
|
7
|
+
* (b) legacy `.history/devices/auto-launch.json` flags fold into the doc
|
|
8
|
+
* `config:` too (oldest store — only fills keys not already set);
|
|
9
|
+
* (c) a top-level `defaultBrowserProfile:` in a device doc folds into that
|
|
10
|
+
* doc's `config:`;
|
|
11
|
+
* (d) agent pins (`agents:` / `isolatedAgents:`) leave the TRACKED
|
|
12
|
+
* per-device docs: THIS machine's pins move to the untracked
|
|
13
|
+
* `.history/devices/pins-<host>.json` (pins file wins on conflict — it
|
|
14
|
+
* is the destination); peers' pins are simply dropped from the tracked
|
|
15
|
+
* file (each peer owns/rewrites its own pins locally).
|
|
8
16
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `isolatedAgents:`), `routines:`, and machine-visibility config STAY in the
|
|
13
|
-
* per-device doc — only shared operator config moves.
|
|
14
|
-
* - `~/.agents/.history/devices/auto-launch.json` — AGI EXT auto-launch
|
|
15
|
-
* enabled/preferred flags, becoming `autoLaunchEnabled` /
|
|
16
|
-
* `autoLaunchPreferred` config keys.
|
|
17
|
+
* What stays put: a device doc's existing `config:` (already the right home)
|
|
18
|
+
* and its `routines:` list (operator-owned, read cross-device by
|
|
19
|
+
* routine-activation.ts).
|
|
17
20
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
+
* Order is crash-safe: destination writes (pins file, device doc) land BEFORE
|
|
22
|
+
* the source strip (central), so a crash mid-fold re-folds on the next run and
|
|
23
|
+
* the destination-wins merges make that a no-op. Idempotent — after a
|
|
24
|
+
* successful run none of the legacy locations hold data, so re-running is a
|
|
25
|
+
* cheap existence check. A doc that fails to parse is LOUDLY skipped (left
|
|
26
|
+
* untouched) so the next run retries — never silently emptied, same corruption
|
|
27
|
+
* contract the device registry keeps.
|
|
21
28
|
*
|
|
22
|
-
* Invoked
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* ordinary `agents config get` dirty it on every machine.
|
|
29
|
+
* Invoked from three places so every install converges regardless of entry
|
|
30
|
+
* point: `runMigration()` (fresh / sentinel-less installs), daemon boot, and
|
|
31
|
+
* the first `lib/device-config.ts` read/write in a process.
|
|
26
32
|
*/
|
|
27
|
-
import type { FleetDeviceOverride, FleetManifest } from '../fleet/types.js';
|
|
28
33
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* currently-registered roster so a config write never silently narrows what
|
|
32
|
-
* `agents apply` targets. (The dynamic "new devices join automatically"
|
|
33
|
-
* semantics of `'all'` do not survive the upgrade — per-device config is
|
|
34
|
-
* inherently a map.)
|
|
34
|
+
* Fold every legacy device-config/pins location into the current layout. Safe
|
|
35
|
+
* to call on every boot / config access: cheap no-op once folded.
|
|
35
36
|
*/
|
|
36
|
-
export declare function
|
|
37
|
-
/**
|
|
38
|
-
* Fold the legacy per-device config stores into the central
|
|
39
|
-
* `fleet.devices.<name>.config` block. Safe to call on every boot / config
|
|
40
|
-
* access: cheap no-op once the legacy stores are stripped.
|
|
41
|
-
*/
|
|
42
|
-
export declare function migrateDeviceConfigToCentral(): void;
|
|
37
|
+
export declare function migrateDeviceConfigStores(): void;
|
|
@@ -1,73 +1,50 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* One-time migration
|
|
3
|
-
* central `fleet.devices.<name>.config` block of `~/.agents/agents.yaml`.
|
|
2
|
+
* One-time migration to the current device-config + pins layout:
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* (a) central `fleet.devices.<name>.config` (the short-lived #2458 store)
|
|
5
|
+
* folds into each per-device doc's `config:` block — central wins
|
|
6
|
+
* (newest intent) — and is stripped from central;
|
|
7
|
+
* (b) legacy `.history/devices/auto-launch.json` flags fold into the doc
|
|
8
|
+
* `config:` too (oldest store — only fills keys not already set);
|
|
9
|
+
* (c) a top-level `defaultBrowserProfile:` in a device doc folds into that
|
|
10
|
+
* doc's `config:`;
|
|
11
|
+
* (d) agent pins (`agents:` / `isolatedAgents:`) leave the TRACKED
|
|
12
|
+
* per-device docs: THIS machine's pins move to the untracked
|
|
13
|
+
* `.history/devices/pins-<host>.json` (pins file wins on conflict — it
|
|
14
|
+
* is the destination); peers' pins are simply dropped from the tracked
|
|
15
|
+
* file (each peer owns/rewrites its own pins locally).
|
|
8
16
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* `isolatedAgents:`), `routines:`, and machine-visibility config STAY in the
|
|
13
|
-
* per-device doc — only shared operator config moves.
|
|
14
|
-
* - `~/.agents/.history/devices/auto-launch.json` — AGI EXT auto-launch
|
|
15
|
-
* enabled/preferred flags, becoming `autoLaunchEnabled` /
|
|
16
|
-
* `autoLaunchPreferred` config keys.
|
|
17
|
+
* What stays put: a device doc's existing `config:` (already the right home)
|
|
18
|
+
* and its `routines:` list (operator-owned, read cross-device by
|
|
19
|
+
* routine-activation.ts).
|
|
17
20
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
+
* Order is crash-safe: destination writes (pins file, device doc) land BEFORE
|
|
22
|
+
* the source strip (central), so a crash mid-fold re-folds on the next run and
|
|
23
|
+
* the destination-wins merges make that a no-op. Idempotent — after a
|
|
24
|
+
* successful run none of the legacy locations hold data, so re-running is a
|
|
25
|
+
* cheap existence check. A doc that fails to parse is LOUDLY skipped (left
|
|
26
|
+
* untouched) so the next run retries — never silently emptied, same corruption
|
|
27
|
+
* contract the device registry keeps.
|
|
21
28
|
*
|
|
22
|
-
* Invoked
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* ordinary `agents config get` dirty it on every machine.
|
|
29
|
+
* Invoked from three places so every install converges regardless of entry
|
|
30
|
+
* point: `runMigration()` (fresh / sentinel-less installs), daemon boot, and
|
|
31
|
+
* the first `lib/device-config.ts` read/write in a process.
|
|
26
32
|
*/
|
|
27
33
|
import * as fs from 'fs';
|
|
28
34
|
import * as path from 'path';
|
|
29
35
|
import * as yaml from 'yaml';
|
|
30
|
-
import { getDevicesAutoLaunchPath, getUserAgentsDir, updateMeta, } from '../state.js';
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
/**
|
|
34
|
-
|
|
35
|
-
* empty; the literal `'all'` upgrades to an explicit map of the
|
|
36
|
-
* currently-registered roster so a config write never silently narrows what
|
|
37
|
-
* `agents apply` targets. (The dynamic "new devices join automatically"
|
|
38
|
-
* semantics of `'all'` do not survive the upgrade — per-device config is
|
|
39
|
-
* inherently a map.)
|
|
40
|
-
*/
|
|
41
|
-
export function fleetDevicesMapForWrite(fleet) {
|
|
42
|
-
if (fleet && fleet.devices !== 'all')
|
|
43
|
-
return { ...fleet.devices };
|
|
44
|
-
if (fleet?.devices !== 'all')
|
|
45
|
-
return {};
|
|
46
|
-
// devices === 'all': expand to the registered roster.
|
|
47
|
-
const roster = loadDevicesSync();
|
|
48
|
-
const devices = {};
|
|
49
|
-
for (const name of Object.keys(roster))
|
|
50
|
-
devices[name] = {};
|
|
51
|
-
return devices;
|
|
52
|
-
}
|
|
53
|
-
function mergeFold(folds, device, values) {
|
|
54
|
-
folds[device] = { ...folds[device], ...values };
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Read every legacy device doc, returning the config to fold per device.
|
|
58
|
-
* A doc that fails to parse is LOUDLY skipped (and left untouched) so the next
|
|
59
|
-
* run retries — never silently emptied, same corruption contract the device
|
|
60
|
-
* registry keeps.
|
|
61
|
-
*/
|
|
62
|
-
function collectDeviceDocFolds(devicesRoot) {
|
|
63
|
-
const folds = {};
|
|
36
|
+
import { META_HEADER, getDevicesAutoLaunchPath, getDevicePinsPath, getUserAgentsDir, readMeta, updateMeta, withMetaLock, } from '../state.js';
|
|
37
|
+
import { atomicWriteFileSync } from '../fs-atomic.js';
|
|
38
|
+
import { machineId } from '../machine-id.js';
|
|
39
|
+
/** Read every device doc. A doc that fails to parse is loudly skipped. */
|
|
40
|
+
function readDeviceDocs(devicesRoot) {
|
|
64
41
|
const docs = [];
|
|
65
42
|
let entries;
|
|
66
43
|
try {
|
|
67
44
|
entries = fs.readdirSync(devicesRoot, { withFileTypes: true });
|
|
68
45
|
}
|
|
69
46
|
catch {
|
|
70
|
-
return
|
|
47
|
+
return docs; // no devices/ tree — nothing to fold
|
|
71
48
|
}
|
|
72
49
|
for (const entry of entries) {
|
|
73
50
|
if (!entry.isDirectory())
|
|
@@ -89,48 +66,38 @@ function collectDeviceDocFolds(devicesRoot) {
|
|
|
89
66
|
console.error(`device config migration: ${docPath} is not a YAML map; leaving it for manual repair`);
|
|
90
67
|
continue;
|
|
91
68
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
69
|
+
docs.push({ name: entry.name, path: docPath, doc: parsed });
|
|
70
|
+
}
|
|
71
|
+
return docs;
|
|
72
|
+
}
|
|
73
|
+
/** Write a device doc, or remove it (and its dir) when nothing remains. */
|
|
74
|
+
function writeDeviceDoc(docPath, doc) {
|
|
75
|
+
try {
|
|
76
|
+
if (Object.keys(doc).length === 0) {
|
|
77
|
+
fs.rmSync(docPath, { force: true });
|
|
78
|
+
try {
|
|
79
|
+
fs.rmdirSync(path.dirname(docPath));
|
|
98
80
|
}
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
if (typeof doc.defaultBrowserProfile === 'string') {
|
|
102
|
-
config.defaultBrowserProfile = doc.defaultBrowserProfile;
|
|
81
|
+
catch { /* not empty — other files live in the device dir */ }
|
|
103
82
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
// the machine-local store the new read path uses (state.ts overlays it
|
|
108
|
-
// as `deviceConfig`), so folding would only copy them into the shared
|
|
109
|
-
// file this whole change exists to keep clean.
|
|
110
|
-
// 2. Copying a PEER's would be a leak. `browserRemoteControl` is a consent
|
|
111
|
-
// flag gating whether other machines may drive that box's browser;
|
|
112
|
-
// hoisting one box's opt-in into the synced file spreads it to the fleet.
|
|
113
|
-
// Each machine keeps its own, in its own doc.
|
|
114
|
-
for (const key of Object.keys(config)) {
|
|
115
|
-
if (MACHINE_LOCAL_YAML_KEYS.has(key))
|
|
116
|
-
delete config[key];
|
|
83
|
+
else {
|
|
84
|
+
fs.mkdirSync(path.dirname(docPath), { recursive: true });
|
|
85
|
+
atomicWriteFileSync(docPath, META_HEADER + yaml.stringify(doc));
|
|
117
86
|
}
|
|
118
|
-
if (Object.keys(config).length === 0)
|
|
119
|
-
continue;
|
|
120
|
-
mergeFold(folds, entry.name, config);
|
|
121
|
-
docs.push({ name: entry.name, path: docPath, doc });
|
|
122
87
|
}
|
|
123
|
-
|
|
88
|
+
catch (err) {
|
|
89
|
+
console.error(`device config migration: could not rewrite ${docPath} (${err.message}); a later run retries`);
|
|
90
|
+
}
|
|
124
91
|
}
|
|
125
|
-
/**
|
|
126
|
-
function
|
|
127
|
-
const
|
|
92
|
+
/** The legacy auto-launch.json flags, keyed by device name ({} when absent). */
|
|
93
|
+
function readAutoLaunchFlags(autoLaunchPath) {
|
|
94
|
+
const out = {};
|
|
128
95
|
let raw;
|
|
129
96
|
try {
|
|
130
97
|
raw = fs.readFileSync(autoLaunchPath, 'utf-8');
|
|
131
98
|
}
|
|
132
99
|
catch {
|
|
133
|
-
return
|
|
100
|
+
return out; // absent — nothing to fold
|
|
134
101
|
}
|
|
135
102
|
let parsed;
|
|
136
103
|
try {
|
|
@@ -138,7 +105,7 @@ function collectAutoLaunchFolds(autoLaunchPath) {
|
|
|
138
105
|
}
|
|
139
106
|
catch (err) {
|
|
140
107
|
console.error(`device config migration: could not parse ${autoLaunchPath} (${err.message}); leaving it for a later retry`);
|
|
141
|
-
return
|
|
108
|
+
return out;
|
|
142
109
|
}
|
|
143
110
|
const devices = parsed?.devices;
|
|
144
111
|
if (devices && typeof devices === 'object' && !Array.isArray(devices)) {
|
|
@@ -149,55 +116,167 @@ function collectAutoLaunchFolds(autoLaunchPath) {
|
|
|
149
116
|
if (pref?.preferred === true)
|
|
150
117
|
config.autoLaunchPreferred = true;
|
|
151
118
|
if (Object.keys(config).length > 0)
|
|
152
|
-
|
|
119
|
+
out[name] = config;
|
|
153
120
|
}
|
|
154
121
|
}
|
|
155
|
-
return
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
function isConfigMap(v) {
|
|
125
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
156
126
|
}
|
|
157
127
|
/**
|
|
158
|
-
* Fold
|
|
159
|
-
*
|
|
160
|
-
* access: cheap no-op once the legacy stores are stripped.
|
|
128
|
+
* Fold every legacy device-config/pins location into the current layout. Safe
|
|
129
|
+
* to call on every boot / config access: cheap no-op once folded.
|
|
161
130
|
*/
|
|
162
|
-
export function
|
|
131
|
+
export function migrateDeviceConfigStores() {
|
|
163
132
|
const devicesRoot = path.join(getUserAgentsDir(), 'devices');
|
|
164
133
|
const autoLaunchPath = getDevicesAutoLaunchPath();
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
134
|
+
const self = machineId();
|
|
135
|
+
// ── 1. Gather ────────────────────────────────────────────────────────────
|
|
136
|
+
// Central per-device config (the #2458 store).
|
|
137
|
+
const fleet = readMeta().fleet;
|
|
138
|
+
const centralDevices = fleet && fleet.devices !== 'all' ? fleet.devices : {};
|
|
139
|
+
const centralHasConfig = Object.values(centralDevices).some((ov) => ov?.config && Object.keys(ov.config).length > 0);
|
|
140
|
+
const autoLaunchFlags = readAutoLaunchFlags(autoLaunchPath);
|
|
141
|
+
const docs = readDeviceDocs(devicesRoot);
|
|
142
|
+
const pinsPath = getDevicePinsPath();
|
|
143
|
+
let selfPins = {};
|
|
144
|
+
try {
|
|
145
|
+
selfPins = JSON.parse(fs.readFileSync(pinsPath, 'utf-8')) || {};
|
|
146
|
+
}
|
|
147
|
+
catch { /* absent or malformed — the fold below recreates it */ }
|
|
148
|
+
// ── 1b. Plan (pure) — so a converged install never takes the meta lock or
|
|
149
|
+
// rewrites a byte-identical doc on every boot.
|
|
150
|
+
const plans = [];
|
|
151
|
+
for (const { name, path: docPath, doc } of docs) {
|
|
152
|
+
const plan = planDeviceDocFold(name, docPath, doc, centralDevices[name]?.config, autoLaunchFlags[name]);
|
|
153
|
+
if (plan)
|
|
154
|
+
plans.push(plan);
|
|
155
|
+
}
|
|
156
|
+
const docNames = new Set(docs.map((d) => d.name));
|
|
157
|
+
const newDocs = [];
|
|
158
|
+
for (const [name, ov] of Object.entries(centralDevices)) {
|
|
159
|
+
if (docNames.has(name) || !isConfigMap(ov?.config))
|
|
160
|
+
continue;
|
|
161
|
+
newDocs.push({ path: path.join(devicesRoot, name, 'agents.yaml'), doc: { config: { ...autoLaunchFlags[name], ...ov.config } } });
|
|
162
|
+
}
|
|
163
|
+
for (const [name, flags] of Object.entries(autoLaunchFlags)) {
|
|
164
|
+
if (docNames.has(name) || isConfigMap(centralDevices[name]?.config))
|
|
165
|
+
continue;
|
|
166
|
+
newDocs.push({ path: path.join(devicesRoot, name, 'agents.yaml'), doc: { config: { ...flags } } });
|
|
167
|
+
}
|
|
168
|
+
const selfDoc = docs.find((d) => d.name === self);
|
|
169
|
+
const docAgents = isConfigMap(selfDoc?.doc.agents) ? selfDoc.doc.agents : undefined;
|
|
170
|
+
const docIsolated = isConfigMap(selfDoc?.doc.isolatedAgents)
|
|
171
|
+
? selfDoc.doc.isolatedAgents
|
|
172
|
+
: undefined;
|
|
173
|
+
const hasDestinationWork = plans.length > 0 || newDocs.length > 0 || docAgents !== undefined || docIsolated !== undefined;
|
|
174
|
+
const autoLaunchPending = fs.existsSync(autoLaunchPath);
|
|
175
|
+
if (!centralHasConfig && !hasDestinationWork && !autoLaunchPending)
|
|
173
176
|
return;
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
177
|
+
// ── 2. Destination writes FIRST (crash-safe), under the meta lock so they
|
|
178
|
+
// serialize against writeMetaUnlocked's own read-merge-write of the doc.
|
|
179
|
+
// Only taken when there IS a write — a converged install never locks
|
|
180
|
+
// (taking it would create a default central agents.yaml as a side effect).
|
|
181
|
+
if (hasDestinationWork) {
|
|
182
|
+
withMetaLock(() => {
|
|
183
|
+
// 2a. THIS machine's pins: doc pins merge INTO the pins file (pins file
|
|
184
|
+
// wins — it is the destination, and a re-fold after a crash must not
|
|
185
|
+
// clobber pins the new CLI already wrote).
|
|
186
|
+
if (docAgents || docIsolated) {
|
|
187
|
+
const pins = { ...selfPins };
|
|
188
|
+
if (docAgents)
|
|
189
|
+
pins.agents = { ...docAgents, ...selfPins.agents };
|
|
190
|
+
if (docIsolated)
|
|
191
|
+
pins.isolatedAgents = { ...docIsolated, ...selfPins.isolatedAgents };
|
|
192
|
+
try {
|
|
193
|
+
fs.mkdirSync(path.dirname(pinsPath), { recursive: true });
|
|
194
|
+
atomicWriteFileSync(pinsPath, JSON.stringify(pins, null, 2) + '\n');
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
console.error(`device config migration: could not write ${pinsPath} (${err.message}); a later run retries`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// 2b/2c. The planned doc rewrites + creations.
|
|
201
|
+
for (const plan of plans)
|
|
202
|
+
writeDeviceDoc(plan.path, plan.next);
|
|
203
|
+
for (const nd of newDocs)
|
|
204
|
+
writeDeviceDoc(nd.path, nd.doc);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
// ── 3. Source strips LAST ────────────────────────────────────────────────
|
|
208
|
+
// 3a. Central: drop every devices.<name>.config block (now folded into the
|
|
209
|
+
// device docs). Overrides left with no other fields are dropped; an
|
|
210
|
+
// emptied fleet block (no defaults/secrets/routines) goes away entirely.
|
|
211
|
+
if (centralHasConfig) {
|
|
212
|
+
updateMeta((m) => {
|
|
213
|
+
const devices = m.fleet?.devices;
|
|
214
|
+
if (!devices || devices === 'all')
|
|
215
|
+
return m;
|
|
216
|
+
const nextDevices = {};
|
|
217
|
+
for (const [name, ov] of Object.entries(devices)) {
|
|
218
|
+
const rest = { ...ov };
|
|
219
|
+
delete rest.config;
|
|
220
|
+
if (Object.keys(rest).length > 0)
|
|
221
|
+
nextDevices[name] = rest;
|
|
222
|
+
}
|
|
223
|
+
const fleet = { ...m.fleet, devices: nextDevices };
|
|
224
|
+
if (Object.keys(nextDevices).length === 0 && !fleet.defaults && !fleet.secrets && !fleet.routines) {
|
|
225
|
+
const { fleet: _, ...rest } = m;
|
|
226
|
+
void _;
|
|
227
|
+
return rest;
|
|
228
|
+
}
|
|
229
|
+
return { ...m, fleet };
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
// 3b. The legacy auto-launch.json.
|
|
233
|
+
if (autoLaunchPending) {
|
|
234
|
+
try {
|
|
235
|
+
fs.rmSync(autoLaunchPath, { force: true });
|
|
184
236
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
237
|
+
catch (err) {
|
|
238
|
+
console.error(`device config migration: could not remove ${autoLaunchPath} (${err.message}); a later run retries`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/** Shallow-set equality for folded doc content (values compared deep via JSON). */
|
|
243
|
+
function sameDocContent(a, b) {
|
|
244
|
+
const ak = Object.keys(a);
|
|
245
|
+
const bk = Object.keys(b);
|
|
246
|
+
if (ak.length !== bk.length)
|
|
247
|
+
return false;
|
|
248
|
+
return ak.every((k) => k in b && JSON.stringify(a[k]) === JSON.stringify(b[k]));
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Compute a device doc's post-fold content: merge the config layers (oldest
|
|
252
|
+
* auto-launch.json flags < the doc's own config: < the central #2458 block —
|
|
253
|
+
* newest wins), fold a top-level defaultBrowserProfile into config:, and strip
|
|
254
|
+
* pins from the tracked file. Returns null when the doc is corrupt (loudly —
|
|
255
|
+
* left for manual repair) or the fold would not change its content.
|
|
256
|
+
*/
|
|
257
|
+
function planDeviceDocFold(name, docPath, doc, centralConfig, autoFlags) {
|
|
258
|
+
const config = {};
|
|
259
|
+
Object.assign(config, autoFlags);
|
|
260
|
+
if (doc.config !== undefined) {
|
|
261
|
+
if (!isConfigMap(doc.config)) {
|
|
262
|
+
console.error(`device config migration: ${docPath} has a non-map config: block; leaving it for manual repair`);
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
Object.assign(config, doc.config);
|
|
266
|
+
}
|
|
267
|
+
if (typeof doc.defaultBrowserProfile === 'string' && config.defaultBrowserProfile === undefined) {
|
|
268
|
+
config.defaultBrowserProfile = doc.defaultBrowserProfile;
|
|
269
|
+
}
|
|
270
|
+
if (isConfigMap(centralConfig))
|
|
271
|
+
Object.assign(config, centralConfig);
|
|
272
|
+
const next = {};
|
|
273
|
+
// Preserve fields the migration does not own (routines:, anything else).
|
|
274
|
+
for (const [k, v] of Object.entries(doc)) {
|
|
275
|
+
if (k === 'config' || k === 'defaultBrowserProfile' || k === 'agents' || k === 'isolatedAgents')
|
|
276
|
+
continue;
|
|
277
|
+
next[k] = v;
|
|
278
|
+
}
|
|
279
|
+
if (Object.keys(config).length > 0)
|
|
280
|
+
next.config = config;
|
|
281
|
+
return sameDocContent(next, doc) ? null : { name, path: docPath, next };
|
|
203
282
|
}
|
|
@@ -44,7 +44,7 @@ export declare function wrapRemoteCommand(device: DeviceProfile, cmd: string[]):
|
|
|
44
44
|
* (`mirrorCwd` is undefined, or resolves to the home root itself) so the caller
|
|
45
45
|
* keeps the plain no-command interactive login.
|
|
46
46
|
*
|
|
47
|
-
* This is the interactive analogue of `agents run --
|
|
47
|
+
* This is the interactive analogue of `agents run --device`'s cwd mirroring, and
|
|
48
48
|
* it reuses the SAME machinery so there is no second resolver: the portable
|
|
49
49
|
* `mirrorCwd` comes from `deriveMirroredCwd`, and — for POSIX — the best-effort
|
|
50
50
|
* `cd` comes from `remoteCdPrefix({ mirror: true })`, whose `|| cd "$HOME"`
|
|
@@ -94,7 +94,7 @@ export declare function deviceIdentityArgs(device: DeviceProfile): string[];
|
|
|
94
94
|
* interactive login (no `cmd`) — from `deriveMirroredCwd(process.cwd())`. When
|
|
95
95
|
* it names a real home-relative sub-path, the login starts there via
|
|
96
96
|
* {@link buildInteractiveShellCommand} (best-effort — a missing dir falls back
|
|
97
|
-
* to the remote home), matching `agents run --
|
|
97
|
+
* to the remote home), matching `agents run --device`. It is ignored when a `cmd`
|
|
98
98
|
* is given: an explicit command keeps its current cwd (the remote home) and its
|
|
99
99
|
* behavior unchanged (RUSH-2412).
|
|
100
100
|
*/
|
|
@@ -93,7 +93,7 @@ export function wrapRemoteCommand(device, cmd) {
|
|
|
93
93
|
* (`mirrorCwd` is undefined, or resolves to the home root itself) so the caller
|
|
94
94
|
* keeps the plain no-command interactive login.
|
|
95
95
|
*
|
|
96
|
-
* This is the interactive analogue of `agents run --
|
|
96
|
+
* This is the interactive analogue of `agents run --device`'s cwd mirroring, and
|
|
97
97
|
* it reuses the SAME machinery so there is no second resolver: the portable
|
|
98
98
|
* `mirrorCwd` comes from `deriveMirroredCwd`, and — for POSIX — the best-effort
|
|
99
99
|
* `cd` comes from `remoteCdPrefix({ mirror: true })`, whose `|| cd "$HOME"`
|
|
@@ -153,7 +153,7 @@ export function deviceIdentityArgs(device) {
|
|
|
153
153
|
* interactive login (no `cmd`) — from `deriveMirroredCwd(process.cwd())`. When
|
|
154
154
|
* it names a real home-relative sub-path, the login starts there via
|
|
155
155
|
* {@link buildInteractiveShellCommand} (best-effort — a missing dir falls back
|
|
156
|
-
* to the remote home), matching `agents run --
|
|
156
|
+
* to the remote home), matching `agents run --device`. It is ignored when a `cmd`
|
|
157
157
|
* is given: an explicit command keeps its current cwd (the remote home) and its
|
|
158
158
|
* behavior unchanged (RUSH-2412).
|
|
159
159
|
*/
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type DeviceDiscoveryStatus = 'approved' | 'ignored';
|
|
2
|
+
export interface DeviceDiscoveryReconcileResult {
|
|
3
|
+
approved: string[];
|
|
4
|
+
ignored: string[];
|
|
5
|
+
registered: string[];
|
|
6
|
+
unresolved: string[];
|
|
7
|
+
}
|
|
8
|
+
/** Read one portable decision. Absence means pending. */
|
|
9
|
+
export declare function getDeviceDiscoveryStatus(name: string): DeviceDiscoveryStatus | undefined;
|
|
10
|
+
/** Persist one portable decision in the central fleet manifest. */
|
|
11
|
+
export declare function setDeviceDiscoveryStatus(name: string, status: DeviceDiscoveryStatus | undefined): void;
|
|
12
|
+
/** Load every explicit decision from the synced central fleet manifest. */
|
|
13
|
+
export declare function loadDeviceDiscoveryPolicies(): Map<string, DeviceDiscoveryStatus>;
|
|
14
|
+
/**
|
|
15
|
+
* Apply synced intent to this machine's local registry. Approval resolves live
|
|
16
|
+
* Tailscale metadata; ignore never needs the network. Missing approved peers are
|
|
17
|
+
* reported as unresolved rather than written with invented connection details.
|
|
18
|
+
*
|
|
19
|
+
* Only devices with an EXPLICIT entry in the synced policy are touched. A
|
|
20
|
+
* device absent from the map is left alone, whether or not the map itself is
|
|
21
|
+
* defined — the map is not treated as authoritative-by-omission, because not
|
|
22
|
+
* every local registration path writes a policy entry (pair-ios control
|
|
23
|
+
* devices, daemon/umbrella auto-refresh, and any device registered before this
|
|
24
|
+
* feature shipped). Wiping those on the next `agents repo pull user` would be
|
|
25
|
+
* silent, fleet-wide data loss for a decision (e.g. "ignore this one iPad")
|
|
26
|
+
* that never meant to touch them.
|
|
27
|
+
*/
|
|
28
|
+
export declare function reconcileDeviceDiscoveryPolicies(): Promise<DeviceDiscoveryReconcileResult>;
|
|
29
|
+
/** Complete reconciliation from real `tailscale status --json` output. */
|
|
30
|
+
export declare function registerApprovedDevicesFromTailscale(json: string, approved: string[], ignored: string[], missing: string[]): Promise<DeviceDiscoveryReconcileResult>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/** Synced device approval/ignore policy and local registry reconciliation. */
|
|
2
|
+
import { readMeta, updateMeta } from '../state.js';
|
|
3
|
+
import { addIgnored, assertValidDeviceName, loadDevices, removeDevice, removeIgnored, upsertDevice, } from './registry.js';
|
|
4
|
+
import { localLoginUser, withDefaultUser } from './sync.js';
|
|
5
|
+
import { nodeToDeviceInput, parseTailscaleStatus, tailscaleStatusJson } from './tailscale.js';
|
|
6
|
+
/** Read one portable decision. Absence means pending. */
|
|
7
|
+
export function getDeviceDiscoveryStatus(name) {
|
|
8
|
+
assertValidDeviceName(name);
|
|
9
|
+
return loadDeviceDiscoveryPolicies().get(name);
|
|
10
|
+
}
|
|
11
|
+
/** Persist one portable decision in the central fleet manifest. */
|
|
12
|
+
export function setDeviceDiscoveryStatus(name, status) {
|
|
13
|
+
assertValidDeviceName(name);
|
|
14
|
+
updateMeta((meta) => {
|
|
15
|
+
const discovery = { ...meta.fleet?.discovery };
|
|
16
|
+
if (status)
|
|
17
|
+
discovery[name] = status;
|
|
18
|
+
else
|
|
19
|
+
delete discovery[name];
|
|
20
|
+
const fleet = {
|
|
21
|
+
...meta.fleet,
|
|
22
|
+
devices: meta.fleet?.devices ?? {},
|
|
23
|
+
// Keep an empty map as the synced tombstone: it distinguishes "policy is
|
|
24
|
+
// authoritative and every device is pending" from an older config that
|
|
25
|
+
// has never opted into portable discovery decisions.
|
|
26
|
+
discovery,
|
|
27
|
+
};
|
|
28
|
+
return { ...meta, fleet };
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/** Load every explicit decision from the synced central fleet manifest. */
|
|
32
|
+
export function loadDeviceDiscoveryPolicies() {
|
|
33
|
+
const policies = new Map();
|
|
34
|
+
for (const [name, status] of Object.entries(readMeta().fleet?.discovery ?? {})) {
|
|
35
|
+
assertValidDeviceName(name);
|
|
36
|
+
if (status !== 'approved' && status !== 'ignored') {
|
|
37
|
+
throw new Error(`Device discovery policy for '${name}' must be approved or ignored.`);
|
|
38
|
+
}
|
|
39
|
+
policies.set(name, status);
|
|
40
|
+
}
|
|
41
|
+
return policies;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Apply synced intent to this machine's local registry. Approval resolves live
|
|
45
|
+
* Tailscale metadata; ignore never needs the network. Missing approved peers are
|
|
46
|
+
* reported as unresolved rather than written with invented connection details.
|
|
47
|
+
*
|
|
48
|
+
* Only devices with an EXPLICIT entry in the synced policy are touched. A
|
|
49
|
+
* device absent from the map is left alone, whether or not the map itself is
|
|
50
|
+
* defined — the map is not treated as authoritative-by-omission, because not
|
|
51
|
+
* every local registration path writes a policy entry (pair-ios control
|
|
52
|
+
* devices, daemon/umbrella auto-refresh, and any device registered before this
|
|
53
|
+
* feature shipped). Wiping those on the next `agents repo pull user` would be
|
|
54
|
+
* silent, fleet-wide data loss for a decision (e.g. "ignore this one iPad")
|
|
55
|
+
* that never meant to touch them.
|
|
56
|
+
*/
|
|
57
|
+
export async function reconcileDeviceDiscoveryPolicies() {
|
|
58
|
+
const configured = readMeta().fleet?.discovery;
|
|
59
|
+
if (configured === undefined) {
|
|
60
|
+
return { approved: [], ignored: [], registered: [], unresolved: [] };
|
|
61
|
+
}
|
|
62
|
+
const policies = loadDeviceDiscoveryPolicies();
|
|
63
|
+
const approved = [...policies].filter(([, s]) => s === 'approved').map(([n]) => n).sort();
|
|
64
|
+
const ignored = [...policies].filter(([, s]) => s === 'ignored').map(([n]) => n).sort();
|
|
65
|
+
for (const name of ignored) {
|
|
66
|
+
await removeDevice(name);
|
|
67
|
+
await addIgnored(name);
|
|
68
|
+
}
|
|
69
|
+
for (const name of approved)
|
|
70
|
+
await removeIgnored(name);
|
|
71
|
+
const currentRegistry = await loadDevices();
|
|
72
|
+
const missing = approved.filter((name) => !currentRegistry[name]);
|
|
73
|
+
if (missing.length === 0)
|
|
74
|
+
return { approved, ignored, registered: [], unresolved: [] };
|
|
75
|
+
let json;
|
|
76
|
+
try {
|
|
77
|
+
json = tailscaleStatusJson();
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return { approved, ignored, registered: [], unresolved: missing };
|
|
81
|
+
}
|
|
82
|
+
return registerApprovedDevicesFromTailscale(json, approved, ignored, missing);
|
|
83
|
+
}
|
|
84
|
+
/** Complete reconciliation from real `tailscale status --json` output. */
|
|
85
|
+
export async function registerApprovedDevicesFromTailscale(json, approved, ignored, missing) {
|
|
86
|
+
const nodes = parseTailscaleStatus(json);
|
|
87
|
+
const byName = new Map(nodes.map((node) => [node.name, node]));
|
|
88
|
+
const registered = [];
|
|
89
|
+
const unresolved = [];
|
|
90
|
+
const user = localLoginUser();
|
|
91
|
+
for (const name of missing) {
|
|
92
|
+
const node = byName.get(name);
|
|
93
|
+
if (!node) {
|
|
94
|
+
unresolved.push(name);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
await upsertDevice(name, withDefaultUser(nodeToDeviceInput(node), undefined, user));
|
|
98
|
+
registered.push(name);
|
|
99
|
+
}
|
|
100
|
+
return { approved, ignored, registered, unresolved };
|
|
101
|
+
}
|