@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
|
@@ -9,11 +9,108 @@ import { readFileSync } from 'node:fs';
|
|
|
9
9
|
import { basename } from 'node:path';
|
|
10
10
|
import { execFileSync } from 'node:child_process';
|
|
11
11
|
import { randomBytes } from 'node:crypto';
|
|
12
|
+
import { hostname as osHostname } from 'node:os';
|
|
12
13
|
import { readShareConfig, readWriteToken } from './config.js';
|
|
13
14
|
import { resolveGitHubUsername } from '../git.js';
|
|
14
15
|
import { captureCover, OG_WIDTH, OG_HEIGHT, OG_SCALE } from './capture.js';
|
|
15
16
|
import { deriveMeta, injectOgMeta } from './og.js';
|
|
16
17
|
import { injectAnalyticsBeacon } from './analytics.js';
|
|
18
|
+
/**
|
|
19
|
+
* Reserved `customMetadata` keys the CLI sets automatically from the exec env,
|
|
20
|
+
* git, and the local clock (plus `label`/`label-source`) — a `--meta key=value`
|
|
21
|
+
* may not target any of these (see {@link parseMetaEntries}).
|
|
22
|
+
*/
|
|
23
|
+
export const RESERVED_META_KEYS = ['agent', 'session', 'host', 'repo', 'date', 'label', 'label-source'];
|
|
24
|
+
const META_KEY_RE = /^[a-z0-9-]{1,64}$/;
|
|
25
|
+
/**
|
|
26
|
+
* Auto-capture publish provenance from the exec env, git, and the local clock.
|
|
27
|
+
* Every field is present only when the environment genuinely carries it — a
|
|
28
|
+
* human running the command by hand outside a git repo yields `session`/`agent`/
|
|
29
|
+
* `repo` all undefined, never an invented value. `host` is always present
|
|
30
|
+
* (`os.hostname()` never fails to return something real about where the publish
|
|
31
|
+
* ran, so it isn't "invented" in the same sense).
|
|
32
|
+
*/
|
|
33
|
+
export function resolveShareProvenance(opts = {}) {
|
|
34
|
+
const env = opts.env ?? process.env;
|
|
35
|
+
return {
|
|
36
|
+
session: env.AGENTS_SESSION_ID || env.AGENT_SESSION_ID || undefined,
|
|
37
|
+
agent: env.AGENTS_AGENT_NAME || undefined,
|
|
38
|
+
host: opts.hostname ?? osHostname(),
|
|
39
|
+
repo: gitRepoName(opts.dir ?? process.cwd()),
|
|
40
|
+
date: (opts.now ?? new Date()).toISOString().slice(0, 10),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Parse repeated `--meta key=value` CLI args into a validated metadata record.
|
|
45
|
+
* Keys are lowercase `[a-z0-9-]`, up to 64 characters, and may not collide with
|
|
46
|
+
* {@link RESERVED_META_KEYS} (the provenance the CLI sets automatically, plus
|
|
47
|
+
* label/label-source) — throws naming the offending pair on any violation.
|
|
48
|
+
*/
|
|
49
|
+
export function parseMetaEntries(pairs) {
|
|
50
|
+
const meta = {};
|
|
51
|
+
for (const pair of pairs) {
|
|
52
|
+
const eq = pair.indexOf('=');
|
|
53
|
+
if (eq <= 0) {
|
|
54
|
+
throw new Error(`Bad --meta '${pair}'. Expected key=value.`);
|
|
55
|
+
}
|
|
56
|
+
const key = pair.slice(0, eq).trim();
|
|
57
|
+
const value = pair.slice(eq + 1);
|
|
58
|
+
if (!META_KEY_RE.test(key)) {
|
|
59
|
+
throw new Error(`Bad --meta key '${key}'. Keys are lowercase letters, digits, and hyphens, up to 64 characters.`);
|
|
60
|
+
}
|
|
61
|
+
if (RESERVED_META_KEYS.includes(key)) {
|
|
62
|
+
throw new Error(`--meta ${key}=… is reserved (set automatically from your session/git) — pass a different key.`);
|
|
63
|
+
}
|
|
64
|
+
meta[key] = value;
|
|
65
|
+
}
|
|
66
|
+
return meta;
|
|
67
|
+
}
|
|
68
|
+
/** S3's `x-amz-meta` convention caps user metadata around 2KB; R2 publishes no
|
|
69
|
+
* hard limit of its own, so stay under that ceiling to keep a share portable to
|
|
70
|
+
* an S3-compatible mirror. Checked over the FULL customMetadata payload
|
|
71
|
+
* (provenance + label + --meta combined), since that's what actually gets
|
|
72
|
+
* written to the object. */
|
|
73
|
+
const MAX_METADATA_BYTES = 2048;
|
|
74
|
+
/** Throws when the combined `customMetadata` payload would exceed {@link MAX_METADATA_BYTES}. */
|
|
75
|
+
export function assertMetadataSize(customMetadata) {
|
|
76
|
+
const bytes = Buffer.byteLength(JSON.stringify(customMetadata), 'utf8');
|
|
77
|
+
if (bytes > MAX_METADATA_BYTES) {
|
|
78
|
+
throw new Error(`Share metadata is ${bytes} bytes, over the ${MAX_METADATA_BYTES}-byte cap ` +
|
|
79
|
+
`(provenance + --label + --meta combined). Trim your --meta values.`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Collapse a label to a single line before it goes into the `x-share-label`
|
|
84
|
+
* header or public customMetadata. `<title>[^<]{1,200}</title>` matches
|
|
85
|
+
* newlines (`[^<]` excludes only `<`), and `.trim()` only strips leading/
|
|
86
|
+
* trailing whitespace, not embedded newlines — a multi-line `<title>` (or an
|
|
87
|
+
* explicit `--label`/`--title` the caller typed with a literal newline) was
|
|
88
|
+
* previously passed straight into `Headers.set()` unsanitized, which throws
|
|
89
|
+
* an unhandled `TypeError: Invalid value` and crashes the publish outright.
|
|
90
|
+
*/
|
|
91
|
+
export function sanitizeLabel(text) {
|
|
92
|
+
return text.replace(/\s+/g, ' ').trim();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Best-effort human title when `--label` is omitted: the HTML `<title>`, else a
|
|
96
|
+
* Markdown frontmatter `title:`, else the filename. Always returns something —
|
|
97
|
+
* a headless publish must never hang waiting on a prompt for one.
|
|
98
|
+
*/
|
|
99
|
+
export function deriveLabel(filePath, body) {
|
|
100
|
+
const text = body.toString('utf8');
|
|
101
|
+
const htmlTitle = /<title[^>]*>([^<]{1,200})<\/title>/i.exec(text);
|
|
102
|
+
if (htmlTitle?.[1]?.trim())
|
|
103
|
+
return sanitizeLabel(htmlTitle[1]);
|
|
104
|
+
const frontmatter = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text);
|
|
105
|
+
if (frontmatter) {
|
|
106
|
+
const titleLine = /^title:\s*(.+)$/m.exec(frontmatter[1]);
|
|
107
|
+
const cleaned = titleLine?.[1]?.trim().replace(/^["']|["']$/g, '').trim();
|
|
108
|
+
if (cleaned)
|
|
109
|
+
return sanitizeLabel(cleaned);
|
|
110
|
+
}
|
|
111
|
+
const base = basename(filePath).replace(/\.[^.]+$/, '').replace(/[-_]+/g, ' ').trim();
|
|
112
|
+
return sanitizeLabel(base || basename(filePath));
|
|
113
|
+
}
|
|
17
114
|
/** Default auto-expire for unflagged publishes — accidental links decay (RUSH-2443). */
|
|
18
115
|
export const DEFAULT_SHARE_EXPIRE = '30d';
|
|
19
116
|
const UNIT_MS = { s: 1e3, m: 6e4, h: 36e5, d: 864e5, w: 6048e5 };
|
|
@@ -118,7 +215,7 @@ export function formatSensitiveContentError(hits) {
|
|
|
118
215
|
: kinds[0] === 'email'
|
|
119
216
|
? 'email addresses'
|
|
120
217
|
: 'credential-shaped strings';
|
|
121
|
-
return (`Refusing to publish:
|
|
218
|
+
return (`Refusing to publish: found ${what} (${samples}) in the file, label, or metadata. ` +
|
|
122
219
|
`Shares are world-readable by URL — pass --force to publish anyway, ` +
|
|
123
220
|
`or --unlisted --expire 12h to bound the blast radius.`);
|
|
124
221
|
}
|
|
@@ -134,8 +231,9 @@ export function slugify(name) {
|
|
|
134
231
|
function sanitizeSlugPart(s) {
|
|
135
232
|
return s.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
136
233
|
}
|
|
137
|
-
/** The
|
|
138
|
-
|
|
234
|
+
/** The current repo's name, or undefined outside a git checkout — never a
|
|
235
|
+
* fallback guess, since callers that want one (detectProject) supply it themselves. */
|
|
236
|
+
function gitRepoName(dir) {
|
|
139
237
|
try {
|
|
140
238
|
const top = execFileSync('git', ['-C', dir, 'rev-parse', '--show-toplevel'], {
|
|
141
239
|
stdio: ['ignore', 'pipe', 'ignore'],
|
|
@@ -143,12 +241,16 @@ export function detectProject(dir = process.cwd()) {
|
|
|
143
241
|
.toString()
|
|
144
242
|
.trim();
|
|
145
243
|
if (top)
|
|
146
|
-
return sanitizeSlugPart(basename(top)) ||
|
|
244
|
+
return sanitizeSlugPart(basename(top)) || undefined;
|
|
147
245
|
}
|
|
148
246
|
catch {
|
|
149
|
-
// not a git repo
|
|
247
|
+
// not a git repo
|
|
150
248
|
}
|
|
151
|
-
return
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
/** The project the file belongs to — git repo name, else the cwd's basename. */
|
|
252
|
+
export function detectProject(dir = process.cwd()) {
|
|
253
|
+
return gitRepoName(dir) ?? (sanitizeSlugPart(basename(dir)) || 'share');
|
|
152
254
|
}
|
|
153
255
|
/**
|
|
154
256
|
* Notion-style default slug: `<project>-<feature>-<16hex>`. Project scopes the link
|
|
@@ -273,31 +375,79 @@ export async function publishToEndpoint(filePath, endpoint, opts = {}) {
|
|
|
273
375
|
const expiresAt = resolveExpire(opts.expire);
|
|
274
376
|
const unlisted = opts.unlisted === true;
|
|
275
377
|
const pageUrl = `${endpoint.baseUrl.replace(/\/+$/, '')}/${key}`;
|
|
378
|
+
const provenance = opts.provenance ?? resolveShareProvenance();
|
|
379
|
+
const meta = opts.meta ?? {};
|
|
276
380
|
const put = opts.uploader ??
|
|
277
381
|
(async (u, b, h) => {
|
|
278
382
|
const res = await fetch(u, { method: 'PUT', headers: h, body: new Uint8Array(b) });
|
|
279
383
|
return { ok: res.ok, status: res.status, url: u };
|
|
280
384
|
});
|
|
281
|
-
const authHeaders = (contentType) => {
|
|
282
|
-
const h = { authorization: `Bearer ${endpoint.token}`, 'content-type': contentType };
|
|
283
|
-
if (expiresAt)
|
|
284
|
-
h['x-share-expires-at'] = expiresAt;
|
|
285
|
-
if (unlisted)
|
|
286
|
-
h['x-share-visibility'] = 'unlisted';
|
|
287
|
-
return h;
|
|
288
|
-
};
|
|
289
385
|
let body = readFileSync(filePath);
|
|
290
386
|
let coverUrl;
|
|
291
387
|
const isHtml = /\.html?$/i.test(filePath);
|
|
292
|
-
|
|
293
|
-
//
|
|
294
|
-
//
|
|
388
|
+
const explicitLabel = opts.label?.trim();
|
|
389
|
+
// sanitizeLabel here (not just inside deriveLabel) covers an explicit
|
|
390
|
+
// --label/--title the caller typed with an embedded newline — deriveLabel
|
|
391
|
+
// is only reached when --label is omitted.
|
|
392
|
+
const label = explicitLabel ? sanitizeLabel(explicitLabel) : deriveLabel(filePath, body);
|
|
393
|
+
const labelSource = explicitLabel ? 'explicit' : 'derived';
|
|
394
|
+
// Pre-publish scan (RUSH-2443/RUSH-2683): refuse emails / credential-shaped
|
|
395
|
+
// strings unless --force. Runs on the raw file body AND on every piece of
|
|
396
|
+
// free-text metadata that lands in public customMetadata — --label (explicit
|
|
397
|
+
// or derived) and every --meta value. Metadata is visible in the gallery,
|
|
398
|
+
// `share list --json`, and `share revisions` just like the page itself, so a
|
|
399
|
+
// credential smuggled in there is exactly as exposed as one in the body; it
|
|
400
|
+
// must not have a free pass around this gate. Runs before analytics/cover
|
|
401
|
+
// mutation so a beacon injection never triggers a false positive on the body
|
|
402
|
+
// scan. Binary media bodies are a no-op for the body scan.
|
|
295
403
|
if (opts.force !== true) {
|
|
296
|
-
const hits =
|
|
404
|
+
const hits = [
|
|
405
|
+
...scanShareContent(body),
|
|
406
|
+
...scanShareContent(label),
|
|
407
|
+
...Object.values(meta).flatMap((v) => scanShareContent(v)),
|
|
408
|
+
];
|
|
297
409
|
if (hits.length > 0) {
|
|
298
410
|
throw new Error(formatSensitiveContentError(hits));
|
|
299
411
|
}
|
|
300
412
|
}
|
|
413
|
+
// Validate the FULL customMetadata payload before any network call — fail
|
|
414
|
+
// fast, not mid-upload.
|
|
415
|
+
const metadataPreview = { ...meta, label, 'label-source': labelSource };
|
|
416
|
+
if (provenance.agent)
|
|
417
|
+
metadataPreview.agent = provenance.agent;
|
|
418
|
+
if (provenance.session)
|
|
419
|
+
metadataPreview.session = provenance.session;
|
|
420
|
+
if (provenance.host)
|
|
421
|
+
metadataPreview.host = provenance.host;
|
|
422
|
+
if (provenance.repo)
|
|
423
|
+
metadataPreview.repo = provenance.repo;
|
|
424
|
+
if (provenance.date)
|
|
425
|
+
metadataPreview.date = provenance.date;
|
|
426
|
+
assertMetadataSize(metadataPreview);
|
|
427
|
+
const authHeaders = (contentType) => {
|
|
428
|
+
const h = { authorization: `Bearer ${endpoint.token}`, 'content-type': contentType };
|
|
429
|
+
if (expiresAt)
|
|
430
|
+
h['x-share-expires-at'] = expiresAt;
|
|
431
|
+
if (unlisted)
|
|
432
|
+
h['x-share-visibility'] = 'unlisted';
|
|
433
|
+
if (provenance.agent)
|
|
434
|
+
h['x-share-agent'] = provenance.agent;
|
|
435
|
+
if (provenance.session)
|
|
436
|
+
h['x-share-session'] = provenance.session;
|
|
437
|
+
if (provenance.host)
|
|
438
|
+
h['x-share-host'] = provenance.host;
|
|
439
|
+
if (provenance.repo)
|
|
440
|
+
h['x-share-repo'] = provenance.repo;
|
|
441
|
+
if (provenance.date)
|
|
442
|
+
h['x-share-date'] = provenance.date;
|
|
443
|
+
h['x-share-label'] = label;
|
|
444
|
+
h['x-share-label-source'] = labelSource;
|
|
445
|
+
if (Object.keys(meta).length > 0)
|
|
446
|
+
h['x-share-meta'] = JSON.stringify(meta);
|
|
447
|
+
if (opts.noRevision)
|
|
448
|
+
h['x-share-no-revision'] = '1';
|
|
449
|
+
return h;
|
|
450
|
+
};
|
|
301
451
|
// Analytics: cookieless CF Web Analytics beacon, injected for HTML by default.
|
|
302
452
|
if (isHtml && opts.analytics !== false && opts.analyticsToken) {
|
|
303
453
|
body = Buffer.from(injectAnalyticsBeacon(body.toString('utf8'), opts.analyticsToken), 'utf8');
|
|
@@ -324,6 +474,8 @@ export async function publishToEndpoint(filePath, endpoint, opts = {}) {
|
|
|
324
474
|
url: r.url ?? pageUrl,
|
|
325
475
|
expiresAt,
|
|
326
476
|
coverUrl,
|
|
477
|
+
label,
|
|
478
|
+
labelSource,
|
|
327
479
|
...(unlisted ? { unlisted: true } : {}),
|
|
328
480
|
};
|
|
329
481
|
}
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
//
|
|
3
3
|
// One tiny Worker does both sides:
|
|
4
4
|
// - PUT /<username>/<slug> — bearer-gated (WRITE_TOKEN secret); writes the body
|
|
5
|
-
// to R2 via the BUCKET binding, storing an optional expires-at value
|
|
6
|
-
//
|
|
5
|
+
// to R2 via the BUCKET binding, storing an optional expires-at value plus
|
|
6
|
+
// provenance (agent/session/host/repo/date), a label, and any `--meta`
|
|
7
|
+
// entries in object metadata. Overwriting an existing slug first copies the
|
|
8
|
+
// current object to <slug>/rev-<ts>-<rand> (revision history) unless
|
|
9
|
+
// x-share-no-revision is set.
|
|
7
10
|
// - GET /<username>/<slug> — public; streams the object from R2, 410s (and lazily
|
|
8
11
|
// deletes) once its expiry has passed. A bucket lifecycle rule is the durable
|
|
9
12
|
// sweeper; this is the immediate gate.
|
|
13
|
+
// - GET /<username>/<slug>?revisions=json — machine-readable history of the
|
|
14
|
+
// retained prior versions under that slug, newest first.
|
|
10
15
|
// - GET /<username> — public gallery of that user's shares (HTML).
|
|
11
16
|
// - GET /<username>?format=json — public machine-readable listing of that user's
|
|
12
17
|
// ACTIVE shares (`agents artifacts share list`). Same single-segment path as the HTML
|
|
@@ -55,9 +60,71 @@ export default {
|
|
|
55
60
|
// keeping the direct URL world-readable (capability URL, not secret).
|
|
56
61
|
const visibility = (request.headers.get('x-share-visibility') || '').toLowerCase();
|
|
57
62
|
const contentType = request.headers.get('content-type') || 'text/html; charset=utf-8';
|
|
58
|
-
|
|
63
|
+
// Provenance (RUSH-2683): captured client-side from the exec env/git/clock,
|
|
64
|
+
// never invented here — a header is simply absent when the CLI had nothing
|
|
65
|
+
// to say. --meta entries ride one JSON header; reserved keys are stripped
|
|
66
|
+
// from that JSON UNCONDITIONALLY (not just overwritten when a provenance
|
|
67
|
+
// header happens to be present) so a same-named x-share-meta entry can
|
|
68
|
+
// never smuggle through on a publish that carries no agent/session/host/
|
|
69
|
+
// repo/date at all — e.g. a human publishing outside an agent session, or
|
|
70
|
+
// outside a git checkout.
|
|
71
|
+
const agent = request.headers.get('x-share-agent') || '';
|
|
72
|
+
const session = request.headers.get('x-share-session') || '';
|
|
73
|
+
const host = request.headers.get('x-share-host') || '';
|
|
74
|
+
const repo = request.headers.get('x-share-repo') || '';
|
|
75
|
+
const date = request.headers.get('x-share-date') || '';
|
|
76
|
+
const label = request.headers.get('x-share-label') || '';
|
|
77
|
+
const labelSource = request.headers.get('x-share-label-source') || '';
|
|
78
|
+
let extraMeta = {};
|
|
79
|
+
const metaHeader = request.headers.get('x-share-meta');
|
|
80
|
+
if (metaHeader) {
|
|
81
|
+
try {
|
|
82
|
+
const parsed = JSON.parse(metaHeader);
|
|
83
|
+
if (parsed && typeof parsed === 'object') extraMeta = parsed;
|
|
84
|
+
} catch {
|
|
85
|
+
// malformed --meta header — ignore rather than fail the whole publish
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const customMetadata = { ...extraMeta };
|
|
89
|
+
// Strip every reserved key UNCONDITIONALLY before re-applying the real
|
|
90
|
+
// provenance below — an if(value)-guarded overwrite alone leaves a
|
|
91
|
+
// same-named --meta entry in place whenever the real header is absent.
|
|
92
|
+
for (const reservedKey of RESERVED_METADATA_KEYS) {
|
|
93
|
+
delete customMetadata[reservedKey];
|
|
94
|
+
}
|
|
59
95
|
if (expiresAt) customMetadata['expires-at'] = expiresAt;
|
|
60
96
|
if (visibility === 'unlisted') customMetadata['visibility'] = 'unlisted';
|
|
97
|
+
if (agent) customMetadata['agent'] = agent;
|
|
98
|
+
if (session) customMetadata['session'] = session;
|
|
99
|
+
if (host) customMetadata['host'] = host;
|
|
100
|
+
if (repo) customMetadata['repo'] = repo;
|
|
101
|
+
if (date) customMetadata['date'] = date;
|
|
102
|
+
if (label) customMetadata['label'] = label;
|
|
103
|
+
if (labelSource) customMetadata['label-source'] = labelSource;
|
|
104
|
+
|
|
105
|
+
// Revision retention (RUSH-2683): R2 has no native object versioning, so a
|
|
106
|
+
// republish over an EXISTING key first copies the current object to
|
|
107
|
+
// <key>/rev-<ts>-<rand> before the canonical key is overwritten. Default
|
|
108
|
+
// keep-all; --no-revision (x-share-no-revision) skips it. The random
|
|
109
|
+
// suffix guards against two rapid overwrites of the same slug colliding on
|
|
110
|
+
// the millisecond, and against a slug whose canonical key already sits 3+
|
|
111
|
+
// segments deep (an unsupported shape outside the CLI) landing on the same
|
|
112
|
+
// literal revision key.
|
|
113
|
+
const noRevision = !!request.headers.get('x-share-no-revision');
|
|
114
|
+
if (!noRevision) {
|
|
115
|
+
const existing = await env.BUCKET.get(path);
|
|
116
|
+
if (existing) {
|
|
117
|
+
const existingHeaders = new Headers();
|
|
118
|
+
if (typeof existing.writeHttpMetadata === 'function') existing.writeHttpMetadata(existingHeaders);
|
|
119
|
+
const existingContentType = existingHeaders.get('content-type');
|
|
120
|
+
const revKey = path + '/rev-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8);
|
|
121
|
+
await env.BUCKET.put(revKey, existing.body, {
|
|
122
|
+
httpMetadata: existingContentType ? { contentType: existingContentType } : undefined,
|
|
123
|
+
customMetadata: existing.customMetadata || {},
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
61
128
|
await env.BUCKET.put(path, request.body, {
|
|
62
129
|
httpMetadata: { contentType },
|
|
63
130
|
customMetadata,
|
|
@@ -88,6 +155,13 @@ export default {
|
|
|
88
155
|
// signal rather than a missing route).
|
|
89
156
|
}
|
|
90
157
|
|
|
158
|
+
// Revision history for one canonical <user>/<slug> key (RUSH-2683). Checked
|
|
159
|
+
// before the plain object GET below so the query param routes even though
|
|
160
|
+
// the canonical key itself resolves to a real object.
|
|
161
|
+
if (segments.length === 2 && url.searchParams.get('revisions') === 'json') {
|
|
162
|
+
return renderRevisions(env.BUCKET, url.origin, path, request.method);
|
|
163
|
+
}
|
|
164
|
+
|
|
91
165
|
const obj = await env.BUCKET.get(path);
|
|
92
166
|
if (!obj) return new Response('not found', { status: 404, headers: { 'content-type': 'text/plain' } });
|
|
93
167
|
const expiresAt = obj.customMetadata && obj.customMetadata['expires-at'];
|
|
@@ -114,6 +188,16 @@ export default {
|
|
|
114
188
|
},
|
|
115
189
|
};
|
|
116
190
|
|
|
191
|
+
// A canonical share object's key is exactly 2 segments (<user>/<slug>, or the
|
|
192
|
+
// sibling <user>/<slug>.png OG cover). A retained revision lives a 3rd segment
|
|
193
|
+
// deeper (<user>/<slug>/rev-<ts>-<rand>) — history, not a page in its own
|
|
194
|
+
// right, so every gallery/listing view hides it. A raw external PUT to an
|
|
195
|
+
// already-3-segment-deep path is treated the same way for the same reason:
|
|
196
|
+
// there is no ambiguity to resolve, and the CLI never produces such a key.
|
|
197
|
+
function isRevisionKey(key) {
|
|
198
|
+
return key.split('/').length > 2;
|
|
199
|
+
}
|
|
200
|
+
|
|
117
201
|
async function renderGallery(bucket, origin, user, method) {
|
|
118
202
|
const objects = [];
|
|
119
203
|
let cursor;
|
|
@@ -124,6 +208,7 @@ async function renderGallery(bucket, origin, user, method) {
|
|
|
124
208
|
} while (cursor);
|
|
125
209
|
|
|
126
210
|
const activeObjects = objects.filter(o => {
|
|
211
|
+
if (isRevisionKey(o.key)) return false;
|
|
127
212
|
if (o.key.endsWith('.png')) return false;
|
|
128
213
|
// Unlisted pages are reachable by direct URL only — never on the gallery.
|
|
129
214
|
if (o.customMetadata && o.customMetadata.visibility === 'unlisted') return false;
|
|
@@ -133,7 +218,9 @@ async function renderGallery(bucket, origin, user, method) {
|
|
|
133
218
|
const items = activeObjects.map(o => {
|
|
134
219
|
const slug = o.key.slice(o.key.indexOf('/') + 1);
|
|
135
220
|
const url = origin + '/' + o.key;
|
|
136
|
-
|
|
221
|
+
const label = (o.customMetadata && o.customMetadata['label']) || '';
|
|
222
|
+
const agent = (o.customMetadata && o.customMetadata['agent']) || '';
|
|
223
|
+
return { slug, url, updated: o.uploaded, label, agent };
|
|
137
224
|
});
|
|
138
225
|
|
|
139
226
|
if (method === 'HEAD') {
|
|
@@ -148,14 +235,17 @@ async function renderGallery(bucket, origin, user, method) {
|
|
|
148
235
|
'body{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;max-width:720px;margin:48px auto;padding:0 24px;color:#111;background:#fafafa}' +
|
|
149
236
|
'h1{font-size:28px;margin-bottom:8px}a{color:#0a0a0a;text-decoration:none;border-bottom:1px solid #999}' +
|
|
150
237
|
'a:hover{border-color:#111}ul{list-style:none;padding:0}li{margin:16px 0}' +
|
|
151
|
-
'.slug{font-weight:600}.meta{color:#666;font-size:14px}' +
|
|
238
|
+
'.slug{font-weight:600}.title{font-weight:600}.meta{color:#666;font-size:14px}' +
|
|
152
239
|
'</style></head><body>' +
|
|
153
240
|
'<h1>@' + escapeHtml(user) + '</h1>' +
|
|
154
241
|
'<p class="meta">' + items.length + ' shared ' + (items.length === 1 ? 'page' : 'pages') + '</p>' +
|
|
155
242
|
'<ul>' +
|
|
156
243
|
items.map(i =>
|
|
157
|
-
'<li
|
|
158
|
-
'<
|
|
244
|
+
'<li>' +
|
|
245
|
+
(i.label ? '<span class="title">' + escapeHtml(i.label) + '</span><br>' : '') +
|
|
246
|
+
'<a class="slug" href="' + escapeHtml(i.url) + '">' + escapeHtml(i.slug) + '</a>' +
|
|
247
|
+
'<br><span class="meta">' + new Date(i.updated).toISOString().slice(0, 10) +
|
|
248
|
+
(i.agent ? ' · ' + escapeHtml(i.agent) : '') + '</span></li>'
|
|
159
249
|
).join('') +
|
|
160
250
|
'</ul></body></html>';
|
|
161
251
|
return new Response(html, { status: 200, headers: { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'public, max-age=60' } });
|
|
@@ -170,11 +260,21 @@ async function renderListing(bucket, origin, user, method) {
|
|
|
170
260
|
cursor = list.truncated ? list.cursor : undefined;
|
|
171
261
|
} while (cursor);
|
|
172
262
|
|
|
263
|
+
// Revisions never appear as their own listing row, but they count toward
|
|
264
|
+
// their canonical object's revisionCount.
|
|
265
|
+
const revisionCounts = {};
|
|
266
|
+
for (const o of objects) {
|
|
267
|
+
if (!isRevisionKey(o.key)) continue;
|
|
268
|
+
const canonicalKey = o.key.split('/').slice(0, 2).join('/');
|
|
269
|
+
revisionCounts[canonicalKey] = (revisionCounts[canonicalKey] || 0) + 1;
|
|
270
|
+
}
|
|
271
|
+
|
|
173
272
|
const now = Date.now();
|
|
174
273
|
const items = objects
|
|
175
274
|
.filter(o => {
|
|
176
|
-
// Mirror the gallery: hide sibling .png OG covers, expired
|
|
177
|
-
// unlisted pages — the listing is the machine-readable public surface.
|
|
275
|
+
// Mirror the gallery: hide revisions, sibling .png OG covers, expired
|
|
276
|
+
// pages, and unlisted pages — the listing is the machine-readable public surface.
|
|
277
|
+
if (isRevisionKey(o.key)) return false;
|
|
178
278
|
if (o.key.endsWith('.png')) return false;
|
|
179
279
|
if (o.customMetadata && o.customMetadata.visibility === 'unlisted') return false;
|
|
180
280
|
const expiresAt = o.customMetadata && o.customMetadata['expires-at'];
|
|
@@ -187,6 +287,13 @@ async function renderListing(bucket, origin, user, method) {
|
|
|
187
287
|
contentType: (o.httpMetadata && o.httpMetadata.contentType) || null,
|
|
188
288
|
publishedAt: new Date(o.uploaded).toISOString(),
|
|
189
289
|
expiresAt: (o.customMetadata && o.customMetadata['expires-at']) || null,
|
|
290
|
+
label: (o.customMetadata && o.customMetadata['label']) || null,
|
|
291
|
+
agent: (o.customMetadata && o.customMetadata['agent']) || null,
|
|
292
|
+
session: (o.customMetadata && o.customMetadata['session']) || null,
|
|
293
|
+
host: (o.customMetadata && o.customMetadata['host']) || null,
|
|
294
|
+
repo: (o.customMetadata && o.customMetadata['repo']) || null,
|
|
295
|
+
revisionCount: revisionCounts[o.key] || 0,
|
|
296
|
+
meta: extraMetaOf(o.customMetadata),
|
|
190
297
|
}));
|
|
191
298
|
// Newest first, so the human table and any script reads the freshest share top.
|
|
192
299
|
items.sort((a, b) => (a.publishedAt < b.publishedAt ? 1 : a.publishedAt > b.publishedAt ? -1 : 0));
|
|
@@ -200,6 +307,62 @@ async function renderListing(bucket, origin, user, method) {
|
|
|
200
307
|
});
|
|
201
308
|
}
|
|
202
309
|
|
|
310
|
+
async function renderRevisions(bucket, origin, key, method) {
|
|
311
|
+
const objects = [];
|
|
312
|
+
let cursor;
|
|
313
|
+
do {
|
|
314
|
+
const list = await bucket.list({ prefix: key + '/rev-', limit: 1000, cursor, include: ['httpMetadata', 'customMetadata'] });
|
|
315
|
+
objects.push(...(list.objects || []));
|
|
316
|
+
cursor = list.truncated ? list.cursor : undefined;
|
|
317
|
+
} while (cursor);
|
|
318
|
+
|
|
319
|
+
const items = objects.map(o => ({
|
|
320
|
+
key: o.key,
|
|
321
|
+
url: origin + '/' + o.key,
|
|
322
|
+
size: typeof o.size === 'number' ? o.size : 0,
|
|
323
|
+
contentType: (o.httpMetadata && o.httpMetadata.contentType) || null,
|
|
324
|
+
uploadedAt: new Date(o.uploaded).toISOString(),
|
|
325
|
+
expiresAt: (o.customMetadata && o.customMetadata['expires-at']) || null,
|
|
326
|
+
label: (o.customMetadata && o.customMetadata['label']) || null,
|
|
327
|
+
agent: (o.customMetadata && o.customMetadata['agent']) || null,
|
|
328
|
+
session: (o.customMetadata && o.customMetadata['session']) || null,
|
|
329
|
+
host: (o.customMetadata && o.customMetadata['host']) || null,
|
|
330
|
+
repo: (o.customMetadata && o.customMetadata['repo']) || null,
|
|
331
|
+
meta: extraMetaOf(o.customMetadata),
|
|
332
|
+
}));
|
|
333
|
+
// Newest first — the most recently replaced version leads.
|
|
334
|
+
items.sort((a, b) => (a.uploadedAt < b.uploadedAt ? 1 : a.uploadedAt > b.uploadedAt ? -1 : 0));
|
|
335
|
+
|
|
336
|
+
if (method === 'HEAD') {
|
|
337
|
+
return new Response(null, { status: 200, headers: { 'content-type': 'application/json; charset=utf-8' } });
|
|
338
|
+
}
|
|
339
|
+
return new Response(JSON.stringify({ key, count: items.length, revisions: items }), {
|
|
340
|
+
status: 200,
|
|
341
|
+
headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'public, max-age=30' },
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// The customMetadata keys the CLI sets automatically (provenance + label) —
|
|
346
|
+
// never a real \`--meta key=value\` entry (the CLI rejects a colliding key
|
|
347
|
+
// before it ever reaches this Worker; see RESERVED_META_KEYS in publish.ts).
|
|
348
|
+
// One list, reused both to strip a same-named --meta collision on write and
|
|
349
|
+
// to split arbitrary --meta entries back out on read.
|
|
350
|
+
var RESERVED_METADATA_KEYS = ['expires-at', 'visibility', 'agent', 'session', 'host', 'repo', 'date', 'label', 'label-source'];
|
|
351
|
+
|
|
352
|
+
// Everything in customMetadata that ISN'T one of the reserved provenance/label
|
|
353
|
+
// keys above — i.e. the caller's own \`--meta key=value\` entries. Surfaced on
|
|
354
|
+
// every read route (listing, revisions) so a value stored with \`--meta
|
|
355
|
+
// kind=plan --meta ticket=RUSH-2683\` is actually visible again, not just
|
|
356
|
+
// write-only (RUSH-2683 review fix).
|
|
357
|
+
function extraMetaOf(customMetadata) {
|
|
358
|
+
var out = {};
|
|
359
|
+
if (!customMetadata) return out;
|
|
360
|
+
for (var k in customMetadata) {
|
|
361
|
+
if (RESERVED_METADATA_KEYS.indexOf(k) === -1) out[k] = customMetadata[k];
|
|
362
|
+
}
|
|
363
|
+
return out;
|
|
364
|
+
}
|
|
365
|
+
|
|
203
366
|
function escapeHtml(s) {
|
|
204
367
|
return String(s)
|
|
205
368
|
.replace(/&/g, '&')
|
package/dist/lib/shims.js
CHANGED
|
@@ -504,6 +504,32 @@ parse_agents_default() {
|
|
|
504
504
|
' "$meta"
|
|
505
505
|
}
|
|
506
506
|
|
|
507
|
+
# Parse the pins JSON (~/.agents/.history/devices/pins-<machine>.json) for this
|
|
508
|
+
# AGENT's pinned version. The file is JSON.stringify(…, 2) output, so the
|
|
509
|
+
# "agents" map sits at 2-space indent and its entries at 4 — a stable shape the
|
|
510
|
+
# awk below scrapes without a JSON parser (shims must stay dependency-free).
|
|
511
|
+
parse_pins_default() {
|
|
512
|
+
local pins="$1"
|
|
513
|
+
[ -f "$pins" ] || return 0
|
|
514
|
+
# Scope carefully: enter ONLY on a line that opens the agents block
|
|
515
|
+
# ( "agents": {) — an inline-empty map ("agents": {}) must NOT enter,
|
|
516
|
+
# or the needle would leak into a following "isolatedAgents" block and an
|
|
517
|
+
# isolated pin would masquerade as the global default. Exit at the block's
|
|
518
|
+
# closing brace (a trailing comma is fine). Entries sit at exactly 4 spaces.
|
|
519
|
+
awk -v agent="$AGENT" '
|
|
520
|
+
/^ "agents": [{]$/ { in_agents=1; next }
|
|
521
|
+
in_agents && /^ }/ { exit }
|
|
522
|
+
in_agents && /^ "/ {
|
|
523
|
+
needle = "\\"" agent "\\":"
|
|
524
|
+
if (index($0, needle) > 0) {
|
|
525
|
+
line = substr($0, index($0, needle) + length(needle))
|
|
526
|
+
gsub(/[[:space:],"]/, "", line)
|
|
527
|
+
print line; exit
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
' "$pins"
|
|
531
|
+
}
|
|
532
|
+
|
|
507
533
|
# This machine's device id — mirrors machineId()/normalizeHost() in
|
|
508
534
|
# src/lib/machine-id.ts: first hostname label, lowercased, non-[a-z0-9_-] -> '-'.
|
|
509
535
|
# MUST stay in sync or the shim reads the wrong device folder.
|
|
@@ -514,15 +540,17 @@ machine_id() {
|
|
|
514
540
|
[ -n "$raw" ] && printf '%s' "$raw" || printf 'unknown'
|
|
515
541
|
}
|
|
516
542
|
|
|
517
|
-
# Resolve the default version. The agents: version pins are
|
|
518
|
-
# devices
|
|
519
|
-
#
|
|
520
|
-
#
|
|
521
|
-
#
|
|
522
|
-
#
|
|
543
|
+
# Resolve the default version. The agents: version pins are MACHINE-LOCAL runtime
|
|
544
|
+
# state at .history/devices/pins-<machine>.json (untracked — auto-written pins in
|
|
545
|
+
# the tracked device doc caused commit churn); read that first, then fall back to
|
|
546
|
+
# the tracked device doc (installs not yet migrated) and finally the central
|
|
547
|
+
# agents.yaml (pre-split installs). Must match readMeta()'s central+pins merge in
|
|
548
|
+
# state.ts -- reading only the central file (the old behavior) missed every device
|
|
549
|
+
# pin and made the shim re-prompt "no default set" on every launch.
|
|
523
550
|
resolve_default_version() {
|
|
524
551
|
local v
|
|
525
|
-
v=$(
|
|
552
|
+
v=$(parse_pins_default "$AGENTS_USER_DIR/.history/devices/pins-$(machine_id).json")
|
|
553
|
+
[ -n "$v" ] || v=$(parse_agents_default "$AGENTS_USER_DIR/devices/$(machine_id)/agents.yaml")
|
|
526
554
|
[ -n "$v" ] || v=$(parse_agents_default "$AGENTS_USER_DIR/agents.yaml")
|
|
527
555
|
printf '%s' "$v"
|
|
528
556
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Device placement for `--device auto
|
|
2
|
+
* Device placement for `--device auto`.
|
|
3
3
|
*
|
|
4
4
|
* Explicit auto placement probes live fleet health and harness readiness.
|
|
5
5
|
* Historical affinity remains for generic host resolution callers.
|
|
@@ -60,7 +60,7 @@ export interface DeviceAffinityOptions {
|
|
|
60
60
|
project?: string;
|
|
61
61
|
}
|
|
62
62
|
export interface DeviceAffinityPlan {
|
|
63
|
-
/** null means run locally (do not pass --
|
|
63
|
+
/** null means run locally (do not pass --device). */
|
|
64
64
|
host: string | null;
|
|
65
65
|
deviceCandidates: WeightedCandidate[];
|
|
66
66
|
pickedDeviceKey: string | null;
|
|
@@ -100,7 +100,7 @@ export declare function resolveDeviceAuto(agent?: string, opts?: {
|
|
|
100
100
|
* Resolve host for `--device auto`. Does NOT pick harness or accounts.
|
|
101
101
|
*
|
|
102
102
|
* Draws from the same automatic-placement pool as {@link resolveDeviceAuto}, so
|
|
103
|
-
* `agents ssh auto`, the generic `--
|
|
103
|
+
* `agents ssh auto`, the generic `--device auto` passthrough, and `matchHost`'s
|
|
104
104
|
* `auto` sentinel honour device roles too. Throws when roles leave the pool
|
|
105
105
|
* empty — a `null` host here means "run locally", which for a box marked
|
|
106
106
|
* `personal` is the outcome the mark exists to prevent.
|
|
@@ -131,7 +131,7 @@ export type DeviceAutoApplyResult = {
|
|
|
131
131
|
};
|
|
132
132
|
};
|
|
133
133
|
/**
|
|
134
|
-
* Apply `--device auto`
|
|
134
|
+
* Apply `--device auto` (and deprecated `--smart`) onto run options.
|
|
135
135
|
* Mutates `options` in place. Placement failures propagate without rewriting
|
|
136
136
|
* `auto`, so callers fail loud instead of silently launching locally.
|
|
137
137
|
*/
|
package/dist/lib/smart-launch.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Device placement for `--device auto
|
|
2
|
+
* Device placement for `--device auto`.
|
|
3
3
|
*
|
|
4
4
|
* Explicit auto placement probes live fleet health and harness readiness.
|
|
5
5
|
* Historical affinity remains for generic host resolution callers.
|
|
@@ -111,7 +111,9 @@ export function formatNoHealthyDeviceError(pool, signals, agent) {
|
|
|
111
111
|
const target = agent ? `can run ${agent}` : "for 'run auto'";
|
|
112
112
|
// Name the role narrowing when there is one: a fleet where every box but two
|
|
113
113
|
// is filtered out by a worker mark reads as "the fleet is down" without it.
|
|
114
|
-
|
|
114
|
+
// Roster on `pool` so a fleet-wide role default reaches a doc-less device
|
|
115
|
+
// in this error's own candidate set, not just the ones with a doc.
|
|
116
|
+
const marked = describeAutoPool({ roster: pool });
|
|
115
117
|
const poolNote = marked ? ` [pool: ${marked}]` : '';
|
|
116
118
|
return `agents: no healthy device ${target}${poolNote} — excluded: ${excluded}; earliest window resets unknown`;
|
|
117
119
|
}
|
|
@@ -177,7 +179,7 @@ export async function resolveDeviceAuto(agent, opts = {}) {
|
|
|
177
179
|
* Resolve host for `--device auto`. Does NOT pick harness or accounts.
|
|
178
180
|
*
|
|
179
181
|
* Draws from the same automatic-placement pool as {@link resolveDeviceAuto}, so
|
|
180
|
-
* `agents ssh auto`, the generic `--
|
|
182
|
+
* `agents ssh auto`, the generic `--device auto` passthrough, and `matchHost`'s
|
|
181
183
|
* `auto` sentinel honour device roles too. Throws when roles leave the pool
|
|
182
184
|
* empty — a `null` host here means "run locally", which for a box marked
|
|
183
185
|
* `personal` is the outcome the mark exists to prevent.
|
|
@@ -242,7 +244,7 @@ export function isDeviceAuto(value) {
|
|
|
242
244
|
}
|
|
243
245
|
const HOST_SLOTS = ['host', 'device', 'on', 'computer'];
|
|
244
246
|
/**
|
|
245
|
-
* Apply `--device auto`
|
|
247
|
+
* Apply `--device auto` (and deprecated `--smart`) onto run options.
|
|
246
248
|
* Mutates `options` in place. Placement failures propagate without rewriting
|
|
247
249
|
* `auto`, so callers fail loud instead of silently launching locally.
|
|
248
250
|
*/
|