@phnx-labs/agents-cli 1.22.119 → 1.22.121
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 +236 -0
- package/README.md +19 -2
- package/dist/bootstrap.d.ts +0 -15
- package/dist/bootstrap.js +10 -409
- package/dist/cli/command-registry.d.ts +0 -58
- package/dist/cli/command-registry.js +2 -74
- package/dist/commands/accounts.d.ts +0 -17
- package/dist/commands/accounts.js +1 -52
- package/dist/commands/alias.d.ts +0 -12
- package/dist/commands/alias.js +0 -6
- package/dist/commands/apply.d.ts +0 -15
- package/dist/commands/apply.js +0 -63
- package/dist/commands/audit.d.ts +0 -12
- package/dist/commands/audit.js +0 -13
- package/dist/commands/auth.js +4 -12
- package/dist/commands/beta.d.ts +0 -6
- package/dist/commands/beta.js +2 -6
- package/dist/commands/browser-sessions-picker.d.ts +0 -8
- package/dist/commands/browser-sessions-picker.js +0 -26
- package/dist/commands/browser.d.ts +0 -57
- package/dist/commands/browser.js +0 -80
- package/dist/commands/budget.d.ts +0 -13
- package/dist/commands/budget.js +0 -2
- package/dist/commands/cli.d.ts +0 -12
- package/dist/commands/cli.js +0 -4
- package/dist/commands/cloud.d.ts +0 -9
- package/dist/commands/cloud.js +0 -43
- package/dist/commands/commands.d.ts +0 -9
- package/dist/commands/commands.js +0 -18
- package/dist/commands/computer-sessions-picker.d.ts +0 -11
- package/dist/commands/computer-sessions-picker.js +0 -29
- package/dist/commands/computer.d.ts +0 -62
- package/dist/commands/computer.js +3 -114
- package/dist/commands/config.d.ts +0 -14
- package/dist/commands/config.js +21 -60
- package/dist/commands/cost.d.ts +0 -11
- package/dist/commands/cost.js +1 -17
- package/dist/commands/daemon-test-harness.d.ts +0 -32
- package/dist/commands/daemon-test-harness.js +1 -36
- package/dist/commands/daemon.d.ts +0 -46
- package/dist/commands/daemon.js +8 -255
- package/dist/commands/detach-core.d.ts +0 -28
- package/dist/commands/detach-core.js +0 -30
- package/dist/commands/detach.d.ts +1 -12
- package/dist/commands/detach.js +16 -52
- package/dist/commands/device-config-test-harness.js +0 -12
- package/dist/commands/doctor.d.ts +0 -103
- package/dist/commands/doctor.js +3 -279
- package/dist/commands/events.d.ts +0 -29
- package/dist/commands/events.js +1 -55
- package/dist/commands/exec.d.ts +0 -163
- package/dist/commands/exec.js +15 -964
- package/dist/commands/factory.d.ts +0 -6
- package/dist/commands/factory.js +0 -2
- package/dist/commands/feed-watch.js +0 -20
- package/dist/commands/feed.d.ts +0 -38
- package/dist/commands/feed.js +1 -151
- package/dist/commands/feedback.d.ts +0 -5
- package/dist/commands/feedback.js +0 -5
- package/dist/commands/fleet-capture.d.ts +0 -12
- package/dist/commands/fleet-capture.js +1 -39
- package/dist/commands/focus.d.ts +6 -94
- package/dist/commands/focus.js +13 -183
- package/dist/commands/fork.d.ts +0 -21
- package/dist/commands/fork.js +0 -45
- package/dist/commands/funnel.d.ts +0 -3
- package/dist/commands/go.d.ts +2 -71
- package/dist/commands/go.js +5 -99
- package/dist/commands/harness-hooks.d.ts +0 -41
- package/dist/commands/harness-hooks.js +0 -48
- package/dist/commands/harness-wizard.d.ts +0 -137
- package/dist/commands/harness-wizard.js +0 -109
- package/dist/commands/harness.d.ts +0 -63
- package/dist/commands/harness.js +0 -103
- package/dist/commands/hooks.d.ts +0 -9
- package/dist/commands/hooks.js +0 -26
- package/dist/commands/humans.d.ts +0 -8
- package/dist/commands/humans.js +0 -8
- package/dist/commands/import.d.ts +0 -22
- package/dist/commands/import.js +0 -79
- package/dist/commands/insights.d.ts +0 -37
- package/dist/commands/insights.js +3 -115
- package/dist/commands/inspect.d.ts +0 -117
- package/dist/commands/inspect.js +2 -448
- package/dist/commands/lease.d.ts +0 -28
- package/dist/commands/lease.js +0 -43
- package/dist/commands/logs.d.ts +0 -23
- package/dist/commands/logs.js +0 -30
- package/dist/commands/mailboxes.d.ts +0 -18
- package/dist/commands/mailboxes.js +0 -29
- package/dist/commands/mcp.d.ts +0 -9
- package/dist/commands/mcp.js +0 -53
- package/dist/commands/memory.d.ts +0 -7
- package/dist/commands/memory.js +0 -7
- package/dist/commands/menubar.d.ts +0 -8
- package/dist/commands/menubar.js +0 -24
- package/dist/commands/message.d.ts +0 -23
- package/dist/commands/message.js +0 -50
- package/dist/commands/mine.d.ts +0 -22
- package/dist/commands/mine.js +0 -21
- package/dist/commands/models.d.ts +0 -8
- package/dist/commands/models.js +0 -33
- package/dist/commands/modes.d.ts +0 -10
- package/dist/commands/modes.js +0 -13
- package/dist/commands/monitors.d.ts +0 -9
- package/dist/commands/monitors.js +3 -160
- package/dist/commands/open.d.ts +0 -26
- package/dist/commands/open.js +0 -10
- package/dist/commands/output.d.ts +0 -18
- package/dist/commands/output.js +1 -34
- package/dist/commands/packages-materialize.d.ts +0 -11
- package/dist/commands/packages-materialize.js +0 -3
- package/dist/commands/packages.d.ts +0 -10
- package/dist/commands/packages.js +0 -50
- package/dist/commands/perf.d.ts +0 -41
- package/dist/commands/perf.js +0 -55
- package/dist/commands/permissions.d.ts +0 -9
- package/dist/commands/permissions.js +0 -43
- package/dist/commands/plugins.d.ts +0 -14
- package/dist/commands/plugins.js +2 -55
- package/dist/commands/profiles.d.ts +0 -25
- package/dist/commands/profiles.js +0 -27
- package/dist/commands/projects-todo.d.ts +2 -0
- package/dist/commands/projects-todo.js +132 -0
- package/dist/commands/projects.d.ts +0 -85
- package/dist/commands/projects.js +344 -291
- package/dist/commands/prune.js +0 -30
- package/dist/commands/ps-roster.d.ts +92 -0
- package/dist/commands/ps-roster.js +744 -0
- package/dist/commands/ps.d.ts +6 -0
- package/dist/commands/ps.js +98 -0
- package/dist/commands/refresh-rules.d.ts +0 -13
- package/dist/commands/refresh-rules.js +0 -14
- package/dist/commands/reminders.d.ts +0 -7
- package/dist/commands/repo.d.ts +0 -89
- package/dist/commands/repo.js +7 -205
- package/dist/commands/resource-view.d.ts +0 -33
- package/dist/commands/resource-view.js +0 -49
- package/dist/commands/resume.d.ts +1 -19
- package/dist/commands/resume.js +0 -50
- package/dist/commands/route.d.ts +0 -10
- package/dist/commands/route.js +0 -19
- package/dist/commands/routines.d.ts +0 -42
- package/dist/commands/routines.js +5 -290
- package/dist/commands/routines.test-fixture.d.ts +0 -34
- package/dist/commands/routines.test-fixture.js +4 -100
- package/dist/commands/rules.d.ts +0 -9
- package/dist/commands/rules.js +1 -6
- package/dist/commands/run-account-picker.d.ts +0 -59
- package/dist/commands/run-account-picker.js +0 -71
- package/dist/commands/run-broadcast.d.ts +0 -9
- package/dist/commands/run-broadcast.js +0 -7
- package/dist/commands/run-cloud.d.ts +0 -15
- package/dist/commands/run-cloud.js +0 -37
- package/dist/commands/run-device-picker.d.ts +0 -25
- package/dist/commands/run-device-picker.js +1 -53
- package/dist/commands/secrets-passthrough.d.ts +0 -31
- package/dist/commands/secrets-passthrough.js +0 -10
- package/dist/commands/send.d.ts +0 -20
- package/dist/commands/send.js +14 -18
- package/dist/commands/sessions-backfill.d.ts +0 -7
- package/dist/commands/sessions-backfill.js +1 -16
- package/dist/commands/sessions-backup-setup.js +0 -11
- package/dist/commands/sessions-bookmark.d.ts +0 -8
- package/dist/commands/sessions-bookmark.js +0 -28
- package/dist/commands/sessions-browser.d.ts +2 -117
- package/dist/commands/sessions-browser.js +5 -243
- package/dist/commands/sessions-export.d.ts +1 -26
- package/dist/commands/sessions-export.js +3 -81
- package/dist/commands/sessions-import.d.ts +0 -14
- package/dist/commands/sessions-import.js +0 -59
- package/dist/commands/sessions-inject.d.ts +0 -60
- package/dist/commands/sessions-inject.js +3 -96
- package/dist/commands/sessions-migrate.d.ts +2 -37
- package/dist/commands/sessions-migrate.js +7 -159
- package/dist/commands/sessions-optimize.d.ts +0 -12
- package/dist/commands/sessions-picker-factory.d.ts +0 -7
- package/dist/commands/sessions-picker-factory.js +0 -8
- package/dist/commands/sessions-picker.d.ts +4 -103
- package/dist/commands/sessions-picker.js +13 -352
- package/dist/commands/sessions-render.d.ts +1 -2
- package/dist/commands/sessions-render.js +3 -7
- package/dist/commands/sessions-resume.d.ts +1 -24
- package/dist/commands/sessions-resume.js +2 -65
- package/dist/commands/sessions-share.d.ts +1 -9
- package/dist/commands/sessions-share.js +1 -45
- package/dist/commands/sessions-stats.d.ts +0 -24
- package/dist/commands/sessions-stats.js +0 -49
- package/dist/commands/sessions-stop.d.ts +1 -20
- package/dist/commands/sessions-stop.js +4 -9
- package/dist/commands/sessions-tail.d.ts +1 -19
- package/dist/commands/sessions-tail.js +3 -36
- package/dist/commands/sessions-trace.d.ts +5 -36
- package/dist/commands/sessions-trace.js +7 -82
- package/dist/commands/sessions.d.ts +1 -666
- package/dist/commands/sessions.js +30 -2279
- package/dist/commands/sessions.test-fixture.d.ts +0 -9
- package/dist/commands/sessions.test-fixture.js +8 -23
- package/dist/commands/setup-accounts.d.ts +0 -6
- package/dist/commands/setup-browser.d.ts +0 -23
- package/dist/commands/setup-browser.js +0 -28
- package/dist/commands/setup-computer.d.ts +0 -16
- package/dist/commands/setup-computer.js +0 -28
- package/dist/commands/setup-fleet.d.ts +0 -8
- package/dist/commands/setup-fleet.js +0 -11
- package/dist/commands/setup-mine.d.ts +0 -14
- package/dist/commands/setup-mine.js +0 -25
- package/dist/commands/setup-preferences.d.ts +0 -47
- package/dist/commands/setup-preferences.js +0 -53
- package/dist/commands/setup-secrets.d.ts +2 -24
- package/dist/commands/setup-secrets.js +0 -24
- package/dist/commands/setup-term.d.ts +0 -21
- package/dist/commands/setup-term.js +0 -21
- package/dist/commands/setup-terminal.d.ts +0 -1
- package/dist/commands/setup-terminal.js +0 -1
- package/dist/commands/setup-tools.d.ts +2 -0
- package/dist/commands/setup-tools.js +73 -0
- package/dist/commands/setup.d.ts +0 -20
- package/dist/commands/setup.js +4 -57
- package/dist/commands/skills.d.ts +0 -9
- package/dist/commands/skills.js +1 -22
- package/dist/commands/snapshot.d.ts +0 -9
- package/dist/commands/snapshot.js +0 -10
- package/dist/commands/ssh.d.ts +0 -64
- package/dist/commands/ssh.js +9 -420
- package/dist/commands/status.d.ts +0 -12
- package/dist/commands/status.js +0 -26
- package/dist/commands/subagents.d.ts +0 -8
- package/dist/commands/subagents.js +0 -31
- package/dist/commands/sync.d.ts +0 -37
- package/dist/commands/sync.js +0 -256
- package/dist/commands/teams-picker.d.ts +0 -3
- package/dist/commands/teams-picker.js +0 -34
- package/dist/commands/teams.d.ts +1 -76
- package/dist/commands/teams.js +9 -477
- package/dist/commands/tmux.d.ts +0 -25
- package/dist/commands/tmux.js +0 -46
- package/dist/commands/traces.js +0 -19
- package/dist/commands/trash.d.ts +0 -17
- package/dist/commands/trash.js +1 -11
- package/dist/commands/uninstall.d.ts +0 -9
- package/dist/commands/uninstall.js +0 -6
- package/dist/commands/update.d.ts +0 -22
- package/dist/commands/update.js +0 -44
- package/dist/commands/upgrade.d.ts +0 -1
- package/dist/commands/upgrade.js +0 -1
- package/dist/commands/utils.d.ts +0 -85
- package/dist/commands/utils.js +1 -95
- package/dist/commands/versions.d.ts +0 -16
- package/dist/commands/versions.js +0 -134
- package/dist/commands/view.d.ts +0 -90
- package/dist/commands/view.js +4 -343
- package/dist/commands/watchdog.d.ts +0 -19
- package/dist/commands/watchdog.js +3 -43
- package/dist/commands/webhook.d.ts +0 -8
- package/dist/commands/webhook.js +0 -14
- package/dist/commands/workflows.d.ts +0 -8
- package/dist/commands/workflows.js +0 -6
- package/dist/index.d.ts +0 -25
- package/dist/index.js +5 -119
- package/dist/lib/account-capabilities.d.ts +0 -34
- package/dist/lib/account-capabilities.js +0 -32
- package/dist/lib/account-catalog.d.ts +0 -128
- package/dist/lib/account-catalog.js +8 -154
- package/dist/lib/account-provider-registry.d.ts +0 -14
- package/dist/lib/account-provider-registry.js +0 -8
- package/dist/lib/account-registry.d.ts +0 -74
- package/dist/lib/account-registry.js +14 -189
- package/dist/lib/account-schema.d.ts +0 -19
- package/dist/lib/account-schema.js +0 -43
- package/dist/lib/accounting/account-launch.d.ts +0 -15
- package/dist/lib/accounting/account-launch.js +1 -3
- package/dist/lib/accounting/account-pool-collect.d.ts +0 -26
- package/dist/lib/accounting/account-pool-collect.js +0 -42
- package/dist/lib/accounting/account-pool.d.ts +0 -41
- package/dist/lib/accounting/account-pool.js +0 -17
- package/dist/lib/accounting/capacity.d.ts +0 -32
- package/dist/lib/accounting/capacity.js +0 -32
- package/dist/lib/accounting/rotate.d.ts +0 -518
- package/dist/lib/accounting/rotate.js +4 -598
- package/dist/lib/accounting/usage-ingest.d.ts +0 -1
- package/dist/lib/accounting/usage-ingest.js +0 -44
- package/dist/lib/accounting/usage-sync.d.ts +0 -60
- package/dist/lib/accounting/usage-sync.js +4 -51
- package/dist/lib/accounting/usage.d.ts +0 -632
- package/dist/lib/accounting/usage.js +14 -1055
- package/dist/lib/accounts/add.d.ts +0 -60
- package/dist/lib/accounts/add.js +0 -127
- package/dist/lib/accounts/auth-operation-lock.d.ts +0 -1
- package/dist/lib/accounts/auth-operation-lock.js +0 -4
- package/dist/lib/accounts/migrate.d.ts +0 -9
- package/dist/lib/accounts/migrate.js +3 -42
- package/dist/lib/accounts/slots.d.ts +0 -25
- package/dist/lib/accounts/slots.js +1 -49
- package/dist/lib/acp/client.d.ts +0 -16
- package/dist/lib/acp/client.js +0 -29
- package/dist/lib/acp/harnesses.d.ts +0 -15
- package/dist/lib/acp/harnesses.js +0 -16
- package/dist/lib/acp/run.d.ts +0 -8
- package/dist/lib/acp/run.js +0 -8
- package/dist/lib/actor.d.ts +1 -71
- package/dist/lib/actor.js +1 -99
- package/dist/lib/add-dir.d.ts +0 -46
- package/dist/lib/add-dir.js +1 -70
- package/dist/lib/address.d.ts +0 -17
- package/dist/lib/address.js +0 -15
- package/dist/lib/agent-cli-commands.d.ts +0 -10
- package/dist/lib/agent-cli-commands.js +0 -10
- package/dist/lib/agent-modes.d.ts +0 -29
- package/dist/lib/agent-modes.js +0 -31
- package/dist/lib/agent-spec/agents.d.ts +0 -426
- package/dist/lib/agent-spec/agents.js +37 -924
- package/dist/lib/agent-spec/index.d.ts +0 -5
- package/dist/lib/agent-spec/index.js +0 -14
- package/dist/lib/agent-spec/materialize.d.ts +0 -10
- package/dist/lib/agent-spec/materialize.js +2 -139
- package/dist/lib/agent-spec/package-resolve.d.ts +0 -8
- package/dist/lib/agent-spec/package-resolve.js +1 -44
- package/dist/lib/agent-spec/package-schema.d.ts +0 -2
- package/dist/lib/agent-spec/package-schema.js +0 -11
- package/dist/lib/agent-spec/package-types.d.ts +0 -27
- package/dist/lib/agent-spec/package-types.js +0 -1
- package/dist/lib/agent-spec/primitives.d.ts +0 -18
- package/dist/lib/agent-spec/primitives.js +0 -27
- package/dist/lib/agent-spec/provider.js +0 -2
- package/dist/lib/agent-spec/resolve.d.ts +0 -23
- package/dist/lib/agent-spec/resolve.js +0 -41
- package/dist/lib/agent-spec/types.d.ts +0 -34
- package/dist/lib/agent-spec/types.js +0 -6
- package/dist/lib/agents.d.ts +0 -1
- package/dist/lib/agents.js +0 -1
- package/dist/lib/analytics/mix-commands.d.ts +0 -23
- package/dist/lib/analytics/mix-commands.js +0 -26
- package/dist/lib/analytics/recipes.d.ts +0 -1
- package/dist/lib/analytics/recipes.js +5 -10
- package/dist/lib/analytics/usage-db.js +4 -6
- package/dist/lib/answer-router.d.ts +0 -61
- package/dist/lib/answer-router.js +0 -57
- package/dist/lib/app-bundle-install.d.ts +0 -13
- package/dist/lib/app-bundle-install.js +0 -50
- package/dist/lib/artifact-actions.d.ts +0 -15
- package/dist/lib/artifact-actions.js +0 -18
- package/dist/lib/artifacts-client.d.ts +0 -10
- package/dist/lib/artifacts-client.js +0 -17
- package/dist/lib/ask-classifier.d.ts +0 -38
- package/dist/lib/ask-classifier.js +0 -27
- package/dist/lib/audit/log.d.ts +0 -47
- package/dist/lib/audit/log.js +1 -59
- package/dist/lib/auth-health.d.ts +0 -213
- package/dist/lib/auth-health.js +16 -266
- package/dist/lib/auth-mint.d.ts +0 -83
- package/dist/lib/auth-mint.js +8 -85
- package/dist/lib/auto-pull-worker.d.ts +0 -10
- package/dist/lib/auto-pull-worker.js +3 -48
- package/dist/lib/auto-pull.d.ts +0 -64
- package/dist/lib/auto-pull.js +0 -79
- package/dist/lib/beta.d.ts +0 -9
- package/dist/lib/beta.js +0 -9
- package/dist/lib/binary-shadow.d.ts +0 -22
- package/dist/lib/binary-shadow.js +4 -34
- package/dist/lib/boot-profile.d.ts +0 -10
- package/dist/lib/boot-profile.js +1 -31
- package/dist/lib/brand.d.ts +0 -20
- package/dist/lib/brand.js +0 -50
- package/dist/lib/browser/context.d.ts +0 -54
- package/dist/lib/browser/context.js +0 -49
- package/dist/lib/browser/paths.d.ts +0 -21
- package/dist/lib/browser/paths.js +0 -26
- package/dist/lib/browser/record.d.ts +0 -34
- package/dist/lib/browser/record.js +0 -38
- package/dist/lib/browser/sessions-list.d.ts +1 -79
- package/dist/lib/browser/sessions-list.js +2 -98
- package/dist/lib/browser-client.d.ts +0 -112
- package/dist/lib/browser-client.js +1 -90
- package/dist/lib/budget/config.d.ts +0 -6
- package/dist/lib/budget/config.js +0 -29
- package/dist/lib/budget/enforce.d.ts +0 -50
- package/dist/lib/budget/enforce.js +0 -27
- package/dist/lib/budget/ledger.d.ts +0 -23
- package/dist/lib/budget/ledger.js +0 -28
- package/dist/lib/budget/live-cloud.d.ts +0 -26
- package/dist/lib/budget/live-cloud.js +0 -12
- package/dist/lib/budget/live-team.d.ts +0 -17
- package/dist/lib/budget/live-team.js +1 -35
- package/dist/lib/budget/preflight.d.ts +0 -51
- package/dist/lib/budget/preflight.js +0 -36
- package/dist/lib/byok-usage.d.ts +0 -20
- package/dist/lib/byok-usage.js +1 -24
- package/dist/lib/capabilities.d.ts +0 -24
- package/dist/lib/capabilities.js +0 -29
- package/dist/lib/catchup.d.ts +0 -87
- package/dist/lib/catchup.js +1 -81
- package/dist/lib/channels/owner-forward.d.ts +0 -70
- package/dist/lib/channels/owner-forward.js +1 -43
- package/dist/lib/channels/owner-sink.js +0 -21
- package/dist/lib/channels/providers/desktop.d.ts +0 -37
- package/dist/lib/channels/providers/desktop.js +0 -72
- package/dist/lib/channels/providers/index.d.ts +0 -1
- package/dist/lib/channels/providers/index.js +2 -6
- package/dist/lib/channels/providers/mailbox.js +0 -7
- package/dist/lib/channels/providers/openclaw-telegram.js +0 -8
- package/dist/lib/channels/providers/rush.d.ts +0 -2
- package/dist/lib/channels/providers/rush.js +0 -26
- package/dist/lib/channels/providers/session.d.ts +2 -0
- package/dist/lib/channels/providers/session.js +26 -0
- package/dist/lib/channels/registry.d.ts +0 -27
- package/dist/lib/channels/registry.js +0 -10
- package/dist/lib/channels/resolve.d.ts +0 -19
- package/dist/lib/channels/resolve.js +0 -2
- package/dist/lib/channels/send.d.ts +0 -50
- package/dist/lib/channels/send.js +0 -25
- package/dist/lib/checkpoint.d.ts +0 -36
- package/dist/lib/checkpoint.js +0 -28
- package/dist/lib/claude-account-token.d.ts +0 -98
- package/dist/lib/claude-account-token.js +7 -169
- package/dist/lib/claude-statusline.d.ts +0 -41
- package/dist/lib/claude-statusline.js +0 -68
- package/dist/lib/cli-entry.d.ts +0 -26
- package/dist/lib/cli-entry.js +1 -61
- package/dist/lib/cli-resources.d.ts +31 -89
- package/dist/lib/cli-resources.js +116 -152
- package/dist/lib/cloud/antigravity.d.ts +0 -29
- package/dist/lib/cloud/antigravity.js +0 -36
- package/dist/lib/cloud/codex.d.ts +0 -8
- package/dist/lib/cloud/codex.js +0 -41
- package/dist/lib/cloud/cursor.d.ts +0 -5
- package/dist/lib/cloud/cursor.js +2 -7
- package/dist/lib/cloud/dispatch.d.ts +0 -13
- package/dist/lib/cloud/dispatch.js +1 -48
- package/dist/lib/cloud/factory.d.ts +0 -52
- package/dist/lib/cloud/factory.js +3 -67
- package/dist/lib/cloud/host.d.ts +0 -39
- package/dist/lib/cloud/host.js +5 -48
- package/dist/lib/cloud/registry.d.ts +0 -25
- package/dist/lib/cloud/registry.js +0 -29
- package/dist/lib/cloud/rush.d.ts +0 -47
- package/dist/lib/cloud/rush.js +1 -82
- package/dist/lib/cloud/session-index.d.ts +0 -27
- package/dist/lib/cloud/session-index.js +1 -32
- package/dist/lib/cloud/store.d.ts +0 -18
- package/dist/lib/cloud/store.js +0 -28
- package/dist/lib/cloud/stream.d.ts +0 -14
- package/dist/lib/cloud/stream.js +0 -25
- package/dist/lib/cloud/types.d.ts +0 -168
- package/dist/lib/cloud/types.js +0 -46
- package/dist/lib/cloudflare/creds.d.ts +0 -2
- package/dist/lib/cloudflare/creds.js +0 -14
- package/dist/lib/cloudflare/provision.d.ts +0 -8
- package/dist/lib/cloudflare/provision.js +1 -19
- package/dist/lib/codex-home.d.ts +0 -60
- package/dist/lib/codex-home.js +2 -72
- package/dist/lib/codex-policy.d.ts +0 -10
- package/dist/lib/codex-policy.js +0 -13
- package/dist/lib/command-skills.d.ts +0 -10
- package/dist/lib/command-skills.js +0 -10
- package/dist/lib/commands.d.ts +0 -74
- package/dist/lib/commands.js +0 -112
- package/dist/lib/comms-render.d.ts +0 -5
- package/dist/lib/comms-render.js +0 -5
- package/dist/lib/computer/context.d.ts +0 -23
- package/dist/lib/computer/context.js +0 -14
- package/dist/lib/computer/policy.d.ts +0 -20
- package/dist/lib/computer/policy.js +0 -53
- package/dist/lib/computer/record.d.ts +0 -33
- package/dist/lib/computer/record.js +1 -48
- package/dist/lib/computer/sessions-list.d.ts +1 -128
- package/dist/lib/computer/sessions-list.js +6 -165
- package/dist/lib/computer-client.d.ts +0 -106
- package/dist/lib/computer-client.js +5 -86
- package/dist/lib/concurrency.d.ts +0 -14
- package/dist/lib/concurrency.js +0 -3
- package/dist/lib/config-drift.d.ts +0 -31
- package/dist/lib/config-drift.js +0 -32
- package/dist/lib/config-keys.d.ts +1 -65
- package/dist/lib/config-keys.js +6 -52
- package/dist/lib/config-transfer.d.ts +0 -14
- package/dist/lib/config-transfer.js +0 -26
- package/dist/lib/convert.d.ts +0 -17
- package/dist/lib/convert.js +0 -18
- package/dist/lib/crabbox/cli.d.ts +0 -156
- package/dist/lib/crabbox/cli.js +1 -188
- package/dist/lib/crabbox/config.d.ts +0 -18
- package/dist/lib/crabbox/config.js +1 -19
- package/dist/lib/crabbox/lease.d.ts +0 -93
- package/dist/lib/crabbox/lease.js +4 -148
- package/dist/lib/crabbox/progress.d.ts +0 -56
- package/dist/lib/crabbox/progress.js +2 -49
- package/dist/lib/crabbox/runtimes.d.ts +0 -94
- package/dist/lib/crabbox/runtimes.js +1 -111
- package/dist/lib/crabbox/setup-copy.d.ts +0 -64
- package/dist/lib/crabbox/setup-copy.js +1 -53
- package/dist/lib/daemon/account-state-daemon-service.d.ts +0 -48
- package/dist/lib/daemon/account-state-daemon-service.js +2 -63
- package/dist/lib/daemon/attention-notify-service.d.ts +0 -12
- package/dist/lib/daemon/attention-notify-service.js +1 -24
- package/dist/lib/daemon/auth-sync-service.d.ts +0 -28
- package/dist/lib/daemon/auth-sync-service.js +0 -56
- package/dist/lib/daemon/catchup-service.d.ts +0 -34
- package/dist/lib/daemon/catchup-service.js +0 -30
- package/dist/lib/daemon/daemon.d.ts +0 -374
- package/dist/lib/daemon/daemon.js +44 -1049
- package/dist/lib/daemon/daemon.test-fixture.d.ts +0 -19
- package/dist/lib/daemon/daemon.test-fixture.js +1 -24
- package/dist/lib/daemon/device-probe-service.d.ts +0 -16
- package/dist/lib/daemon/device-probe-service.js +0 -20
- package/dist/lib/daemon/feed-stream-service.d.ts +0 -15
- package/dist/lib/daemon/feed-stream-service.js +0 -20
- package/dist/lib/daemon/harness-update-service.d.ts +2 -61
- package/dist/lib/daemon/harness-update-service.js +6 -86
- package/dist/lib/daemon/heartbeat-service.d.ts +0 -1
- package/dist/lib/daemon/heartbeat-service.js +0 -1
- package/dist/lib/daemon/leaked-daemons.d.ts +0 -46
- package/dist/lib/daemon/leaked-daemons.js +2 -78
- package/dist/lib/daemon/monitor-engine-service.d.ts +0 -13
- package/dist/lib/daemon/monitor-engine-service.js +3 -15
- package/dist/lib/daemon/runner.d.ts +0 -194
- package/dist/lib/daemon/runner.js +39 -760
- package/dist/lib/daemon/self-heal-service.d.ts +18 -17
- package/dist/lib/daemon/self-heal-service.js +83 -37
- package/dist/lib/daemon/self-update-service.d.ts +1 -131
- package/dist/lib/daemon/self-update-service.js +26 -189
- package/dist/lib/daemon/service.d.ts +0 -73
- package/dist/lib/daemon/service.js +0 -34
- package/dist/lib/daemon/session-index-service.d.ts +0 -12
- package/dist/lib/daemon/session-index-service.js +0 -23
- package/dist/lib/daemon/session-state-service.d.ts +0 -8
- package/dist/lib/daemon/session-state-service.js +0 -8
- package/dist/lib/daemon/session-summarizer-service.d.ts +0 -14
- package/dist/lib/daemon/session-summarizer-service.js +1 -19
- package/dist/lib/daemon/session-title-service.d.ts +0 -25
- package/dist/lib/daemon/session-title-service.js +0 -32
- package/dist/lib/daemon/state-dir-check-service.d.ts +0 -24
- package/dist/lib/daemon/state-dir-check-service.js +0 -29
- package/dist/lib/daemon/supervisor.d.ts +0 -112
- package/dist/lib/daemon/supervisor.js +4 -147
- package/dist/lib/daemon/testdata/process-view-daemon.js +0 -2
- package/dist/lib/daemon/testdata/process-view-start.js +0 -5
- package/dist/lib/daemon/tmux-reap-service.d.ts +0 -1
- package/dist/lib/daemon/tmux-reap-service.js +0 -1
- package/dist/lib/daemon/usage-sync-service.d.ts +0 -23
- package/dist/lib/daemon/usage-sync-service.js +0 -26
- package/dist/lib/daemon/watchdog-service.d.ts +0 -9
- package/dist/lib/daemon/watchdog-service.js +0 -13
- package/dist/lib/daemon/webhook-receiver-service.d.ts +0 -1
- package/dist/lib/daemon/webhook-receiver-service.js +0 -1
- package/dist/lib/daemon-health.d.ts +0 -55
- package/dist/lib/daemon-health.js +4 -77
- package/dist/lib/daemon-services.d.ts +0 -36
- package/dist/lib/daemon-services.js +0 -45
- package/dist/lib/daemon-ticks.d.ts +0 -126
- package/dist/lib/daemon-ticks.js +1 -156
- package/dist/lib/daemon-webhooks.d.ts +0 -57
- package/dist/lib/daemon-webhooks.js +2 -54
- package/dist/lib/deeplink/register.d.ts +0 -15
- package/dist/lib/deeplink/register.js +0 -60
- package/dist/lib/deeplink/url.d.ts +0 -24
- package/dist/lib/deeplink/url.js +1 -33
- package/dist/lib/device-config.d.ts +1 -192
- package/dist/lib/device-config.js +86 -240
- package/dist/lib/devices/config-migration.d.ts +0 -43
- package/dist/lib/devices/config-migration.js +7 -127
- package/dist/lib/devices/connect.d.ts +0 -168
- package/dist/lib/devices/connect.js +6 -254
- package/dist/lib/devices/device-docs.d.ts +0 -24
- package/dist/lib/devices/device-docs.js +0 -46
- package/dist/lib/devices/discovery-policy.d.ts +0 -30
- package/dist/lib/devices/discovery-policy.js +3 -34
- package/dist/lib/devices/doctor-findings.d.ts +0 -109
- package/dist/lib/devices/doctor-findings.js +30 -326
- package/dist/lib/devices/doctor-overview-cache.d.ts +0 -33
- package/dist/lib/devices/doctor-overview-cache.js +0 -81
- package/dist/lib/devices/fleet-divergence.d.ts +0 -89
- package/dist/lib/devices/fleet-divergence.js +1 -60
- package/dist/lib/devices/fleet-inventory.d.ts +0 -27
- package/dist/lib/devices/fleet-inventory.js +0 -38
- package/dist/lib/devices/fleet.d.ts +0 -95
- package/dist/lib/devices/fleet.js +0 -79
- package/dist/lib/devices/harness-inventory.d.ts +0 -75
- package/dist/lib/devices/harness-inventory.js +0 -101
- package/dist/lib/devices/health-report.d.ts +0 -37
- package/dist/lib/devices/health-report.js +0 -73
- package/dist/lib/devices/health.d.ts +0 -71
- package/dist/lib/devices/health.js +2 -82
- package/dist/lib/devices/interactive-host.d.ts +0 -10
- package/dist/lib/devices/interactive-host.js +0 -34
- package/dist/lib/devices/known-hosts.d.ts +0 -45
- package/dist/lib/devices/known-hosts.js +0 -77
- package/dist/lib/devices/pending.d.ts +0 -31
- package/dist/lib/devices/pending.js +7 -67
- package/dist/lib/devices/pool.d.ts +0 -36
- package/dist/lib/devices/pool.js +0 -30
- package/dist/lib/devices/reachability.d.ts +0 -25
- package/dist/lib/devices/reachability.js +0 -14
- package/dist/lib/devices/registry.d.ts +0 -141
- package/dist/lib/devices/registry.js +4 -151
- package/dist/lib/devices/resolve-profile.d.ts +0 -18
- package/dist/lib/devices/resolve-profile.js +0 -18
- package/dist/lib/devices/resolve-target.d.ts +0 -20
- package/dist/lib/devices/resolve-target.js +1 -51
- package/dist/lib/devices/rollout-verify.d.ts +1 -81
- package/dist/lib/devices/rollout-verify.js +0 -77
- package/dist/lib/devices/self-host.d.ts +0 -7
- package/dist/lib/devices/self-host.js +1 -29
- package/dist/lib/devices/ssh-config.d.ts +0 -18
- package/dist/lib/devices/ssh-config.js +0 -9
- package/dist/lib/devices/stats-cache.d.ts +0 -48
- package/dist/lib/devices/stats-cache.js +0 -80
- package/dist/lib/devices/sync.d.ts +0 -97
- package/dist/lib/devices/sync.js +0 -88
- package/dist/lib/devices/tailscale.d.ts +0 -18
- package/dist/lib/devices/tailscale.js +1 -38
- package/dist/lib/devices/terminfo.d.ts +0 -27
- package/dist/lib/devices/terminfo.js +2 -64
- package/dist/lib/devices/worker-pick.d.ts +0 -15
- package/dist/lib/devices/worker-pick.js +0 -48
- package/dist/lib/diff-text.d.ts +0 -18
- package/dist/lib/diff-text.js +0 -15
- package/dist/lib/doctor-diff.d.ts +0 -79
- package/dist/lib/doctor-diff.js +2 -181
- package/dist/lib/drift-sync.d.ts +0 -29
- package/dist/lib/drift-sync.js +0 -40
- package/dist/lib/drift.d.ts +0 -43
- package/dist/lib/drift.js +0 -31
- package/dist/lib/event-families.d.ts +0 -17
- package/dist/lib/event-families.js +0 -33
- package/dist/lib/event-provenance.d.ts +0 -4
- package/dist/lib/event-provenance.js +0 -5
- package/dist/lib/event-stream.d.ts +0 -29
- package/dist/lib/event-stream.js +0 -36
- package/dist/lib/events-ingest.d.ts +0 -27
- package/dist/lib/events-ingest.js +0 -54
- package/dist/lib/exec-account-home.d.ts +0 -24
- package/dist/lib/exec-account-home.js +0 -41
- package/dist/lib/exec-bounded.d.ts +1 -37
- package/dist/lib/exec-bounded.js +10 -46
- package/dist/lib/exec.d.ts +3 -583
- package/dist/lib/exec.js +18 -1025
- package/dist/lib/factory/snapshot.js +1 -15
- package/dist/lib/feed/activity-stream.d.ts +0 -27
- package/dist/lib/feed/activity-stream.js +4 -80
- package/dist/lib/feed/activity.d.ts +1 -243
- package/dist/lib/feed/activity.js +8 -273
- package/dist/lib/feed/answer.d.ts +0 -103
- package/dist/lib/feed/answer.js +0 -267
- package/dist/lib/feed/attention.d.ts +0 -56
- package/dist/lib/feed/attention.js +0 -161
- package/dist/lib/feed/envelope.d.ts +2 -17
- package/dist/lib/feed/envelope.js +0 -14
- package/dist/lib/feed/events.d.ts +0 -118
- package/dist/lib/feed/events.js +13 -213
- package/dist/lib/feed/feed.d.ts +1 -250
- package/dist/lib/feed/feed.js +24 -334
- package/dist/lib/feed/hub-server.d.ts +0 -100
- package/dist/lib/feed/hub-server.js +1 -191
- package/dist/lib/feed/hub.d.ts +0 -53
- package/dist/lib/feed/hub.js +0 -89
- package/dist/lib/feed/pr-status.d.ts +1 -19
- package/dist/lib/feed/pr-status.js +0 -18
- package/dist/lib/feed/tool-activity.d.ts +0 -59
- package/dist/lib/feed/tool-activity.js +1 -119
- package/dist/lib/feed/tools.d.ts +0 -100
- package/dist/lib/feed/tools.js +0 -89
- package/dist/lib/feed/watch.d.ts +0 -33
- package/dist/lib/feed/watch.js +2 -94
- package/dist/lib/feed-broadcast.d.ts +0 -148
- package/dist/lib/feed-broadcast.js +1 -283
- package/dist/lib/feed-outcome.d.ts +0 -50
- package/dist/lib/feed-outcome.js +1 -67
- package/dist/lib/feed-policy.d.ts +0 -6
- package/dist/lib/feed-policy.js +1 -27
- package/dist/lib/feed-post.d.ts +0 -61
- package/dist/lib/feed-post.js +4 -61
- package/dist/lib/feed-ranking.d.ts +1 -1
- package/dist/lib/fleet/apply.d.ts +0 -64
- package/dist/lib/fleet/apply.js +0 -125
- package/dist/lib/fleet/auth-sync.d.ts +0 -48
- package/dist/lib/fleet/auth-sync.js +4 -49
- package/dist/lib/fleet/capture.d.ts +0 -26
- package/dist/lib/fleet/capture.js +1 -36
- package/dist/lib/fleet/manifest.d.ts +0 -38
- package/dist/lib/fleet/manifest.js +0 -40
- package/dist/lib/fleet/types.d.ts +1 -138
- package/dist/lib/fleet/types.js +0 -12
- package/dist/lib/fleet-cache.d.ts +0 -12
- package/dist/lib/fleet-cache.js +0 -24
- package/dist/lib/fleet-shared-state.d.ts +6 -59
- package/dist/lib/fleet-shared-state.js +5 -51
- package/dist/lib/fleet-status.d.ts +0 -27
- package/dist/lib/fleet-status.js +0 -48
- package/dist/lib/format.d.ts +0 -74
- package/dist/lib/format.js +3 -77
- package/dist/lib/friction-heuristics.d.ts +0 -20
- package/dist/lib/friction-heuristics.js +0 -8
- package/dist/lib/fs-atomic.d.ts +0 -51
- package/dist/lib/fs-atomic.js +8 -66
- package/dist/lib/fs-walk.d.ts +0 -13
- package/dist/lib/fs-walk.js +0 -22
- package/dist/lib/fuzzy.d.ts +0 -29
- package/dist/lib/fuzzy.js +0 -31
- package/dist/lib/gemini-settings.js +0 -12
- package/dist/lib/git.d.ts +0 -366
- package/dist/lib/git.js +7 -574
- package/dist/lib/github/ci-failure.d.ts +30 -0
- package/dist/lib/github/ci-failure.js +95 -0
- package/dist/lib/github/gh-overload.d.ts +0 -38
- package/dist/lib/github/gh-overload.js +3 -55
- package/dist/lib/github/pr-mergeable.d.ts +3 -34
- package/dist/lib/github/pr-mergeable.js +2 -42
- package/dist/lib/github/pr-verdict.d.ts +0 -44
- package/dist/lib/github/pr-verdict.js +0 -36
- package/dist/lib/github/project-prs.d.ts +135 -105
- package/dist/lib/github/project-prs.js +530 -170
- package/dist/lib/github/release-drift.d.ts +45 -0
- package/dist/lib/github/release-drift.js +91 -0
- package/dist/lib/github/rest.d.ts +0 -50
- package/dist/lib/github/rest.js +0 -49
- package/dist/lib/github/viewer.d.ts +27 -0
- package/dist/lib/github/viewer.js +101 -0
- package/dist/lib/goose-commands.d.ts +0 -29
- package/dist/lib/goose-commands.js +3 -48
- package/dist/lib/harness/adapter.d.ts +0 -151
- package/dist/lib/harness/adapter.js +0 -41
- package/dist/lib/harness/adapters/claude.d.ts +0 -8
- package/dist/lib/harness/adapters/claude.js +0 -89
- package/dist/lib/harness/adapters/codex.js +0 -18
- package/dist/lib/harness/adapters/copilot.js +0 -3
- package/dist/lib/harness/adapters/cursor.js +0 -16
- package/dist/lib/harness/adapters/droid.js +0 -3
- package/dist/lib/harness/adapters/kimi.js +0 -19
- package/dist/lib/harness/adapters/muse.js +0 -9
- package/dist/lib/harness/adapters/opencode.js +0 -2
- package/dist/lib/harness/exec-config-version.d.ts +0 -2
- package/dist/lib/harness/exec-config-version.js +0 -13
- package/dist/lib/harness/index.js +0 -10
- package/dist/lib/harness-auth-capabilities.d.ts +0 -26
- package/dist/lib/harness-auth-capabilities.js +0 -18
- package/dist/lib/harness-connection-test.d.ts +0 -27
- package/dist/lib/harness-connection-test.js +2 -20
- package/dist/lib/heal.d.ts +0 -45
- package/dist/lib/heal.js +2 -82
- package/dist/lib/help.d.ts +0 -32
- package/dist/lib/help.js +0 -41
- package/dist/lib/helper-download.d.ts +0 -85
- package/dist/lib/helper-download.js +0 -95
- package/dist/lib/helper-versions.d.ts +0 -51
- package/dist/lib/helper-versions.js +1 -45
- package/dist/lib/hooks/cache.d.ts +0 -40
- package/dist/lib/hooks/cache.js +8 -122
- package/dist/lib/hooks/install.d.ts +0 -253
- package/dist/lib/hooks/install.js +49 -822
- package/dist/lib/hooks/match.d.ts +0 -24
- package/dist/lib/hooks/match.js +0 -31
- package/dist/lib/hooks/profile.d.ts +0 -21
- package/dist/lib/hooks/profile.js +0 -28
- package/dist/lib/hosts/credential-transport.d.ts +0 -6
- package/dist/lib/hosts/credential-transport.js +0 -17
- package/dist/lib/hosts/credentials.d.ts +0 -35
- package/dist/lib/hosts/credentials.js +0 -38
- package/dist/lib/hosts/dispatch.d.ts +0 -140
- package/dist/lib/hosts/dispatch.js +0 -176
- package/dist/lib/hosts/logs.d.ts +0 -25
- package/dist/lib/hosts/logs.js +1 -51
- package/dist/lib/hosts/option.d.ts +0 -12
- package/dist/lib/hosts/option.js +0 -12
- package/dist/lib/hosts/passthrough.d.ts +0 -129
- package/dist/lib/hosts/passthrough.js +12 -249
- package/dist/lib/hosts/progress.d.ts +0 -90
- package/dist/lib/hosts/progress.js +5 -115
- package/dist/lib/hosts/providers/devices.d.ts +0 -19
- package/dist/lib/hosts/providers/devices.js +1 -34
- package/dist/lib/hosts/providers/local.d.ts +0 -14
- package/dist/lib/hosts/providers/local.js +0 -22
- package/dist/lib/hosts/ready.d.ts +0 -99
- package/dist/lib/hosts/ready.js +0 -101
- package/dist/lib/hosts/reconcile.d.ts +0 -38
- package/dist/lib/hosts/reconcile.js +1 -50
- package/dist/lib/hosts/reconnect.d.ts +0 -75
- package/dist/lib/hosts/reconnect.js +0 -98
- package/dist/lib/hosts/registry.d.ts +0 -74
- package/dist/lib/hosts/registry.js +0 -110
- package/dist/lib/hosts/remote-cmd.d.ts +1 -228
- package/dist/lib/hosts/remote-cmd.js +19 -294
- package/dist/lib/hosts/remote-cmd.test-fixture.d.ts +0 -1
- package/dist/lib/hosts/remote-cmd.test-fixture.js +0 -12
- package/dist/lib/hosts/remote-os.d.ts +0 -19
- package/dist/lib/hosts/remote-os.js +0 -22
- package/dist/lib/hosts/remote-session-id.d.ts +0 -22
- package/dist/lib/hosts/remote-session-id.js +0 -24
- package/dist/lib/hosts/routing-flag.d.ts +0 -21
- package/dist/lib/hosts/routing-flag.js +0 -21
- package/dist/lib/hosts/run-target.d.ts +0 -53
- package/dist/lib/hosts/run-target.js +0 -56
- package/dist/lib/hosts/session-index.d.ts +1 -53
- package/dist/lib/hosts/session-index.js +2 -59
- package/dist/lib/hosts/session-marker.d.ts +0 -31
- package/dist/lib/hosts/session-marker.js +0 -32
- package/dist/lib/hosts/ssh-config.d.ts +0 -25
- package/dist/lib/hosts/ssh-config.js +1 -32
- package/dist/lib/hosts/tasks.d.ts +0 -54
- package/dist/lib/hosts/tasks.js +0 -35
- package/dist/lib/hosts/types.d.ts +0 -39
- package/dist/lib/hosts/types.js +0 -22
- package/dist/lib/humans.d.ts +0 -21
- package/dist/lib/humans.js +0 -30
- package/dist/lib/identity/client.d.ts +1 -35
- package/dist/lib/identity/client.js +3 -29
- package/dist/lib/identity/index.d.ts +3 -27
- package/dist/lib/identity/index.js +8 -24
- package/dist/lib/import.d.ts +0 -104
- package/dist/lib/import.js +1 -137
- package/dist/lib/installations/active-check.d.ts +0 -53
- package/dist/lib/installations/active-check.js +0 -49
- package/dist/lib/installations/index.d.ts +0 -9
- package/dist/lib/installations/index.js +0 -9
- package/dist/lib/installations/installation-lock.js +0 -8
- package/dist/lib/installations/launch-gate.d.ts +0 -56
- package/dist/lib/installations/launch-gate.js +0 -83
- package/dist/lib/installations/migrate.d.ts +0 -100
- package/dist/lib/installations/migrate.js +105 -572
- package/dist/lib/installations/native-command.d.ts +0 -1
- package/dist/lib/installations/native-command.js +0 -6
- package/dist/lib/installations/resolve.d.ts +0 -24
- package/dist/lib/installations/resolve.js +0 -24
- package/dist/lib/installations/shims.d.ts +0 -395
- package/dist/lib/installations/shims.js +30 -957
- package/dist/lib/installations/store.d.ts +0 -199
- package/dist/lib/installations/store.js +1 -297
- package/dist/lib/installations/strategies.d.ts +0 -44
- package/dist/lib/installations/strategies.js +0 -87
- package/dist/lib/installations/types.d.ts +1 -67
- package/dist/lib/installations/types.js +0 -6
- package/dist/lib/installations/update-cancellation.d.ts +0 -74
- package/dist/lib/installations/update-cancellation.js +0 -74
- package/dist/lib/installations/update-policy.d.ts +0 -57
- package/dist/lib/installations/update-policy.js +0 -62
- package/dist/lib/installations/update-runtime.d.ts +0 -88
- package/dist/lib/installations/update-runtime.js +1 -127
- package/dist/lib/installations/update.d.ts +0 -53
- package/dist/lib/installations/update.js +0 -95
- package/dist/lib/installations/versions.d.ts +0 -310
- package/dist/lib/installations/versions.js +14 -837
- package/dist/lib/isolation-boundary-report.d.ts +0 -7
- package/dist/lib/isolation-boundary-report.js +0 -7
- package/dist/lib/launch-identity.d.ts +0 -8
- package/dist/lib/launch-identity.js +0 -8
- package/dist/lib/linear-autoclose.d.ts +0 -25
- package/dist/lib/linear-autoclose.js +0 -19
- package/dist/lib/linear-cache.d.ts +0 -57
- package/dist/lib/linear-cache.js +1 -81
- package/dist/lib/linear-project-counts.d.ts +0 -83
- package/dist/lib/linear-project-counts.js +2 -64
- package/dist/lib/linear-projects.d.ts +0 -62
- package/dist/lib/linear-projects.js +0 -85
- package/dist/lib/linear-rate-limit.d.ts +0 -21
- package/dist/lib/linear-rate-limit.js +1 -93
- package/dist/lib/linux-userns.d.ts +1 -42
- package/dist/lib/linux-userns.js +0 -47
- package/dist/lib/lock-compromise.d.ts +0 -7
- package/dist/lib/lock-compromise.js +0 -7
- package/dist/lib/log-follow.d.ts +0 -2
- package/dist/lib/log-follow.js +5 -15
- package/dist/lib/loop.d.ts +0 -106
- package/dist/lib/loop.js +0 -135
- package/dist/lib/machine-id.d.ts +0 -19
- package/dist/lib/machine-id.js +0 -19
- package/dist/lib/mailbox-gc.d.ts +0 -7
- package/dist/lib/mailbox-gc.js +0 -25
- package/dist/lib/mailbox-target.d.ts +0 -31
- package/dist/lib/mailbox-target.js +0 -27
- package/dist/lib/mailbox.d.ts +0 -77
- package/dist/lib/mailbox.js +5 -105
- package/dist/lib/manifest.d.ts +0 -4
- package/dist/lib/manifest.js +0 -36
- package/dist/lib/markdown.d.ts +0 -3
- package/dist/lib/markdown.js +0 -9
- package/dist/lib/mcp-registry.d.ts +1 -50
- package/dist/lib/mcp-registry.js +0 -64
- package/dist/lib/mcp.d.ts +0 -115
- package/dist/lib/mcp.js +3 -199
- package/dist/lib/memory-cache.d.ts +0 -11
- package/dist/lib/memory-cache.js +0 -9
- package/dist/lib/memory.d.ts +0 -52
- package/dist/lib/memory.js +12 -74
- package/dist/lib/menubar/download-menubar.d.ts +0 -35
- package/dist/lib/menubar/download-menubar.js +0 -38
- package/dist/lib/menubar/install-menubar.d.ts +0 -405
- package/dist/lib/menubar/install-menubar.js +25 -667
- package/dist/lib/menubar/migrate-prefs.d.ts +0 -47
- package/dist/lib/menubar/migrate-prefs.js +1 -70
- package/dist/lib/menubar/notify-desktop.d.ts +0 -82
- package/dist/lib/menubar/notify-desktop.js +0 -68
- package/dist/lib/menubar/resolve-version.d.ts +0 -41
- package/dist/lib/menubar/resolve-version.js +2 -44
- package/dist/lib/menubar/snapshot.d.ts +13 -66
- package/dist/lib/menubar/snapshot.js +45 -39
- package/dist/lib/merged-resources.d.ts +0 -10
- package/dist/lib/merged-resources.js +0 -10
- package/dist/lib/migrate-fold.d.ts +0 -31
- package/dist/lib/migrate-fold.js +6 -38
- package/dist/lib/model-tier-overrides.d.ts +0 -30
- package/dist/lib/model-tier-overrides.js +0 -14
- package/dist/lib/model-tiers.d.ts +0 -43
- package/dist/lib/model-tiers.js +5 -78
- package/dist/lib/models.d.ts +0 -145
- package/dist/lib/models.js +3 -333
- package/dist/lib/monitors/config.d.ts +0 -187
- package/dist/lib/monitors/config.js +4 -101
- package/dist/lib/monitors/dispatch.d.ts +0 -22
- package/dist/lib/monitors/dispatch.js +0 -35
- package/dist/lib/monitors/engine.d.ts +1 -53
- package/dist/lib/monitors/engine.js +17 -106
- package/dist/lib/monitors/fingerprint.d.ts +0 -43
- package/dist/lib/monitors/fingerprint.js +0 -57
- package/dist/lib/monitors/pid-watch.d.ts +0 -31
- package/dist/lib/monitors/pid-watch.js +0 -31
- package/dist/lib/monitors/remote.d.ts +0 -52
- package/dist/lib/monitors/remote.js +0 -42
- package/dist/lib/monitors/sources/command.d.ts +2 -9
- package/dist/lib/monitors/sources/command.js +13 -34
- package/dist/lib/monitors/sources/device.d.ts +0 -10
- package/dist/lib/monitors/sources/device.js +0 -14
- package/dist/lib/monitors/sources/failure.d.ts +0 -27
- package/dist/lib/monitors/sources/failure.js +0 -27
- package/dist/lib/monitors/sources/file.d.ts +0 -10
- package/dist/lib/monitors/sources/file.js +0 -11
- package/dist/lib/monitors/sources/http.d.ts +0 -7
- package/dist/lib/monitors/sources/http.js +0 -9
- package/dist/lib/monitors/sources/index.d.ts +0 -9
- package/dist/lib/monitors/sources/index.js +0 -9
- package/dist/lib/monitors/sources/poll.d.ts +0 -8
- package/dist/lib/monitors/sources/poll.js +0 -8
- package/dist/lib/monitors/sources/types.d.ts +0 -18
- package/dist/lib/monitors/sources/types.js +0 -8
- package/dist/lib/monitors/sources/webhook.d.ts +0 -7
- package/dist/lib/monitors/sources/webhook.js +0 -7
- package/dist/lib/monitors/sources/ws.d.ts +0 -10
- package/dist/lib/monitors/sources/ws.js +3 -13
- package/dist/lib/monitors/state.d.ts +0 -132
- package/dist/lib/monitors/state.js +2 -86
- package/dist/lib/native-accounts.d.ts +0 -32
- package/dist/lib/native-accounts.js +0 -17
- package/dist/lib/net-close.d.ts +0 -9
- package/dist/lib/net-close.js +0 -5
- package/dist/lib/notify.d.ts +0 -47
- package/dist/lib/notify.js +0 -30
- package/dist/lib/onepassword.d.ts +0 -14
- package/dist/lib/onepassword.js +0 -12
- package/dist/lib/open-url.d.ts +0 -38
- package/dist/lib/open-url.js +1 -69
- package/dist/lib/openclaw-keychain.js +2 -7
- package/dist/lib/operator.d.ts +0 -9
- package/dist/lib/operator.js +0 -34
- package/dist/lib/origin-machine.d.ts +0 -16
- package/dist/lib/origin-machine.js +0 -16
- package/dist/lib/output/git-output.d.ts +0 -31
- package/dist/lib/output/git-output.js +4 -43
- package/dist/lib/overdue.d.ts +0 -35
- package/dist/lib/overdue.js +0 -60
- package/dist/lib/owner-message.d.ts +0 -20
- package/dist/lib/owner-message.js +1 -40
- package/dist/lib/packages/output-home.d.ts +0 -28
- package/dist/lib/packages/output-home.js +0 -114
- package/dist/lib/paths.d.ts +0 -26
- package/dist/lib/paths.js +1 -27
- package/dist/lib/percentile.d.ts +0 -11
- package/dist/lib/percentile.js +0 -11
- package/dist/lib/perf/db.d.ts +0 -16
- package/dist/lib/perf/db.js +3 -32
- package/dist/lib/perf/spool.d.ts +0 -12
- package/dist/lib/perf/spool.js +0 -13
- package/dist/lib/perf/types.d.ts +0 -26
- package/dist/lib/perf/types.js +0 -1
- package/dist/lib/permissions-registry.d.ts +0 -48
- package/dist/lib/permissions-registry.js +0 -108
- package/dist/lib/permissions.d.ts +0 -215
- package/dist/lib/permissions.js +4 -407
- package/dist/lib/picker.d.ts +0 -124
- package/dist/lib/picker.js +0 -140
- package/dist/lib/placement.d.ts +0 -57
- package/dist/lib/placement.js +0 -47
- package/dist/lib/platform/exec.d.ts +0 -73
- package/dist/lib/platform/exec.js +0 -80
- package/dist/lib/platform/index.d.ts +0 -14
- package/dist/lib/platform/index.js +0 -14
- package/dist/lib/platform/ipc.d.ts +0 -10
- package/dist/lib/platform/ipc.js +0 -13
- package/dist/lib/platform/links.d.ts +0 -14
- package/dist/lib/platform/links.js +0 -25
- package/dist/lib/platform/paths.d.ts +0 -48
- package/dist/lib/platform/paths.js +0 -52
- package/dist/lib/platform/posixpath.d.ts +0 -18
- package/dist/lib/platform/posixpath.js +0 -62
- package/dist/lib/platform/process.d.ts +0 -67
- package/dist/lib/platform/process.js +5 -99
- package/dist/lib/platform/winpath.d.ts +0 -50
- package/dist/lib/platform/winpath.js +0 -81
- package/dist/lib/plugins/plugin-marketplace.d.ts +0 -165
- package/dist/lib/plugins/plugin-marketplace.js +10 -238
- package/dist/lib/plugins/plugins.d.ts +0 -238
- package/dist/lib/plugins/plugins.js +20 -454
- package/dist/lib/plugins/skills.d.ts +0 -86
- package/dist/lib/plugins/skills.js +1 -139
- package/dist/lib/pr-land-detach.d.ts +0 -17
- package/dist/lib/pr-land-detach.js +0 -30
- package/dist/lib/pricing/cost.d.ts +0 -29
- package/dist/lib/pricing/cost.js +0 -38
- package/dist/lib/pricing/index.d.ts +0 -6
- package/dist/lib/pricing/index.js +0 -6
- package/dist/lib/pricing/table.d.ts +0 -8
- package/dist/lib/pricing/table.js +3 -56
- package/dist/lib/probe.d.ts +0 -5
- package/dist/lib/probe.js +0 -40
- package/dist/lib/profiles-presets.d.ts +0 -20
- package/dist/lib/profiles-presets.js +1 -36
- package/dist/lib/profiles.d.ts +0 -185
- package/dist/lib/profiles.js +1 -158
- package/dist/lib/project-doctor.d.ts +0 -29
- package/dist/lib/project-doctor.js +0 -26
- package/dist/lib/project-focus.d.ts +0 -41
- package/dist/lib/project-focus.js +0 -49
- package/dist/lib/project-import.d.ts +0 -41
- package/dist/lib/project-import.js +0 -36
- package/dist/lib/project-key.d.ts +0 -65
- package/dist/lib/project-key.js +0 -70
- package/dist/lib/project-launch.d.ts +0 -49
- package/dist/lib/project-launch.js +2 -91
- package/dist/lib/project-probe.d.ts +0 -86
- package/dist/lib/project-probe.js +1 -88
- package/dist/lib/project-pull.d.ts +0 -96
- package/dist/lib/project-pull.js +0 -122
- package/dist/lib/project-resources.d.ts +0 -44
- package/dist/lib/project-resources.js +7 -171
- package/dist/lib/project-root.d.ts +0 -95
- package/dist/lib/project-root.js +0 -101
- package/dist/lib/project-schedule.d.ts +0 -43
- package/dist/lib/project-schedule.js +0 -52
- package/dist/lib/project-status.d.ts +0 -108
- package/dist/lib/project-status.js +0 -117
- package/dist/lib/projects.d.ts +0 -197
- package/dist/lib/projects.js +1 -213
- package/dist/lib/pwsh.d.ts +0 -41
- package/dist/lib/pwsh.js +0 -51
- package/dist/lib/quick-todo.d.ts +84 -0
- package/dist/lib/quick-todo.js +243 -0
- package/dist/lib/reconcile-and-repair.d.ts +0 -78
- package/dist/lib/reconcile-and-repair.js +3 -66
- package/dist/lib/redact.d.ts +0 -29
- package/dist/lib/redact.js +0 -54
- package/dist/lib/refresh-coordinator.d.ts +0 -15
- package/dist/lib/refresh-coordinator.js +0 -10
- package/dist/lib/refresh.d.ts +0 -39
- package/dist/lib/refresh.js +0 -45
- package/dist/lib/registry.d.ts +0 -65
- package/dist/lib/registry.js +0 -127
- package/dist/lib/reminders.d.ts +0 -21
- package/dist/lib/reminders.js +0 -30
- package/dist/lib/remote-agents-json.d.ts +0 -44
- package/dist/lib/remote-agents-json.js +1 -44
- package/dist/lib/reserved-stores.d.ts +0 -28
- package/dist/lib/reserved-stores.js +2 -28
- package/dist/lib/resource-aliases.d.ts +0 -12
- package/dist/lib/resource-aliases.js +0 -12
- package/dist/lib/resource-content-diff.d.ts +0 -28
- package/dist/lib/resource-content-diff.js +7 -34
- package/dist/lib/resource-inventory.d.ts +0 -51
- package/dist/lib/resource-inventory.js +0 -45
- package/dist/lib/resource-patterns.d.ts +0 -32
- package/dist/lib/resource-patterns.js +0 -34
- package/dist/lib/resource-profiles.d.ts +0 -7
- package/dist/lib/resource-profiles.js +0 -11
- package/dist/lib/resources/types.d.ts +0 -50
- package/dist/lib/resources/types.js +0 -7
- package/dist/lib/resources/workflows.d.ts +0 -7
- package/dist/lib/resources/workflows.js +0 -13
- package/dist/lib/resources.d.ts +0 -65
- package/dist/lib/resources.js +0 -78
- package/dist/lib/routers.d.ts +0 -67
- package/dist/lib/routers.js +0 -60
- package/dist/lib/routine-activation.d.ts +0 -23
- package/dist/lib/routine-activation.js +0 -24
- package/dist/lib/routine-context.d.ts +1 -91
- package/dist/lib/routine-context.js +0 -107
- package/dist/lib/routine-notify-owner.d.ts +0 -79
- package/dist/lib/routine-notify-owner.js +1 -103
- package/dist/lib/routine-notify.d.ts +0 -70
- package/dist/lib/routine-notify.js +1 -75
- package/dist/lib/routine-process-cleanup.d.ts +0 -1
- package/dist/lib/routine-process-cleanup.js +1 -4
- package/dist/lib/routine-readiness.d.ts +0 -63
- package/dist/lib/routine-readiness.js +4 -86
- package/dist/lib/routines-format.d.ts +0 -40
- package/dist/lib/routines-format.js +0 -67
- package/dist/lib/routines-placement.d.ts +0 -33
- package/dist/lib/routines-placement.js +0 -40
- package/dist/lib/routines-project.d.ts +0 -57
- package/dist/lib/routines-project.js +6 -80
- package/dist/lib/rules/compile.d.ts +0 -66
- package/dist/lib/rules/compile.js +6 -118
- package/dist/lib/rules/compose.d.ts +0 -56
- package/dist/lib/rules/compose.js +2 -83
- package/dist/lib/rules/rules.d.ts +0 -23
- package/dist/lib/rules/rules.js +0 -35
- package/dist/lib/rules/run-sync.d.ts +0 -16
- package/dist/lib/rules/run-sync.js +1 -44
- package/dist/lib/run-config.d.ts +0 -7
- package/dist/lib/run-config.js +0 -8
- package/dist/lib/run-defaults.d.ts +0 -14
- package/dist/lib/run-defaults.js +0 -14
- package/dist/lib/run-notify.d.ts +0 -18
- package/dist/lib/run-notify.js +0 -36
- package/dist/lib/run-trace-sync.d.ts +0 -21
- package/dist/lib/run-trace-sync.js +2 -66
- package/dist/lib/rush-session.d.ts +0 -26
- package/dist/lib/rush-session.js +0 -28
- package/dist/lib/sandbox.d.ts +0 -45
- package/dist/lib/sandbox.js +5 -93
- package/dist/lib/scheduler.d.ts +0 -28
- package/dist/lib/scheduler.js +0 -45
- package/dist/lib/scheduling/routines.d.ts +0 -652
- package/dist/lib/scheduling/routines.js +8 -475
- package/dist/lib/secrets-cli.d.ts +3 -8
- package/dist/lib/secrets-cli.js +1 -19
- package/dist/lib/secrets-client.d.ts +0 -117
- package/dist/lib/secrets-client.js +4 -275
- package/dist/lib/secrets-policy.d.ts +0 -142
- package/dist/lib/secrets-policy.js +4 -237
- package/dist/lib/secrets-types.d.ts +0 -87
- package/dist/lib/secrets-types.js +0 -13
- package/dist/lib/self-heal/checks/hook-manifest.js +0 -25
- package/dist/lib/self-heal/checks/hook-runtime.js +0 -5
- package/dist/lib/self-heal/checks/install-staging.d.ts +0 -1
- package/dist/lib/self-heal/checks/install-staging.js +1 -28
- package/dist/lib/self-heal/checks/menubar-helper.js +0 -5
- package/dist/lib/self-heal/checks/path.js +0 -9
- package/dist/lib/self-heal/checks/resources.js +0 -5
- package/dist/lib/self-heal/checks/shadowing.js +2 -16
- package/dist/lib/self-heal/checks/shims.js +0 -14
- package/dist/lib/self-heal/child.d.ts +12 -0
- package/dist/lib/self-heal/child.js +23 -0
- package/dist/lib/self-heal/registry.d.ts +0 -9
- package/dist/lib/self-heal/registry.js +0 -16
- package/dist/lib/self-heal/types.d.ts +0 -12
- package/dist/lib/self-heal/types.js +0 -15
- package/dist/lib/self-update.d.ts +0 -312
- package/dist/lib/self-update.js +9 -360
- package/dist/lib/service-manifest.d.ts +0 -39
- package/dist/lib/service-manifest.js +0 -72
- package/dist/lib/session/active.d.ts +13 -869
- package/dist/lib/session/active.js +20 -976
- package/dist/lib/session/actor-sidecar.d.ts +1 -32
- package/dist/lib/session/actor-sidecar.js +1 -41
- package/dist/lib/session/bookmarks.d.ts +0 -33
- package/dist/lib/session/bookmarks.js +0 -37
- package/dist/lib/session/bundle.d.ts +0 -86
- package/dist/lib/session/bundle.js +0 -54
- package/dist/lib/session/claude-accounts.d.ts +0 -40
- package/dist/lib/session/claude-accounts.js +0 -49
- package/dist/lib/session/cloud.d.ts +1 -23
- package/dist/lib/session/cloud.js +0 -26
- package/dist/lib/session/db.d.ts +5 -658
- package/dist/lib/session/db.js +22 -1443
- package/dist/lib/session/detached.d.ts +0 -21
- package/dist/lib/session/detached.js +0 -29
- package/dist/lib/session/discover.d.ts +3 -420
- package/dist/lib/session/discover.js +30 -1123
- package/dist/lib/session/fork.d.ts +1 -41
- package/dist/lib/session/fork.js +0 -19
- package/dist/lib/session/ghostty-tabs.d.ts +0 -24
- package/dist/lib/session/ghostty-tabs.js +0 -37
- package/dist/lib/session/glance-files.d.ts +19 -0
- package/dist/lib/session/glance-files.js +258 -0
- package/dist/lib/session/hook-sessions.d.ts +0 -33
- package/dist/lib/session/hook-sessions.js +4 -99
- package/dist/lib/session/host-link.d.ts +1 -94
- package/dist/lib/session/host-link.js +1 -81
- package/dist/lib/session/inject-target.d.ts +8 -0
- package/dist/lib/session/inject-target.js +32 -0
- package/dist/lib/session/inject.d.ts +0 -15
- package/dist/lib/session/inject.js +0 -15
- package/dist/lib/session/live-metadata.d.ts +1 -34
- package/dist/lib/session/live-metadata.js +1 -73
- package/dist/lib/session/local-tmux-attach.d.ts +0 -37
- package/dist/lib/session/local-tmux-attach.js +1 -76
- package/dist/lib/session/migrate-targets.d.ts +0 -46
- package/dist/lib/session/migrate-targets.js +0 -24
- package/dist/lib/session/migrations.d.ts +0 -12
- package/dist/lib/session/migrations.js +1 -20
- package/dist/lib/session/mirror.d.ts +0 -32
- package/dist/lib/session/mirror.js +0 -77
- package/dist/lib/session/origin-machine.js +0 -3
- package/dist/lib/session/pid-registry.d.ts +0 -80
- package/dist/lib/session/pid-registry.js +2 -81
- package/dist/lib/session/presence.d.ts +0 -39
- package/dist/lib/session/presence.js +2 -52
- package/dist/lib/session/process-view.d.ts +0 -11
- package/dist/lib/session/process-view.js +0 -25
- package/dist/lib/session/projection.d.ts +0 -3
- package/dist/lib/session/projection.js +0 -10
- package/dist/lib/session/provenance.d.ts +1 -37
- package/dist/lib/session/provenance.js +0 -69
- package/dist/lib/session/recovery.d.ts +1 -40
- package/dist/lib/session/recovery.js +2 -80
- package/dist/lib/session/relative-time.js +0 -3
- package/dist/lib/session/remote/peer-stream.d.ts +0 -42
- package/dist/lib/session/remote/peer-stream.js +0 -64
- package/dist/lib/session/remote/remote-bundle.d.ts +0 -6
- package/dist/lib/session/remote/remote-bundle.js +0 -21
- package/dist/lib/session/remote/remote-list.d.ts +1 -110
- package/dist/lib/session/remote/remote-list.js +5 -139
- package/dist/lib/session/remote/remote.d.ts +0 -98
- package/dist/lib/session/remote/remote.js +3 -119
- package/dist/lib/session/remote/watch.d.ts +1 -34
- package/dist/lib/session/remote/watch.js +12 -72
- package/dist/lib/session/remote-active.d.ts +0 -35
- package/dist/lib/session/remote-active.js +0 -48
- package/dist/lib/session/remote-bundle.js +0 -2
- package/dist/lib/session/remote-list.js +0 -2
- package/dist/lib/session/remote-preview-cache.d.ts +0 -7
- package/dist/lib/session/remote-preview-cache.js +1 -76
- package/dist/lib/session/remote.js +0 -2
- package/dist/lib/session/resume-command.d.ts +0 -6
- package/dist/lib/session/resume-command.js +0 -6
- package/dist/lib/session/resume-owner.d.ts +1 -52
- package/dist/lib/session/resume-owner.js +0 -56
- package/dist/lib/session/run-names.d.ts +0 -24
- package/dist/lib/session/run-names.js +0 -26
- package/dist/lib/session/session-cache.d.ts +2 -146
- package/dist/lib/session/session-cache.js +26 -203
- package/dist/lib/session/short-id.js +0 -3
- package/dist/lib/session/sync/agents.d.ts +0 -68
- package/dist/lib/session/sync/agents.js +0 -0
- package/dist/lib/session/sync/backend.d.ts +0 -39
- package/dist/lib/session/sync/backend.js +0 -45
- package/dist/lib/session/sync/config.d.ts +0 -27
- package/dist/lib/session/sync/config.js +0 -56
- package/dist/lib/session/sync/managed-config.d.ts +0 -17
- package/dist/lib/session/sync/managed-config.js +0 -17
- package/dist/lib/session/sync/managed-key.d.ts +0 -38
- package/dist/lib/session/sync/managed-key.js +1 -42
- package/dist/lib/session/sync/net-client.d.ts +0 -36
- package/dist/lib/session/sync/net-client.js +0 -30
- package/dist/lib/session/sync/provision.d.ts +0 -2
- package/dist/lib/session/sync/provision.js +0 -13
- package/dist/lib/session/sync/r2.d.ts +0 -20
- package/dist/lib/session/sync/r2.js +0 -20
- package/dist/lib/session/sync/transcript-crypto.d.ts +0 -37
- package/dist/lib/session/sync/transcript-crypto.js +5 -37
- package/dist/lib/session/sync/worker-template.d.ts +0 -5
- package/dist/lib/session/sync/worker-template.js +0 -40
- package/dist/lib/session/testdata/pid-registry-namespace.js +0 -2
- package/dist/lib/session/testdata/process-view-private.js +0 -1
- package/dist/lib/session/throughput.d.ts +0 -24
- package/dist/lib/session/throughput.js +1 -25
- package/dist/lib/session/timeline-pass.d.ts +1 -63
- package/dist/lib/session/timeline-pass.js +161 -148
- package/dist/lib/session/title.d.ts +0 -182
- package/dist/lib/session/title.js +0 -139
- package/dist/lib/session/tool-index.d.ts +2 -21
- package/dist/lib/session/tool-index.js +3 -75
- package/dist/lib/session/tool-store.d.ts +2 -48
- package/dist/lib/session/tool-store.js +1 -33
- package/dist/lib/session/viewing-in.d.ts +0 -67
- package/dist/lib/session/viewing-in.js +1 -71
- package/dist/lib/session/watch.js +0 -2
- package/dist/lib/session/width.js +0 -3
- package/dist/lib/sessions-client.d.ts +0 -46
- package/dist/lib/sessions-client.js +36 -113
- package/dist/lib/settings-manifest.d.ts +1 -17
- package/dist/lib/settings-manifest.js +4 -57
- package/dist/lib/setup-tool-install.d.ts +0 -1
- package/dist/lib/setup-tool-install.js +2 -7
- package/dist/lib/setup-tool-status.d.ts +0 -3
- package/dist/lib/setup-tool-status.js +4 -14
- package/dist/lib/sha256-asset.d.ts +0 -20
- package/dist/lib/sha256-asset.js +0 -20
- package/dist/lib/share-runtime.d.ts +0 -10
- package/dist/lib/share-runtime.js +1 -27
- package/dist/lib/shim-heal.d.ts +0 -15
- package/dist/lib/shim-heal.js +3 -29
- package/dist/lib/signin-badge.d.ts +0 -72
- package/dist/lib/signin-badge.js +0 -86
- package/dist/lib/sink-format.d.ts +0 -32
- package/dist/lib/sink-format.js +0 -14
- package/dist/lib/smart-launch.d.ts +0 -75
- package/dist/lib/smart-launch.js +1 -83
- package/dist/lib/snapshot.d.ts +0 -46
- package/dist/lib/snapshot.js +5 -31
- package/dist/lib/spinner.d.ts +0 -37
- package/dist/lib/spinner.js +0 -37
- package/dist/lib/sqlite.d.ts +0 -13
- package/dist/lib/sqlite.js +3 -71
- package/dist/lib/ssh-exec.d.ts +0 -209
- package/dist/lib/ssh-exec.js +11 -248
- package/dist/lib/ssh-tunnel.d.ts +0 -43
- package/dist/lib/ssh-tunnel.js +2 -48
- package/dist/lib/staleness/checkers/commands.d.ts +0 -4
- package/dist/lib/staleness/checkers/commands.js +0 -4
- package/dist/lib/staleness/checkers/hooks.d.ts +0 -10
- package/dist/lib/staleness/checkers/hooks.js +0 -15
- package/dist/lib/staleness/checkers/mcp.d.ts +0 -9
- package/dist/lib/staleness/checkers/mcp.js +0 -9
- package/dist/lib/staleness/checkers/permissions.d.ts +0 -12
- package/dist/lib/staleness/checkers/permissions.js +0 -13
- package/dist/lib/staleness/checkers/plugins.d.ts +0 -8
- package/dist/lib/staleness/checkers/plugins.js +0 -8
- package/dist/lib/staleness/checkers/rules.d.ts +0 -15
- package/dist/lib/staleness/checkers/rules.js +0 -26
- package/dist/lib/staleness/checkers/skills.d.ts +0 -4
- package/dist/lib/staleness/checkers/skills.js +0 -4
- package/dist/lib/staleness/checkers/subagents.d.ts +0 -9
- package/dist/lib/staleness/checkers/subagents.js +0 -9
- package/dist/lib/staleness/checkers/types.d.ts +0 -34
- package/dist/lib/staleness/checkers/types.js +0 -19
- package/dist/lib/staleness/checkers/workflows.d.ts +0 -7
- package/dist/lib/staleness/checkers/workflows.js +0 -7
- package/dist/lib/staleness/detectors/commands.js +0 -17
- package/dist/lib/staleness/detectors/hooks.js +1 -6
- package/dist/lib/staleness/detectors/mcp.js +0 -4
- package/dist/lib/staleness/detectors/permissions.js +10 -23
- package/dist/lib/staleness/detectors/rules.js +0 -6
- package/dist/lib/staleness/detectors/skills.d.ts +0 -1
- package/dist/lib/staleness/detectors/skills.js +1 -12
- package/dist/lib/staleness/detectors/types.d.ts +0 -10
- package/dist/lib/staleness/fingerprint.d.ts +0 -19
- package/dist/lib/staleness/fingerprint.js +0 -35
- package/dist/lib/staleness/index.d.ts +0 -28
- package/dist/lib/staleness/index.js +1 -45
- package/dist/lib/staleness/layers.d.ts +0 -23
- package/dist/lib/staleness/layers.js +0 -34
- package/dist/lib/staleness/prune.d.ts +0 -71
- package/dist/lib/staleness/prune.js +2 -27
- package/dist/lib/staleness/registry.d.ts +0 -10
- package/dist/lib/staleness/registry.js +3 -33
- package/dist/lib/staleness/types.d.ts +0 -36
- package/dist/lib/staleness/types.js +0 -5
- package/dist/lib/staleness/writers/commands.js +1 -48
- package/dist/lib/staleness/writers/hooks.js +1 -18
- package/dist/lib/staleness/writers/kinds.d.ts +0 -12
- package/dist/lib/staleness/writers/kinds.js +0 -1
- package/dist/lib/staleness/writers/lazy-map.d.ts +0 -11
- package/dist/lib/staleness/writers/mcp.js +0 -13
- package/dist/lib/staleness/writers/plugins.js +0 -4
- package/dist/lib/staleness/writers/rules.d.ts +0 -1
- package/dist/lib/staleness/writers/rules.js +1 -19
- package/dist/lib/staleness/writers/skills.js +3 -14
- package/dist/lib/staleness/writers/sources.d.ts +0 -11
- package/dist/lib/staleness/writers/sources.js +0 -32
- package/dist/lib/staleness/writers/subagents.js +0 -16
- package/dist/lib/staleness/writers/types.d.ts +0 -58
- package/dist/lib/staleness/writers/workflows.js +1 -1
- package/dist/lib/standalone-tools.d.ts +24 -0
- package/dist/lib/standalone-tools.js +58 -0
- package/dist/lib/star-nudge.d.ts +0 -32
- package/dist/lib/star-nudge.js +2 -36
- package/dist/lib/startup/command-registry.d.ts +0 -45
- package/dist/lib/startup/command-registry.js +1 -46
- package/dist/lib/startup/dev-build.d.ts +0 -9
- package/dist/lib/startup/dev-build.js +1 -42
- package/dist/lib/startup/root-command.d.ts +0 -19
- package/dist/lib/startup/root-command.js +0 -19
- package/dist/lib/startup/spellcheck.d.ts +0 -13
- package/dist/lib/startup/spellcheck.js +0 -13
- package/dist/lib/state.d.ts +0 -376
- package/dist/lib/state.js +19 -737
- package/dist/lib/storage/selection.d.ts +0 -40
- package/dist/lib/storage/selection.js +0 -29
- package/dist/lib/subagents-registry.d.ts +0 -56
- package/dist/lib/subagents-registry.js +0 -99
- package/dist/lib/subagents.d.ts +0 -128
- package/dist/lib/subagents.js +1 -158
- package/dist/lib/summarizer/config.d.ts +0 -37
- package/dist/lib/summarizer/config.js +0 -37
- package/dist/lib/summarizer/pass.d.ts +0 -20
- package/dist/lib/summarizer/pass.js +1 -34
- package/dist/lib/summarizer/summarize.d.ts +1 -49
- package/dist/lib/summarizer/summarize.js +0 -35
- package/dist/lib/sync-passphrase.d.ts +0 -16
- package/dist/lib/sync-passphrase.js +1 -18
- package/dist/lib/sync-status.d.ts +0 -72
- package/dist/lib/sync-status.js +0 -55
- package/dist/lib/sync-umbrella.d.ts +0 -54
- package/dist/lib/sync-umbrella.js +0 -48
- package/dist/lib/system-run-sync.d.ts +0 -5
- package/dist/lib/system-run-sync.js +1 -31
- package/dist/lib/teams/agents.d.ts +1 -444
- package/dist/lib/teams/agents.js +11 -871
- package/dist/lib/teams/api.d.ts +2 -52
- package/dist/lib/teams/api.js +4 -63
- package/dist/lib/teams/debug.d.ts +0 -6
- package/dist/lib/teams/debug.js +0 -6
- package/dist/lib/teams/delivery.d.ts +0 -41
- package/dist/lib/teams/delivery.js +0 -32
- package/dist/lib/teams/file_ops.d.ts +0 -11
- package/dist/lib/teams/file_ops.js +0 -11
- package/dist/lib/teams/forEach.d.ts +0 -76
- package/dist/lib/teams/forEach.js +1 -77
- package/dist/lib/teams/index.d.ts +1 -7
- package/dist/lib/teams/index.js +1 -7
- package/dist/lib/teams/parsers.d.ts +0 -4
- package/dist/lib/teams/parsers.js +0 -81
- package/dist/lib/teams/persistence.d.ts +0 -2
- package/dist/lib/teams/persistence.js +0 -12
- package/dist/lib/teams/placement-probe.d.ts +0 -12
- package/dist/lib/teams/placement-probe.js +1 -51
- package/dist/lib/teams/pr-watch.d.ts +0 -107
- package/dist/lib/teams/pr-watch.js +1 -107
- package/dist/lib/teams/registry.d.ts +0 -36
- package/dist/lib/teams/registry.js +0 -47
- package/dist/lib/teams/remoteWorktree.d.ts +0 -50
- package/dist/lib/teams/remoteWorktree.js +1 -96
- package/dist/lib/teams/scheduler.d.ts +0 -111
- package/dist/lib/teams/scheduler.js +2 -125
- package/dist/lib/teams/summarizer.d.ts +0 -22
- package/dist/lib/teams/summarizer.js +6 -50
- package/dist/lib/teams/supervisor.d.ts +0 -38
- package/dist/lib/teams/supervisor.js +0 -21
- package/dist/lib/teams/worktree.d.ts +0 -95
- package/dist/lib/teams/worktree.js +3 -110
- package/dist/lib/template.d.ts +0 -21
- package/dist/lib/template.js +0 -23
- package/dist/lib/term-client.d.ts +0 -26
- package/dist/lib/term-client.js +0 -48
- package/dist/lib/term-driver.d.ts +0 -5
- package/dist/lib/term-driver.js +0 -8
- package/dist/lib/terminal/backends/ghostty.d.ts +0 -2
- package/dist/lib/terminal/backends/ghostty.js +0 -12
- package/dist/lib/terminal/backends/index.d.ts +0 -17
- package/dist/lib/terminal/backends/index.js +0 -15
- package/dist/lib/terminal/backends/iterm.d.ts +0 -2
- package/dist/lib/terminal/backends/iterm.js +0 -10
- package/dist/lib/terminal/backends/terminal-app.d.ts +0 -10
- package/dist/lib/terminal/backends/terminal-app.js +0 -30
- package/dist/lib/terminal/backends/tmux.d.ts +0 -10
- package/dist/lib/terminal/backends/tmux.js +0 -2
- package/dist/lib/terminal/backends/vscodium-agent.d.ts +0 -25
- package/dist/lib/terminal/backends/vscodium-agent.js +0 -36
- package/dist/lib/terminal/engine.d.ts +0 -17
- package/dist/lib/terminal/engine.js +0 -10
- package/dist/lib/terminal/index.d.ts +0 -8
- package/dist/lib/terminal/inject.d.ts +1 -173
- package/dist/lib/terminal/inject.js +0 -146
- package/dist/lib/terminal/policy.d.ts +0 -8
- package/dist/lib/terminal/policy.js +0 -1
- package/dist/lib/terminal/preferred.d.ts +0 -66
- package/dist/lib/terminal/preferred.js +0 -30
- package/dist/lib/terminal/quote.d.ts +0 -8
- package/dist/lib/terminal/quote.js +0 -8
- package/dist/lib/terminal/resolve.d.ts +0 -46
- package/dist/lib/terminal/resolve.js +0 -30
- package/dist/lib/terminal/run-surface.d.ts +0 -56
- package/dist/lib/terminal/run-surface.js +0 -46
- package/dist/lib/terminal/shell.d.ts +0 -3
- package/dist/lib/terminal/shell.js +0 -13
- package/dist/lib/terminal/transport.d.ts +0 -14
- package/dist/lib/terminal/transport.js +1 -30
- package/dist/lib/terminal/types.d.ts +0 -40
- package/dist/lib/terminal/types.js +0 -10
- package/dist/lib/text/relative-time.d.ts +0 -36
- package/dist/lib/text/relative-time.js +0 -43
- package/dist/lib/text/short-id.d.ts +0 -16
- package/dist/lib/text/short-id.js +0 -16
- package/dist/lib/text/width.d.ts +0 -24
- package/dist/lib/text/width.js +10 -52
- package/dist/lib/tmux/binary.d.ts +0 -36
- package/dist/lib/tmux/binary.js +0 -28
- package/dist/lib/tmux/index.d.ts +0 -5
- package/dist/lib/tmux/index.js +0 -5
- package/dist/lib/tmux/orphan-reap.d.ts +0 -253
- package/dist/lib/tmux/orphan-reap.js +3 -299
- package/dist/lib/tmux/paths.d.ts +0 -14
- package/dist/lib/tmux/paths.js +0 -14
- package/dist/lib/tmux/session.d.ts +0 -263
- package/dist/lib/tmux/session.js +6 -344
- package/dist/lib/traces/backend.d.ts +0 -20
- package/dist/lib/traces/backend.js +0 -23
- package/dist/lib/traces/classify.d.ts +0 -20
- package/dist/lib/traces/classify.js +0 -7
- package/dist/lib/traces/insights.d.ts +1 -84
- package/dist/lib/traces/insights.js +0 -126
- package/dist/lib/traces/phenotype.d.ts +0 -69
- package/dist/lib/traces/phenotype.js +0 -150
- package/dist/lib/traces/provision.d.ts +0 -1
- package/dist/lib/traces/provision.js +0 -5
- package/dist/lib/traces/schema2-build.d.ts +3 -60
- package/dist/lib/traces/schema2-build.js +8 -149
- package/dist/lib/traces/schema2-danger.d.ts +0 -30
- package/dist/lib/traces/schema2-danger.js +1 -63
- package/dist/lib/traces/schema2.d.ts +0 -11
- package/dist/lib/traces/segments.d.ts +0 -44
- package/dist/lib/traces/segments.js +0 -65
- package/dist/lib/traces/sync.d.ts +2 -239
- package/dist/lib/traces/sync.js +15 -237
- package/dist/lib/traces/worker-template.d.ts +0 -3
- package/dist/lib/traces/worker-template.js +0 -29
- package/dist/lib/triggers/handlers.d.ts +0 -82
- package/dist/lib/triggers/handlers.js +0 -75
- package/dist/lib/triggers/webhook.d.ts +0 -158
- package/dist/lib/triggers/webhook.js +0 -143
- package/dist/lib/types.d.ts +0 -736
- package/dist/lib/types.js +0 -50
- package/dist/lib/uninstall.d.ts +0 -17
- package/dist/lib/uninstall.js +0 -75
- package/dist/lib/usage-backoff.d.ts +0 -20
- package/dist/lib/usage-backoff.js +3 -60
- package/dist/lib/usage-refresh.d.ts +0 -154
- package/dist/lib/usage-refresh.js +8 -212
- package/dist/lib/verbs.d.ts +0 -12
- package/dist/lib/verbs.js +0 -12
- package/dist/lib/version-duplicates.d.ts +0 -6
- package/dist/lib/version-duplicates.js +0 -6
- package/dist/lib/version.d.ts +0 -55
- package/dist/lib/version.js +1 -58
- package/dist/lib/view-types.d.ts +0 -48
- package/dist/lib/warn-unpushed.d.ts +0 -27
- package/dist/lib/warn-unpushed.js +1 -45
- package/dist/lib/watchdog/history.d.ts +0 -1
- package/dist/lib/watchdog/history.js +0 -3
- package/dist/lib/watchdog/index.js +0 -2
- package/dist/lib/watchdog/log.d.ts +0 -19
- package/dist/lib/watchdog/log.js +0 -34
- package/dist/lib/watchdog/read.d.ts +0 -27
- package/dist/lib/watchdog/read.js +3 -58
- package/dist/lib/watchdog/rotate.d.ts +0 -139
- package/dist/lib/watchdog/rotate.js +2 -151
- package/dist/lib/watchdog/runner.d.ts +0 -125
- package/dist/lib/watchdog/runner.js +3 -223
- package/dist/lib/watchdog/service.d.ts +0 -1
- package/dist/lib/watchdog/service.js +0 -2
- package/dist/lib/watchdog/watchdog-agent.d.ts +0 -31
- package/dist/lib/watchdog/watchdog-agent.js +0 -27
- package/dist/lib/watchdog/watchdog.d.ts +0 -7
- package/dist/lib/watchdog/watchdog.js +0 -10
- package/dist/lib/watchdog/watchdogTail.js +0 -7
- package/dist/lib/whats-new.d.ts +0 -10
- package/dist/lib/whats-new.js +0 -21
- package/dist/lib/workflows-registry.d.ts +0 -45
- package/dist/lib/workflows-registry.js +0 -60
- package/dist/lib/workflows.d.ts +0 -282
- package/dist/lib/workflows.js +3 -213
- package/dist/lib/worktree/held.d.ts +0 -89
- package/dist/lib/worktree/held.js +1 -103
- package/dist/lib/wrap.d.ts +0 -32
- package/dist/lib/wrap.js +0 -32
- package/dist/lib/yaml-io.d.ts +0 -45
- package/dist/lib/yaml-io.js +0 -47
- package/dist/session-tracker/dist/adapters/claude.js +0 -2
- package/dist/session-tracker/dist/hook.sh +4 -37
- package/dist/session-tracker/dist/index.d.ts +0 -7
- package/dist/session-tracker/dist/index.js +0 -5
- package/dist/session-tracker/dist/install-hook.d.ts +0 -5
- package/dist/session-tracker/dist/install-hook.js +1 -15
- package/dist/session-tracker/dist/prune-state.js +0 -4
- package/dist/session-tracker/dist/reader.js +0 -4
- package/dist/session-tracker/dist/state-file.d.ts +0 -3
- package/dist/session-tracker/dist/state-file.js +3 -8
- package/package.json +3 -4
- package/scripts/postinstall.js +8 -116
- package/dist/lib/session/artifacts.d.ts +0 -14
- package/dist/lib/session/artifacts.js +0 -101
- package/dist/lib/session/bash-command.d.ts +0 -63
- package/dist/lib/session/bash-command.js +0 -490
- package/dist/lib/session/digest.d.ts +0 -66
- package/dist/lib/session/digest.js +0 -328
- package/dist/lib/session/highlights.d.ts +0 -151
- package/dist/lib/session/highlights.js +0 -391
- package/dist/lib/session/insights.d.ts +0 -165
- package/dist/lib/session/insights.js +0 -563
- package/dist/lib/session/linear.d.ts +0 -19
- package/dist/lib/session/linear.js +0 -99
- package/dist/lib/session/parse.d.ts +0 -224
- package/dist/lib/session/parse.js +0 -2408
- package/dist/lib/session/prompt.d.ts +0 -213
- package/dist/lib/session/prompt.js +0 -601
- package/dist/lib/session/render.d.ts +0 -133
- package/dist/lib/session/render.js +0 -1047
- package/dist/lib/session/share-html.d.ts +0 -35
- package/dist/lib/session/share-html.js +0 -319
- package/dist/lib/session/shell-programs.d.ts +0 -33
- package/dist/lib/session/shell-programs.js +0 -380
- package/dist/lib/session/state.d.ts +0 -269
- package/dist/lib/session/state.js +0 -777
- package/dist/lib/session/stream-render.d.ts +0 -4
- package/dist/lib/session/stream-render.js +0 -131
- package/dist/lib/session/tail.d.ts +0 -88
- package/dist/lib/session/tail.js +0 -294
- package/dist/lib/session/team-filter.d.ts +0 -129
- package/dist/lib/session/team-filter.js +0 -269
- package/dist/lib/session/timeline.d.ts +0 -172
- package/dist/lib/session/timeline.js +0 -636
- package/dist/lib/session/tool-calls.d.ts +0 -132
- package/dist/lib/session/tool-calls.js +0 -674
- package/dist/lib/session/trajectory-compare.d.ts +0 -48
- package/dist/lib/session/trajectory-compare.js +0 -116
- package/dist/lib/session/trajectory-html.d.ts +0 -19
- package/dist/lib/session/trajectory-html.js +0 -771
- package/dist/lib/session/trajectory-lineage.d.ts +0 -93
- package/dist/lib/session/trajectory-lineage.js +0 -195
- package/dist/lib/session/trajectory-text.d.ts +0 -38
- package/dist/lib/session/trajectory-text.js +0 -284
- package/dist/lib/session/trajectory.d.ts +0 -145
- package/dist/lib/session/trajectory.js +0 -394
- package/dist/lib/session/types.d.ts +0 -627
- package/dist/lib/session/types.js +0 -43
package/dist/commands/exec.js
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Agent execution command.
|
|
3
|
-
*
|
|
4
|
-
* Registers the `agents run` command which spawns agent CLIs interactively
|
|
5
|
-
* or headlessly. Supports profile resolution, version rotation, secrets
|
|
6
|
-
* injection, and multi-agent fallback chains for rate-limit resilience.
|
|
7
|
-
*/
|
|
8
1
|
import { InvalidArgumentError, Option } from 'commander';
|
|
9
2
|
import chalk from 'chalk';
|
|
10
3
|
import { isTierToken } from '../lib/model-tiers.js';
|
|
@@ -26,28 +19,17 @@ import * as path from 'path';
|
|
|
26
19
|
import * as os from 'os';
|
|
27
20
|
import { spawnSync } from 'child_process';
|
|
28
21
|
import { randomUUID } from 'crypto';
|
|
29
|
-
import { isSessionTrackedAgent } from '
|
|
22
|
+
import { isSessionTrackedAgent } from '@phnx-labs/sessions-cli/reader';
|
|
30
23
|
import { applyActiveRulesPresetAtRun } from '../lib/rules/run-sync.js';
|
|
31
24
|
import { applySystemResourcesAtRun } from '../lib/system-run-sync.js';
|
|
32
25
|
import { handleBroadcast } from './run-broadcast.js';
|
|
33
26
|
import { bootMark } from '../lib/boot-profile.js';
|
|
34
|
-
/** Validate a caller-supplied session id before it reaches tmux, paths, indexes, or remote dispatch. */
|
|
35
27
|
export function parseExplicitSessionId(value) {
|
|
36
28
|
if (!/^[A-Za-z0-9._-]+$/.test(value)) {
|
|
37
29
|
throw new InvalidArgumentError('must contain only ASCII letters, digits, dots, underscores, or hyphens');
|
|
38
30
|
}
|
|
39
31
|
return value;
|
|
40
32
|
}
|
|
41
|
-
/**
|
|
42
|
-
* Parse the trailing picker markers on an `agents run` agent spec. A terminal
|
|
43
|
-
* run of `#`/`@` characters requests the account picker (`#`) and/or the
|
|
44
|
-
* device picker (`@`) — each at most once, in either order (`claude#@`,
|
|
45
|
-
* `claude@#`). Stripping them yields the normalized spec (`claude#work@` →
|
|
46
|
-
* `claude#work`, version pins and `#label` account pins intact). A picker
|
|
47
|
-
* cannot combine with an explicit pin of what it picks: `claude@2.1.218#`
|
|
48
|
-
* (the account picker already chooses the version — the old `claude@2.1.218@`
|
|
49
|
-
* rule), `claude#work#`, `claude@@`.
|
|
50
|
-
*/
|
|
51
33
|
export function parseRunPickerMarkers(agentSpec) {
|
|
52
34
|
let rest = agentSpec;
|
|
53
35
|
let accountPicker = false;
|
|
@@ -80,24 +62,9 @@ export function parseRunPickerMarkers(agentSpec) {
|
|
|
80
62
|
}
|
|
81
63
|
return { accountPicker, devicePicker, normalizedAgentSpec: rest, valid: reason === undefined, reason };
|
|
82
64
|
}
|
|
83
|
-
/**
|
|
84
|
-
* The `--device` alias family — the flags that mean "dispatch this run to another
|
|
85
|
-
* machine over SSH". `--device` is canonical; `--on`/`--computer` are hidden
|
|
86
|
-
* aliases. Returns the values actually given (so callers can both test presence
|
|
87
|
-
* and read the target). Kept in ONE place because a guard that listed only a
|
|
88
|
-
* subset silently let `--terminal --device` open a local tab and drop the remote
|
|
89
|
-
* target — the drift this predicate exists to prevent.
|
|
90
|
-
*/
|
|
91
65
|
export function hostTargetGiven(options) {
|
|
92
66
|
return [options.host, options.device, options.on, options.computer].filter((v) => !!v);
|
|
93
67
|
}
|
|
94
|
-
/**
|
|
95
|
-
* Turn a host target that names THIS machine into an explicit local pin: the
|
|
96
|
-
* host-family flags are cleared and `local` is set, so no dispatch path
|
|
97
|
-
* self-SSHes and the bare-interactive default (`bareInteractiveRunDefaultsToDeviceAuto`)
|
|
98
|
-
* sees a decided placement. Returns true when the pin was applied. Pure over
|
|
99
|
-
* the `isSelf` predicate so the rule is testable without a device registry.
|
|
100
|
-
*/
|
|
101
68
|
export function pinLocalWhenTargetIsSelf(options, isSelf) {
|
|
102
69
|
const targets = hostTargetGiven(options);
|
|
103
70
|
if (targets.length === 0 || !targets.every(isSelf))
|
|
@@ -109,11 +76,6 @@ export function pinLocalWhenTargetIsSelf(options, isSelf) {
|
|
|
109
76
|
options.local = true;
|
|
110
77
|
return true;
|
|
111
78
|
}
|
|
112
|
-
/**
|
|
113
|
-
* Return every option whose selection semantics conflict with an account
|
|
114
|
-
* choice (`agent#`). Device routing is deliberately absent: the marker rides
|
|
115
|
-
* the hop and the peer picks from ITS slots.
|
|
116
|
-
*/
|
|
117
79
|
export function runAccountPickerConflicts(options) {
|
|
118
80
|
const conflicts = [];
|
|
119
81
|
if (options.resume !== undefined)
|
|
@@ -130,11 +92,6 @@ export function runAccountPickerConflicts(options) {
|
|
|
130
92
|
conflicts.push(`--account ${options.account}`);
|
|
131
93
|
return conflicts;
|
|
132
94
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Return every option that already decides where the run lands, so a device
|
|
135
|
-
* choice (`agent@`) would be silently ignored: any explicit host flag, and the
|
|
136
|
-
* lease/box paths, which own placement outright.
|
|
137
|
-
*/
|
|
138
95
|
export function runDevicePickerConflicts(options) {
|
|
139
96
|
const conflicts = hostTargetGiven(options).map((h) => `--device ${h}`);
|
|
140
97
|
if (options.local)
|
|
@@ -145,30 +102,11 @@ export function runDevicePickerConflicts(options) {
|
|
|
145
102
|
conflicts.push('--box');
|
|
146
103
|
return conflicts;
|
|
147
104
|
}
|
|
148
|
-
/** Type guard that narrows a string to a known AgentId. */
|
|
149
105
|
function isValidAgent(agent) {
|
|
150
106
|
return agent in AGENTS;
|
|
151
107
|
}
|
|
152
|
-
// Reserved `<agent>` keyword for `agents run auto` — canonical definition in
|
|
153
|
-
// lib/types.ts (shared with the host dispatch layer); re-exported here.
|
|
154
108
|
export { RUN_AUTO_KEYWORD };
|
|
155
|
-
/**
|
|
156
|
-
* Whether `run auto` should default its host layer to the affinity pick (the
|
|
157
|
-
* same machinery as `--device auto`). False when the caller pinned any host
|
|
158
|
-
* flag, and false when this process was itself dispatched by a host run —
|
|
159
|
-
* the dispatcher exports AGENTS_RUN_AUTO_HOST_RESOLVED=1 into the remote SHELL
|
|
160
|
-
* (hosts/dispatch.ts remoteRunShellPrelude) because it already resolved the
|
|
161
|
-
* host layer, and re-picking here would chain-hop the run across the fleet.
|
|
162
|
-
* An INTERACTIVE dispatch of a named harness also reaches the remote as a bare
|
|
163
|
-
* `agents run <harness>` (its argv forwards without the routing flag), so the
|
|
164
|
-
* interactive prelude's AGENTS_REMOTE_INTERACTIVE=1 counts as "already placed"
|
|
165
|
-
* too — without it the remote would re-place the run and ping-pong across the
|
|
166
|
-
* fleet. Pure so the pinning matrix is unit-testable.
|
|
167
|
-
*/
|
|
168
109
|
export function runAutoDefaultsToAffinity(options, env = process.env) {
|
|
169
|
-
// An explicit local pin (--local, --where local, --device <this machine>)
|
|
170
|
-
// is a decided host layer with an empty host set; read it here so the
|
|
171
|
-
// `run auto` and bare-interactive defaults share one rule.
|
|
172
110
|
if (options.local)
|
|
173
111
|
return false;
|
|
174
112
|
if (hostTargetGiven(options).length > 0)
|
|
@@ -177,27 +115,6 @@ export function runAutoDefaultsToAffinity(options, env = process.env) {
|
|
|
177
115
|
return false;
|
|
178
116
|
return env.AGENTS_REMOTE_INTERACTIVE !== '1';
|
|
179
117
|
}
|
|
180
|
-
/**
|
|
181
|
-
* Whether a bare human-facing `agents run <harness>` — no prompt, so an
|
|
182
|
-
* interactive TUI run — defaults its placement to `--device auto` (PHNX-4083).
|
|
183
|
-
* A marker left off is decided for you: no `#` means balanced rotation, and no
|
|
184
|
-
* `@` (and no other placement flag) now means automatic device placement — the
|
|
185
|
-
* same engine as `--device auto`, whose pool never contains a box marked
|
|
186
|
-
* `personal`. ALL of these must hold:
|
|
187
|
-
*
|
|
188
|
-
* - no prompt (headless runs — teams, routines, hooks, `run <agent> "…"` —
|
|
189
|
-
* keep running in place, unchanged);
|
|
190
|
-
* - a human-facing surface: a real TTY and no `--json`. This is the same
|
|
191
|
-
* two-condition gate `signInLaunchDecision` uses in run-account-picker.ts —
|
|
192
|
-
* reused here through isHumanFacingRun, not re-derived;
|
|
193
|
-
* - no device-picker marker (`agent@` already chose the device; picking this
|
|
194
|
-
* machine there is a plain local run);
|
|
195
|
-
* - no `--resume` / `--lease` / `--box` / `--cloud` (those own placement);
|
|
196
|
-
* - the host layer is unpinned and this process is not itself a dispatched
|
|
197
|
-
* hop — delegated to runAutoDefaultsToAffinity, which encodes both.
|
|
198
|
-
*
|
|
199
|
-
* Pure so the default-placement matrix is unit-testable.
|
|
200
|
-
*/
|
|
201
118
|
export function bareInteractiveRunDefaultsToDeviceAuto(options, run, surface, env = process.env) {
|
|
202
119
|
if (run.prompt !== undefined)
|
|
203
120
|
return false;
|
|
@@ -209,15 +126,6 @@ export function bareInteractiveRunDefaultsToDeviceAuto(options, run, surface, en
|
|
|
209
126
|
return false;
|
|
210
127
|
return runAutoDefaultsToAffinity(options, env);
|
|
211
128
|
}
|
|
212
|
-
/**
|
|
213
|
-
* Whether an interactive host dispatch must mint a correlation launch id and
|
|
214
|
-
* resolve the remote session via the launch-id join (RUSH-2034), rather than
|
|
215
|
-
* trusting a pre-known session id. `run auto` ALWAYS joins: the harness is
|
|
216
|
-
* picked on the remote, so an explicit --session-id is only adopted when the
|
|
217
|
-
* pick lands on claude — pre-registering it would strand a stale session-index
|
|
218
|
-
* entry naming an id a non-claude pick never used (RUSH-2132). Pure so the
|
|
219
|
-
* decision matrix is unit-testable.
|
|
220
|
-
*/
|
|
221
129
|
export function hostInteractiveNeedsCorrelationId(runAgent, hostSessionId, resumeId) {
|
|
222
130
|
if (resumeId)
|
|
223
131
|
return false;
|
|
@@ -225,70 +133,39 @@ export function hostInteractiveNeedsCorrelationId(runAgent, hostSessionId, resum
|
|
|
225
133
|
return true;
|
|
226
134
|
return !hostSessionId && isSessionTrackedAgent(runAgent);
|
|
227
135
|
}
|
|
228
|
-
/** Build a one-line banner describing which version the strategy picked. */
|
|
229
136
|
function formatRotationBanner(result, verb = 'balanced') {
|
|
230
137
|
const { picked, healthy, excluded } = result;
|
|
231
138
|
const label = picked.email ? `${picked.email} · ${picked.agent}@${picked.version}` : `${picked.agent}@${picked.version}`;
|
|
232
139
|
const ratio = `${healthy.length} of ${healthy.length + excluded.length} healthy`;
|
|
233
|
-
// Say it when the pick was a guess. A machine whose usage refresh is failing
|
|
234
|
-
// reports old percentages with total confidence, so a silent banner reads
|
|
235
|
-
// identical whether the router knew the account had headroom or merely hoped
|
|
236
|
-
// so — and the operator only finds out when the agent answers "you've hit
|
|
237
|
-
// your weekly limit".
|
|
238
140
|
const caveat = result.usageUnverified ? ', usage unverified — no account could be refreshed' : '';
|
|
239
141
|
return `[agents] ${verb} picked ${label} (${ratio}${caveat})`;
|
|
240
142
|
}
|
|
241
|
-
/**
|
|
242
|
-
* Whether `cwd` is inside a git work tree.
|
|
243
|
-
*
|
|
244
|
-
* `--lease` / `--box` sync the working directory to the box through crabbox,
|
|
245
|
-
* which enumerates the files to copy with `git ls-files`. Outside a git repo
|
|
246
|
-
* that exits 128 (`fatal: not a git repository`) and the whole run dies at
|
|
247
|
-
* "build sync file list: exit status 128" — AFTER the box is provisioned and
|
|
248
|
-
* billed. Checking this up front lets the caller fail fast, before provisioning.
|
|
249
|
-
*/
|
|
250
143
|
export function isInsideGitWorkTree(cwd) {
|
|
251
144
|
const r = spawnSync('git', ['-C', cwd, 'rev-parse', '--is-inside-work-tree'], {
|
|
252
145
|
encoding: 'utf-8',
|
|
253
146
|
});
|
|
254
147
|
return r.status === 0 && r.stdout.trim() === 'true';
|
|
255
148
|
}
|
|
256
|
-
/** Absolute git toplevel for `cwd`, or null when it is not a git repo. */
|
|
257
149
|
export function gitToplevel(cwd) {
|
|
258
150
|
const r = spawnSync('git', ['-C', cwd, 'rev-parse', '--show-toplevel'], { encoding: 'utf-8' });
|
|
259
151
|
return r.status === 0 ? r.stdout.trim() : null;
|
|
260
152
|
}
|
|
261
|
-
/**
|
|
262
|
-
* Network mode for a `--lease` run (F5, RUSH-1924). `--tailscale` forces the
|
|
263
|
-
* tailnet, `--no-tailscale` forces public, and neither (undefined) defaults to
|
|
264
|
-
* the tailnet ONLY in a reuse context (`--reuse`, `--box`, or a picked warm
|
|
265
|
-
* box) — a one-shot solo `--lease` stays public. Pure so it is unit-testable;
|
|
266
|
-
* the caller downgrades to `'public'` when no auth key is configured.
|
|
267
|
-
*/
|
|
268
153
|
export function computeNetMode(opts) {
|
|
269
154
|
if (opts.tailscale === false)
|
|
270
|
-
return 'public';
|
|
155
|
+
return 'public';
|
|
271
156
|
if (opts.tailscale === true)
|
|
272
|
-
return 'tailscale';
|
|
157
|
+
return 'tailscale';
|
|
273
158
|
return opts.reuseContext ? 'tailscale' : 'public';
|
|
274
159
|
}
|
|
275
|
-
// ── "Always provision fresh" per-repo memory (F3, RUSH-1922) ─────────────────
|
|
276
|
-
// The picker's "Always provision fresh (remember for this repo)" choice is
|
|
277
|
-
// persisted as a list of git-toplevel paths in a small state file, so a repo
|
|
278
|
-
// that opted out of the reuse picker is never prompted again.
|
|
279
|
-
/** True when `repoRoot` is in the remembered always-fresh set. Pure. */
|
|
280
160
|
export function isAlwaysFreshRepo(repos, repoRoot) {
|
|
281
161
|
return repos.includes(repoRoot);
|
|
282
162
|
}
|
|
283
|
-
/** Add `repoRoot` to the always-fresh set (idempotent). Pure. */
|
|
284
163
|
export function addAlwaysFreshRepo(repos, repoRoot) {
|
|
285
164
|
return repos.includes(repoRoot) ? repos : [...repos, repoRoot];
|
|
286
165
|
}
|
|
287
|
-
/** Path to the always-fresh state file under the USER agents dir (CLI-written per-user preference, never the maintainer-owned `.system` repo). */
|
|
288
166
|
export function leaseFreshReposPath() {
|
|
289
167
|
return path.join(getUserAgentsDir(), 'lease-fresh-repos.json');
|
|
290
168
|
}
|
|
291
|
-
/** Read the remembered always-fresh repo roots (empty on any read/parse error). */
|
|
292
169
|
export function readAlwaysFreshRepos() {
|
|
293
170
|
try {
|
|
294
171
|
const parsed = JSON.parse(fs.readFileSync(leaseFreshReposPath(), 'utf-8'));
|
|
@@ -298,7 +175,6 @@ export function readAlwaysFreshRepos() {
|
|
|
298
175
|
return [];
|
|
299
176
|
}
|
|
300
177
|
}
|
|
301
|
-
/** Persist the always-fresh repo roots. Best-effort — never throws. */
|
|
302
178
|
export function writeAlwaysFreshRepos(repos) {
|
|
303
179
|
try {
|
|
304
180
|
const p = leaseFreshReposPath();
|
|
@@ -306,26 +182,13 @@ export function writeAlwaysFreshRepos(repos) {
|
|
|
306
182
|
fs.writeFileSync(p, JSON.stringify(repos, null, 2));
|
|
307
183
|
}
|
|
308
184
|
catch {
|
|
309
|
-
/* best-effort — losing the preference just means the picker shows next time */
|
|
310
185
|
}
|
|
311
186
|
}
|
|
312
|
-
/**
|
|
313
|
-
* Build the LoopConfig the driver consumes from CLI flags and/or a workflow's
|
|
314
|
-
* `loop:` frontmatter block (issue #332). Returns undefined when neither source
|
|
315
|
-
* activates a loop (the common single-shot run). CLI flags take precedence over
|
|
316
|
-
* the workflow's declared values field-by-field, so `--max-iterations 5`
|
|
317
|
-
* overrides a workflow's `max_iterations: 3`.
|
|
318
|
-
*
|
|
319
|
-
* `--loop` with no sub-options is a valid bare loop (driver applies its own
|
|
320
|
-
* maxIterations safety cap). A workflow `loop:` block activates a loop even
|
|
321
|
-
* without `--loop` so `agents run <workflow>` honors a declared loop.
|
|
322
|
-
*/
|
|
323
187
|
export function buildLoopConfig(flags, workflowLoop) {
|
|
324
188
|
const active = flags.loop === true || workflowLoop !== undefined;
|
|
325
189
|
if (!active)
|
|
326
190
|
return undefined;
|
|
327
191
|
const cfg = {};
|
|
328
|
-
// until: CLI > workflow. Only `signal` is supported.
|
|
329
192
|
const until = flags.until ?? workflowLoop?.until;
|
|
330
193
|
if (until !== undefined) {
|
|
331
194
|
if (until !== 'signal') {
|
|
@@ -333,7 +196,6 @@ export function buildLoopConfig(flags, workflowLoop) {
|
|
|
333
196
|
}
|
|
334
197
|
cfg.until = 'signal';
|
|
335
198
|
}
|
|
336
|
-
// max_iterations: CLI > workflow.
|
|
337
199
|
if (flags.maxIterations !== undefined) {
|
|
338
200
|
const n = Number(flags.maxIterations);
|
|
339
201
|
if (!Number.isInteger(n) || n <= 0) {
|
|
@@ -344,7 +206,6 @@ export function buildLoopConfig(flags, workflowLoop) {
|
|
|
344
206
|
else if (workflowLoop?.max_iterations !== undefined) {
|
|
345
207
|
cfg.maxIterations = workflowLoop.max_iterations;
|
|
346
208
|
}
|
|
347
|
-
// budget (tokens): CLI > workflow.
|
|
348
209
|
if (flags.budget !== undefined) {
|
|
349
210
|
const b = Number(flags.budget);
|
|
350
211
|
if (!Number.isFinite(b) || b <= 0) {
|
|
@@ -355,9 +216,6 @@ export function buildLoopConfig(flags, workflowLoop) {
|
|
|
355
216
|
else if (workflowLoop?.budget !== undefined) {
|
|
356
217
|
cfg.budget = workflowLoop.budget;
|
|
357
218
|
}
|
|
358
|
-
// interval: CLI > workflow. Validate eagerly — an unparseable interval
|
|
359
|
-
// (e.g. "30s", "5", "abc") must be rejected here, not silently coalesced to
|
|
360
|
-
// 0ms (back-to-back) at run time. "0" is the one accepted non-duration value.
|
|
361
219
|
const interval = flags.interval ?? workflowLoop?.interval;
|
|
362
220
|
if (interval !== undefined) {
|
|
363
221
|
try {
|
|
@@ -370,35 +228,21 @@ export function buildLoopConfig(flags, workflowLoop) {
|
|
|
370
228
|
}
|
|
371
229
|
return cfg;
|
|
372
230
|
}
|
|
373
|
-
/** Map a loop stop reason to a process exit code. condition-met/max are clean exits. */
|
|
374
231
|
export function loopExitCode(stoppedBy) {
|
|
375
232
|
switch (stoppedBy) {
|
|
376
233
|
case 'condition-met':
|
|
377
234
|
case 'max':
|
|
378
235
|
return 0;
|
|
379
236
|
case 'budget':
|
|
380
|
-
return 7;
|
|
237
|
+
return 7;
|
|
381
238
|
case 'signal':
|
|
382
|
-
return 130;
|
|
239
|
+
return 130;
|
|
383
240
|
case 'stalled':
|
|
384
241
|
case 'error':
|
|
385
242
|
default:
|
|
386
243
|
return 1;
|
|
387
244
|
}
|
|
388
245
|
}
|
|
389
|
-
/**
|
|
390
|
-
* Drive a workflow's declarative `for_each:` fan-out end-to-end (issue #343).
|
|
391
|
-
*
|
|
392
|
-
* Runs the producer, expands one stage teammate per produced item (respecting
|
|
393
|
-
* `max_items` / `DEFAULT_FOR_EACH_CAP`, surfacing any truncation — never a
|
|
394
|
-
* silent cap), stages them into a fresh team via the existing `runForEach`
|
|
395
|
-
* bridge, then drives the teams supervisor until the DAG drains. When a verify
|
|
396
|
-
* panel is declared, tallies each item's `keep_if` gate from the skeptics'
|
|
397
|
-
* terminal status and logs which items survived.
|
|
398
|
-
*
|
|
399
|
-
* Reuses the teams substrate wholesale — no new orchestration engine. Returns
|
|
400
|
-
* the process exit code (0 on drain, 1 on producer failure / non-drain).
|
|
401
|
-
*/
|
|
402
246
|
export async function runWorkflowForEach(spec, opts) {
|
|
403
247
|
const [{ produceItems, runForEach, tallyForEach }, { expandForEach, DEFAULT_FOR_EACH_CAP }, { AgentManager }, { createTeam }, { runSupervisor }, { ALL_AGENT_IDS }] = await Promise.all([
|
|
404
248
|
import('../lib/teams/forEach.js'),
|
|
@@ -408,9 +252,6 @@ export async function runWorkflowForEach(spec, opts) {
|
|
|
408
252
|
import('../lib/teams/supervisor.js'),
|
|
409
253
|
import('../lib/agents.js'),
|
|
410
254
|
]);
|
|
411
|
-
// The teams substrate spawns teammates as a real harness. When `agent:` names
|
|
412
|
-
// a known harness id, honor it; otherwise fall back to claude (the workflow
|
|
413
|
-
// harness) so a subagent-style name in `agent:` still runs.
|
|
414
255
|
const isHarness = (a) => ALL_AGENT_IDS.includes(a);
|
|
415
256
|
const runSpec = {
|
|
416
257
|
...spec,
|
|
@@ -422,7 +263,6 @@ export async function runWorkflowForEach(spec, opts) {
|
|
|
422
263
|
if (runSpec.agent !== spec.agent) {
|
|
423
264
|
process.stderr.write(chalk.gray(`[for_each] '${spec.agent}' is not a harness id — staging stage teammates as claude\n`));
|
|
424
265
|
}
|
|
425
|
-
// 1. Producer: run the shell command (or resolve itemsRef) into the item list.
|
|
426
266
|
let items;
|
|
427
267
|
try {
|
|
428
268
|
items = await produceItems(runSpec, { cwd: opts.cwd });
|
|
@@ -435,14 +275,12 @@ export async function runWorkflowForEach(spec, opts) {
|
|
|
435
275
|
process.stderr.write(chalk.yellow('[for_each] producer emitted no items — nothing to fan out.\n'));
|
|
436
276
|
return 0;
|
|
437
277
|
}
|
|
438
|
-
// 2. Cap accounting (surfaced, never silent — acceptance criterion in #343).
|
|
439
278
|
const cap = runSpec.max_items ?? DEFAULT_FOR_EACH_CAP;
|
|
440
279
|
const { truncated } = expandForEach(runSpec, items);
|
|
441
280
|
if (truncated > 0) {
|
|
442
281
|
process.stderr.write(chalk.yellow(`[for_each] producer emitted ${items.length} items; capping at ${cap} (${truncated} dropped). Raise \`max_items\` to fan out more.\n`));
|
|
443
282
|
}
|
|
444
283
|
process.stderr.write(chalk.gray(`[for_each] ${Math.min(items.length, cap)} stage teammate(s) from ${items.length} produced item(s)\n`));
|
|
445
|
-
// 3. Stage the expanded teammates into a fresh team via the existing bridge.
|
|
446
284
|
const team = `foreach-${opts.workflowName.replace(/[^a-zA-Z0-9_-]/g, '-')}-${Date.now().toString(36)}`;
|
|
447
285
|
await createTeam(team, { description: `for_each fan-out from workflow '${opts.workflowName}'` });
|
|
448
286
|
const mgr = new AgentManager();
|
|
@@ -451,8 +289,6 @@ export async function runWorkflowForEach(spec, opts) {
|
|
|
451
289
|
effort: opts.effort,
|
|
452
290
|
concurrency: runSpec.concurrency,
|
|
453
291
|
});
|
|
454
|
-
// 4. Drive the supervisor until the DAG drains (the same loop `teams start
|
|
455
|
-
// --watch` uses; it absorbs the staged teammates via rescanFromDisk).
|
|
456
292
|
const result = await runSupervisor(mgr, {
|
|
457
293
|
team,
|
|
458
294
|
onWave: (s) => {
|
|
@@ -460,8 +296,6 @@ export async function runWorkflowForEach(spec, opts) {
|
|
|
460
296
|
process.stderr.write(`[${ts}] [for_each] wave ${s.wave} launched=${s.launched.length} running=${s.running} pending=${s.pending} done=${s.completed} failed=${s.failed}\n`);
|
|
461
297
|
},
|
|
462
298
|
});
|
|
463
|
-
// 5. keep_if tally: a skeptic that COMPLETED is a keep vote; a failed skeptic
|
|
464
|
-
// votes to drop. Gate each item and report which survived.
|
|
465
299
|
if (runSpec.verify) {
|
|
466
300
|
const loaded = await mgr.listByTask(team);
|
|
467
301
|
const statusByName = new Map(loaded.map((a) => [a.name, a.status]));
|
|
@@ -480,19 +314,6 @@ export async function runWorkflowForEach(spec, opts) {
|
|
|
480
314
|
process.stderr.write(chalk.yellow(`[for_each] stopped by ${result.stoppedBy} after ${result.waves} waves. Team: ${team}\n`));
|
|
481
315
|
return 1;
|
|
482
316
|
}
|
|
483
|
-
/**
|
|
484
|
-
* The run's working directory from `--cwd` / `--project`. `--project <slug>` owns
|
|
485
|
-
* the directory and is mutually exclusive with `--cwd`/`--remote-cwd`; both the
|
|
486
|
-
* main dispatch and the `--terminal` handoff need the same answer, so the rule
|
|
487
|
-
* and its error live here once instead of in two places that can drift.
|
|
488
|
-
*
|
|
489
|
-
* A project that binds several directories also contributes the ones it is not
|
|
490
|
-
* landing in as `--add-dir` grants, so an agent on a multi-repo project can
|
|
491
|
-
* actually reach the sibling checkouts. Claude / Cursor / Kimi take the native
|
|
492
|
-
* flag; Codex folds them into workspace_roots; Grok widens its sandbox profile
|
|
493
|
-
* (and always injects a rules note). Other harnesses have no multi-root surface
|
|
494
|
-
* and ignore the grants (cwd only).
|
|
495
|
-
*/
|
|
496
317
|
export async function resolveRunCwd(options, opts) {
|
|
497
318
|
if (!options.project) {
|
|
498
319
|
if (!options.cwd || opts.forRemote)
|
|
@@ -509,8 +330,6 @@ export async function resolveRunCwd(options, opts) {
|
|
|
509
330
|
const { cwd, extraDirs } = await resolveProjectDirs(options.project, {
|
|
510
331
|
forRemote: opts.forRemote,
|
|
511
332
|
});
|
|
512
|
-
// Explicit --add-dir values keep their position; a directory the project
|
|
513
|
-
// already contributes is not passed twice.
|
|
514
333
|
if (extraDirs.length > 0) {
|
|
515
334
|
const seen = new Set(options.addDir ?? []);
|
|
516
335
|
options.addDir = [...(options.addDir ?? []), ...extraDirs.filter((d) => !seen.has(d))];
|
|
@@ -522,15 +341,6 @@ export async function resolveRunCwd(options, opts) {
|
|
|
522
341
|
process.exit(1);
|
|
523
342
|
}
|
|
524
343
|
}
|
|
525
|
-
/**
|
|
526
|
-
* `--terminal`: hand this run to a real terminal tab and exit.
|
|
527
|
-
*
|
|
528
|
-
* The terminal is detected from the user's live sessions, so a run started from
|
|
529
|
-
* a surface that cannot host a TUI (the menu bar's "New Session", a script) lands
|
|
530
|
-
* in the terminal they actually work in instead of a hardcoded Terminal.app.
|
|
531
|
-
* Exits non-zero when no terminal could be opened — the caller must not believe
|
|
532
|
-
* a session started when none did.
|
|
533
|
-
*/
|
|
534
344
|
async function handleTerminalHandoff(agentSpec, options, prompt) {
|
|
535
345
|
const { parseTerminalFlag, openRunInTerminal, toHostSamples, currentContext } = await import('../lib/terminal/index.js');
|
|
536
346
|
const parsed = parseTerminalFlag(options.terminal);
|
|
@@ -538,14 +348,6 @@ async function handleTerminalHandoff(agentSpec, options, prompt) {
|
|
|
538
348
|
console.error(chalk.red(parsed.error));
|
|
539
349
|
process.exit(1);
|
|
540
350
|
}
|
|
541
|
-
// Reject an unrunnable target HERE, where the person can read it. The tab would
|
|
542
|
-
// otherwise open, print the same error, and close — the failure lands in a
|
|
543
|
-
// window that is gone before it can be read, which reads as "nothing happened".
|
|
544
|
-
//
|
|
545
|
-
// `agents run <thing>` takes an agent id, a PROFILE, or a WORKFLOW (see the
|
|
546
|
-
// isValidAgent / profileExists / resolveWorkflowRef chain below), so this must
|
|
547
|
-
// accept all three. Gating on the agent table alone rejected every profile —
|
|
548
|
-
// the whole Kimi/DeepSeek/Qwen/GLM path — for `--terminal` runs only.
|
|
549
351
|
const rawTarget = parseRunPickerMarkers(agentSpec).normalizedAgentSpec.split('#')[0].split('@')[0];
|
|
550
352
|
const knownAgent = resolveAgentName(rawTarget);
|
|
551
353
|
const [{ profileExists }, { resolveWorkflowRef }] = await Promise.all([
|
|
@@ -564,30 +366,16 @@ async function handleTerminalHandoff(agentSpec, options, prompt) {
|
|
|
564
366
|
process.exit(1);
|
|
565
367
|
}
|
|
566
368
|
}
|
|
567
|
-
// --device and its aliases (--on/--computer) all mean "dispatch this
|
|
568
|
-
// run to another machine over SSH", which is incompatible with opening a
|
|
569
|
-
// terminal tab on THIS machine — so reject the whole alias family, not just
|
|
570
|
-
// the canonical flag. The rule and its wording live once, in the --device
|
|
571
|
-
// forwarding table, so the classification a reviewer reads and the error a
|
|
572
|
-
// user sees can't drift.
|
|
573
369
|
if (hostTargetGiven(options).length) {
|
|
574
370
|
const { RUN_OPTION_REJECT_MESSAGES } = await import('../lib/hosts/remote-cmd.js');
|
|
575
371
|
console.error(chalk.red(RUN_OPTION_REJECT_MESSAGES.terminal));
|
|
576
372
|
process.exit(1);
|
|
577
373
|
}
|
|
578
|
-
// Machine-readable output would land in the tab, where the caller that asked
|
|
579
|
-
// for it can never read it. Same class of failure as --device: refuse, don't
|
|
580
|
-
// hand back a stream that goes nowhere.
|
|
581
374
|
const streamFlag = options.json ? '--json' : options.emitSessionId ? '--emit-session-id' : undefined;
|
|
582
375
|
if (streamFlag) {
|
|
583
376
|
console.error(chalk.red(`${streamFlag} streams to stdout, but --terminal moves the run into a tab where you cannot read it. Drop one.`));
|
|
584
377
|
process.exit(1);
|
|
585
378
|
}
|
|
586
|
-
// `--project` owns the working directory, but the main action resolves it far
|
|
587
|
-
// below this handoff — so without this the tab would open in THIS process's
|
|
588
|
-
// cwd (launchd's `/` for a menu-bar click) while the run inside it moved to
|
|
589
|
-
// the project. `forRemote: false` because --terminal is always local (--device
|
|
590
|
-
// is rejected above).
|
|
591
379
|
const cwd = await resolveRunCwd(options, { forRemote: false });
|
|
592
380
|
const { getActiveSessions } = await import('../lib/session/active.js');
|
|
593
381
|
let sessions = [];
|
|
@@ -595,8 +383,6 @@ async function handleTerminalHandoff(agentSpec, options, prompt) {
|
|
|
595
383
|
sessions = await toHostSamples(await getActiveSessions());
|
|
596
384
|
}
|
|
597
385
|
catch {
|
|
598
|
-
// Detection is best-effort — an unreadable session index must not block the
|
|
599
|
-
// launch; resolution falls through to the available-backend floor.
|
|
600
386
|
}
|
|
601
387
|
const result = await openRunInTerminal({
|
|
602
388
|
argv: process.argv.slice(2),
|
|
@@ -615,7 +401,6 @@ async function handleTerminalHandoff(agentSpec, options, prompt) {
|
|
|
615
401
|
console.log(chalk.gray(`Opened the ${what} in ${result.description}.`));
|
|
616
402
|
}
|
|
617
403
|
}
|
|
618
|
-
/** Register the `agents run <agent> [prompt]` command. */
|
|
619
404
|
export function registerRunCommand(program) {
|
|
620
405
|
const runCmd = program
|
|
621
406
|
.command('run [agent] [prompt]')
|
|
@@ -684,19 +469,9 @@ export function registerRunCommand(program) {
|
|
|
684
469
|
.option('--repo <owner/repo>', 'With --cloud: GitHub repository. Repeatable for multi-repo dispatch (Rush Cloud only).', (val, prev) => [...prev, val], [])
|
|
685
470
|
.option('--branch <name>', 'With --cloud: target git branch.')
|
|
686
471
|
.option('--cloud-env <id>', 'With --cloud: Codex Cloud environment ID (run\'s --env is the KEY=VAL passthrough, so the cloud env id gets its own flag).');
|
|
687
|
-
// `--on` and `--computer` are hidden aliases of `--device` — same behavior.
|
|
688
472
|
runCmd.addOption(new Option('--on <name>', 'Alias of --device.').hideHelp());
|
|
689
473
|
runCmd.addOption(new Option('--computer <name>', 'Alias of --device.').hideHelp());
|
|
690
|
-
// Internal: the `--device` dispatch forwards this so the REMOTE run prints its
|
|
691
|
-
// resolved session id as a one-line stdout sentinel (hosts/session-marker.ts),
|
|
692
|
-
// letting the launcher relate the remote-created session back to itself for
|
|
693
|
-
// every agent — not just Claude, whose id it forces up front.
|
|
694
474
|
runCmd.addOption(new Option('--emit-session-id', 'internal: print the resolved session id for a --device launcher to capture').hideHelp());
|
|
695
|
-
// Required for the documented `agents run <agent> [prompt] -- <native flags>`
|
|
696
|
-
// passthrough: commander >=13 rejects excess operands by default, so any
|
|
697
|
-
// post-`--` token died with "too many arguments" before the action ran. The
|
|
698
|
-
// action re-derives the `--` boundary from rawArgs and still errors on excess
|
|
699
|
-
// operands that are NOT behind `--`.
|
|
700
475
|
runCmd.allowExcessArguments(true);
|
|
701
476
|
setHelpSections(runCmd, {
|
|
702
477
|
examples: `
|
|
@@ -841,12 +616,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
841
616
|
});
|
|
842
617
|
runCmd.action(async (agentSpec, prompt, options, command) => {
|
|
843
618
|
bootMark('run-action:enter');
|
|
844
|
-
// Capture everything after -- as passthrough args forwarded verbatim to the
|
|
845
|
-
// underlying CLI. Commander strips the literal `--` and folds what follows
|
|
846
|
-
// into the positional operands (so `agents run codex -- --yolo` would parse
|
|
847
|
-
// `--yolo` as the PROMPT) — recover the boundary from rawArgs instead of
|
|
848
|
-
// operand counts. Excess operands not behind `--` are still an error (an
|
|
849
|
-
// unquoted prompt must not silently become agent flags).
|
|
850
619
|
const rawArgs = process.argv;
|
|
851
620
|
const separatorIdx = rawArgs.indexOf('--');
|
|
852
621
|
const passthroughArgs = separatorIdx === -1 ? [] : rawArgs.slice(separatorIdx + 1);
|
|
@@ -856,12 +625,8 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
856
625
|
process.exit(1);
|
|
857
626
|
}
|
|
858
627
|
if (prompt !== undefined && operandsBeforeSeparator < 2) {
|
|
859
|
-
// The token commander assigned to [prompt] came from behind `--` — it is
|
|
860
|
-
// a native flag, not a prompt. Run interactively.
|
|
861
628
|
prompt = undefined;
|
|
862
629
|
}
|
|
863
|
-
// Broadcast matrix (formerly `agents bench`): list/results/run cells, then exit.
|
|
864
|
-
// --broadcast is local-only fan-out — it is mutually exclusive with --host/--device.
|
|
865
630
|
if (options.broadcast || options.listTasks || options.results !== undefined) {
|
|
866
631
|
const whereIsRemote = typeof options.where === 'string' && options.where.trim().toLowerCase() !== 'local';
|
|
867
632
|
if (hostTargetGiven(options).length > 0 || whereIsRemote) {
|
|
@@ -891,9 +656,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
891
656
|
console.error(chalk.red("Missing required argument 'agent'. Example: agents run claude \"hello\"."));
|
|
892
657
|
process.exit(1);
|
|
893
658
|
}
|
|
894
|
-
// --cloud: vendor cloud placement. Validate BEFORE the terminal handoff
|
|
895
|
-
// and every local dispatch path — flags like --terminal/--loop/--resume
|
|
896
|
-
// belong to the local runner and must error, never ride along silently.
|
|
897
659
|
if (options.cloud || (typeof options.where === 'string' && /^cloud(:|$)/i.test(options.where.trim()))) {
|
|
898
660
|
const { runCloudConflicts } = await import('./run-cloud.js');
|
|
899
661
|
const conflicts = runCloudConflicts(options);
|
|
@@ -902,25 +664,14 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
902
664
|
process.exit(1);
|
|
903
665
|
}
|
|
904
666
|
}
|
|
905
|
-
// --terminal: this process can't host the TUI (a menu-bar click, a script),
|
|
906
|
-
// so hand the run to a real terminal and exit. Resolved from the user's own
|
|
907
|
-
// live sessions, so it opens where they already work. Done before every
|
|
908
|
-
// other dispatch path because the tab re-runs this same argv without the
|
|
909
|
-
// flag — arming --notify or picking a version here would happen twice.
|
|
910
667
|
if (options.terminal) {
|
|
911
668
|
await handleTerminalHandoff(agentSpec, options, prompt);
|
|
912
669
|
return;
|
|
913
670
|
}
|
|
914
|
-
// Placement: --where expands into --device / --lease / --cloud before any
|
|
915
|
-
// dispatch. One door for "where does the body run?" — old flags remain
|
|
916
|
-
// aliases. See lib/placement.ts and docs/concepts.md#placement.
|
|
917
671
|
{
|
|
918
672
|
const { placementFromRunFlags, expandPlacementToRunFlags, PlacementError } = await import('../lib/placement.js');
|
|
919
673
|
try {
|
|
920
674
|
const placement = placementFromRunFlags(options);
|
|
921
|
-
// An explicit local placement (--local, --where local) must outlive
|
|
922
|
-
// this block: expansion yields no host flag, and the bare-interactive
|
|
923
|
-
// default below reads an empty host set as "decide for me".
|
|
924
675
|
if (placement.kind === 'local' && placement.source !== 'default')
|
|
925
676
|
options.local = true;
|
|
926
677
|
if (options.where) {
|
|
@@ -937,8 +688,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
937
688
|
options.cloud = expanded.cloud;
|
|
938
689
|
if (expanded.provider !== undefined)
|
|
939
690
|
options.provider = expanded.provider;
|
|
940
|
-
// Clear the where flag so remote re-entry (host dispatch) does not
|
|
941
|
-
// re-expand and conflict with the concrete host we just set.
|
|
942
691
|
options.where = undefined;
|
|
943
692
|
}
|
|
944
693
|
}
|
|
@@ -950,17 +699,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
950
699
|
throw err;
|
|
951
700
|
}
|
|
952
701
|
}
|
|
953
|
-
// --device naming this machine (short id, MagicDNS name, loopback, or the
|
|
954
|
-
// `interactive` sentinel pinned here) is a local run, not a self-SSH: the
|
|
955
|
-
// hop probes its own login shell and times out under load. Pinned here,
|
|
956
|
-
// ahead of every placement gate, so the bare-interactive default sees an
|
|
957
|
-
// explicit local choice rather than an empty host set.
|
|
958
702
|
{
|
|
959
703
|
const { isSelfHost } = await import('../lib/devices/self-host.js');
|
|
960
704
|
const { isDeviceInteractive, resolveInteractiveDevice } = await import('../lib/devices/interactive-host.js');
|
|
961
705
|
pinLocalWhenTargetIsSelf(options, (name) => isSelfHost(isDeviceInteractive(name) ? resolveInteractiveDevice() ?? name : name));
|
|
962
706
|
}
|
|
963
|
-
// Cloud refinement flags without the placement are a typo, not a no-op.
|
|
964
707
|
if (!options.cloud) {
|
|
965
708
|
const { cloudFlagsWithoutCloud } = await import('./run-cloud.js');
|
|
966
709
|
const stray = cloudFlagsWithoutCloud(options);
|
|
@@ -969,17 +712,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
969
712
|
process.exit(1);
|
|
970
713
|
}
|
|
971
714
|
}
|
|
972
|
-
// --cloud: dispatch through the cloud provider registry and return — the
|
|
973
|
-
// run never touches the local/host/lease paths below.
|
|
974
715
|
if (options.cloud) {
|
|
975
716
|
const { handleRunCloud } = await import('./run-cloud.js');
|
|
976
717
|
await handleRunCloud(agentSpec, prompt, options, command);
|
|
977
718
|
return;
|
|
978
719
|
}
|
|
979
|
-
// --notify: post a desktop notification when this run finishes. Armed on
|
|
980
|
-
// process exit so it covers EVERY dispatch path below (local, --device,
|
|
981
|
-
// --lease, the error path) instead of one branch. Only for headless runs
|
|
982
|
-
// — an interactive run ends in front of the person who started it.
|
|
983
720
|
if (options.notify && prompt !== undefined) {
|
|
984
721
|
const { armRunFinishNotification } = await import('../lib/run-notify.js');
|
|
985
722
|
armRunFinishNotification({
|
|
@@ -990,11 +727,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
990
727
|
host: options.host,
|
|
991
728
|
});
|
|
992
729
|
}
|
|
993
|
-
// Trailing picker markers request an interactive choice: `#` picks the
|
|
994
|
-
// account (and the version it signs in with), `@` picks the device, and
|
|
995
|
-
// `#@`/`@#` ask both. Strip only those terminal markers; concrete
|
|
996
|
-
// agent@version pins and `#label` account pins retain their meaning in
|
|
997
|
-
// every dispatch path below.
|
|
998
730
|
const pickerMarkers = parseRunPickerMarkers(agentSpec);
|
|
999
731
|
const accountPickerRequested = pickerMarkers.accountPicker;
|
|
1000
732
|
const devicePickerRequested = pickerMarkers.devicePicker;
|
|
@@ -1005,10 +737,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1005
737
|
'Use agents run <agent># to pick an account, <agent>@ to pick a device, <agent>#@ for both.'));
|
|
1006
738
|
process.exit(1);
|
|
1007
739
|
}
|
|
1008
|
-
// Peel `#name` off before --device dispatch so the selector rides the hop
|
|
1009
|
-
// unchanged and the peer resolves ITS slot (PHNX-3940 T5). The later local
|
|
1010
|
-
// parse is idempotent when the values match. A bare trailing `#` was the
|
|
1011
|
-
// picker marker above, so it can never land here as an empty label.
|
|
1012
740
|
{
|
|
1013
741
|
const labelParts = normalizedAgentSpec.split('#');
|
|
1014
742
|
if (labelParts.length > 2 || labelParts[1] === '') {
|
|
@@ -1023,8 +751,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1023
751
|
if (specAccountLabel)
|
|
1024
752
|
options.account = specAccountLabel;
|
|
1025
753
|
}
|
|
1026
|
-
// Bare resume is a session selection request, before fresh-run defaults or placement.
|
|
1027
|
-
// Concrete IDs re-enter the executor below, so this cannot recurse.
|
|
1028
754
|
if (options.resume === true || options.resume === '') {
|
|
1029
755
|
if (options.sessionId || options.loop || options.fallback || options.resumeCheckpoint || options.lease) {
|
|
1030
756
|
throw new Error('--resume cannot be combined with --session-id, --loop, --fallback, --resume-checkpoint, or --lease.');
|
|
@@ -1046,7 +772,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1046
772
|
});
|
|
1047
773
|
return;
|
|
1048
774
|
}
|
|
1049
|
-
// Hard-deprecated harnesses cannot be run — point the user at the successor.
|
|
1050
775
|
const runBaseAgentName = normalizedAgentSpec.split('#')[0].split('@')[0];
|
|
1051
776
|
const runBaseAgentId = resolveAgentName(runBaseAgentName);
|
|
1052
777
|
const { profileExists: runProfileExists } = await import('../lib/profiles.js');
|
|
@@ -1054,9 +779,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1054
779
|
console.error(chalk.red(hardDeprecationError(runBaseAgentId)));
|
|
1055
780
|
process.exit(1);
|
|
1056
781
|
}
|
|
1057
|
-
// Picker conflict checks run BEFORE --resume/--device auto may place the
|
|
1058
|
-
// run implicitly, so an implied placement never surfaces as a fake
|
|
1059
|
-
// "cannot be combined with --device" when the user only typed a marker.
|
|
1060
782
|
if (accountPickerRequested) {
|
|
1061
783
|
const conflicts = runAccountPickerConflicts(options);
|
|
1062
784
|
if (conflicts.length > 0) {
|
|
@@ -1073,8 +795,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1073
795
|
process.exit(1);
|
|
1074
796
|
}
|
|
1075
797
|
}
|
|
1076
|
-
// `agents run auto`: the reserved harness keyword — full-auto dispatch
|
|
1077
|
-
// (host affinity → cross-harness balance → account balance, RUSH-2132).
|
|
1078
798
|
if (normalizedAgentSpec.split('#')[0].split('@')[0] === RUN_AUTO_KEYWORD && normalizedAgentSpec !== RUN_AUTO_KEYWORD) {
|
|
1079
799
|
console.error(chalk.red(`agents run auto picks the harness itself — a @version pin does not apply. ` +
|
|
1080
800
|
`Pin a concrete harness instead: agents run <harness>@<version>.`));
|
|
@@ -1083,10 +803,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1083
803
|
let autoHarnessRequested = normalizedAgentSpec === RUN_AUTO_KEYWORD;
|
|
1084
804
|
let resolvedResumeSource;
|
|
1085
805
|
let resolvedRecoveryTarget;
|
|
1086
|
-
// Concrete resume ids resolve BEFORE placement. Full UUIDs take the local
|
|
1087
|
-
// SQLite fast path; only a local miss fans out to the fleet. This lets a
|
|
1088
|
-
// command entered on zion discover that the owning version-home is on a
|
|
1089
|
-
// worker, while a command entered on that worker never pays for SSH.
|
|
1090
806
|
if (typeof options.resume === 'string' && options.resume.trim()) {
|
|
1091
807
|
const selector = options.resume.trim();
|
|
1092
808
|
const injectedSource = (() => {
|
|
@@ -1103,10 +819,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1103
819
|
? { kind: 'resolved', session: injectedSource }
|
|
1104
820
|
: await (await import('./sessions.js')).resolveSessionMetadataValue(selector, { agent: runBaseAgentId ?? undefined });
|
|
1105
821
|
if (outcome.kind === 'partial') {
|
|
1106
|
-
// RUSH-2492: an unreachable peer is a warning, not a hard failure. The
|
|
1107
|
-
// resolver already resolves an id found on the reachable fleet (SES-9a),
|
|
1108
|
-
// so reaching here means the session was not found on any device we
|
|
1109
|
-
// COULD reach — it may live on an unreachable peer we could not check.
|
|
1110
822
|
const offline = outcome.failedPeers;
|
|
1111
823
|
console.error(chalk.yellow(`Warning: ${offline.length} device(s) unreachable, not checked: ${offline.join(', ')}`));
|
|
1112
824
|
console.error(chalk.red(`No session matching "${selector}" on any reachable device (${offline.length} unreachable, not checked).`));
|
|
@@ -1128,9 +840,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1128
840
|
`Use: agents sessions resume ${resolvedResumeSource.id}`));
|
|
1129
841
|
process.exit(1);
|
|
1130
842
|
}
|
|
1131
|
-
// Omitted --mode inherits the effective source mode. Commander keeps
|
|
1132
|
-
// the normal new-run default as a real value, so consult its provenance
|
|
1133
|
-
// rather than mistaking the default for an explicit override.
|
|
1134
843
|
if (command.getOptionValueSource('mode') === 'default') {
|
|
1135
844
|
if (resolvedResumeSource.mode) {
|
|
1136
845
|
options.mode = resolvedResumeSource.mode;
|
|
@@ -1152,10 +861,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1152
861
|
`the requested device was ${hostTargetGiven(options).join(', ') || 'this machine'}.`));
|
|
1153
862
|
process.exit(1);
|
|
1154
863
|
}
|
|
1155
|
-
// Recovery is resolved on the device that owns the transcript. A remote
|
|
1156
|
-
// dispatch is pinned to the source HARNESS (not `run auto`'s cross-harness
|
|
1157
|
-
// picker); the peer repeats this block with the injected SessionMeta and
|
|
1158
|
-
// chooses its own healthy version. Locally, resolve it now.
|
|
1159
864
|
const sourceAgent = resolvedResumeSource.agent;
|
|
1160
865
|
if (!sourcePeer) {
|
|
1161
866
|
try {
|
|
@@ -1177,8 +882,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1177
882
|
}
|
|
1178
883
|
}
|
|
1179
884
|
if (autoHarnessRequested) {
|
|
1180
|
-
// `auto` is reserved. If a future harness registers that id, the
|
|
1181
|
-
// keyword collides — fail loud rather than silently shadow the harness.
|
|
1182
885
|
if (RUN_AUTO_KEYWORD in AGENTS) {
|
|
1183
886
|
console.error(chalk.red(`'${RUN_AUTO_KEYWORD}' is now a registered harness and collides with the reserved 'run auto' keyword. ` +
|
|
1184
887
|
`Run the harness by name instead.`));
|
|
@@ -1192,21 +895,9 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1192
895
|
console.error(chalk.red(`agents run auto picks the harness and its placement itself — the trailing-@ device picker needs a concrete harness (agents run <harness>@).`));
|
|
1193
896
|
process.exit(1);
|
|
1194
897
|
}
|
|
1195
|
-
// Host layer: with no explicit --device, default to the
|
|
1196
|
-
// affinity pick. Skipped on a device-dispatched run — its dispatcher
|
|
1197
|
-
// already resolved this layer (see runAutoDefaultsToAffinity).
|
|
1198
898
|
if (!resolvedResumeSource && runAutoDefaultsToAffinity(options))
|
|
1199
899
|
options.device = 'auto';
|
|
1200
900
|
}
|
|
1201
|
-
// The picker menus run HERE — after every conflict check, before
|
|
1202
|
-
// placement resolves — so the picked account labels the device rows and
|
|
1203
|
-
// the picked device is concrete for every host branch below.
|
|
1204
|
-
// `#@`/`@#`: account first, against THIS machine's slots; the picked
|
|
1205
|
-
// account becomes options.account and the device menu shows its
|
|
1206
|
-
// ✓/– per-device mark. A remote device pick dispatches with
|
|
1207
|
-
// `<agent>#<label>` so the peer resolves its own slot.
|
|
1208
|
-
// `@`: just the device menu; picking this machine is a plain local run.
|
|
1209
|
-
// Either menu cancelled (Esc/Ctrl-C) launches nothing and exits 0.
|
|
1210
901
|
let upFrontAccountPick = null;
|
|
1211
902
|
if (accountPickerRequested && devicePickerRequested) {
|
|
1212
903
|
const baseName = normalizedAgentSpec.split('#')[0].split('@')[0];
|
|
@@ -1227,7 +918,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1227
918
|
const { pickRunAccountCandidate } = await import('./run-account-picker.js');
|
|
1228
919
|
const selected = await pickRunAccountCandidate(baseAgentId);
|
|
1229
920
|
if (!selected)
|
|
1230
|
-
return;
|
|
921
|
+
return;
|
|
1231
922
|
if (selected.nativeAccount)
|
|
1232
923
|
options.account = selected.nativeAccount;
|
|
1233
924
|
upFrontAccountPick = selected;
|
|
@@ -1237,8 +928,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1237
928
|
}
|
|
1238
929
|
}
|
|
1239
930
|
if (devicePickerRequested) {
|
|
1240
|
-
// --resume above may have pinned the host implicitly (recovery to the
|
|
1241
|
-
// source peer); a device menu against it would be a silent no-op.
|
|
1242
931
|
const impliedHost = hostTargetGiven(options);
|
|
1243
932
|
if (impliedHost.length > 0) {
|
|
1244
933
|
console.error(chalk.red(`Device selection with ${agentSpec} cannot be combined with the placement --resume already chose (${impliedHost.join(', ')}). ` +
|
|
@@ -1252,39 +941,26 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1252
941
|
accountLabel: options.account,
|
|
1253
942
|
});
|
|
1254
943
|
if (pickedDevice === null)
|
|
1255
|
-
return;
|
|
944
|
+
return;
|
|
1256
945
|
const { isSelfHost } = await import('../lib/devices/self-host.js');
|
|
1257
|
-
// Picking this machine is a plain local run — leave options.device unset.
|
|
1258
946
|
if (!isSelfHost(pickedDevice))
|
|
1259
947
|
options.device = pickedDevice;
|
|
1260
948
|
}
|
|
1261
|
-
// Default placement (PHNX-4083): a bare human-facing `agents run
|
|
1262
|
-
// <harness>` (no prompt, real TTY, no placement flags, not a dispatched
|
|
1263
|
-
// hop) places itself like `--device auto` — a marker left off is decided
|
|
1264
|
-
// for you. Headless runs (a prompt, --json, teams/routines/hooks) keep
|
|
1265
|
-
// running in place, unchanged.
|
|
1266
949
|
const defaultPlacement = bareInteractiveRunDefaultsToDeviceAuto(options, { prompt, devicePickerRequested }, { tty: isInteractiveTerminal(), json: options.json });
|
|
1267
950
|
if (defaultPlacement)
|
|
1268
951
|
options.device = 'auto';
|
|
1269
|
-
// --device auto: live fleet pick.
|
|
1270
|
-
// Harness is always the agent the user typed — never auto-picked.
|
|
1271
|
-
// Placement failure propagates; an automatic request never becomes local.
|
|
1272
952
|
{
|
|
1273
953
|
const { applyDeviceAutoToOptions } = await import('../lib/smart-launch.js');
|
|
1274
954
|
let result;
|
|
1275
955
|
try {
|
|
1276
956
|
result = await applyDeviceAutoToOptions(options, {
|
|
1277
957
|
accountPickerRequested,
|
|
1278
|
-
// `run auto` selects its harness after placement, so do not filter
|
|
1279
|
-
// candidates against an arbitrary proxy harness at this stage.
|
|
1280
958
|
agent: normalizedAgentSpec.split('#')[0].split('@')[0] === RUN_AUTO_KEYWORD
|
|
1281
959
|
? undefined
|
|
1282
960
|
: (resolveAgentName(normalizedAgentSpec.split('#')[0].split('@')[0]) ?? undefined),
|
|
1283
961
|
});
|
|
1284
962
|
}
|
|
1285
963
|
catch (err) {
|
|
1286
|
-
// Placement the DEFAULT chose must fail loud AND name the local
|
|
1287
|
-
// escape hatch — never silently fall back to a local launch.
|
|
1288
964
|
if (!defaultPlacement)
|
|
1289
965
|
throw err;
|
|
1290
966
|
console.error(chalk.red(err.message));
|
|
@@ -1298,9 +974,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1298
974
|
` · ${acctNote}\n`));
|
|
1299
975
|
}
|
|
1300
976
|
}
|
|
1301
|
-
// --lease: invent a disposable cloud box for this run (via crabbox), run
|
|
1302
|
-
// the agent there, then tear it down. --box: reuse a named warm crabbox
|
|
1303
|
-
// box, run the same bootstrap there, and leave the box running.
|
|
1304
977
|
if (options.lease || options.box) {
|
|
1305
978
|
if (prompt === undefined) {
|
|
1306
979
|
console.error(chalk.red(`A prompt is required for crabbox runs: agents run <agent> "<task>" ${options.box ? '--box <slug>' : '--lease'}`));
|
|
@@ -1319,17 +992,12 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1319
992
|
process.exit(1);
|
|
1320
993
|
}
|
|
1321
994
|
const backend = typeof options.lease === 'string' ? options.lease : undefined;
|
|
1322
|
-
// crabbox syncs this directory to the box via `git ls-files`; outside a
|
|
1323
|
-
// git repo that fails with "build sync file list: exit status 128" — but
|
|
1324
|
-
// only AFTER the box is provisioned and billed. Fail fast here instead.
|
|
1325
995
|
const leaseCwd = options.cwd ?? process.cwd();
|
|
1326
996
|
if (!isInsideGitWorkTree(leaseCwd)) {
|
|
1327
997
|
console.error(chalk.red(`${options.box ? '--box' : '--lease'} syncs the working directory to the box, but ${leaseCwd} is not a git repository.`));
|
|
1328
998
|
console.error(chalk.yellow(`Run from inside a git repo, or initialize one: (cd ${leaseCwd} && git init)`));
|
|
1329
999
|
process.exit(1);
|
|
1330
1000
|
}
|
|
1331
|
-
// First-run: no provider credential resolves (no env var, no config, no
|
|
1332
|
-
// detectable bundle) → guide the user through one-time setup, then continue.
|
|
1333
1001
|
const { resolveLeaseBundle } = await import('../lib/crabbox/cli.js');
|
|
1334
1002
|
if (options.lease && !resolveLeaseBundle()) {
|
|
1335
1003
|
const { runLeaseSetup } = await import('./lease.js');
|
|
@@ -1339,19 +1007,9 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1339
1007
|
process.exit(1);
|
|
1340
1008
|
}
|
|
1341
1009
|
}
|
|
1342
|
-
// ── F3 reuse (RUSH-1922) + F5 net-mode (RUSH-1924) ───────────────────
|
|
1343
|
-
// Resolve which box this run targets and how it is networked BEFORE any
|
|
1344
|
-
// provisioning. `--box` is an explicit reuse; otherwise, on an
|
|
1345
|
-
// interactive tty, offer the warm boxes as a reuse picker. Headless runs
|
|
1346
|
-
// never block: leaseAndRun itself is reuse-first against the profile
|
|
1347
|
-
// pool (a ready pool box is reused; none ready → warm a fresh one).
|
|
1348
|
-
// `--fresh` opts out of every reuse path.
|
|
1349
1010
|
const leaseSecretsBundle = process.env.AGENTS_LEASE_SECRETS_BUNDLE;
|
|
1350
1011
|
const nowSecs = Math.floor(Date.now() / 1000);
|
|
1351
1012
|
let reuseSlug = options.box;
|
|
1352
|
-
// Lease runs share one default warm pool across repositories. The generic
|
|
1353
|
-
// `.crabbox.yaml profile:` remains available to repo sandbox/CI scripts;
|
|
1354
|
-
// `leaseProfile:` is the explicit opt-in for a dedicated lease hot box.
|
|
1355
1013
|
const repoRoot = gitToplevel(leaseCwd);
|
|
1356
1014
|
const { readCrabboxLeaseProfile } = await import('../lib/crabbox/config.js');
|
|
1357
1015
|
const poolProfile = repoRoot ? readCrabboxLeaseProfile(repoRoot) : 'default';
|
|
@@ -1366,12 +1024,12 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1366
1024
|
});
|
|
1367
1025
|
}
|
|
1368
1026
|
catch {
|
|
1369
|
-
warm = [];
|
|
1027
|
+
warm = [];
|
|
1370
1028
|
}
|
|
1371
1029
|
const alwaysFresh = repoRoot ? isAlwaysFreshRepo(readAlwaysFreshRepos(), repoRoot) : false;
|
|
1372
1030
|
if (warm.length > 0 && !alwaysFresh) {
|
|
1373
1031
|
if (options.reuse) {
|
|
1374
|
-
reuseSlug = warm[0].slug;
|
|
1032
|
+
reuseSlug = warm[0].slug;
|
|
1375
1033
|
}
|
|
1376
1034
|
else if (isInteractiveTerminal() && options.json !== true) {
|
|
1377
1035
|
const { select } = await import('@inquirer/prompts');
|
|
@@ -1400,21 +1058,14 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1400
1058
|
console.error(chalk.yellow('Selection cancelled — provisioning a fresh box.'));
|
|
1401
1059
|
}
|
|
1402
1060
|
}
|
|
1403
|
-
// Headless with no --reuse falls through here → leaseAndRun's
|
|
1404
|
-
// profile-pool check decides (reuse a ready pool box, else warm fresh).
|
|
1405
1061
|
}
|
|
1406
1062
|
else if (options.reuse && warm.length > 0) {
|
|
1407
|
-
// --reuse still honors a warm box even when the picker is suppressed.
|
|
1408
1063
|
reuseSlug = warm[0].slug;
|
|
1409
1064
|
}
|
|
1410
1065
|
}
|
|
1411
|
-
// reuseContext: an existing box (picked, --box, or --reuse) defaults the
|
|
1412
|
-
// network to the tailnet; a solo one-shot --lease stays public.
|
|
1413
1066
|
const reuseContext = !!reuseSlug || !!options.reuse;
|
|
1414
1067
|
let netMode = computeNetMode({ tailscale: options.tailscale, reuseContext });
|
|
1415
1068
|
const copySetup = !options.bare;
|
|
1416
|
-
// Tailscale requested but no auth key configured → downgrade to public
|
|
1417
|
-
// with an actionable hint instead of hard-failing the run (F5).
|
|
1418
1069
|
if (netMode === 'tailscale') {
|
|
1419
1070
|
const { pickTailscaleBundleFromList } = await import('../lib/crabbox/cli.js');
|
|
1420
1071
|
const { listBundles } = await import('../lib/secrets-client.js');
|
|
@@ -1443,10 +1094,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1443
1094
|
let runtime = null;
|
|
1444
1095
|
let credentialRuntimes = [];
|
|
1445
1096
|
let dispatchProfile;
|
|
1446
|
-
// `--lease` requires a prompt (guarded above), so it is headless by
|
|
1447
|
-
// contract — never block on an interactive picker. Provision exactly the
|
|
1448
|
-
// one runtime this run needs, inferred from the agent, not every
|
|
1449
|
-
// signed-in CLI (which would ship unrelated tokens to a throwaway box).
|
|
1450
1097
|
if (profileExists(agentName)) {
|
|
1451
1098
|
try {
|
|
1452
1099
|
const profile = readProfile(agentName);
|
|
@@ -1484,14 +1131,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1484
1131
|
console.error(chalk.yellow(`Profile '${agentName}' needs ${runtime} credentials, but ${runtime} is not signed in locally. Sign in locally, then retry.`));
|
|
1485
1132
|
process.exit(1);
|
|
1486
1133
|
}
|
|
1487
|
-
// Refuse before account selection, OAuth reads, box lookup, or lease
|
|
1488
|
-
// provisioning. A provider-backed profile has no credentialRuntimes and
|
|
1489
|
-
// proceeds with its portable provider environment instead.
|
|
1490
1134
|
assertNoNativeOAuthTransfer(credentialRuntimes, detected);
|
|
1491
|
-
// Headless-by-contract: don't prompt, but print exactly what ships and
|
|
1492
|
-
// where — copying an auth token to a cloud box is a credential transfer.
|
|
1493
|
-
// The box is destroyed after the run, so the credential's lifetime is
|
|
1494
|
-
// bounded by the run.
|
|
1495
1135
|
const whatShips = dispatchProfile
|
|
1496
1136
|
? `profile '${dispatchProfile.name}'`
|
|
1497
1137
|
: `${runtime} runtime setup`;
|
|
@@ -1509,13 +1149,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1509
1149
|
: 'the shared-pool box is kept after the run';
|
|
1510
1150
|
console.error(chalk.gray(`${boxLifecycle} · shipping ${whatShips}; ${boxAfterRun}.`));
|
|
1511
1151
|
const claudeCredentialsJson = null;
|
|
1512
|
-
// Progress UI (F2, RUSH-1921). A self-throttled spinner (NOT ora — see
|
|
1513
|
-
// progress.ts) covers provisioning; the box-side bootstrap then streams a
|
|
1514
|
-
// structured step stream (sync → install → runtime → creds → …) via the
|
|
1515
|
-
// router's `onStep`, and each step renders as a checklist line through the
|
|
1516
|
-
// lib's `renderStepLine` (✔ <Step> — <detail> (<elapsed>)). The agent's own
|
|
1517
|
-
// output prints verbatim after the box-side marker. Rule: only ONE spinner
|
|
1518
|
-
// phase is active at a time, so it can never storm.
|
|
1519
1152
|
const { createLeaseOutputRouter, createSpinner, renderStepLine } = await import('../lib/crabbox/progress.js');
|
|
1520
1153
|
const spinner = createSpinner({ stream: process.stderr });
|
|
1521
1154
|
let warmupTimer;
|
|
@@ -1525,10 +1158,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1525
1158
|
} };
|
|
1526
1159
|
const jsonMode = options.json === true;
|
|
1527
1160
|
const stepsTty = Boolean(process.stderr.isTTY) && !jsonMode;
|
|
1528
|
-
// The step currently in flight (its label spins on a TTY). It is persisted
|
|
1529
|
-
// as a ✔ line when the NEXT step arrives (whose elapsedMs measures how long
|
|
1530
|
-
// THIS step's block took) — or, for the last step, when agent output or
|
|
1531
|
-
// teardown begins.
|
|
1532
1161
|
let activeStep = null;
|
|
1533
1162
|
const flushStep = (elapsedMs) => {
|
|
1534
1163
|
if (!activeStep)
|
|
@@ -1544,18 +1173,15 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1544
1173
|
};
|
|
1545
1174
|
const router = createLeaseOutputRouter({
|
|
1546
1175
|
now: () => Date.now(),
|
|
1547
|
-
// Raw setup lines stay captured for a failure dump (router.setupLines());
|
|
1548
|
-
// the structured step stream drives the visible checklist, so plain lines
|
|
1549
|
-
// are not shown (they would fight the step spinner).
|
|
1550
1176
|
onSetupLine: () => { },
|
|
1551
1177
|
onStep: (step) => {
|
|
1552
|
-
flushStep(step.elapsedMs);
|
|
1178
|
+
flushStep(step.elapsedMs);
|
|
1553
1179
|
activeStep = step;
|
|
1554
1180
|
if (stepsTty)
|
|
1555
1181
|
spinner.start(renderStepLine(step));
|
|
1556
1182
|
},
|
|
1557
1183
|
onAgentChunk: (chunk) => {
|
|
1558
|
-
flushStep();
|
|
1184
|
+
flushStep();
|
|
1559
1185
|
if (spinner.active)
|
|
1560
1186
|
spinner.stop();
|
|
1561
1187
|
process.stdout.write(chunk);
|
|
@@ -1595,7 +1221,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1595
1221
|
else if (phase.kind === 'ready') {
|
|
1596
1222
|
stopTimer();
|
|
1597
1223
|
const addr = boxAddress(phase.box);
|
|
1598
|
-
// Steps drive the spinner from here — no generic "Setting up box…".
|
|
1599
1224
|
spinner.stopAndPersist('✔', `Box ${phase.box.slug} ready${addr ? ` (${addr})` : ''} · ${Math.round(phase.elapsedMs / 1000)}s`);
|
|
1600
1225
|
}
|
|
1601
1226
|
else if (phase.kind === 'teardown') {
|
|
@@ -1610,9 +1235,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1610
1235
|
stopTimer();
|
|
1611
1236
|
if (spinner.active)
|
|
1612
1237
|
spinner.stop();
|
|
1613
|
-
// Safety net: if setup failed before the agent ever ran, the setup log
|
|
1614
|
-
// was only shown as transient spinner text — surface it so the error is
|
|
1615
|
-
// diagnosable.
|
|
1616
1238
|
if (exitCode !== 0 && !router.sawAgent()) {
|
|
1617
1239
|
const log = router.setupLines();
|
|
1618
1240
|
if (log.length)
|
|
@@ -1634,19 +1256,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1634
1256
|
process.exit(1);
|
|
1635
1257
|
}
|
|
1636
1258
|
}
|
|
1637
|
-
// --device/--on/--computer: offload this run onto a registered agent host
|
|
1638
|
-
// over SSH instead of running locally. The three flags are aliases.
|
|
1639
1259
|
const hostGiven = hostTargetGiven(options);
|
|
1640
|
-
// Auto-sync this run's redacted trajectory when it exits, so the console is
|
|
1641
|
-
// never stale and a session link/QR resolves the moment the run finishes
|
|
1642
|
-
// (PHNX-3628). Armed HERE — after hostGiven is finalized — so every
|
|
1643
|
-
// remote-placement signal is already reflected in options: --device/--on/
|
|
1644
|
-
// --computer and --where device: (expanded to options.host above), AND the
|
|
1645
|
-
// --resume-to-peer redirect that sets options.host during resume
|
|
1646
|
-
// resolution. A run that will dispatch remotely (hostGiven non-empty, or
|
|
1647
|
-
// --lease/--box) has its trajectory on that box and never arms a local
|
|
1648
|
-
// sync; --cloud returned earlier. The module additionally gates on opt-in
|
|
1649
|
-
// (signed in + already synced once) and is best-effort.
|
|
1650
1260
|
if (prompt !== undefined &&
|
|
1651
1261
|
hostGiven.length === 0 &&
|
|
1652
1262
|
!options.lease &&
|
|
@@ -1654,8 +1264,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1654
1264
|
const { armRunFinishTraceSync } = await import('../lib/run-trace-sync.js');
|
|
1655
1265
|
armRunFinishTraceSync({ disabled: options.traceSync === false });
|
|
1656
1266
|
}
|
|
1657
|
-
// Home anchors belong to the executing host; preserve them until a remote
|
|
1658
|
-
// invocation reaches its local execution path.
|
|
1659
1267
|
options.cwd = await resolveRunCwd(options, { forRemote: hostGiven.length > 0 });
|
|
1660
1268
|
if (hostGiven.length > 0) {
|
|
1661
1269
|
if (new Set(hostGiven).size > 1) {
|
|
@@ -1663,18 +1271,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1663
1271
|
process.exit(1);
|
|
1664
1272
|
}
|
|
1665
1273
|
const hostName = hostGiven[0];
|
|
1666
|
-
// Note: a `run auto` dispatch needs no marker forwarded from here — the
|
|
1667
|
-
// dispatch layer (hosts/dispatch.ts remoteRunShellPrelude) exports the
|
|
1668
|
-
// chain-hop guard into the remote shell for BOTH interactive and
|
|
1669
|
-
// headless paths, keyed off the agent name being `auto`.
|
|
1670
1274
|
const { resolveHostRunTarget, resolveHostSessionId, dispatchPromptToHost, HostResolutionError } = await import('../lib/hosts/run-target.js');
|
|
1671
1275
|
const { runInteractiveOnHost } = await import('../lib/hosts/dispatch.js');
|
|
1672
1276
|
const { registerInteractiveHostSession } = await import('../lib/hosts/session-index.js');
|
|
1673
1277
|
const { RUN_OPTION_REJECT_MESSAGES } = await import('../lib/hosts/remote-cmd.js');
|
|
1674
1278
|
const { normalizeRunStrategy, RUN_STRATEGIES } = await import('../lib/accounting/rotate.js');
|
|
1675
|
-
// The forwarding contract (RUN_OPTION_FORWARDING): options that cannot
|
|
1676
|
-
// cross the SSH boundary fail loud BEFORE dispatch — never a silent
|
|
1677
|
-
// drop. Value-aware: only reject what was actually passed.
|
|
1678
1279
|
const hostRejects = [];
|
|
1679
1280
|
if (options.secrets.length > 0)
|
|
1680
1281
|
hostRejects.push(RUN_OPTION_REJECT_MESSAGES.secrets);
|
|
@@ -1695,10 +1296,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1695
1296
|
process.exit(1);
|
|
1696
1297
|
return;
|
|
1697
1298
|
}
|
|
1698
|
-
// Shared resolution (name → capability tag → error). A password-auth
|
|
1699
|
-
// device throws DeviceOffloadUnsupportedError inside the helper and
|
|
1700
|
-
// propagates untouched — it's printed cleanly by the top-level catch in
|
|
1701
|
-
// index.ts (covers every resolveHost caller).
|
|
1702
1299
|
let host;
|
|
1703
1300
|
try {
|
|
1704
1301
|
host = await resolveHostRunTarget(hostName, { any: options.any });
|
|
@@ -1712,13 +1309,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1712
1309
|
}
|
|
1713
1310
|
try {
|
|
1714
1311
|
const [runAgent, rawRunVersion] = normalizedAgentSpec.split('#')[0].split('@');
|
|
1715
|
-
// Forward the explicit @version pin verbatim. Resolving aliases like
|
|
1716
|
-
// @latest locally would check local installs, but the remote host may
|
|
1717
|
-
// have versions the laptop does not. The remote agents CLI resolves
|
|
1718
|
-
// aliases against its own installed versions.
|
|
1719
1312
|
const runVersion = rawRunVersion || undefined;
|
|
1720
|
-
// Normalize the effective strategy exactly like the local path so we
|
|
1721
|
-
// fail fast on invalid input and can forward --balanced/--strategy.
|
|
1722
1313
|
const explicitStrategy = options.strategy ? normalizeRunStrategy(options.strategy) : null;
|
|
1723
1314
|
if (options.strategy && !explicitStrategy) {
|
|
1724
1315
|
console.error(chalk.red(`Invalid strategy: ${options.strategy}. Use ${RUN_STRATEGIES.join(', ')}.`));
|
|
@@ -1729,73 +1320,34 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1729
1320
|
process.exit(1);
|
|
1730
1321
|
}
|
|
1731
1322
|
const runStrategy = options.balanced ? 'balanced' : explicitStrategy ?? undefined;
|
|
1732
|
-
// Working directory on the host: an explicit --remote-cwd is used
|
|
1733
|
-
// verbatim; --cwd/--project are made portable (a local-home absolute
|
|
1734
|
-
// becomes `~/…` so the remote shell re-roots it at ITS home).
|
|
1735
|
-
//
|
|
1736
|
-
// With neither flag, mirror the LOCAL cwd's home-relative path onto
|
|
1737
|
-
// the host (deriveMirroredCwd). Otherwise every host run starts in the
|
|
1738
|
-
// remote `$HOME` — launch an agent from a repo and it opens with no
|
|
1739
|
-
// project, and you `cd` by hand every time. The same checkout at the
|
|
1740
|
-
// same home-relative path on both boxes is the normal fleet layout, so
|
|
1741
|
-
// the mirror usually hits; when the host lacks that directory the run
|
|
1742
|
-
// falls back to the remote home rather than failing.
|
|
1743
1323
|
const { toRemotePortable } = await import('../lib/project-root.js');
|
|
1744
1324
|
const { deriveMirroredCwd } = await import('../lib/hosts/dispatch.js');
|
|
1745
1325
|
const explicitHostCwd = options.remoteCwd ?? (options.cwd ? toRemotePortable(options.cwd) : undefined);
|
|
1746
1326
|
const hostCwd = explicitHostCwd ?? deriveMirroredCwd(process.cwd());
|
|
1747
1327
|
const mirrorHostCwd = explicitHostCwd === undefined;
|
|
1748
1328
|
const hostAddDirs = options.addDir.length > 0 ? options.addDir.map(toRemotePortable) : undefined;
|
|
1749
|
-
// `--resume [id]`: commander yields the string id, or `true` when the
|
|
1750
|
-
// flag is passed bare. A bare resume needs the interactive picker,
|
|
1751
|
-
// which can't run over a detached remote dispatch — only forward a
|
|
1752
|
-
// concrete id.
|
|
1753
1329
|
const resumeId = typeof options.resume === 'string' ? options.resume : undefined;
|
|
1754
1330
|
let hostCopyCreds;
|
|
1755
|
-
// Decide whether this host run is interactive. No prompt always means
|
|
1756
|
-
// interactive (matching local resolveInteractive); --interactive forces
|
|
1757
|
-
// interactive even when a prompt is provided; --headless forces headless
|
|
1758
|
-
// and therefore requires a prompt.
|
|
1759
1331
|
if (options.interactive && options.headless) {
|
|
1760
1332
|
console.error(chalk.red('--interactive and --headless are mutually exclusive. Pass one, or neither (mode is inferred from prompt presence).'));
|
|
1761
1333
|
process.exit(1);
|
|
1762
1334
|
}
|
|
1763
1335
|
const interactiveHost = options.interactive === true || (prompt === undefined && options.headless !== true);
|
|
1764
|
-
// When the account was already picked up front (`#@`), the dispatch
|
|
1765
|
-
// forwards `#label` and the peer needs no interactive picker.
|
|
1766
1336
|
if (accountPickerRequested && !upFrontAccountPick && !interactiveHost) {
|
|
1767
1337
|
console.error(chalk.red(`Account selection with ${agentSpec} requires an interactive host run. ` +
|
|
1768
1338
|
`Use agents run ${runAgent}# --device ${host.name} --interactive.`));
|
|
1769
1339
|
process.exit(1);
|
|
1770
1340
|
}
|
|
1771
1341
|
if (interactiveHost) {
|
|
1772
|
-
// Interactive host run: forward the local TTY over SSH and let the
|
|
1773
|
-
// remote agent start its normal interactive UI (tmux on the host).
|
|
1774
1342
|
if (options.follow === false) {
|
|
1775
1343
|
console.error(chalk.red('--no-follow is not compatible with interactive host runs. Interactive runs are attached by definition.'));
|
|
1776
1344
|
process.exit(1);
|
|
1777
1345
|
}
|
|
1778
|
-
// Mirror the local path (lib/exec.ts): only Claude accepts a forced
|
|
1779
|
-
// `--session-id`. Adopt the caller's id when present; otherwise mint
|
|
1780
|
-
// one here. Registering that same id keeps the local index aligned
|
|
1781
|
-
// with the remote agent. On resume, don't mint a new one.
|
|
1782
1346
|
const hostSessionId = resolveHostSessionId(runAgent, resumeId, options.sessionId);
|
|
1783
|
-
// For every OTHER agent the remote coins its own id, which we can't
|
|
1784
|
-
// know up front. Forward a launch id we control as AGENT_LAUNCH_ID:
|
|
1785
|
-
// the remote `agents run` adopts it (exec.ts resolveLaunchId) and its
|
|
1786
|
-
// SessionStart hook records the real id under that exact key, so after
|
|
1787
|
-
// the stream we resolve the id by one ssh read of the remote hook
|
|
1788
|
-
// record — the same launch-id join used locally (RUSH-2034). Not
|
|
1789
|
-
// needed for Claude (id forced) or resume (id already known).
|
|
1790
|
-
// `run auto` ALWAYS joins: the remote picks the harness, so an
|
|
1791
|
-
// explicit --session-id is only adopted by a claude pick.
|
|
1792
1347
|
const correlationLaunchId = hostInteractiveNeedsCorrelationId(runAgent, hostSessionId, resumeId) ? randomUUID() : undefined;
|
|
1793
1348
|
const hostEnv = correlationLaunchId
|
|
1794
1349
|
? [...options.env, `AGENT_LAUNCH_ID=${correlationLaunchId}`]
|
|
1795
1350
|
: options.env;
|
|
1796
|
-
// `run auto` never pre-registers: the explicit id is only real when
|
|
1797
|
-
// the remote pick lands on claude. The launch-id join below records
|
|
1798
|
-
// the id the remote ACTUALLY used, whatever the pick.
|
|
1799
1351
|
if (hostSessionId && runAgent !== RUN_AUTO_KEYWORD) {
|
|
1800
1352
|
registerInteractiveHostSession({
|
|
1801
1353
|
cwd: process.cwd(),
|
|
@@ -1852,13 +1404,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1852
1404
|
forceInteractive: options.interactive,
|
|
1853
1405
|
copyCreds: hostCopyCreds,
|
|
1854
1406
|
});
|
|
1855
|
-
// Resolve a non-Claude agent's REAL remote session id now the run has
|
|
1856
|
-
// booted (its hook has fired on the peer): one ssh read of the remote
|
|
1857
|
-
// hook record, keyed by the launch id we forwarded. Register it so the
|
|
1858
|
-
// run shows in `agents sessions` and can be reconnected/focused —
|
|
1859
|
-
// closing the non-Claude gap RUSH-2033 left. Best-effort: an
|
|
1860
|
-
// unreachable host or a not-yet-landed record leaves the run un-mapped
|
|
1861
|
-
// rather than mis-mapped.
|
|
1862
1407
|
let resolvedRemoteId;
|
|
1863
1408
|
if (correlationLaunchId) {
|
|
1864
1409
|
const { resolveRemoteSessionId } = await import('../lib/hosts/remote-session-id.js');
|
|
@@ -1867,7 +1412,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1867
1412
|
resolvedRemoteId = resolveRemoteSessionId(sshTargetFor(host), correlationLaunchId);
|
|
1868
1413
|
}
|
|
1869
1414
|
catch {
|
|
1870
|
-
/* ssh read is best-effort — keep the run un-mapped, never guess */
|
|
1871
1415
|
}
|
|
1872
1416
|
if (resolvedRemoteId) {
|
|
1873
1417
|
registerInteractiveHostSession({
|
|
@@ -1879,19 +1423,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1879
1423
|
});
|
|
1880
1424
|
}
|
|
1881
1425
|
}
|
|
1882
|
-
// A network drop kills the local ssh client (exit 255). What the
|
|
1883
|
-
// remote agent does next depends on the peer's tmux.enabled
|
|
1884
|
-
// (PHNX-3316): wrapped, it survives in its detached pane and the
|
|
1885
|
-
// reconnect rejoins it; bare (the default), the drop SIGHUPs it and
|
|
1886
|
-
// the reconnect resumes the session in place from disk. Either way,
|
|
1887
|
-
// with a known session id (Claude's forced id, a resumed run, or a
|
|
1888
|
-
// non-Claude id we just resolved from the remote hook record) we
|
|
1889
|
-
// reconnect automatically instead of exiting — the user never has
|
|
1890
|
-
// to notice the drop and `agents sessions focus` by hand.
|
|
1891
|
-
// `raw` runs opted out of all of this, so there is nothing to
|
|
1892
|
-
// reconnect to. For `run auto` prefer the join-resolved id (the
|
|
1893
|
-
// harness the remote ACTUALLY picked) over the explicit
|
|
1894
|
-
// --session-id only claude adopts.
|
|
1895
1426
|
const { pickReconnectTarget, reconnectInteractiveSession, afterInteractiveRemoteExit, SSH_CONN_FAILURE } = await import('../lib/hosts/reconnect.js');
|
|
1896
1427
|
const reconnectTarget = pickReconnectTarget({
|
|
1897
1428
|
agent: runAgent,
|
|
@@ -1900,9 +1431,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1900
1431
|
resumeId,
|
|
1901
1432
|
launchId: correlationLaunchId,
|
|
1902
1433
|
});
|
|
1903
|
-
// Raw is not tmux-wrapped, so it never auto-reconnects — but it
|
|
1904
|
-
// still prints the session id (EXEC-55). Bundling the notice
|
|
1905
|
-
// behind `!isRaw` left a dropped `--raw` tab as a bare shell.
|
|
1906
1434
|
const next = afterInteractiveRemoteExit({
|
|
1907
1435
|
target: reconnectTarget,
|
|
1908
1436
|
host: host.name,
|
|
@@ -1920,14 +1448,10 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1920
1448
|
process.stderr.write(next.notice);
|
|
1921
1449
|
process.exit(exitCode);
|
|
1922
1450
|
}
|
|
1923
|
-
// Headless host run: launch detached, tail the remote log, and follow
|
|
1924
|
-
// until the remote process exits.
|
|
1925
1451
|
if (prompt === undefined) {
|
|
1926
1452
|
console.error(chalk.red('A prompt is required for headless host runs: agents run <agent> "<task>" --device <name>'));
|
|
1927
1453
|
process.exit(1);
|
|
1928
1454
|
}
|
|
1929
|
-
// Session-id mint, detached dispatch, and local session-index
|
|
1930
|
-
// registration all live in the shared helper (lib/hosts/run-target.ts).
|
|
1931
1455
|
const { modeForRemoteDispatch } = await import('../lib/codex-policy.js');
|
|
1932
1456
|
const forwardedMode = modeForRemoteDispatch(options.mode, command.getOptionValueSource('mode'));
|
|
1933
1457
|
if (process.env.AGENTS_DISPATCH_DEBUG || options.verbose) {
|
|
@@ -1966,18 +1490,12 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1966
1490
|
copyCreds: hostCopyCreds,
|
|
1967
1491
|
});
|
|
1968
1492
|
if (options.follow === false) {
|
|
1969
|
-
// The handle the caller uses to check on the run: the name if given,
|
|
1970
|
-
// else the real host-task id (never the old literal `<id>`). Steer
|
|
1971
|
-
// to the compact `agents sessions` digest over the raw log first.
|
|
1972
1493
|
const handle = task.name ?? task.id;
|
|
1973
1494
|
console.log(chalk.green(`Dispatched to ${host.name}${task.name ? ` as "${task.name}"` : ''}.`) + '\n' +
|
|
1974
1495
|
chalk.gray(` Status: agents sessions ${handle}`) + chalk.gray(' (compact digest — use this)') + '\n' +
|
|
1975
1496
|
chalk.gray(` Raw log: agents logs ${handle} -f`) + chalk.gray(' (heavy, only if needed)'));
|
|
1976
1497
|
process.exit(0);
|
|
1977
1498
|
}
|
|
1978
|
-
// -1 = the follow window closed but the run continues on the host (the
|
|
1979
|
-
// reattach hint is already printed). That's a detach, not a failure —
|
|
1980
|
-
// exit 0. Any real remote code passes through.
|
|
1981
1499
|
if (exitCode === -1)
|
|
1982
1500
|
process.exit(0);
|
|
1983
1501
|
process.exit(exitCode ?? 1);
|
|
@@ -1987,11 +1505,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
1987
1505
|
process.exit(1);
|
|
1988
1506
|
}
|
|
1989
1507
|
}
|
|
1990
|
-
// --resume-checkpoint short-circuits normal dispatch entirely: the
|
|
1991
|
-
// checkpoint already carries the agent, version, prompt, session id,
|
|
1992
|
-
// iteration, and loop config of the killed run. Reconstruct ExecOptions
|
|
1993
|
-
// straight from it and continue the loop from the last completed
|
|
1994
|
-
// iteration, reusing the SAME runId/runDir (issue #332).
|
|
1995
1508
|
if (options.resumeCheckpoint) {
|
|
1996
1509
|
const { readCheckpoint } = await import('../lib/checkpoint.js');
|
|
1997
1510
|
const { runLoop } = await import('../lib/loop.js');
|
|
@@ -2014,10 +1527,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2014
1527
|
json: true,
|
|
2015
1528
|
headless: true,
|
|
2016
1529
|
};
|
|
2017
|
-
// Resume honors the checkpoint's loop config, but lets the resume
|
|
2018
|
-
// command RAISE the bounds field-by-field — `--max-iterations 4` on a
|
|
2019
|
-
// checkpoint capped at 2 is the natural "continue, run more" gesture.
|
|
2020
|
-
// Flags override; unspecified fields fall through from the checkpoint.
|
|
2021
1530
|
const resumeLoop = { ...cp.loop };
|
|
2022
1531
|
if (options.maxIterations !== undefined) {
|
|
2023
1532
|
const n = Number(options.maxIterations);
|
|
@@ -2063,9 +1572,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2063
1572
|
sessionId: cp.sessionId,
|
|
2064
1573
|
});
|
|
2065
1574
|
process.stderr.write(chalk.gray(`[loop] stopped: ${result.stoppedBy} after ${result.iterations} iteration(s), ${result.tokens} tokens\n`));
|
|
2066
|
-
// Governance chokepoint (#347): --resume-checkpoint short-circuits normal
|
|
2067
|
-
// dispatch and exits here — record its one audit entry with the agent,
|
|
2068
|
-
// version, and cwd reconstructed from the checkpoint.
|
|
2069
1575
|
const resumeExit = loopExitCode(result.stoppedBy);
|
|
2070
1576
|
recordDispatchedRun({
|
|
2071
1577
|
agent: cp.agent,
|
|
@@ -2074,8 +1580,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2074
1580
|
cwd: resumeExec.cwd ?? process.cwd(),
|
|
2075
1581
|
exitCode: resumeExit,
|
|
2076
1582
|
});
|
|
2077
|
-
// A resumed loop is always headless; surface any commits it left unpushed
|
|
2078
|
-
// and any open PR it left unattended (RUSH-2394).
|
|
2079
1583
|
if (shouldWarnUnpushed(resumeExec.mode ?? 'auto', false)) {
|
|
2080
1584
|
const resumeCwd = resumeExec.cwd ?? process.cwd();
|
|
2081
1585
|
await warnUnpushedWork(resumeCwd);
|
|
@@ -2083,10 +1587,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2083
1587
|
}
|
|
2084
1588
|
process.exit(resumeExit);
|
|
2085
1589
|
}
|
|
2086
|
-
const [{ buildExecCommand, parseExecEnv, execAgent, runWithFallback, normalizeMode, resolveMode, implicitModeFor, headlessPlanStallCommand, nativeResume, resolveInteractive, inferredInteractiveWithoutTty }, { ALL_AGENT_IDS, ACCOUNT_INSPECTION_AGENT_IDS, agentLabel, supportsAccountInspection }, { profileExists, readProfile, resolveProfileForRun },
|
|
2087
|
-
// Engine DATA ops resolve through the standalone `secrets` process client
|
|
2088
|
-
// (PHNX-3989); the agents-owned `bundle@host` policy helpers stay in agents-cli.
|
|
2089
|
-
{ readAndResolveBundleEnv, describeBundle, remoteResolveEnv }, { assertRemoteBundleFlagsUnsupported, splitBundleRef, resolveSecretsContextForRun }, { resolveHostSshTarget }, { getConfiguredRunStrategy, normalizeRunStrategy, resolveRunVersion, rotationFailoverChain, DEFAULT_ROTATION_FAILOVER_LIMIT, shouldArmRotationFailover, preflightFallbackHandoff, preflightHandoffEligible, RUN_STRATEGIES, collectHarnessCandidates, pickHarnessWeighted, classifyHarnessCandidates, formatHarnessPickBanner, formatNoHealthyHarnessError, formatNoHealthyAccountError, formatNoVerifiedUsageError, signInRecoverableCandidates }, { getGlobalDefault, getVersionHomePath, resolveVersion, resolveVersionAlias, ensureAgentRunnable }, { buildDiscoveredPlugin, loadPluginManifest, syncPluginToVersion }, { parseWorkflowFrontmatter, resolveWorkflowRef, resolveAllowedSubagents, pruneStaleWorkflowSubagents, ensureSubagentDispatchTool }, { resolveRunDefaults }, { getMcpServersByName, buildWorkflowMcpConfig }, { supports, capableAgents }, { shareRuntimeEnv },] = await Promise.all([
|
|
1590
|
+
const [{ buildExecCommand, parseExecEnv, execAgent, runWithFallback, normalizeMode, resolveMode, implicitModeFor, headlessPlanStallCommand, nativeResume, resolveInteractive, inferredInteractiveWithoutTty }, { ALL_AGENT_IDS, ACCOUNT_INSPECTION_AGENT_IDS, agentLabel, supportsAccountInspection }, { profileExists, readProfile, resolveProfileForRun }, { readAndResolveBundleEnv, describeBundle, remoteResolveEnv }, { assertRemoteBundleFlagsUnsupported, splitBundleRef, resolveSecretsContextForRun }, { resolveHostSshTarget }, { getConfiguredRunStrategy, normalizeRunStrategy, resolveRunVersion, rotationFailoverChain, DEFAULT_ROTATION_FAILOVER_LIMIT, shouldArmRotationFailover, preflightFallbackHandoff, preflightHandoffEligible, RUN_STRATEGIES, collectHarnessCandidates, pickHarnessWeighted, classifyHarnessCandidates, formatHarnessPickBanner, formatNoHealthyHarnessError, formatNoHealthyAccountError, formatNoVerifiedUsageError, signInRecoverableCandidates }, { getGlobalDefault, getVersionHomePath, resolveVersion, resolveVersionAlias, ensureAgentRunnable }, { buildDiscoveredPlugin, loadPluginManifest, syncPluginToVersion }, { parseWorkflowFrontmatter, resolveWorkflowRef, resolveAllowedSubagents, pruneStaleWorkflowSubagents, ensureSubagentDispatchTool }, { resolveRunDefaults }, { getMcpServersByName, buildWorkflowMcpConfig }, { supports, capableAgents }, { shareRuntimeEnv },] = await Promise.all([
|
|
2090
1591
|
import('../lib/exec.js'),
|
|
2091
1592
|
import('../lib/agents.js'),
|
|
2092
1593
|
import('../lib/profiles.js'),
|
|
@@ -2104,8 +1605,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2104
1605
|
]);
|
|
2105
1606
|
bootMark('run-deps:imported');
|
|
2106
1607
|
const isValidAgent = (agent) => ALL_AGENT_IDS.includes(agent);
|
|
2107
|
-
// Parse agent@version#label. The label selects native auth without pinning
|
|
2108
|
-
// the binary version; --account remains the equivalent flag form.
|
|
2109
1608
|
const labelParts = normalizedAgentSpec.split('#');
|
|
2110
1609
|
if (labelParts.length > 2 || labelParts[1] === '') {
|
|
2111
1610
|
console.error(chalk.red(`Invalid account label in '${normalizedAgentSpec}'.`));
|
|
@@ -2137,25 +1636,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2137
1636
|
let profileName;
|
|
2138
1637
|
let profileFallbackModel;
|
|
2139
1638
|
let workflowModel;
|
|
2140
|
-
// WORKFLOW.md capability scoping, translated to Claude headless flags below.
|
|
2141
1639
|
let workflowToolsRestrict;
|
|
2142
1640
|
let workflowMcpConfigPath;
|
|
2143
|
-
// Full paths of workflow subagent files THIS run copied into the shared
|
|
2144
|
-
// per-agent agents dir. Torn down after the run to restore the shared dir
|
|
2145
|
-
// (issue #401), mirroring cleanupWorkflowMcpConfig for the mcp-config.
|
|
2146
1641
|
const workflowSubagentTargets = [];
|
|
2147
|
-
// WORKFLOW.md `loop:` block (issue #332). When a workflow declares it,
|
|
2148
|
-
// `agents run <workflow>` honors the loop without a --loop flag.
|
|
2149
1642
|
let workflowLoop;
|
|
2150
|
-
// WORKFLOW.md `for_each:` block (issue #343). When a workflow declares it,
|
|
2151
|
-
// `agents run <workflow>` runs the producer, expands one stage teammate per
|
|
2152
|
-
// produced item, and drives the teams supervisor to drain — no `teams`
|
|
2153
|
-
// subcommands needed.
|
|
2154
1643
|
let workflowForEach;
|
|
2155
|
-
// True once this run copies ≥1 dispatchable subagent into the shared agents
|
|
2156
|
-
// dir. Used below to keep the `Task` tool in a `tools:`-restricted workflow —
|
|
2157
|
-
// an orchestrator handed subagents but denied `Task` cannot reach them and
|
|
2158
|
-
// degenerates to a no-op ("I'll wait for the completion notification").
|
|
2159
1644
|
let workflowHasSubagents = false;
|
|
2160
1645
|
const cwd = options.cwd ?? process.cwd();
|
|
2161
1646
|
if (accountPickerRequested && profileExists(rawAgent)) {
|
|
@@ -2169,15 +1654,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2169
1654
|
}
|
|
2170
1655
|
}
|
|
2171
1656
|
if (autoHarnessRequested) {
|
|
2172
|
-
// Harness layer (RUSH-2132): weighted pick across installed harnesses
|
|
2173
|
-
// by best-account headroom. Zero healthy accounts anywhere fails loud
|
|
2174
|
-
// — launching a default "because it's there" is how a rotate loop
|
|
2175
|
-
// hammers an exhausted account.
|
|
2176
1657
|
const byHarness = await collectHarnessCandidates();
|
|
2177
|
-
// F1 (RUSH-2185 / EXEC-23a): a prompt-less run is interactive; only
|
|
2178
|
-
// harnesses that can open a REPL with no argv are valid candidates.
|
|
2179
|
-
// cursor-agent and similar exit immediately without a prompt, which
|
|
2180
|
-
// leaves a silent [detached] pane and an orphan session.
|
|
2181
1658
|
const interactive = prompt === undefined && options.headless !== true;
|
|
2182
1659
|
const replCapable = interactive ? new Set(capableAgents('interactiveRepl')) : null;
|
|
2183
1660
|
const candidateHarness = replCapable
|
|
@@ -2198,17 +1675,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2198
1675
|
if (!options.quiet) {
|
|
2199
1676
|
process.stderr.write(chalk.gray(formatHarnessPickBanner(harnessPick) + '\n'));
|
|
2200
1677
|
}
|
|
2201
|
-
// --session-id keeps its claude-only semantics: honored when auto
|
|
2202
|
-
// picks claude, ignored (loudly) otherwise.
|
|
2203
1678
|
if (options.sessionId && agent !== 'claude' && !options.quiet) {
|
|
2204
1679
|
process.stderr.write(chalk.yellow(`[agents] --session-id ignored: auto picked ${agent} (only claude accepts a forced session id)\n`));
|
|
2205
1680
|
}
|
|
2206
1681
|
}
|
|
2207
1682
|
else if (profileExists(rawAgent)) {
|
|
2208
|
-
// A profile by this exact name exists. Profiles bind (host agent,
|
|
2209
|
-
// version, env overrides, keychain-backed auth) so Chinese models
|
|
2210
|
-
// (Kimi, DeepSeek, Qwen, GLM) can run inside Claude Code without a
|
|
2211
|
-
// local proxy, including when the profile name matches a native id.
|
|
2212
1683
|
try {
|
|
2213
1684
|
const resolved = resolveProfileForRun(rawAgent, options.model);
|
|
2214
1685
|
agent = resolved.agent;
|
|
@@ -2223,16 +1694,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2223
1694
|
if (resolved.tierNote) {
|
|
2224
1695
|
process.stderr.write(chalk.gray(`[agents] ${resolved.tierNote}\n`));
|
|
2225
1696
|
}
|
|
2226
|
-
// A tier token (cheap/default/best/ultra) already resolved against
|
|
2227
|
-
// this PROFILE's own `models:` map above, when the profile opts in.
|
|
2228
|
-
// Replace the raw --model value here so the tier never reaches the
|
|
2229
|
-
// native, HOST-catalog tier block below. When the profile has no
|
|
2230
|
-
// `models:` opt-in at all, resolvedModel stays undefined and
|
|
2231
|
-
// options.model is left as the raw tier token on purpose — the
|
|
2232
|
-
// "cost tiers don't apply to custom harness ..." discard guard further
|
|
2233
|
-
// down this function is the canonical fallback for that case, and
|
|
2234
|
-
// this block must not race it with a second, differently-worded
|
|
2235
|
-
// message.
|
|
2236
1697
|
if (resolved.resolvedModel !== undefined) {
|
|
2237
1698
|
options.model = resolved.resolvedModel;
|
|
2238
1699
|
}
|
|
@@ -2246,11 +1707,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2246
1707
|
agent = rawAgent;
|
|
2247
1708
|
}
|
|
2248
1709
|
else if (resolveWorkflowRef(rawAgent, cwd)) {
|
|
2249
|
-
// Workflow: explicit directory, project .agents/workflows/<name>, user, system, or extra repo.
|
|
2250
|
-
// Resolution follows resource precedence: direct path, then project > user > system > extras.
|
|
2251
|
-
// Structure:
|
|
2252
|
-
// WORKFLOW.md ← orchestrator instructions fed to claude as system prompt
|
|
2253
|
-
// subagents/*.md ← flat .md files copied to ~/.claude/agents/ for Agent tool discovery
|
|
2254
1710
|
const workflowDir = resolveWorkflowRef(rawAgent, cwd);
|
|
2255
1711
|
agent = 'claude';
|
|
2256
1712
|
const workflowFrontmatter = parseWorkflowFrontmatter(workflowDir);
|
|
@@ -2262,29 +1718,14 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2262
1718
|
const resolvedVersion = resolveVersionAlias('claude', version);
|
|
2263
1719
|
const versionHome = getVersionHomePath('claude', resolvedVersion ?? getGlobalDefault('claude') ?? '');
|
|
2264
1720
|
const claudeAgentsDir = path.join(versionHome, '.claude', 'agents');
|
|
2265
|
-
//
|
|
2266
|
-
// them. allowedAgents enforcement (issue #324): when the workflow declares
|
|
2267
|
-
// `allowedAgents:`, copy ONLY those subagent files (matched by filename
|
|
2268
|
-
// stem, e.g. security.md -> "security"). A subagent whose definition isn't
|
|
2269
|
-
// on disk can't be dispatched — this is the actual, fail-closed mechanism.
|
|
2270
|
-
// (Claude's `--agents` flag DEFINES custom agents; it does not restrict
|
|
2271
|
-
// which subagents may be dispatched, so it is not used here.)
|
|
1721
|
+
// allowedAgents copies only named definitions; an explicit empty list means none, and pruning touches only managed copies.
|
|
2272
1722
|
const subagentsDir = path.join(workflowDir, 'subagents');
|
|
2273
1723
|
const allowedAgents = workflowFrontmatter?.allowedAgents;
|
|
2274
1724
|
if (fs.existsSync(subagentsDir)) {
|
|
2275
1725
|
fs.mkdirSync(claudeAgentsDir, { recursive: true });
|
|
2276
|
-
// Fail-closed subagent scoping (issue #324). resolveAllowedSubagents
|
|
2277
|
-
// distinguishes "allowedAgents absent" (undefined -> copy all) from
|
|
2278
|
-
// "present but empty" (=> copy ZERO). An explicit `allowedAgents: []`
|
|
2279
|
-
// must mean "allow none", never silently widen to "allow all".
|
|
2280
1726
|
const allFiles = fs.readdirSync(subagentsDir).filter(f => f.endsWith('.md'));
|
|
2281
1727
|
const { allowedStems, missing } = resolveAllowedSubagents(allFiles, allowedAgents);
|
|
2282
1728
|
const allowStemSet = new Set(allowedStems);
|
|
2283
|
-
// Fail-closed prune (issue #401, follow-up to #324). A prior
|
|
2284
|
-
// unrestricted run may have left workflow subagent files that THIS
|
|
2285
|
-
// scoped run does not permit; they linger in the shared dir and stay
|
|
2286
|
-
// dispatchable. Remove those no-longer-permitted workflow-managed
|
|
2287
|
-
// files BEFORE writing the allowed set — never a user's own subagent.
|
|
2288
1729
|
const pruned = pruneStaleWorkflowSubagents(claudeAgentsDir, allFiles, allowedStems);
|
|
2289
1730
|
if (pruned.length > 0) {
|
|
2290
1731
|
process.stderr.write(chalk.gray(`[workflow] pruned ${pruned.length} stale workflow subagent(s) from shared dir: ${pruned.join(', ')}\n`));
|
|
@@ -2305,15 +1746,12 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2305
1746
|
if (copied > 0)
|
|
2306
1747
|
workflowHasSubagents = true;
|
|
2307
1748
|
if (allowedAgents !== undefined) {
|
|
2308
|
-
// Surface any allowedAgents entry with no matching subagent file, and
|
|
2309
|
-
// report how many were filtered out, so the scope is auditable.
|
|
2310
1749
|
if (missing.length > 0) {
|
|
2311
1750
|
process.stderr.write(chalk.yellow(`[workflow] allowedAgents not found in subagents/: ${missing.join(', ')}\n`));
|
|
2312
1751
|
}
|
|
2313
1752
|
process.stderr.write(chalk.gray(`[workflow] subagents restricted to allowedAgents: copied ${copied}, withheld ${skipped}\n`));
|
|
2314
1753
|
}
|
|
2315
1754
|
}
|
|
2316
|
-
// Feed WORKFLOW.md body (strip frontmatter) as orchestrator system context.
|
|
2317
1755
|
const workflowMd = path.join(workflowDir, 'WORKFLOW.md');
|
|
2318
1756
|
const orchestratorBody = fs.existsSync(workflowMd)
|
|
2319
1757
|
? fs.readFileSync(workflowMd, 'utf-8').replace(/^---[\s\S]*?---\n/, '').trim()
|
|
@@ -2321,7 +1759,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2321
1759
|
if (orchestratorBody && prompt !== undefined) {
|
|
2322
1760
|
prompt = `${orchestratorBody}\n\n---\n\n${prompt}`;
|
|
2323
1761
|
}
|
|
2324
|
-
// Sync workflow-scoped skills into the version home's skills dir.
|
|
2325
1762
|
const workflowSkillsDir = path.join(workflowDir, 'skills');
|
|
2326
1763
|
if (fs.existsSync(workflowSkillsDir)) {
|
|
2327
1764
|
const skillsTarget = path.join(claudeAgentsDir, '..', 'skills');
|
|
@@ -2332,7 +1769,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2332
1769
|
fs.cpSync(path.join(workflowSkillsDir, entry.name), path.join(skillsTarget, entry.name), { recursive: true });
|
|
2333
1770
|
}
|
|
2334
1771
|
}
|
|
2335
|
-
// Sync workflow-scoped plugins into the version home.
|
|
2336
1772
|
const workflowPluginsDir = path.join(workflowDir, 'plugins');
|
|
2337
1773
|
if (fs.existsSync(workflowPluginsDir)) {
|
|
2338
1774
|
for (const entry of fs.readdirSync(workflowPluginsDir, { withFileTypes: true })) {
|
|
@@ -2345,10 +1781,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2345
1781
|
syncPluginToVersion(buildDiscoveredPlugin(pluginRoot, manifest), 'claude', versionHome);
|
|
2346
1782
|
}
|
|
2347
1783
|
}
|
|
2348
|
-
// Auto-inject secrets bundles declared in the workflow's frontmatter `secrets:` field.
|
|
2349
|
-
// Union with any --secrets flags the user passed; dedupe. Skip when --no-auto-secrets is set.
|
|
2350
|
-
// (Commander stores the negated flag as `autoSecrets: false` — the old
|
|
2351
|
-
// `noAutoSecrets` read was never populated, making the flag a no-op.)
|
|
2352
1784
|
if (options.autoSecrets !== false) {
|
|
2353
1785
|
const declared = workflowFrontmatter?.secrets ?? [];
|
|
2354
1786
|
if (declared.length > 0) {
|
|
@@ -2366,14 +1798,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2366
1798
|
}
|
|
2367
1799
|
}
|
|
2368
1800
|
}
|
|
2369
|
-
// Capability scoping: translate WORKFLOW.md `tools:` / `mcpServers:` into
|
|
2370
|
-
// the Claude headless flags that ACTUALLY restrict the run (verified
|
|
2371
|
-
// against `claude --help`): tools -> `--tools` (restricts the available
|
|
2372
|
-
// built-in tool set), mcpServers -> `--mcp-config` + `--strict-mcp-config`
|
|
2373
|
-
// (loads ONLY the named servers). `allowedAgents:` is enforced separately,
|
|
2374
|
-
// above, by copying only the allowed subagent definition files. Gated
|
|
2375
|
-
// behind the `allowlist` capability — if the resolved agent lacks it, warn
|
|
2376
|
-
// loudly rather than silently dropping the declaration (issue #324).
|
|
2377
1801
|
const scopeVersion = resolveVersionAlias('claude', version) ?? getGlobalDefault('claude') ?? undefined;
|
|
2378
1802
|
const allowlist = supports('claude', 'allowlist', scopeVersion);
|
|
2379
1803
|
const tools = workflowFrontmatter?.tools;
|
|
@@ -2386,15 +1810,13 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2386
1810
|
}
|
|
2387
1811
|
else if (hasScoping) {
|
|
2388
1812
|
if (tools && tools.length > 0) {
|
|
2389
|
-
// An orchestrator with dispatchable subagents MUST retain the `Task`
|
|
2390
|
-
// tool, or it can't reach the subagents this run just installed for it
|
|
2391
|
-
// — the run silently no-ops ("I'll wait for the completion notification").
|
|
2392
1813
|
workflowToolsRestrict = ensureSubagentDispatchTool(tools, workflowHasSubagents);
|
|
2393
1814
|
process.stderr.write(chalk.gray(`[workflow] restricting available tools to: ${workflowToolsRestrict.join(', ')} (Write/Bash/Edit unavailable unless listed)\n`));
|
|
2394
1815
|
if (workflowToolsRestrict.length !== tools.length) {
|
|
2395
1816
|
process.stderr.write(chalk.gray(`[workflow] kept Task tool: workflow ships subagents to dispatch\n`));
|
|
2396
1817
|
}
|
|
2397
1818
|
}
|
|
1819
|
+
// Named MCP scope always writes strict config, even when no name resolves, so ambient servers cannot leak into the workflow.
|
|
2398
1820
|
if (mcpServerNames && mcpServerNames.length > 0) {
|
|
2399
1821
|
const servers = getMcpServersByName(mcpServerNames, { cwd });
|
|
2400
1822
|
const found = new Set(servers.map(s => s.name));
|
|
@@ -2402,16 +1824,9 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2402
1824
|
if (missing.length > 0) {
|
|
2403
1825
|
process.stderr.write(chalk.yellow(`[workflow] mcpServers not found in registry, skipped: ${missing.join(', ')}\n`));
|
|
2404
1826
|
}
|
|
2405
|
-
// Fail-closed: `mcpServers:` was declared, so the run MUST be scoped to
|
|
2406
|
-
// a config — never fall through to the user's ambient MCP set. When
|
|
2407
|
-
// zero declared names resolve to installed servers, write a locked-down
|
|
2408
|
-
// empty config (`{ "mcpServers": {} }`); with `--strict-mcp-config` the
|
|
2409
|
-
// run gets NO MCP servers, which is LESS access than ambient (issue #324).
|
|
2410
1827
|
const mcpConfig = buildWorkflowMcpConfig(servers);
|
|
2411
1828
|
const configDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agents-workflow-mcp-'));
|
|
2412
1829
|
workflowMcpConfigPath = path.join(configDir, 'mcp-config.json');
|
|
2413
|
-
// 0o600: the config embeds server `env` which can carry tokens.
|
|
2414
|
-
// Cleaned up after the run (finally block below).
|
|
2415
1830
|
fs.writeFileSync(workflowMcpConfigPath, mcpConfig, { mode: 0o600 });
|
|
2416
1831
|
if (servers.length > 0) {
|
|
2417
1832
|
process.stderr.write(chalk.gray(`[workflow] scoping MCP servers to ONLY: ${servers.map(s => s.name).join(', ')}\n`));
|
|
@@ -2421,17 +1836,12 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2421
1836
|
}
|
|
2422
1837
|
}
|
|
2423
1838
|
}
|
|
2424
|
-
// Count the subagents THIS workflow made available (after allowedAgents
|
|
2425
|
-
// filtering), not every file in the shared agents dir. Same fail-closed
|
|
2426
|
-
// semantics as the copy above: `allowedAgents: []` -> 0.
|
|
2427
1839
|
const subagentCount = fs.existsSync(subagentsDir)
|
|
2428
1840
|
? resolveAllowedSubagents(fs.readdirSync(subagentsDir).filter(f => f.endsWith('.md')), allowedAgents).allowedStems.length
|
|
2429
1841
|
: 0;
|
|
2430
1842
|
process.stderr.write(chalk.gray(`Workflow '${rawAgent}' → claude (${subagentCount} subagents)\n`));
|
|
2431
1843
|
}
|
|
2432
1844
|
else {
|
|
2433
|
-
// Smart pick: auto-correct a single typo (insertion/deletion/substitution/transposition)
|
|
2434
|
-
// against the known agent ids before giving up. Example: `cladue` -> `claude`, `grk` -> `grok`.
|
|
2435
1845
|
const { fuzzyMatch, FUZZY_PRESETS } = await import('../lib/fuzzy.js');
|
|
2436
1846
|
const suggested = fuzzyMatch(rawAgent, ALL_AGENT_IDS, FUZZY_PRESETS.agents);
|
|
2437
1847
|
if (suggested && isValidAgent(suggested)) {
|
|
@@ -2445,9 +1855,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2445
1855
|
process.exit(1);
|
|
2446
1856
|
}
|
|
2447
1857
|
}
|
|
2448
|
-
// `#@` already asked the account up front (before the device menu) — a
|
|
2449
|
-
// remote device pick never reaches here, so apply the local pick's
|
|
2450
|
-
// version/home and skip the on-the-spot menu.
|
|
2451
1858
|
if (accountPickerRequested && !upFrontAccountPick) {
|
|
2452
1859
|
if (!supportsAccountInspection(agent)) {
|
|
2453
1860
|
console.error(chalk.red(`${agentLabel(agent)} does not expose local account state, so agents-cli cannot safely select an account.`));
|
|
@@ -2496,8 +1903,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2496
1903
|
accountEnv = { ...accountEnv, ...launchAccount.env };
|
|
2497
1904
|
}
|
|
2498
1905
|
else {
|
|
2499
|
-
// Binding key: a custom harness keys on its own profile name; a native /
|
|
2500
|
-
// global run keys on the exact `agent@version` (default when unpinned).
|
|
2501
1906
|
const bindingTarget = fromProfile ? rawAgent : (version ? `${agent}@${version}` : `${agent}@${getGlobalDefault(agent) ?? ''}`);
|
|
2502
1907
|
try {
|
|
2503
1908
|
spawnAccount = resolveSpawnAccount(options.account, agent, version, readMeta(), { useDefault: !fromProfile, provider: profileProvider, target: bindingTarget });
|
|
@@ -2506,15 +1911,12 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2506
1911
|
console.error(chalk.red(err.message));
|
|
2507
1912
|
process.exit(1);
|
|
2508
1913
|
}
|
|
2509
|
-
// Downstream rotation gating asks only "was an account selected?".
|
|
2510
1914
|
if (spawnAccount) {
|
|
2511
1915
|
if (options.cloud || options.provider || options.lease) {
|
|
2512
1916
|
console.error(chalk.red('--account selects a device-local credential and cannot be combined with cloud or lease placement.'));
|
|
2513
1917
|
process.exit(1);
|
|
2514
1918
|
}
|
|
2515
1919
|
if (spawnAccount.kind === 'native') {
|
|
2516
|
-
// `#name` / `--account` on a --device run is forwarded unchanged at
|
|
2517
|
-
// dispatch time; the peer resolves ITS slot. This block is local-only.
|
|
2518
1920
|
const remoteTarget = options.host || options.device;
|
|
2519
1921
|
if (!remoteTarget) {
|
|
2520
1922
|
const { adoptedConfigPointsAtHome, adoptedSymlinkMismatchError, durableSlotEnv, isSymlinkAdoptedHarness, resolveNativeSpawnHome, symlinkAdoptedAccountError, } = await import('../lib/exec-account-home.js');
|
|
@@ -2534,16 +1936,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2534
1936
|
process.exit(1);
|
|
2535
1937
|
}
|
|
2536
1938
|
execHome = resolved.execHome;
|
|
2537
|
-
// A worker's durable api-key slot holds no file: the pushed key
|
|
2538
|
-
// rides the harness env var (CURSOR_API_KEY, …) on this launch.
|
|
2539
1939
|
const durable = durableSlotEnv(agent, spawnAccount, resolved, meta);
|
|
2540
1940
|
if (Object.keys(durable).length > 0)
|
|
2541
1941
|
accountEnv = { ...accountEnv, ...durable };
|
|
2542
1942
|
if (resolved.source === 'legacy-home') {
|
|
2543
1943
|
accountConfigVersion = resolved.label;
|
|
2544
|
-
// A leftover version-labeled home is both the spawn HOME and
|
|
2545
|
-
// the account's installation — the pre-T5 `resolveAccountVersion`
|
|
2546
|
-
// behavior. An explicit `@<label>` still controls the binary.
|
|
2547
1944
|
if (!version && !fromProfile && resolved.label)
|
|
2548
1945
|
version = resolved.label;
|
|
2549
1946
|
}
|
|
@@ -2552,7 +1949,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2552
1949
|
console.error(chalk.red(err.message));
|
|
2553
1950
|
process.exit(1);
|
|
2554
1951
|
}
|
|
2555
|
-
// Slot / provisioned: binary comes from the one managed install unless `@<label>` pins it.
|
|
2556
1952
|
if (!version && !fromProfile) {
|
|
2557
1953
|
const { ensureHarnessInstallation } = await import('../lib/installations/store.js');
|
|
2558
1954
|
const { installation } = await ensureHarnessInstallation(agent);
|
|
@@ -2568,7 +1964,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2568
1964
|
}
|
|
2569
1965
|
}
|
|
2570
1966
|
const configuredAccount = launchAccount?.account?.name ?? spawnAccount?.name;
|
|
2571
|
-
// The account and native context were resolved before launch defaults.
|
|
2572
1967
|
let resumeNative = false;
|
|
2573
1968
|
let resumeSessionId;
|
|
2574
1969
|
let forceInteractive = false;
|
|
@@ -2600,10 +1995,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2600
1995
|
if (resolvedRecoveryTarget.mode === 'native') {
|
|
2601
1996
|
resumeNative = true;
|
|
2602
1997
|
resumeSessionId = session.id;
|
|
2603
|
-
// The centralized recovery decision proves the transcript belongs to
|
|
2604
|
-
// this exact isolated home and resolves any harness-specific launch cwd.
|
|
2605
|
-
// Claude's indexed `session.cwd` is the first user-turn cwd, which may
|
|
2606
|
-
// differ from the earlier cwd that selected projects/<cwd-key>.
|
|
2607
1998
|
if (!options.cwd && resolvedRecoveryTarget.cwd)
|
|
2608
1999
|
options.cwd = resolvedRecoveryTarget.cwd;
|
|
2609
2000
|
if (!options.quiet)
|
|
@@ -2627,39 +2018,10 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2627
2018
|
}
|
|
2628
2019
|
const configuredStrategy = getConfiguredRunStrategy(agent, cwd);
|
|
2629
2020
|
const explicitStrategy = options.strategy ? normalizeRunStrategy(options.strategy) : null;
|
|
2630
|
-
// Captured from resolveRunVersion below so mid-run rate-limit failover can
|
|
2631
|
-
// synthesize a same-agent fallback chain from the other healthy accounts
|
|
2632
|
-
// (issue #348). Stays null unless a non-pinned strategy actually rotated.
|
|
2633
2021
|
let rotationResult = null;
|
|
2634
|
-
/**
|
|
2635
|
-
* The PRIMARY harness's configured run-default mode/effort, carried across a
|
|
2636
|
-
* preflight alternate-harness handoff (PHNX-3999 F19).
|
|
2637
|
-
*
|
|
2638
|
-
* Run defaults are resolved after the harness is known, so without this a
|
|
2639
|
-
* handoff would silently adopt the ALTERNATE's configured defaults — a
|
|
2640
|
-
* primary configured `mode: plan` becoming the alternate's `mode: skip`
|
|
2641
|
-
* escalates a read-only intent into an unattended writable run. The
|
|
2642
|
-
* canonical mid-run cascade keeps the primary's resolved mode for the same
|
|
2643
|
-
* reason (`runWithFallback` forwards `options.mode` and only re-derives the
|
|
2644
|
-
* mode that was never configured at all). An IMPLICIT mode is deliberately
|
|
2645
|
-
* not carried: it is the harness's own safe default, so the alternate's
|
|
2646
|
-
* applies (identical to `modeWasImplicit ? implicitModeFor(agent)`).
|
|
2647
|
-
*/
|
|
2648
2022
|
let handoffRunDefaults;
|
|
2649
|
-
// Precomputed launchable-signed-in verdict for the ACTUAL launched
|
|
2650
|
-
// candidate, fed to the pre-launch `run.launch` event so it need not
|
|
2651
|
-
// re-probe. Sourced per resolution branch from the candidate that WON, not
|
|
2652
|
-
// the original auto-pick: the interactive picker (RUSH-2334 / PHNX-2526)
|
|
2653
|
-
// deliberately lets the user launch a LOGGED-OUT account, which is a
|
|
2654
|
-
// different candidate than `rotationResult.picked` — reading the verdict off
|
|
2655
|
-
// the auto-pick there would report `launchedLoggedOut:false` for a version
|
|
2656
|
-
// that is actually logged out, the exact false-negative this event exists to
|
|
2657
|
-
// prevent. Left undefined for pinned-default / explicit-pin so emitRunLaunch
|
|
2658
|
-
// falls back to probing the version home itself.
|
|
2659
2023
|
let launchSignedIn;
|
|
2660
2024
|
let launchEmail;
|
|
2661
|
-
// Set when the zero-healthy path already announced a deliberate
|
|
2662
|
-
// launch-to-sign-in, so the login preflight below does not repeat it.
|
|
2663
2025
|
let signInLaunch = false;
|
|
2664
2026
|
if (options.strategy && !explicitStrategy) {
|
|
2665
2027
|
console.error(chalk.red(`Invalid strategy: ${options.strategy}. Use ${RUN_STRATEGIES.join(', ')}.`));
|
|
@@ -2670,26 +2032,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2670
2032
|
process.exit(1);
|
|
2671
2033
|
}
|
|
2672
2034
|
const strategy = options.balanced ? 'balanced' : explicitStrategy ?? configuredStrategy;
|
|
2673
|
-
// Strategy applies to bare (unpinned) invocations. Explicit @version and
|
|
2674
|
-
// profiles already name the target. A --fallback chain does NOT pin the
|
|
2675
|
-
// primary: it only names where to cascade on a rate limit, so the bare
|
|
2676
|
-
// primary still resolves through the strategy — otherwise every
|
|
2677
|
-
// `agents run claude --fallback codex` run lands on the pinned default
|
|
2678
|
-
// account and account rotation silently stops (the gh-monitor heal bug).
|
|
2679
|
-
// `pinned` still resolves so a logged-out default can yield to a signed-in
|
|
2680
|
-
// sibling on this device (PHNX-2685); an explicit @version pin is unchanged.
|
|
2681
|
-
// Bounded handoff loop: each iteration resolves an account for `agent`, and
|
|
2682
|
-
// the only `continue` is the preflight exhaustion handoff below, which
|
|
2683
|
-
// consumes one entry of the `--fallback` spec before retrying as that
|
|
2684
|
-
// alternate. The spec is finite, so this terminates (PHNX-3999 F19).
|
|
2685
|
-
// A balanced pick or the no-fresh-usage picker returns a CANDIDATE. Since
|
|
2686
|
-
// PHNX-3940 a native candidate is a registered account SLOT, not the
|
|
2687
|
-
// version home the executable lives in, so the spawn must resolve that
|
|
2688
|
-
// slot (home + durable env) through the canonical local launch resolver.
|
|
2689
|
-
// Without this the run launched the version home and whichever login it
|
|
2690
|
-
// held: on yosemite-m0 (2026-09-23) the picker chose trp and Claude
|
|
2691
|
-
// started as a different account in its first-run wizard. A remote run
|
|
2692
|
-
// re-resolves on the peer, which runs this same code locally.
|
|
2693
2035
|
const applyPickedCandidate = async (candidate) => {
|
|
2694
2036
|
if (!candidate.nativeAccount || options.host || options.device)
|
|
2695
2037
|
return;
|
|
@@ -2723,11 +2065,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2723
2065
|
}
|
|
2724
2066
|
else {
|
|
2725
2067
|
try {
|
|
2726
|
-
// Account-centric candidate list: native version-home logins PLUS
|
|
2727
|
-
// provider accounts (setup-token / API-key) that can auth this agent,
|
|
2728
|
-
// so `--strategy balanced` spreads across ALL accounts, not just the
|
|
2729
|
-
// ones sitting in a version home (RUSH-3182). Run-path only — the
|
|
2730
|
-
// picker's other callers keep the native-only collector.
|
|
2731
2068
|
const { collectRunCandidatesForRun } = await import('../lib/accounting/account-pool-collect.js');
|
|
2732
2069
|
bootMark('resolve-version:start');
|
|
2733
2070
|
const routingModel = options.model ?? resolvedResumeSource?.model ?? workflowModel
|
|
@@ -2735,20 +2072,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2735
2072
|
const resolved = await resolveRunVersion(agent, strategy, cwd, collectRunCandidatesForRun, routingModel);
|
|
2736
2073
|
bootMark('resolve-version:done');
|
|
2737
2074
|
if (resolved.exhausted) {
|
|
2738
|
-
// Zero healthy accounts splits two ways, and conflating them is what
|
|
2739
|
-
// stranded a logged-out harness with no way in at all (RUSH-2334):
|
|
2740
|
-
//
|
|
2741
|
-
// - THROTTLED (rate_limited / out_of_credits) -> fail loud (RUSH-2132).
|
|
2742
|
-
// The old behavior warned "found no usable version; falling back to
|
|
2743
|
-
// defaults" and launched the pinned default anyway — the exact move
|
|
2744
|
-
// that loops a rotate into an exhausted account. Only a window reset
|
|
2745
|
-
// clears it. The message text is a contract the Factory watchdog
|
|
2746
|
-
// tail-detects; do not reword it.
|
|
2747
|
-
// - NEEDS A SIGN-IN (signed_out / revoked) -> launching IS the fix,
|
|
2748
|
-
// because the harness's own TUI is the login surface. So on a TTY we
|
|
2749
|
-
// carry the user into that login instead of erroring. Exiting here
|
|
2750
|
-
// made `agents run <agent>`, `agents run <agent>#`, and `agents use`
|
|
2751
|
-
// all dead-end with no reachable way to authenticate.
|
|
2752
2075
|
const recoverable = signInRecoverableCandidates(resolved.exhausted);
|
|
2753
2076
|
const { signInLaunchDecision } = await import('./run-account-picker.js');
|
|
2754
2077
|
const decision = signInLaunchDecision({
|
|
@@ -2759,33 +2082,12 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2759
2082
|
if (decision === 'launch') {
|
|
2760
2083
|
const { pickSignInLaunchVersion } = await import('./run-account-picker.js');
|
|
2761
2084
|
const signInVersion = await pickSignInLaunchVersion(agent, recoverable, !!options.quiet);
|
|
2762
|
-
// A cancelled prompt launches nothing — same contract as the
|
|
2763
|
-
// trailing-# account picker above.
|
|
2764
2085
|
if (!signInVersion)
|
|
2765
2086
|
return;
|
|
2766
2087
|
version = signInVersion;
|
|
2767
|
-
// We just told the user this account is logged out and why we're
|
|
2768
|
-
// launching it, so suppress the downstream login preflight — it
|
|
2769
|
-
// would print a second, near-identical "looks logged out" warning.
|
|
2770
2088
|
signInLaunch = true;
|
|
2771
2089
|
}
|
|
2772
2090
|
else {
|
|
2773
|
-
// Every account of this harness is throttled. A configured
|
|
2774
|
-
// alternate exists for exactly this case, so hand off to it here
|
|
2775
|
-
// rather than exiting — `runWithFallback` would only reach it
|
|
2776
|
-
// after a run that can no longer start (PHNX-3999 F19). The
|
|
2777
|
-
// alternate becomes the primary and is dropped from the spec, so
|
|
2778
|
-
// the chain that remains never lists the agent now running.
|
|
2779
|
-
//
|
|
2780
|
-
// ONLY for a run shape `--fallback` is valid on. The handoff
|
|
2781
|
-
// consumes the entry it uses, and the canonical --fallback
|
|
2782
|
-
// validation runs later (it rejects interactive/--acp/--loop/
|
|
2783
|
-
// --resume-checkpoint chains and requires a prompt) — so
|
|
2784
|
-
// switching first on an ineligible shape would empty the spec,
|
|
2785
|
-
// leave that guard nothing to reject, and start the alternate
|
|
2786
|
-
// harness on a run the CLI refuses today. An ineligible shape
|
|
2787
|
-
// never switches, so the spec survives and still fails there
|
|
2788
|
-
// with its own message. See preflightHandoffEligible.
|
|
2789
2091
|
const handoff = preflightHandoffEligible({
|
|
2790
2092
|
hasPrompt: prompt !== undefined,
|
|
2791
2093
|
interactive: options.interactive === true,
|
|
@@ -2799,12 +2101,8 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2799
2101
|
: null;
|
|
2800
2102
|
if (handoff) {
|
|
2801
2103
|
process.stderr.write(chalk.yellow(`[agents] every ${agent} account is exhausted — handing off to ${handoff.agent}${handoff.version ? `@${handoff.version}` : ''}\n`));
|
|
2802
|
-
// Snapshot the PRIMARY's configured defaults BEFORE the switch —
|
|
2803
|
-
// this is the operator's intent for this run, not the alternate's.
|
|
2804
2104
|
handoffRunDefaults ??= fromProfile ? undefined : resolveRunDefaults(agent, version ?? resolveVersion(agent, cwd), cwd);
|
|
2805
2105
|
agent = handoff.agent;
|
|
2806
|
-
// Alias-resolve against the NEW harness's installs, exactly as
|
|
2807
|
-
// the canonical --fallback parse does for its own entries.
|
|
2808
2106
|
version = resolveVersionAlias(agent, handoff.version);
|
|
2809
2107
|
options.fallback = handoff.remainingSpec;
|
|
2810
2108
|
rotationResult = null;
|
|
@@ -2812,9 +2110,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2812
2110
|
}
|
|
2813
2111
|
console.error(chalk.red(formatNoHealthyAccountError(agent, strategy, resolved.exhausted)));
|
|
2814
2112
|
if (recoverable.length > 0) {
|
|
2815
|
-
// Off a TTY nobody can complete a login, so we still exit — but
|
|
2816
|
-
// name the actual fix rather than only offering --strategy pinned,
|
|
2817
|
-
// which would just pin the same unauthenticated account.
|
|
2818
2113
|
const { loginHint } = await import('../lib/signin-badge.js');
|
|
2819
2114
|
console.error(chalk.gray(`To sign in: ${loginHint(agent)} — or run \`agents run ${agent}\` from a terminal.`));
|
|
2820
2115
|
}
|
|
@@ -2822,13 +2117,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2822
2117
|
}
|
|
2823
2118
|
}
|
|
2824
2119
|
else if (resolved.noVerifiedUsage) {
|
|
2825
|
-
// Entirely stale usage (PHNX-2526): every eligible account carries
|
|
2826
|
-
// a stale-but-present usage number and none is verified, so the
|
|
2827
|
-
// route would be a guess. NEVER auto-pick it. Interactive: show the
|
|
2828
|
-
// account picker so a human chooses with the (stale) numbers in
|
|
2829
|
-
// view. Unattended: fail loud with NO_VERIFIED_USAGE. The stale
|
|
2830
|
-
// pool survives ONLY as `resolved.rotation.healthy` for bounded
|
|
2831
|
-
// post-rejection failover, never as the initial pick.
|
|
2832
2120
|
const { noVerifiedUsageDecision, pickRunAccountCandidate } = await import('./run-account-picker.js');
|
|
2833
2121
|
const decision = noVerifiedUsageDecision({
|
|
2834
2122
|
tty: isInteractiveTerminal(),
|
|
@@ -2837,18 +2125,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2837
2125
|
});
|
|
2838
2126
|
if (decision === 'picker') {
|
|
2839
2127
|
const selected = await pickRunAccountCandidate(agent);
|
|
2840
|
-
// A cancelled picker launches nothing — same contract as the
|
|
2841
|
-
// trailing-# account picker and the sign-in launch above.
|
|
2842
2128
|
if (!selected)
|
|
2843
2129
|
return;
|
|
2844
2130
|
version = selected.version;
|
|
2845
|
-
// Source the run.launch verdict from the account the user ACTUALLY
|
|
2846
|
-
// picked — the picker may deliberately return a logged-out one
|
|
2847
|
-
// (RUSH-2334), so it can differ from rotationResult.picked.
|
|
2848
2131
|
launchSignedIn = selected.signedIn;
|
|
2849
2132
|
launchEmail = selected.email;
|
|
2850
|
-
// Keep the rotation so mid-run failover can still cascade across
|
|
2851
|
-
// the other (stale) healthy accounts after a real rejection.
|
|
2852
2133
|
rotationResult = resolved.rotation;
|
|
2853
2134
|
await applyPickedCandidate(selected);
|
|
2854
2135
|
if (!options.quiet) {
|
|
@@ -2864,18 +2145,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2864
2145
|
else if (resolved.version) {
|
|
2865
2146
|
version = resolved.version;
|
|
2866
2147
|
rotationResult = resolved.rotation;
|
|
2867
|
-
// The auto-pick already computed the launchable-signed-in verdict for
|
|
2868
|
-
// this exact version via the same gate — reuse it for run.launch.
|
|
2869
2148
|
if (resolved.rotation) {
|
|
2870
2149
|
launchSignedIn = resolved.rotation.picked.signedIn;
|
|
2871
2150
|
launchEmail = resolved.rotation.picked.email;
|
|
2872
2151
|
await applyPickedCandidate(resolved.rotation.picked);
|
|
2873
2152
|
}
|
|
2874
|
-
// A balanced/available pick of a PROVIDER account (setup-token /
|
|
2875
|
-
// API-key) carries `providerAccount`. Resolve its env through the
|
|
2876
|
-
// same `resolveSpawnAccount` path an explicit `--account` uses, so
|
|
2877
|
-
// exec injects the credential; a native pick has no providerAccount
|
|
2878
|
-
// and resolved its slot home in applyPickedCandidate above.
|
|
2879
2153
|
const pickedProviderAccount = resolved.rotation?.picked.providerAccount;
|
|
2880
2154
|
if (pickedProviderAccount) {
|
|
2881
2155
|
try {
|
|
@@ -2894,8 +2168,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2894
2168
|
}
|
|
2895
2169
|
}
|
|
2896
2170
|
else if (!options.quiet) {
|
|
2897
|
-
// No installed version at all (not "accounts exhausted" — that
|
|
2898
|
-
// fails loud above): keep the pre-existing default resolution.
|
|
2899
2171
|
process.stderr.write(chalk.yellow(`[agents] strategy ${strategy} found no usable ${agent} version; falling back to defaults\n`));
|
|
2900
2172
|
}
|
|
2901
2173
|
}
|
|
@@ -2908,21 +2180,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2908
2180
|
}
|
|
2909
2181
|
break;
|
|
2910
2182
|
}
|
|
2911
|
-
// Self-heal the launch target. A gutted install (JS wrapper present,
|
|
2912
|
-
// native binary missing — a partial/raced npm extraction of the optional
|
|
2913
|
-
// per-arch dependency) would otherwise spawn and die with a raw ENOENT
|
|
2914
|
-
// inside the agent's own wrapper. Repair it in place (or fall back to a
|
|
2915
|
-
// runnable version, re-pinning it) BEFORE we build the launch command.
|
|
2916
|
-
// Skipped for headless resume-native/acp/loop paths only if it errored;
|
|
2917
|
-
// here it runs for every normal dispatch. Best-effort log to stderr.
|
|
2918
2183
|
{
|
|
2919
2184
|
const launchTarget = version ?? resolveVersion(agent, cwd) ?? undefined;
|
|
2920
2185
|
if (launchTarget) {
|
|
2921
2186
|
const healed = await ensureAgentRunnable(agent, launchTarget, options.quiet ? undefined : (m) => process.stderr.write(chalk.yellow(`[agents] ${m}\n`)));
|
|
2922
2187
|
if (healed === null) {
|
|
2923
|
-
// An isolated copy is never repaired by adopting another version, so
|
|
2924
|
-
// `add <agent>@latest` would build an unrelated NORMAL install rather
|
|
2925
|
-
// than fix what the user asked to run. Point at the isolated re-add.
|
|
2926
2188
|
const { isVersionIsolated } = await import('../lib/installations/versions.js');
|
|
2927
2189
|
const hint = isVersionIsolated(agent, launchTarget)
|
|
2928
2190
|
? `agents add ${agent}@${launchTarget} --isolated`
|
|
@@ -2934,22 +2196,8 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2934
2196
|
}
|
|
2935
2197
|
}
|
|
2936
2198
|
bootMark('ensure-runnable:done');
|
|
2937
|
-
// The harness may simply not be on this machine. The self-heal above only
|
|
2938
|
-
// runs when a managed version resolved, so with nothing installed we used
|
|
2939
|
-
// to fall through and spawn the bare `cliCommand`, which dies as
|
|
2940
|
-
// `exec: cursor-agent: not found` (exit 127) after a misleading
|
|
2941
|
-
// "looks logged out" banner (RUSH-2339). Probe the executable
|
|
2942
|
-
// buildExecCommand will actually spawn and fail loud instead.
|
|
2943
|
-
//
|
|
2944
|
-
// This is an EXISTENCE probe, not "does agents-cli manage a version". A
|
|
2945
|
-
// harness the user installed themselves (Homebrew, a vendor `curl | sh`, a
|
|
2946
|
-
// distro package) has no version home and MUST still launch — the PATH
|
|
2947
|
-
// branch of resolveLaunchBinary is what keeps that working.
|
|
2948
2199
|
{
|
|
2949
2200
|
const { resolveLaunchBinary } = await import('../lib/exec.js');
|
|
2950
|
-
// `version` already carries the self-heal's resolution above (it assigns
|
|
2951
|
-
// `version = healed` whenever a version resolved at all), so re-deriving
|
|
2952
|
-
// it with resolveVersion here would be dead.
|
|
2953
2201
|
if (!resolveLaunchBinary(agent, version)) {
|
|
2954
2202
|
const target = version ? `${agent}@${version}` : agent;
|
|
2955
2203
|
console.error(chalk.red(`agents: ${target} is not installed on this machine.`));
|
|
@@ -2958,43 +2206,21 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2958
2206
|
}
|
|
2959
2207
|
}
|
|
2960
2208
|
const defaultVersion = version ?? resolveVersion(agent, cwd);
|
|
2961
|
-
// Re-apply the active rules preset before every launch (issue: preset
|
|
2962
|
-
// changes via `setActiveRulesPreset` only took effect after an explicit
|
|
2963
|
-
// `agents rules switch` / `agents sync`). Version-scoped, skip-fast when
|
|
2964
|
-
// nothing changed — see lib/rules/run-sync.ts. Placed here (immediately
|
|
2965
|
-
// after the resolved version is known, before ACP/loop/fallback branch
|
|
2966
|
-
// off) so every downstream dispatch path for this agent+version sees a
|
|
2967
|
-
// fresh rules file, not just the plain execAgent path. `defaultVersion`
|
|
2968
|
-
// is null when nothing is installed yet — execAgent handles that error
|
|
2969
|
-
// path itself; there's no version home to sync into.
|
|
2970
2209
|
if (defaultVersion) {
|
|
2971
2210
|
applyActiveRulesPresetAtRun(agent, defaultVersion, getVersionHomePath(agent, defaultVersion));
|
|
2972
2211
|
applySystemResourcesAtRun(agent, defaultVersion, getVersionHomePath(agent, defaultVersion));
|
|
2973
2212
|
}
|
|
2974
2213
|
bootMark('rules-sync:done');
|
|
2975
|
-
// Login preflight (advisory, warn + continue). On a local INTERACTIVE
|
|
2976
|
-
// launch, probe whether this agent's account has a credential and print a
|
|
2977
|
-
// one-line warning if it looks logged out — so you find out BEFORE the TUI
|
|
2978
|
-
// opens, not after typing a prompt and getting "/login" back. Inspect the
|
|
2979
|
-
// selected account home, not an unrelated global login. This file-based
|
|
2980
|
-
// read makes no Keychain ACL prompt. It can still false-negative for opaque
|
|
2981
|
-
// credentials, so this NEVER blocks — it warns and launches anyway. Skipped
|
|
2982
|
-
// for --json/--quiet, when a rotation already picked a signed-in account,
|
|
2983
|
-
// and via --no-auth-check / AGENTS_NO_AUTH_CHECK=1. (--device/--lease return
|
|
2984
|
-
// earlier.)
|
|
2985
2214
|
{
|
|
2986
2215
|
const { shouldCheckLoginBeforeLaunch, loginHint } = await import('../lib/signin-badge.js');
|
|
2987
2216
|
const preflight = shouldCheckLoginBeforeLaunch({
|
|
2988
2217
|
interactive: options.interactive,
|
|
2989
|
-
forceInteractive,
|
|
2218
|
+
forceInteractive,
|
|
2990
2219
|
headless: options.headless,
|
|
2991
2220
|
hasPrompt: prompt !== undefined,
|
|
2992
2221
|
json: options.json,
|
|
2993
2222
|
quiet: options.quiet,
|
|
2994
2223
|
authCheckDisabled: options.authCheck === false || process.env.AGENTS_NO_AUTH_CHECK === '1',
|
|
2995
|
-
// `signInLaunch` means the zero-healthy path already reported this exact
|
|
2996
|
-
// account as logged out and named the login command, so re-probing here
|
|
2997
|
-
// only prints a second, near-identical warning.
|
|
2998
2224
|
rotated: !!rotationResult || accountPickerRequested || signInLaunch || (launchAccount?.account?.kind ?? spawnAccount?.kind) === 'provider',
|
|
2999
2225
|
});
|
|
3000
2226
|
if (preflight) {
|
|
@@ -3002,11 +2228,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3002
2228
|
const { getAccountInfo } = await import('../lib/agents.js');
|
|
3003
2229
|
const authVersion = accountConfigVersion ?? version;
|
|
3004
2230
|
const info = await getAccountInfo(agent, execHome ?? (authVersion ? getVersionHomePath(agent, authVersion) : undefined));
|
|
3005
|
-
// Claude authenticates interactively from a per-version setup-token on a
|
|
3006
|
-
// keychain-less worker (the shim's .oauth_token fallback), which the
|
|
3007
|
-
// native-credential probe above can't see — so don't warn "logged out" when
|
|
3008
|
-
// a setup-token resolves for this version. No-op on macOS, where the
|
|
3009
|
-
// credential lives in the keychain and resolveClaudeSetupToken returns null.
|
|
3010
2231
|
let authedViaSetupToken = false;
|
|
3011
2232
|
if (!info.signedIn && agent === 'claude' && version) {
|
|
3012
2233
|
const { resolveClaudeSetupToken } = await import('../lib/claude-account-token.js');
|
|
@@ -3024,19 +2245,14 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3024
2245
|
}
|
|
3025
2246
|
}
|
|
3026
2247
|
catch {
|
|
3027
|
-
// Advisory only — a probe failure must never block a launch.
|
|
3028
2248
|
}
|
|
3029
2249
|
}
|
|
3030
2250
|
}
|
|
3031
2251
|
const runDefaults = fromProfile
|
|
3032
2252
|
? { sources: {} }
|
|
3033
2253
|
: resolveRunDefaults(agent, defaultVersion, cwd);
|
|
3034
|
-
// Accept the four canonical modes plus 'full' as a permanent silent
|
|
3035
|
-
// alias for 'skip' (rewritten downstream by normalizeMode in exec.ts).
|
|
3036
2254
|
let mode = options.mode;
|
|
3037
2255
|
const modeSource = runCmd.getOptionValueSource('mode');
|
|
3038
|
-
// A configured mode carried across a preflight handoff wins over the
|
|
3039
|
-
// alternate harness's own configured default (see handoffRunDefaults).
|
|
3040
2256
|
const configuredMode = handoffRunDefaults?.mode ?? runDefaults.mode;
|
|
3041
2257
|
const modeFromRunDefault = modeSource === 'default' && !!configuredMode;
|
|
3042
2258
|
if (modeFromRunDefault) {
|
|
@@ -3046,20 +2262,8 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3046
2262
|
console.error(chalk.red(`Invalid mode: ${mode}. Use plan, edit, auto, or skip ('full' accepted as alias for skip).`));
|
|
3047
2263
|
process.exit(1);
|
|
3048
2264
|
}
|
|
3049
|
-
// Default CLI mode is the generic 'plan'. Agents without a read-only
|
|
3050
|
-
// mode (antigravity, …) degrade via resolveMode to their
|
|
3051
|
-
// safest native mode (modes[0], typically edit). That covers both the
|
|
3052
|
-
// implicit default and an explicit `--mode plan`, so multi-agent
|
|
3053
|
-
// scripts can pass a uniform plan flag without per-agent branching.
|
|
3054
|
-
// Mode degradation is never silent: buildExecCommand emits one stderr
|
|
3055
|
-
// warning for the requested-to-resolved transition unless --quiet is set.
|
|
3056
|
-
// `skip` still hard-fails when unsupported — pretending we bypassed
|
|
3057
|
-
// permissions would be unsafe.
|
|
3058
2265
|
const modeIsDefault = modeSource === 'default';
|
|
3059
2266
|
let requestedMode = normalizeMode(mode);
|
|
3060
|
-
// Codex's intrinsic omitted-mode default is safe writable: workspace plus
|
|
3061
|
-
// common caches, network enabled, approvals on request. An explicit
|
|
3062
|
-
// --mode plan and a configured run default remain read-only.
|
|
3063
2267
|
const { modeWasImplicit } = await import('../lib/codex-policy.js');
|
|
3064
2268
|
const wasModeImplicit = modeWasImplicit(modeSource, modeFromRunDefault);
|
|
3065
2269
|
if (wasModeImplicit)
|
|
@@ -3073,11 +2277,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3073
2277
|
process.exit(1);
|
|
3074
2278
|
}
|
|
3075
2279
|
mode = resolvedMode;
|
|
3076
|
-
// Fail fast on the headless-plan stall footgun: a slash command run
|
|
3077
|
-
// headless under the implicit default 'plan' mode hangs forever at
|
|
3078
|
-
// ExitPlanMode (no TTY to approve the plan). Tell the user how to fix it
|
|
3079
|
-
// instead of leaving them staring at a frozen process. Explicit
|
|
3080
|
-
// `--mode plan` is respected for genuine read-only command runs.
|
|
3081
2280
|
const stallCmd = headlessPlanStallCommand({
|
|
3082
2281
|
prompt,
|
|
3083
2282
|
interactive: resolveInteractive({ prompt, headless: options.headless, interactive: options.interactive || forceInteractive }),
|
|
@@ -3105,29 +2304,16 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3105
2304
|
console.error(chalk.red(err.message));
|
|
3106
2305
|
process.exit(1);
|
|
3107
2306
|
}
|
|
3108
|
-
// Resolve --secrets bundles in flag order. Later bundles override earlier
|
|
3109
|
-
// ones. Any resolution failure (missing keychain item, blocked exec ref)
|
|
3110
|
-
// aborts before spawn so the agent never sees a partial env.
|
|
3111
2307
|
const secretsKeysSubset = options.secretsKeys
|
|
3112
2308
|
? options.secretsKeys.split(',').map((k) => k.trim()).filter(Boolean)
|
|
3113
2309
|
: undefined;
|
|
3114
2310
|
let secretsEnv = {};
|
|
3115
|
-
// Resource-profile scoping (CTX-1): agents-cli computes which bundle
|
|
3116
|
-
// names the active profile allows and forwards it as the client's
|
|
3117
|
-
// `allowedBundles` on every local resolution — the standalone has no
|
|
3118
|
-
// concept of a profile. undefined (no active profile) is full trust.
|
|
3119
2311
|
const secretsContext = await resolveSecretsContextForRun(agent);
|
|
3120
2312
|
for (const bundleRef of options.secrets) {
|
|
3121
2313
|
try {
|
|
3122
2314
|
const { bundle: bundleName, host } = splitBundleRef(bundleRef);
|
|
3123
2315
|
if (host) {
|
|
3124
|
-
// Least-privilege flags (--secrets-keys / --allow-expired) do not
|
|
3125
|
-
// yet cross the SSH resolver — silently applying them would inject
|
|
3126
|
-
// the full remote env or an expired key. Fail loud so the user
|
|
3127
|
-
// can drop the flag or resolve locally instead.
|
|
3128
2316
|
assertRemoteBundleFlagsUnsupported(bundleName, host, { keys: secretsKeysSubset, allowExpired: options.allowExpired }, { keysFlag: '--secrets-keys', allowExpiredFlag: '--allow-expired' });
|
|
3129
|
-
// Remote bundle (`bundle@host`): resolve over SSH and inject
|
|
3130
|
-
// ephemerally — values never touch this machine's keychain or disk.
|
|
3131
2317
|
const target = await resolveHostSshTarget(host);
|
|
3132
2318
|
const bundleEnv = await remoteResolveEnv(target, bundleName, { osLookupName: host });
|
|
3133
2319
|
console.log(chalk.gray(`[secrets] Resolved ${bundleName}@${host}: ${Object.keys(bundleEnv).length} keys (remote, ephemeral)`));
|
|
@@ -3139,12 +2325,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3139
2325
|
agent,
|
|
3140
2326
|
keys: secretsKeysSubset,
|
|
3141
2327
|
allowExpired: options.allowExpired,
|
|
3142
|
-
// The harness identity scopes any cached grant. An agent launch
|
|
3143
|
-
// resolves broker-only and fails fast naming
|
|
3144
|
-
// `agents secrets unlock <bundle>` (bundles.ts:interactiveUnlock) — it
|
|
3145
|
-
// MUST NOT raise a Touch ID sheet regardless of tty (SEC-13). Gating on
|
|
3146
|
-
// isHeadlessSecretsContext() left `--interactive` launches (the watchdog's
|
|
3147
|
-
// `agents run auto --interactive`) able to prompt, piling up helper sheets.
|
|
3148
2328
|
agentOnly: true,
|
|
3149
2329
|
}, secretsContext);
|
|
3150
2330
|
const entries = await describeBundle(bundle, secretsContext);
|
|
@@ -3165,11 +2345,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3165
2345
|
const autoShareEnv = options.autoSecrets !== false
|
|
3166
2346
|
? shareRuntimeEnv()
|
|
3167
2347
|
: undefined;
|
|
3168
|
-
// Merge order (later wins): profile env < selected account < auto share token < secrets bundles < --env K=V.
|
|
3169
|
-
// Profile carries provider auth; secrets bundles carry user-defined
|
|
3170
|
-
// values; --env is the per-invocation override. The share token is
|
|
3171
|
-
// best-effort: if it is not already in env or an unlocked bundle, unrelated
|
|
3172
|
-
// runs keep working, and `agents artifacts share` itself still fails loudly on use.
|
|
3173
2348
|
const hasOverrides = profileEnv || accountEnv || autoShareEnv || options.secrets.length > 0 || userEnv;
|
|
3174
2349
|
const env = hasOverrides
|
|
3175
2350
|
? { ...(profileEnv ?? {}), ...(accountEnv ?? {}), ...(autoShareEnv ?? {}), ...secretsEnv, ...(userEnv ?? {}) }
|
|
@@ -3180,10 +2355,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3180
2355
|
?? (!fromProfile && modelSource === undefined
|
|
3181
2356
|
? (workflowModel ?? (options.fallback ? undefined : runDefaults.model))
|
|
3182
2357
|
: undefined);
|
|
3183
|
-
// Cost tiers (cheap|default|best|ultra) resolve against a harness's own model
|
|
3184
|
-
// catalog. A custom harness's model comes from its endpoint, not the host
|
|
3185
|
-
// harness, so a tier here would forward an incompatible host-harness model to a
|
|
3186
|
-
// different API. Discard it loudly and let the custom harness's own model stand.
|
|
3187
2358
|
if (fromProfile && model && isTierToken(model)) {
|
|
3188
2359
|
process.stderr.write(chalk.yellow(`[agents] --model ${model}: cost tiers don't apply to custom harness '${rawAgent}' ` +
|
|
3189
2360
|
`(its model comes from the endpoint) — ignoring the tier, using the custom harness's configured model\n`));
|
|
@@ -3211,34 +2382,19 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3211
2382
|
resume: resumeNative,
|
|
3212
2383
|
verbose: options.verbose,
|
|
3213
2384
|
modeWarningState: { quiet: options.quiet },
|
|
3214
|
-
// --raw, --no-tmux (commander negation → options.tmux === false), and
|
|
3215
|
-
// --disable-tmux all bypass the interactive tmux wrapper. AGENTS_NO_TMUX=1
|
|
3216
|
-
// does the same via the env check in exec.ts.
|
|
3217
2385
|
raw: options.raw || options.tmux === false || options.disableTmux === true,
|
|
3218
2386
|
timeout: options.timeout,
|
|
3219
2387
|
env,
|
|
3220
2388
|
toolsRestrict: workflowToolsRestrict,
|
|
3221
2389
|
mcpConfigPath: workflowMcpConfigPath,
|
|
3222
2390
|
passthroughArgs,
|
|
3223
|
-
// Set only on the REMOTE side of a `--device` dispatch (the launcher
|
|
3224
|
-
// forwards `--emit-session-id`): print the resolved session id as a
|
|
3225
|
-
// stdout sentinel so the launcher captures the id this run coined.
|
|
3226
2391
|
emitSessionId: options.emitSessionId === true,
|
|
3227
|
-
// Observability-only: carried onto the pre-launch `run.launch` event so
|
|
3228
|
-
// the stream records HOW this version was chosen. Neither affects the
|
|
3229
|
-
// spawn. `resolvedVia` attributes the version source cheaply — an
|
|
3230
|
-
// explicit @version pin, a strategy rotation, or the pinned default.
|
|
3231
2392
|
strategy,
|
|
3232
2393
|
resolvedVia: rawVersion
|
|
3233
2394
|
? 'explicit-pin'
|
|
3234
2395
|
: rotationResult
|
|
3235
2396
|
? 'rotated'
|
|
3236
2397
|
: 'pinned-default',
|
|
3237
|
-
// Launchable-signed-in verdict for the ACTUAL launched candidate, set per
|
|
3238
|
-
// resolution branch above (auto-pick from rotation.picked; interactive
|
|
3239
|
-
// picker from the user's `selected`, which may be logged out). Undefined
|
|
3240
|
-
// for a pinned-default / explicit-pin launch, where spawnAgent probes the
|
|
3241
|
-
// version home itself.
|
|
3242
2398
|
launchSignedIn,
|
|
3243
2399
|
launchEmail,
|
|
3244
2400
|
};
|
|
@@ -3289,11 +2445,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3289
2445
|
fallback.push({ agent: fbAgent, version: resolveVersionAlias(fbAgent, fbVersion || undefined) });
|
|
3290
2446
|
}
|
|
3291
2447
|
}
|
|
3292
|
-
// Profile-declared same-host model swap (issue #325). Inserted BEFORE any
|
|
3293
|
-
// user --fallback entries so a rate limit first tries the cheaper/backup
|
|
3294
|
-
// model on the same provider (auth + base URL preserved via envOverride);
|
|
3295
|
-
// only if THAT still rate-limits do we cascade to a different agent CLI.
|
|
3296
|
-
// Requires a prompt for the same reason --fallback does — headless-only.
|
|
3297
2448
|
if (fromProfile && profileFallbackModel && prompt !== undefined && !options.interactive) {
|
|
3298
2449
|
fallback.unshift({
|
|
3299
2450
|
agent,
|
|
@@ -3301,26 +2452,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3301
2452
|
envOverride: { [profileFallbackModel.envKey]: profileFallbackModel.model },
|
|
3302
2453
|
});
|
|
3303
2454
|
}
|
|
3304
|
-
// Mid-run rate-limit failover (issue #348). When a pre-flight rotation
|
|
3305
|
-
// picked an account and there are OTHER healthy accounts for the same
|
|
3306
|
-
// agent, synthesize a same-agent fallback chain from them so a 429 mid-run
|
|
3307
|
-
// re-dispatches on the next healthy account via the SAME runWithFallback
|
|
3308
|
-
// path (continuing the session via /continue). Because this injects into
|
|
3309
|
-
// the same `fallback` array `--fallback` uses, it must only arm for run
|
|
3310
|
-
// shapes that accept a fallback chain — shouldArmRotationFailover excludes
|
|
3311
|
-
// acp/loop/resume-checkpoint (which reject a non-empty fallback below)
|
|
3312
|
-
// and interactive/no-prompt runs. Pinned/single-account runs stay
|
|
3313
|
-
// unchanged because rotationResult is null or rotationFailoverChain
|
|
3314
|
-
// returns []. version is set here because rotationResult is only
|
|
3315
|
-
// populated when resolveRunVersion picked one.
|
|
3316
|
-
//
|
|
3317
|
-
// Composes with an explicit --fallback chain: the same-agent accounts are
|
|
3318
|
-
// UNSHIFTED ahead of the user's cross-agent entries, so a rate limit
|
|
3319
|
-
// first tries the other accounts of the same agent (cheapest recovery —
|
|
3320
|
-
// same CLI, session continues) and only then cascades to codex/gemini/etc.
|
|
3321
|
-
// Profiles never compose: strategy is skipped for them, rotationResult
|
|
3322
|
-
// stays null. (fromProfile's model-swap unshift above is therefore never
|
|
3323
|
-
// displaced by this one.)
|
|
3324
2455
|
if (shouldArmRotationFailover({
|
|
3325
2456
|
hasRotation: !!rotationResult,
|
|
3326
2457
|
hasVersion: !!version,
|
|
@@ -3330,11 +2461,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3330
2461
|
loop: !!options.loop,
|
|
3331
2462
|
resumeCheckpoint: !!options.resumeCheckpoint,
|
|
3332
2463
|
})) {
|
|
3333
|
-
// With an explicit alternate harness configured, "use the alternate once
|
|
3334
|
-
// the primary's accounts are exhausted" is the policy — so EVERY healthy
|
|
3335
|
-
// same-agent account has to be tried first, not the default cap of three
|
|
3336
|
-
// (PHNX-3999 F19). Without one, the cap stands: it bounds how long a
|
|
3337
|
-
// rate-limited run keeps retrying itself.
|
|
3338
2464
|
const failover = rotationFailoverChain(rotationResult, version, fallback.length > 0 ? (rotationResult.healthy.length || DEFAULT_ROTATION_FAILOVER_LIMIT) : undefined);
|
|
3339
2465
|
if (failover.length > 0) {
|
|
3340
2466
|
fallback.unshift(...failover);
|
|
@@ -3367,11 +2493,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3367
2493
|
mode,
|
|
3368
2494
|
json: options.json ?? false,
|
|
3369
2495
|
});
|
|
3370
|
-
// Governance chokepoint (#347): the --acp path exits here, bypassing
|
|
3371
|
-
// the normal finalize below — record its one audit entry.
|
|
3372
2496
|
recordDispatchedRun({ agent, version: defaultVersion ?? 'unknown', mode, cwd, exitCode });
|
|
3373
|
-
// ACP headless run always has a prompt; surface any unpushed commits
|
|
3374
|
-
// and any open PR left unattended (RUSH-2394).
|
|
3375
2497
|
if (shouldWarnUnpushed(mode, false)) {
|
|
3376
2498
|
await warnUnpushedWork(cwd);
|
|
3377
2499
|
await warnOrphanedOpenPr(cwd);
|
|
@@ -3383,21 +2505,9 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3383
2505
|
process.exit(1);
|
|
3384
2506
|
}
|
|
3385
2507
|
}
|
|
3386
|
-
// Budget pre-flight gate (issue #346). Estimate the run's cost and, when a
|
|
3387
|
-
// cap is configured with on_exceed:block, refuse to launch if it would push
|
|
3388
|
-
// a cap over the line — exiting non-zero so CI/headless inherit the block.
|
|
3389
|
-
// --yes skips ONLY the interactive confirm threshold, never a hard block.
|
|
3390
2508
|
{
|
|
3391
2509
|
const { runPreflightGate } = await import('../lib/budget/preflight.js');
|
|
3392
2510
|
const { resolveEffectiveModel } = await import('../lib/models.js');
|
|
3393
|
-
// Estimate against the model that will ACTUALLY run, not an unpriced
|
|
3394
|
-
// `${agent}-default` placeholder (which made estimateCost return $0 and
|
|
3395
|
-
// silently neutered the per_run/per_day gate for the common no-`--model`
|
|
3396
|
-
// case). When `model` is undefined the spawned CLI uses its built-in
|
|
3397
|
-
// default, which we recover from the extracted catalog. If we still can't
|
|
3398
|
-
// resolve a concrete model, pass the placeholder — the gate now treats an
|
|
3399
|
-
// unpriced estimate under active caps as needing confirmation, so it is
|
|
3400
|
-
// never a silent $0 wave-through.
|
|
3401
2511
|
const effectiveModel = resolveEffectiveModel(agent, version ?? '', model) ?? `${agent}-default`;
|
|
3402
2512
|
const gate = runPreflightGate({
|
|
3403
2513
|
agent,
|
|
@@ -3412,14 +2522,12 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3412
2522
|
process.stderr.write(chalk.gray(gate.banner + '\n'));
|
|
3413
2523
|
}
|
|
3414
2524
|
if (!gate.decision.allow) {
|
|
3415
|
-
// Hard block. --yes does NOT override (acceptance criterion).
|
|
3416
2525
|
console.error(chalk.red(`[budget] BLOCKED: ${gate.decision.reason}`));
|
|
3417
2526
|
console.error(chalk.gray(`Raise the cap in agents.yaml budget: or set on_exceed: warn to proceed.`));
|
|
3418
2527
|
process.exit(2);
|
|
3419
2528
|
}
|
|
3420
2529
|
if (gate.decision.needsConfirm && !options.yes) {
|
|
3421
2530
|
if (!process.stdin.isTTY) {
|
|
3422
|
-
// Non-interactive (CI/headless) and no --yes: cannot confirm — refuse.
|
|
3423
2531
|
console.error(chalk.red(`[budget] ${gate.decision.reason}`));
|
|
3424
2532
|
console.error(chalk.gray(`Re-run with --yes to confirm the spend, or lower require_confirm_over.`));
|
|
3425
2533
|
process.exit(2);
|
|
@@ -3435,7 +2543,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3435
2543
|
}
|
|
3436
2544
|
}
|
|
3437
2545
|
else if (gate.decision.blockedCap && gate.decision.allow && !options.quiet) {
|
|
3438
|
-
// on_exceed:warn overrun notice (allowed but reported).
|
|
3439
2546
|
process.stderr.write(chalk.yellow(`[budget] WARN: ${gate.decision.reason}\n`));
|
|
3440
2547
|
}
|
|
3441
2548
|
}
|
|
@@ -3444,9 +2551,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3444
2551
|
if (!options.quiet) {
|
|
3445
2552
|
process.stderr.write(chalk.gray(`Running: ${cmd.join(' ')}\n\n`));
|
|
3446
2553
|
}
|
|
3447
|
-
// Remove the ephemeral mcp-config (and its temp dir) after the run. It is
|
|
3448
|
-
// written at mode 0o600 but still embeds server `env` (possibly tokens),
|
|
3449
|
-
// so it must not linger in tmp. Synchronous so it completes before exit.
|
|
3450
2554
|
const cleanupWorkflowMcpConfig = () => {
|
|
3451
2555
|
if (!workflowMcpConfigPath)
|
|
3452
2556
|
return;
|
|
@@ -3454,29 +2558,17 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3454
2558
|
fs.rmSync(path.dirname(workflowMcpConfigPath), { recursive: true, force: true });
|
|
3455
2559
|
}
|
|
3456
2560
|
catch {
|
|
3457
|
-
// best-effort: nothing actionable if the temp dir is already gone.
|
|
3458
2561
|
}
|
|
3459
2562
|
};
|
|
3460
|
-
// Restore the shared per-agent agents dir after the run (issue #401):
|
|
3461
|
-
// remove the workflow subagent files THIS run copied in, so a scoped
|
|
3462
|
-
// workflow never leaves definitions behind for the next, unrelated run to
|
|
3463
|
-
// inherit. Mirrors cleanupWorkflowMcpConfig — tear down only what we made.
|
|
3464
2563
|
const cleanupWorkflowSubagents = () => {
|
|
3465
2564
|
for (const target of workflowSubagentTargets) {
|
|
3466
2565
|
try {
|
|
3467
2566
|
fs.rmSync(target, { force: true });
|
|
3468
2567
|
}
|
|
3469
2568
|
catch {
|
|
3470
|
-
// best-effort: nothing actionable if the file is already gone.
|
|
3471
2569
|
}
|
|
3472
2570
|
}
|
|
3473
2571
|
};
|
|
3474
|
-
// for_each dispatch (issue #343). A workflow that declares `for_each:` is a
|
|
3475
|
-
// declarative dynamic fan-out, not a single-agent run: execute the producer,
|
|
3476
|
-
// expand one stage teammate per produced item (+ optional verify panel),
|
|
3477
|
-
// stage them into a team, then drive the supervisor until the DAG drains.
|
|
3478
|
-
// This is mutually exclusive with the single-agent loop/fallback paths — the
|
|
3479
|
-
// fan-out IS the run.
|
|
3480
2572
|
if (workflowForEach) {
|
|
3481
2573
|
cleanupWorkflowMcpConfig();
|
|
3482
2574
|
cleanupWorkflowSubagents();
|
|
@@ -3487,10 +2579,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3487
2579
|
});
|
|
3488
2580
|
process.exit(exitCode);
|
|
3489
2581
|
}
|
|
3490
|
-
// Loop dispatch (issue #332). Active when --loop is passed OR a workflow
|
|
3491
|
-
// declares a `loop:` block. The loop path runs AFTER the #346 pre-flight
|
|
3492
|
-
// gate above (which fired once) — the loop's token budget is an ADDITIONAL
|
|
3493
|
-
// guard, not a replacement. Composable, not bypassing.
|
|
3494
2582
|
let loopConfig;
|
|
3495
2583
|
try {
|
|
3496
2584
|
loopConfig = buildLoopConfig(options, workflowLoop);
|
|
@@ -3528,12 +2616,8 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3528
2616
|
cleanupWorkflowMcpConfig();
|
|
3529
2617
|
cleanupWorkflowSubagents();
|
|
3530
2618
|
process.stderr.write(chalk.gray(`[loop] stopped: ${result.stoppedBy} after ${result.iterations} iteration(s), ${result.tokens} tokens (checkpoint: ${path.join(runDir, 'checkpoint.json')})\n`));
|
|
3531
|
-
// Governance chokepoint (#347): the --loop path exits here, bypassing
|
|
3532
|
-
// the normal finalize below — record its one audit entry.
|
|
3533
2619
|
const loopExit = loopExitCode(result.stoppedBy);
|
|
3534
2620
|
recordDispatchedRun({ agent, version: defaultVersion ?? 'unknown', mode, cwd, exitCode: loopExit });
|
|
3535
|
-
// A loop is always headless; surface any commits it left unpushed
|
|
3536
|
-
// and any open PR left without a durable lander (RUSH-2394).
|
|
3537
2621
|
if (shouldWarnUnpushed(mode, false)) {
|
|
3538
2622
|
await warnUnpushedWork(cwd);
|
|
3539
2623
|
await warnOrphanedOpenPr(cwd);
|
|
@@ -3547,15 +2631,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3547
2631
|
process.exit(1);
|
|
3548
2632
|
}
|
|
3549
2633
|
}
|
|
3550
|
-
// Agent footgun (RUSH-1829): a run with no prompt and no explicit
|
|
3551
|
-
// --interactive resolves to interactive intent, but in a non-TTY shell
|
|
3552
|
-
// (a headless agent, a pipe, CI) there is no terminal to host the REPL —
|
|
3553
|
-
// the TUI attaches to dead stdin and hangs forever. Fail fast with the
|
|
3554
|
-
// headless alternatives instead of launching a doomed interactive session.
|
|
3555
2634
|
if (inferredInteractiveWithoutTty(execOptions, isInteractiveTerminal())) {
|
|
3556
|
-
// Tear down the workflow MCP config + subagents staged above before we
|
|
3557
|
-
// exit — same as every sibling exit path; requireInteractiveSelection
|
|
3558
|
-
// process.exits, so cleanup must happen first or it leaks.
|
|
3559
2635
|
cleanupWorkflowMcpConfig();
|
|
3560
2636
|
cleanupWorkflowSubagents();
|
|
3561
2637
|
requireInteractiveSelection(`Launching ${agent} interactively`, [
|
|
@@ -3568,10 +2644,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3568
2644
|
let ranAgent = agent;
|
|
3569
2645
|
let ranVersion = defaultVersion;
|
|
3570
2646
|
if (fallback.length > 0 || (rotationResult !== null && prompt !== undefined && !options.interactive)) {
|
|
3571
|
-
// Fallback and balanced runs need captured output so a clean-exit
|
|
3572
|
-
// session-limit refusal can update account availability.
|
|
3573
|
-
// The sink reports which chain entry actually executed (may differ from
|
|
3574
|
-
// the primary after a rate-limit handoff) so the audit record is honest.
|
|
3575
2647
|
const sink = {};
|
|
3576
2648
|
exitCode = await runWithFallback({ ...execOptions, prompt: prompt, fallback, dispatchSink: sink });
|
|
3577
2649
|
ranAgent = sink.agent ?? agent;
|
|
@@ -3582,28 +2654,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3582
2654
|
}
|
|
3583
2655
|
cleanupWorkflowMcpConfig();
|
|
3584
2656
|
cleanupWorkflowSubagents();
|
|
3585
|
-
// Surface committed-but-unpushed work a headless writable run left
|
|
3586
|
-
// behind, so it isn't silently stranded in a worktree. Also warn when
|
|
3587
|
-
// the branch still has an OPEN PR (RUSH-2394) — a background
|
|
3588
|
-
// `gh pr checks --watch` dies with the agent. Advisory only,
|
|
3589
|
-
// never throws; skipped for interactive runs (the human sees the shell)
|
|
3590
|
-
// and read-only plan mode (can't commit).
|
|
3591
2657
|
if (shouldWarnUnpushed(mode, resolveInteractive(execOptions))) {
|
|
3592
2658
|
await warnUnpushedWork(cwd);
|
|
3593
2659
|
await warnOrphanedOpenPr(cwd);
|
|
3594
2660
|
}
|
|
3595
|
-
// Governance chokepoint (#347): every dispatched run finalizes here.
|
|
3596
|
-
// ONE tamper-evident audit record per run — non-fatal by contract.
|
|
3597
2661
|
recordDispatchedRun({ agent: ranAgent, version: ranVersion ?? 'unknown', mode, cwd, exitCode });
|
|
3598
|
-
// A clean headless exit is real auth evidence — the account authenticated
|
|
3599
|
-
// and produced a result. Record it as the per-account FACT `agents view`
|
|
3600
|
-
// renders (`last used ok`), keyed to the slot the run used so it lands on
|
|
3601
|
-
// the right row and clears any stale failure fact (PHNX-4116). A non-zero
|
|
3602
|
-
// exit is NOT recorded as an auth failure: the exit code alone does not
|
|
3603
|
-
// prove the token was rejected (a task can fail for a hundred reasons), and
|
|
3604
|
-
// a lying "auth failure" fact is worse than none. Real auth failures are
|
|
3605
|
-
// recorded where they are actually detected (the routine runner's
|
|
3606
|
-
// isAuthFailureFromLog sites) and by the daemon probe.
|
|
3607
2662
|
if (exitCode === 0) {
|
|
3608
2663
|
recordRunAuthOutcome({
|
|
3609
2664
|
agent: ranAgent,
|
|
@@ -3613,8 +2668,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3613
2668
|
outcome: { ok: true },
|
|
3614
2669
|
});
|
|
3615
2670
|
}
|
|
3616
|
-
// First-successful-run star nudge (one-time, non-nagging). Only on a
|
|
3617
|
-
// clean run, and never when output is machine-readable/quiet.
|
|
3618
2671
|
if (exitCode === 0)
|
|
3619
2672
|
maybeShowStarNudge({ quiet: options.json || options.quiet });
|
|
3620
2673
|
process.exit(exitCode);
|
|
@@ -3622,8 +2675,6 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
3622
2675
|
catch (err) {
|
|
3623
2676
|
cleanupWorkflowMcpConfig();
|
|
3624
2677
|
cleanupWorkflowSubagents();
|
|
3625
|
-
// An agent that committed then crashed is the case where stranded work
|
|
3626
|
-
// matters most — warn before exiting the error path too.
|
|
3627
2678
|
if (shouldWarnUnpushed(mode, resolveInteractive(execOptions))) {
|
|
3628
2679
|
await warnUnpushedWork(cwd);
|
|
3629
2680
|
await warnOrphanedOpenPr(cwd);
|