@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/lib/exec.js
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
import { captureLaunchBinding, recordCompletedLaunch } from './session/hook-sessions.js';
|
|
2
|
-
/**
|
|
3
|
-
* Agent execution -- command building, process spawning, and rate-limit fallback.
|
|
4
|
-
*
|
|
5
|
-
* Translates high-level ExecOptions into CLI invocations for each supported agent,
|
|
6
|
-
* manages environment isolation per agent, and chains fallback agents on rate limits.
|
|
7
|
-
*/
|
|
8
2
|
import { spawn } from 'child_process';
|
|
9
3
|
import { randomUUID } from 'crypto';
|
|
10
4
|
import * as fs from 'fs';
|
|
@@ -49,13 +43,6 @@ import { getAccountInfo } from './agents.js';
|
|
|
49
43
|
import { getUsageLookupKey, noteClaudeSessionLimit, noteClaudeOutOfCredits, clearClaudeAccountRefusal, parseClaudeSessionLimitReset, noteClaudeModelRefusal, clearClaudeModelRefusal, parseClaudeModelRefusal, claudeModelRefusalKey, } from './accounting/usage.js';
|
|
50
44
|
import { claudeProjectDirName } from './project-key.js';
|
|
51
45
|
import { bootMark, flushBootProfile } from './boot-profile.js';
|
|
52
|
-
/**
|
|
53
|
-
* Map a raw mode string (CLI flag, YAML field, env var) to the canonical Mode.
|
|
54
|
-
*
|
|
55
|
-
* Accepts the historical `full` spelling and rewrites it to `skip`. Throws on
|
|
56
|
-
* anything outside the four canonical values so bad input fails loud at the
|
|
57
|
-
* boundary rather than silently picking a wrong code path.
|
|
58
|
-
*/
|
|
59
46
|
export function normalizeMode(input) {
|
|
60
47
|
if (!input) {
|
|
61
48
|
throw new Error(`Mode is required. Use one of: ${ALL_MODES.join(', ')}.`);
|
|
@@ -67,23 +54,6 @@ export function normalizeMode(input) {
|
|
|
67
54
|
return v;
|
|
68
55
|
throw new Error(`Invalid mode '${input}'. Use one of: ${ALL_MODES.join(', ')} (or 'full' as a deprecated alias for 'skip').`);
|
|
69
56
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Detect the headless-plan stall footgun.
|
|
72
|
-
*
|
|
73
|
-
* A slash command (e.g. `/code:commit`) run headless under the IMPLICIT default
|
|
74
|
-
* `plan` mode hangs forever: plan is read-only, so the agent calls ExitPlanMode
|
|
75
|
-
* to start working, and in a headless run there is no TTY to approve it. The
|
|
76
|
-
* process just sits there. Callers use this to fail fast with a fix instead.
|
|
77
|
-
*
|
|
78
|
-
* Returns the offending command token (e.g. `/code:commit`) when the run should
|
|
79
|
-
* be blocked, else null. Guards are deliberately narrow:
|
|
80
|
-
* - interactive runs / no prompt -> not headless, never blocks
|
|
81
|
-
* - explicit --mode (modeIsDefault false) -> respected; `--mode plan` is a
|
|
82
|
-
* legitimate read-only command run and must not be blocked
|
|
83
|
-
* - resolved mode is not `plan` -> only plan stalls at ExitPlanMode
|
|
84
|
-
* - prompt is not a slash command -> natural-language read-only prompts
|
|
85
|
-
* ("summarize commits") are a valid default-plan use and must not be blocked
|
|
86
|
-
*/
|
|
87
57
|
export function headlessPlanStallCommand(args) {
|
|
88
58
|
const { prompt, interactive, mode, modeIsDefault } = args;
|
|
89
59
|
if (interactive === true || prompt === undefined)
|
|
@@ -97,35 +67,14 @@ export function headlessPlanStallCommand(args) {
|
|
|
97
67
|
return null;
|
|
98
68
|
return trimmed.split(/\s+/)[0];
|
|
99
69
|
}
|
|
100
|
-
/**
|
|
101
|
-
* Resolve a requested mode against an agent's capability table.
|
|
102
|
-
*
|
|
103
|
-
* - `auto` on an agent without auto support silently degrades to `edit`
|
|
104
|
-
* (every agent supports edit-like behavior as its default).
|
|
105
|
-
* - `plan` on an agent without a read-only mode degrades to the agent's
|
|
106
|
-
* safest native mode (`capabilities.modes[0]`, typically `edit`). Agents
|
|
107
|
-
* like antigravity have no plan flag; hard-failing made
|
|
108
|
-
* multi-agent scripts (`--mode plan` for everyone) unusable and diverged
|
|
109
|
-
* from `agents teams add`, which already defaults to `edit`. Callers that
|
|
110
|
-
* care (the `agents run` CLI) must surface a warning when requested ≠
|
|
111
|
-
* resolved so the elevation is not silent.
|
|
112
|
-
* - `skip` on an agent without skip support throws with a clear message
|
|
113
|
-
* naming the agent's supported modes. No silent fallback — the user
|
|
114
|
-
* explicitly asked to bypass permissions; pretending we did is unsafe.
|
|
115
|
-
*/
|
|
116
70
|
export function resolveMode(agent, requested) {
|
|
117
71
|
const supported = AGENTS[agent].capabilities.modes;
|
|
118
72
|
if (supported.includes(requested))
|
|
119
73
|
return requested;
|
|
120
74
|
if (requested === 'auto') {
|
|
121
|
-
// Fall back to edit — guaranteed to exist on every agent (every agent has
|
|
122
|
-
// at least 'edit' in its modes table, since that's the default behavior).
|
|
123
75
|
return 'edit';
|
|
124
76
|
}
|
|
125
77
|
if (requested === 'plan') {
|
|
126
|
-
// No read-only mode on this agent. modes[0] is the declared safest mode
|
|
127
|
-
// (edit for antigravity/…). Prefer that over hard-fail so
|
|
128
|
-
// uniform multi-agent `--mode plan` dispatches still run.
|
|
129
78
|
return supported[0];
|
|
130
79
|
}
|
|
131
80
|
throw new Error(`${agent} does not support '${requested}' mode. Supported modes: ${supported.join(', ')}.`);
|
|
@@ -173,21 +122,9 @@ export function resolveHeadlessMode(agent, requested, interactive, warningContex
|
|
|
173
122
|
}
|
|
174
123
|
return mode;
|
|
175
124
|
}
|
|
176
|
-
/**
|
|
177
|
-
* The mode an agent should run in when the caller has no preference.
|
|
178
|
-
*
|
|
179
|
-
* Returns the first entry in the agent's `capabilities.modes` table — the
|
|
180
|
-
* declaration order is the source of truth for "the safest mode this agent
|
|
181
|
-
* supports." Agents that include `plan` list it first; agents like
|
|
182
|
-
* antigravity that have no read-only mode list `edit` first.
|
|
183
|
-
*
|
|
184
|
-
* Prefer this over a hard-coded `'plan'` when the agent is known. `resolveMode`
|
|
185
|
-
* also maps an unsupported `'plan'` request onto this same value.
|
|
186
|
-
*/
|
|
187
125
|
export function defaultModeFor(agent) {
|
|
188
126
|
return AGENTS[agent].capabilities.modes[0];
|
|
189
127
|
}
|
|
190
|
-
/** Safe mode used when the user did not provide --mode or a configured default. */
|
|
191
128
|
export function implicitModeFor(agent) {
|
|
192
129
|
return agent === 'codex' ? 'edit' : 'plan';
|
|
193
130
|
}
|
|
@@ -234,32 +171,16 @@ export function codexSandboxPreflight(args) {
|
|
|
234
171
|
`\n` +
|
|
235
172
|
`Or run codex WITHOUT a filesystem sandbox instead: add --mode skip.`);
|
|
236
173
|
}
|
|
237
|
-
/**
|
|
238
|
-
* Identity a custom-harness run stamps on env / pid-registry / sidecars.
|
|
239
|
-
* `agent` is the host CLI; `harnessName` is the profile the user launched.
|
|
240
|
-
* Empty/whitespace harness names fall back to the host so a blank stamp
|
|
241
|
-
* never hides a real agent.
|
|
242
|
-
*/
|
|
243
174
|
export function stampedAgentName(options) {
|
|
244
175
|
const harness = options.harnessName?.trim();
|
|
245
176
|
return harness || options.agent;
|
|
246
177
|
}
|
|
247
|
-
/**
|
|
248
|
-
* Profile name when it differs from the host agent. Undefined for a native
|
|
249
|
-
* run, so pid-registry / sidecar records stay sparse.
|
|
250
|
-
*/
|
|
251
178
|
export function customHarnessName(options) {
|
|
252
179
|
const harness = options.harnessName?.trim();
|
|
253
180
|
if (!harness || harness === options.agent)
|
|
254
181
|
return undefined;
|
|
255
182
|
return harness;
|
|
256
183
|
}
|
|
257
|
-
/**
|
|
258
|
-
* Resolve interactive vs headless. Explicit flags are definitive and win over
|
|
259
|
-
* inference: `--interactive` forces interactive, `--headless` forces headless.
|
|
260
|
-
* With neither flag, prompt presence decides (prompt -> headless, none -> interactive).
|
|
261
|
-
* `--interactive` takes precedence over `--headless`; the CLI layer rejects passing both.
|
|
262
|
-
*/
|
|
263
184
|
export function resolveInteractive(options) {
|
|
264
185
|
if (options.interactive === true)
|
|
265
186
|
return true;
|
|
@@ -267,48 +188,17 @@ export function resolveInteractive(options) {
|
|
|
267
188
|
return false;
|
|
268
189
|
return options.prompt === undefined;
|
|
269
190
|
}
|
|
270
|
-
/**
|
|
271
|
-
* True when a run resolved to *inferred* interactive intent — no prompt and no
|
|
272
|
-
* explicit `--interactive` — but there is no terminal to host the REPL. Launching
|
|
273
|
-
* would attach a TUI to a dead stdin and hang forever, so the caller should fail
|
|
274
|
-
* fast with the headless alternatives instead (RUSH-1829).
|
|
275
|
-
*
|
|
276
|
-
* An explicit `--interactive` is the caller's deliberate choice and is never
|
|
277
|
-
* blocked (they may be driving a PTY we can't detect). Pure — the TTY state is a
|
|
278
|
-
* parameter so this is unit-testable without touching `process.std*`.
|
|
279
|
-
*/
|
|
280
191
|
export function inferredInteractiveWithoutTty(options, isTty) {
|
|
281
192
|
if (options.interactive === true)
|
|
282
193
|
return false;
|
|
283
194
|
return resolveInteractive(options) && !isTty;
|
|
284
195
|
}
|
|
285
|
-
/**
|
|
286
|
-
* Decide whether spawnAgent must capture (PIPE + tee) the child's stdout so the
|
|
287
|
-
* live budget watcher can parse it (issue #346, FIX 3).
|
|
288
|
-
*
|
|
289
|
-
* The bug this fixes: stdout used to be PIPED only when downstream output was
|
|
290
|
-
* piped (`piped = !isTTY`). For a normal headless run AT A TERMINAL, stdout was
|
|
291
|
-
* 'inherit', so `child.stdout` was null and the watcher — hence the mid-run
|
|
292
|
-
* hard-cap kill — was silently skipped. We now tap stdout for ALL
|
|
293
|
-
* non-interactive runs when caps are active, regardless of TTY, and tee it back
|
|
294
|
-
* so the user still sees output. Interactive REPLs are never tapped (the human
|
|
295
|
-
* owns the TTY; they rely on the pre-flight gate).
|
|
296
|
-
*
|
|
297
|
-
* @param interactive resolveInteractive() result for the run
|
|
298
|
-
* @param piped true when the parent's stdout is NOT a TTY (output piped)
|
|
299
|
-
* @param capsActive true when a budget watcher is attached (caps configured)
|
|
300
|
-
*/
|
|
301
196
|
export function shouldTapStdout(interactive, piped, capsActive, captureTail = false) {
|
|
302
197
|
if (interactive)
|
|
303
198
|
return false;
|
|
304
|
-
// Always pipe when the caller pipes us downstream (preserve composability),
|
|
305
|
-
// when caps are active so the watcher can read the stream at a TTY, or when
|
|
306
|
-
// a fallback chain needs a stdout tail for rate-limit detection.
|
|
307
199
|
return piped || capsActive || captureTail;
|
|
308
200
|
}
|
|
309
|
-
/** Pattern for valid environment variable names (C identifier rules). */
|
|
310
201
|
const EXEC_ENV_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
311
|
-
/** Parse a single KEY=VALUE string into a tuple, validating the key name. */
|
|
312
202
|
function parseExecEnvEntry(entry) {
|
|
313
203
|
const separatorIndex = entry.indexOf('=');
|
|
314
204
|
if (separatorIndex <= 0) {
|
|
@@ -321,52 +211,21 @@ function parseExecEnvEntry(entry) {
|
|
|
321
211
|
}
|
|
322
212
|
return [key, value];
|
|
323
213
|
}
|
|
324
|
-
/** Parse an array of KEY=VALUE strings into an env record. Returns undefined for empty input. */
|
|
325
214
|
export function parseExecEnv(entries) {
|
|
326
215
|
if (entries.length === 0) {
|
|
327
216
|
return undefined;
|
|
328
217
|
}
|
|
329
218
|
return Object.fromEntries(entries.map(parseExecEnvEntry));
|
|
330
219
|
}
|
|
331
|
-
/**
|
|
332
|
-
* Resolve the launch id a run exports as `AGENT_LAUNCH_ID`.
|
|
333
|
-
*
|
|
334
|
-
* The launch id is the stable correlation key the SessionStart hook records
|
|
335
|
-
* alongside the agent's real session id (terminals/sessions/<pid>.json), so it
|
|
336
|
-
* is what maps a launch to its exact session even when the hook runs under a
|
|
337
|
-
* different pid (tmux pane leaf / cmd.exe wrapper) — and, across an SSH hop, what
|
|
338
|
-
* lets a `--device` launcher resolve the remote-coined id for agents that never
|
|
339
|
-
* accept a forced `--session-id`.
|
|
340
|
-
*
|
|
341
|
-
* ADOPT a caller-supplied `AGENT_LAUNCH_ID` (a `--device` launcher forwards one via
|
|
342
|
-
* `--env` so it controls the key end-to-end); MINT a fresh one otherwise (every
|
|
343
|
-
* local run, which passes none). A malformed inbound value is ignored in favour
|
|
344
|
-
* of a fresh mint — the key must be a real correlation id, never an empty string.
|
|
345
|
-
*/
|
|
346
220
|
export function resolveLaunchId(envLaunchId) {
|
|
347
221
|
const inbound = envLaunchId?.trim();
|
|
348
222
|
return inbound ? inbound : randomUUID();
|
|
349
223
|
}
|
|
350
|
-
|
|
351
|
-
* Build the process environment for an agent invocation.
|
|
352
|
-
* Pins CLAUDE_CONFIG_DIR for Claude, CODEX_HOME for Codex, and COPILOT_HOME
|
|
353
|
-
* for GitHub Copilot; strips the other agents' env vars so they don't leak
|
|
354
|
-
* into unrelated invocations.
|
|
355
|
-
*/
|
|
224
|
+
// Child runs shed parent session/mailbox/account/exec-home identity; lineage is reintroduced only through explicit parent fields.
|
|
356
225
|
export function buildExecEnv(options) {
|
|
357
226
|
const result = { ...sanitizeProcessEnv(process.env) };
|
|
358
|
-
// Config-dir env vars are agent-specific. When the caller is running inside
|
|
359
|
-
// an agent-managed shell, process.env already carries one; spreading into a
|
|
360
|
-
// different agent's env would leak a config pointer the target CLI doesn't
|
|
361
|
-
// understand. Each harness adapter pins its own config-dir var to the versioned
|
|
362
|
-
// home and strips the foreign ones; a harness with no config-dir env (the old
|
|
363
|
-
// `else`) has no adapter override, so all four are stripped here.
|
|
364
227
|
const configAdapter = resolveHarnessAdapter(options.agent);
|
|
365
228
|
if (configAdapter.applyExecConfigEnv) {
|
|
366
|
-
// Resolve version/versionHome here (this module already imports
|
|
367
|
-
// installations/versions); the adapters must not import it themselves or they
|
|
368
|
-
// close a versions -> shims -> harness -> adapter import cycle. execHome is
|
|
369
|
-
// the account slot (PHNX-3940 T5) and wins over a legacy configVersion label.
|
|
370
229
|
const { version, versionHome } = resolveExecConfigHome(options);
|
|
371
230
|
configAdapter.applyExecConfigEnv(result, {
|
|
372
231
|
agent: options.agent,
|
|
@@ -380,108 +239,59 @@ export function buildExecEnv(options) {
|
|
|
380
239
|
else {
|
|
381
240
|
stripForeignConfigDir(result);
|
|
382
241
|
}
|
|
383
|
-
// A new harness must not inherit its spawner's own session/mailbox or editor
|
|
384
|
-
// ownership. Keep those relationships as lineage, including across SSH.
|
|
385
242
|
delete result.AGENT_SESSION_ID;
|
|
386
243
|
delete result.AGENTS_SESSION_ID;
|
|
387
244
|
delete result.AGENTS_MAILBOX_DIR;
|
|
388
245
|
delete result.AGENT_TERMINAL_ID;
|
|
389
246
|
const launchIdentity = launchIdentityEnv();
|
|
390
247
|
Object.assign(result, launchIdentity);
|
|
391
|
-
// Point the agent at its own mailbox so the PreToolUse `mailbox-inject` hook
|
|
392
|
-
// knows which box to drain and inject mid-run. Keyed by the session id — the
|
|
393
|
-
// same id the writer resolves via mailboxIdForActiveSession(). A loop run
|
|
394
|
-
// overrides this to its run-level box via options.env (spread below), so all
|
|
395
|
-
// iterations share one inbox.
|
|
396
248
|
if (options.sessionId && isValidMailboxId(options.sessionId)) {
|
|
397
249
|
result.AGENTS_MAILBOX_DIR = mailboxDir(options.sessionId);
|
|
398
|
-
// Full session id for agent-callable tools (`agents feed post`, etc.).
|
|
399
250
|
result.AGENT_SESSION_ID = options.sessionId;
|
|
400
251
|
result.AGENTS_SESSION_ID = options.sessionId;
|
|
401
252
|
}
|
|
402
|
-
// Lineage edge: the child's parent is THIS process's session (the spawner), so a
|
|
403
|
-
// sub-agent's events carry a walkable edge back to who spawned it. The event floor
|
|
404
|
-
// (events.ts::resolveProvenance) reads AGENTS_PARENT_SESSION_ID and stamps it on
|
|
405
|
-
// every event the child emits. `options.sessionId` is the CHILD's id, so read the
|
|
406
|
-
// spawner from the live env; guard a same-session resume from naming itself parent.
|
|
407
|
-
// An SSH continuation has no runtime marker; keep its forwarded parent edge.
|
|
408
253
|
delete result.AGENTS_PARENT_SESSION_ID;
|
|
409
254
|
const spawnerSessionId = launchIdentity.AGENTS_PARENT_SESSION_ID;
|
|
410
255
|
if (spawnerSessionId && spawnerSessionId !== options.sessionId) {
|
|
411
256
|
result.AGENTS_PARENT_SESSION_ID = spawnerSessionId;
|
|
412
257
|
}
|
|
413
258
|
result.AGENTS_RUNTIME = resolveInteractive(options) ? 'terminal' : 'headless';
|
|
414
|
-
//
|
|
415
|
-
// for it: the process client points the standalone at the user agents dir
|
|
416
|
-
// (buildServeEnv, MIG-1), while a bare `secrets` defaults to ~/.secrets. Left
|
|
417
|
-
// unset, an agent's `secrets exec` ran against a second broker and a second
|
|
418
|
-
// event log, and an unlock in one was invisible in the other. An explicit
|
|
419
|
-
// SECRETS_HOME in the launching environment wins, matching buildServeEnv.
|
|
259
|
+
// Bind the standalone secrets client to the same store agents-cli resolved.
|
|
420
260
|
result.SECRETS_HOME = result.SECRETS_HOME ?? getUserAgentsDir();
|
|
421
|
-
// Durable SessionStart metadata. The hook joins these launch facts to the
|
|
422
|
-
// harness-provided real session id and writes them under the shared history
|
|
423
|
-
// directory, so a later resume can restore the permission boundary without
|
|
424
|
-
// re-parsing harness-specific transcripts.
|
|
425
261
|
result.AGENTS_RUN_MODE = resolveHeadlessMode(options.agent, normalizeMode(options.mode), resolveInteractive(options), options.modeWarningContext, options.modeWarningState);
|
|
426
262
|
result.AGENTS_HISTORY_DIR = getHistoryDir();
|
|
427
|
-
// Durable origin version for a later native resume. The SessionStart hook joins
|
|
428
|
-
// this to the harness's real session id (like AGENTS_RUN_MODE), so recovery can
|
|
429
|
-
// pin the exact origin version even when the transcript carries no derivable one
|
|
430
|
-
// (codex's `.codex-homes/<version>/` home) — the "version not recorded" fallback
|
|
431
|
-
// to `/continue` this closes (PHNX-3626). Resolve the concrete version-home id
|
|
432
|
-
// the same way the spawn path does; only stamp a real one.
|
|
433
263
|
if (options.agent) {
|
|
434
264
|
const runVersion = options.version ?? resolveVersion(options.agent, options.cwd || process.cwd());
|
|
435
265
|
if (runVersion)
|
|
436
266
|
result.AGENTS_RUN_VERSION = runVersion;
|
|
437
267
|
}
|
|
438
|
-
// So activity / feed posts stamp the right harness without re-detecting.
|
|
439
|
-
// A custom-harness run (`agents run deepseek`) must stamp the PROFILE name,
|
|
440
|
-
// not the host CLI (`claude`) — otherwise sessions and feed posts cannot
|
|
441
|
-
// tell the two apart (PHNX-2935).
|
|
442
268
|
if (options.agent) {
|
|
443
269
|
result.AGENTS_AGENT_NAME = stampedAgentName(options);
|
|
444
270
|
}
|
|
445
271
|
if (options.cwd) {
|
|
446
272
|
result.AGENTS_CWD = options.cwd;
|
|
447
273
|
}
|
|
448
|
-
// An account-slot launch (PHNX-3940 T5) tells the versioned alias which
|
|
449
|
-
// HOME-shaped dir owns this run's config, so the alias's version-home pin
|
|
450
|
-
// (claude: CLAUDE_CONFIG_DIR) yields to the slot instead of overriding the
|
|
451
|
-
// adapter's pin above. Set only for a slot launch and cleared otherwise, so a
|
|
452
|
-
// run spawned from inside a slot session never inherits its parent's slot.
|
|
453
274
|
if (options.execHome) {
|
|
454
275
|
result.AGENTS_EXEC_HOME = options.execHome;
|
|
455
276
|
}
|
|
456
277
|
else {
|
|
457
278
|
delete result.AGENTS_EXEC_HOME;
|
|
458
279
|
}
|
|
459
|
-
// Durable account identity for this run (PHNX-3940 model-refusal tracking).
|
|
460
|
-
// Cleared when absent so a run spawned from inside an account-scoped session
|
|
461
|
-
// never inherits its parent's account id.
|
|
462
280
|
if (options.accountId) {
|
|
463
281
|
result.AGENTS_RUN_ACCOUNT_ID = options.accountId;
|
|
464
282
|
}
|
|
465
283
|
else {
|
|
466
284
|
delete result.AGENTS_RUN_ACCOUNT_ID;
|
|
467
285
|
}
|
|
468
|
-
// Export the run's durable name (companion to AGENT_SESSION_ID) so a
|
|
469
|
-
// SessionStart hook / the agent can associate its transcript with the handle
|
|
470
|
-
// the user gave the run. Only set when --name was passed.
|
|
471
286
|
if (options.name) {
|
|
472
287
|
result.AGENT_SESSION_NAME = options.name;
|
|
473
288
|
}
|
|
474
|
-
// Actor provenance -- who initiated this run. Rides the env so the whole spawn
|
|
475
|
-
// tree shares one actor, and (for a resolved human) so the agent's own git
|
|
476
|
-
// commits are credited to the person instead of the shared account. options.env
|
|
477
|
-
// (spread last) overrides any of these keys a caller sets explicitly.
|
|
478
289
|
Object.assign(result, actorEnv(resolveActor()));
|
|
479
290
|
return {
|
|
480
291
|
...result,
|
|
481
292
|
...options.env,
|
|
482
293
|
};
|
|
483
294
|
}
|
|
484
|
-
/** Materialize config roots for vendor CLIs that do not create parents recursively. */
|
|
485
295
|
export function ensureVendorHomeDir(agent, versionHome) {
|
|
486
296
|
if (agent !== 'cursor' && agent !== 'grok' && agent !== 'copilot')
|
|
487
297
|
return null;
|
|
@@ -502,12 +312,6 @@ function ensureVendorHomeForSpawn(options) {
|
|
|
502
312
|
if (versionHome)
|
|
503
313
|
ensureVendorHomeDir(options.agent, versionHome);
|
|
504
314
|
}
|
|
505
|
-
/**
|
|
506
|
-
* CLI command templates for every supported agent.
|
|
507
|
-
*
|
|
508
|
-
* Each agent's `modeFlags` keys MUST match the modes listed in
|
|
509
|
-
* AGENTS[agent].capabilities.modes. A test in exec.test.ts asserts this.
|
|
510
|
-
*/
|
|
511
315
|
export const AGENT_COMMANDS = {
|
|
512
316
|
claude: {
|
|
513
317
|
base: ['claude'],
|
|
@@ -529,13 +333,9 @@ export const AGENT_COMMANDS = {
|
|
|
529
333
|
promptFlag: 'positional',
|
|
530
334
|
resume: { subcommand: 'resume' },
|
|
531
335
|
modeFlags: {
|
|
532
|
-
// Native Codex modes are assembled by codexPolicyArgs below. Named
|
|
533
|
-
// permission profiles keep filesystem access and network access
|
|
534
|
-
// independent; legacy --sandbox flags cannot express that combination.
|
|
535
336
|
plan: [],
|
|
536
337
|
edit: [],
|
|
537
338
|
auto: [],
|
|
538
|
-
// skip = codex --yolo: drops the sandbox entirely and approves anything.
|
|
539
339
|
skip: ['--dangerously-bypass-approvals-and-sandbox'],
|
|
540
340
|
},
|
|
541
341
|
jsonFlags: ['--json'],
|
|
@@ -556,9 +356,6 @@ export const AGENT_COMMANDS = {
|
|
|
556
356
|
opencode: {
|
|
557
357
|
base: ['opencode', 'run'],
|
|
558
358
|
promptFlag: 'positional',
|
|
559
|
-
// opencode's native resume is `opencode --session <id>` (NOT under `run`), so
|
|
560
|
-
// it does not compose with this headless `run` base. Until that's verified on
|
|
561
|
-
// a box with opencode installed, opencode resumes via Tier-2 `/continue`.
|
|
562
359
|
modeFlags: {
|
|
563
360
|
plan: ['--agent', 'plan'],
|
|
564
361
|
edit: ['--agent', 'build'],
|
|
@@ -577,17 +374,6 @@ export const AGENT_COMMANDS = {
|
|
|
577
374
|
jsonFlags: ['--output-format', 'stream-json'],
|
|
578
375
|
modelFlag: '--model',
|
|
579
376
|
},
|
|
580
|
-
// GitHub Copilot CLI (`@github/copilot`, GA 2026-02-25). Flags verified
|
|
581
|
-
// against `copilot --help` from v0.0.413+:
|
|
582
|
-
// -p, --prompt <text> non-interactive one-shot
|
|
583
|
-
// --mode <interactive|plan|autopilot>
|
|
584
|
-
// --autopilot start in autopilot (smart-classifier) mode
|
|
585
|
-
// --allow-all-tools required for non-interactive tool exec
|
|
586
|
-
// --allow-all (alias --yolo) tools + paths + URLs
|
|
587
|
-
// --output-format <text|json> json => JSONL, one object per line
|
|
588
|
-
// --model <model>
|
|
589
|
-
// Plan mode is read-only so it does not need an allow-tools grant; edit
|
|
590
|
-
// needs --allow-all-tools so headless runs don't stall on prompts.
|
|
591
377
|
copilot: {
|
|
592
378
|
base: ['copilot'],
|
|
593
379
|
promptFlag: '-p',
|
|
@@ -613,20 +399,14 @@ export const AGENT_COMMANDS = {
|
|
|
613
399
|
base: ['goose', 'run'],
|
|
614
400
|
promptFlag: 'positional',
|
|
615
401
|
modeFlags: {
|
|
616
|
-
// goose has no permission flags — edit is the default behavior.
|
|
617
402
|
edit: [],
|
|
618
403
|
},
|
|
619
404
|
},
|
|
620
405
|
// TODO: --output-format json is documented but currently broken upstream
|
|
621
|
-
// ("flags provided but not defined: -output-format"). Track resolution at
|
|
622
|
-
// https://github.com/google-antigravity/antigravity-cli/issues/7 before
|
|
623
|
-
// adding `jsonFlags` here.
|
|
624
406
|
antigravity: {
|
|
625
407
|
base: ['agy'],
|
|
626
408
|
promptFlag: 'positional',
|
|
627
409
|
modeFlags: {
|
|
628
|
-
// agy --help shows no plan/edit flags; default behavior is edit-like
|
|
629
|
-
// (prompts on tool use). Only skip has an explicit flag.
|
|
630
410
|
edit: [],
|
|
631
411
|
skip: ['--dangerously-skip-permissions'],
|
|
632
412
|
},
|
|
@@ -637,7 +417,6 @@ export const AGENT_COMMANDS = {
|
|
|
637
417
|
base: ['grok'],
|
|
638
418
|
promptFlag: '-p',
|
|
639
419
|
modeFlags: {
|
|
640
|
-
// grok --help lists `--permission-mode plan`; the TUI defaults to ask.
|
|
641
420
|
plan: ['--permission-mode', 'plan'],
|
|
642
421
|
edit: [],
|
|
643
422
|
skip: ['--always-approve'],
|
|
@@ -659,18 +438,13 @@ export const AGENT_COMMANDS = {
|
|
|
659
438
|
modelFlag: '--model',
|
|
660
439
|
resume: { flag: '--session', since: '0.19.2' },
|
|
661
440
|
},
|
|
662
|
-
// Factory AI Droid (`droid exec` for headless, `droid` for TUI). Flags from
|
|
663
|
-
// docs.factory.ai CLI reference: prompt is positional; --auto low|medium|high
|
|
664
|
-
// escalates autonomy (default is read-only); --skip-permissions-unsafe drops
|
|
665
|
-
// all guardrails; -o stream-json streams JSONL events; -m selects the model.
|
|
666
|
-
// The `exec` subcommand is dropped for interactive runs (see buildExecCommand).
|
|
667
441
|
droid: {
|
|
668
442
|
base: ['droid', 'exec'],
|
|
669
443
|
promptFlag: 'positional',
|
|
670
444
|
modeFlags: {
|
|
671
|
-
plan: [],
|
|
672
|
-
edit: ['--auto', 'low'],
|
|
673
|
-
auto: ['--auto', 'high'],
|
|
445
|
+
plan: [],
|
|
446
|
+
edit: ['--auto', 'low'],
|
|
447
|
+
auto: ['--auto', 'high'],
|
|
674
448
|
skip: ['--skip-permissions-unsafe'],
|
|
675
449
|
},
|
|
676
450
|
jsonFlags: ['-o', 'stream-json'],
|
|
@@ -685,14 +459,6 @@ export const AGENT_COMMANDS = {
|
|
|
685
459
|
},
|
|
686
460
|
modelFlag: '--model',
|
|
687
461
|
},
|
|
688
|
-
// Meta Muse Code (`muse exec` headless, `muse` TUI). Flags from
|
|
689
|
-
// `muse --help` / `muse exec --help` (v0.1.0): prompt is positional;
|
|
690
|
-
// --model selects muse-spark-*; --reasoning-effort is the effort dial;
|
|
691
|
-
// --disable-write approximates plan (no non-shell writes); --disable-approval
|
|
692
|
-
// keeps the sandbox (auto); --yolo drops approval+sandbox and trusts the
|
|
693
|
-
// workspace (skip). --json emits JSONL on stdout. Interactive resume is
|
|
694
|
-
// `muse resume <id>`; headless resume is `muse exec --session-id <id>` —
|
|
695
|
-
// see the muse resume branch in buildExecCommand.
|
|
696
462
|
muse: {
|
|
697
463
|
base: ['muse', 'exec'],
|
|
698
464
|
promptFlag: 'positional',
|
|
@@ -704,20 +470,8 @@ export const AGENT_COMMANDS = {
|
|
|
704
470
|
},
|
|
705
471
|
jsonFlags: ['--json'],
|
|
706
472
|
modelFlag: '--model',
|
|
707
|
-
// Flag form covers headless (`--session-id`). Interactive uses the
|
|
708
|
-
// `resume` subcommand — special-cased in buildExecCommand.
|
|
709
473
|
resume: { flag: '--session-id' },
|
|
710
474
|
},
|
|
711
|
-
// Warp Agent CLI (`warp`) — the interactive TUI. It has NO headless one-shot
|
|
712
|
-
// form: the documented flags are --api-key/--auto-approve/--resume <token>/
|
|
713
|
-
// --set-provider-api-key/--clear-provider-api-key/--version/--help — no
|
|
714
|
-
// -p/--prompt, no --model (model is the `/model` picker), no JSON output. So
|
|
715
|
-
// bare `warp` opens the TUI and the single `edit` mode maps to no flags
|
|
716
|
-
// (mirrors hermes); there are no jsonFlags/modelFlag to declare. No `resume`:
|
|
717
|
-
// `warp --resume <token>` reopens a SERVER-SIDE conversation by token, but
|
|
718
|
-
// warp is not session-tracked (absent from SESSION_AGENTS) so agents-cli has
|
|
719
|
-
// no local id to feed — declaring it would make nativeResume(warp) true
|
|
720
|
-
// against an unreachable path.
|
|
721
475
|
warp: {
|
|
722
476
|
base: ['warp'],
|
|
723
477
|
promptFlag: 'positional',
|
|
@@ -726,11 +480,6 @@ export const AGENT_COMMANDS = {
|
|
|
726
480
|
},
|
|
727
481
|
},
|
|
728
482
|
};
|
|
729
|
-
/**
|
|
730
|
-
* Whether `agent` has a native resume form (Tier 1). Derived solely from the
|
|
731
|
-
* command template's `resume` field — the single source of truth. Agents that
|
|
732
|
-
* return false resume via the universal Tier-2 `/continue` replay instead.
|
|
733
|
-
*/
|
|
734
483
|
export function nativeResume(agent, version) {
|
|
735
484
|
const resume = AGENT_COMMANDS[agent]?.resume;
|
|
736
485
|
if (!resume)
|
|
@@ -739,41 +488,9 @@ export function nativeResume(agent, version) {
|
|
|
739
488
|
return true;
|
|
740
489
|
return !!version && compareVersions(installedReleaseFor(agent, version), resume.since) >= 0;
|
|
741
490
|
}
|
|
742
|
-
/**
|
|
743
|
-
* Build the `-c` value that adds `dir` to codex's workspace-write writable
|
|
744
|
-
* roots. Codex parses the value as TOML, so it's a single-element TOML array of
|
|
745
|
-
* one quoted string. Used on codex resume forms, which reject `--add-dir` and
|
|
746
|
-
* only accept `-c` config overrides.
|
|
747
|
-
*/
|
|
748
491
|
export function codexWritableRootsConfig(dir) {
|
|
749
492
|
return `sandbox_workspace_write.writable_roots=[${JSON.stringify(dir)}]`;
|
|
750
493
|
}
|
|
751
|
-
/**
|
|
752
|
-
* Resolve the executable `buildExecCommand` will put in `cmd[0]`, or null when
|
|
753
|
-
* that resolution finds nothing on disk.
|
|
754
|
-
*
|
|
755
|
-
* This is an EXISTENCE probe, not an "is it managed by us" check. A harness the
|
|
756
|
-
* user installed themselves (Homebrew, a vendor `curl | sh`, a distro package)
|
|
757
|
-
* has no version home at all, and running it is a supported state — so with no
|
|
758
|
-
* version pinned we answer with a PATH lookup of the bare launch command, the
|
|
759
|
-
* same thing `spawnAgent` would resolve.
|
|
760
|
-
*
|
|
761
|
-
* `findInPath` deliberately excludes our own shims dir, because a shim is a
|
|
762
|
-
* dispatcher rather than an install. That exclusion alone is too strong here:
|
|
763
|
-
* the shim DOES launch whenever agents-cli owns at least one version of the
|
|
764
|
-
* agent — it resolves the version itself, and when no default is pinned it
|
|
765
|
-
* prints its own accurate `no default set … agents use <agent> <version>`
|
|
766
|
-
* guidance. Pre-empting that with "not installed" would name the wrong fix
|
|
767
|
-
* (`agents add`) for a machine that already has the harness. So the shim counts
|
|
768
|
-
* only when a managed version exists; with zero managed versions it is the dead
|
|
769
|
-
* end this probe was written to catch (RUSH-2339).
|
|
770
|
-
*
|
|
771
|
-
* The version-pinned branch mirrors buildExecCommand exactly: versioned shim
|
|
772
|
-
* first, then the version home's real binary. It deliberately does NOT fall back
|
|
773
|
-
* to PATH — with a version pinned, buildExecCommand spawns the literal
|
|
774
|
-
* `<cli>@<version>`, which is not on PATH, so a PATH hit here would be a lie
|
|
775
|
-
* that still exits 127.
|
|
776
|
-
*/
|
|
777
494
|
export function resolveLaunchBinary(agent, version) {
|
|
778
495
|
const command = AGENT_COMMANDS[agent].base[0];
|
|
779
496
|
if (version) {
|
|
@@ -791,19 +508,12 @@ export function resolveLaunchBinary(agent, version) {
|
|
|
791
508
|
return native;
|
|
792
509
|
if (listInstalledVersions(agent).length === 0)
|
|
793
510
|
return null;
|
|
794
|
-
// Re-scan PATH accepting the shim: point findInPath's exclusion at a path that
|
|
795
|
-
// matches nothing, so the real shims dir participates like any other PATH entry.
|
|
796
511
|
return findInPath(command, { shimsDir: path.join(getShimsDir(), '.no-such-dir') });
|
|
797
512
|
}
|
|
798
|
-
/** Assemble the full CLI argument array for an agent invocation. */
|
|
799
513
|
export function buildExecCommand(options) {
|
|
800
514
|
const template = AGENT_COMMANDS[options.agent];
|
|
801
515
|
const cmd = [...template.base];
|
|
802
516
|
const interactive = resolveInteractive(options);
|
|
803
|
-
// For Codex, Droid, and Muse, 'exec' is the headless subcommand; for OpenCode,
|
|
804
|
-
// 'run' is. Drop it for interactive mode so we launch the TUI (`codex` /
|
|
805
|
-
// `droid` / `muse` / `opencode`) instead of the one-shot headless subcommand
|
|
806
|
-
// ('codex exec' / 'droid exec' / 'muse exec' / 'opencode run').
|
|
807
517
|
if (interactive) {
|
|
808
518
|
if ((options.agent === 'codex' || options.agent === 'droid' || options.agent === 'muse') &&
|
|
809
519
|
cmd[1] === 'exec') {
|
|
@@ -813,16 +523,6 @@ export function buildExecCommand(options) {
|
|
|
813
523
|
cmd.splice(1, 1);
|
|
814
524
|
}
|
|
815
525
|
}
|
|
816
|
-
// Native resume with a `{ subcommand }` shape (codex) appends the resume verb
|
|
817
|
-
// to the base: `codex exec` -> `codex exec resume` (headless) and, after the
|
|
818
|
-
// interactive drop above, `codex` -> `codex resume` (TUI). The session id is
|
|
819
|
-
// pushed later as the first positional (before any prompt). `{ flag }` agents
|
|
820
|
-
// (claude) need no base change — the flag is appended with the id below.
|
|
821
|
-
//
|
|
822
|
-
// Muse interactive resume is also a subcommand (`muse resume <id>`), but the
|
|
823
|
-
// session id MUST sit immediately after the verb — mode/model flags come
|
|
824
|
-
// after. So for interactive muse we push both `resume` and the id here, and
|
|
825
|
-
// skip the later generic resume flag path.
|
|
826
526
|
const resumeSpec = options.resume ? template.resume : undefined;
|
|
827
527
|
let museInteractiveResumeDone = false;
|
|
828
528
|
if (options.agent === 'muse' && options.resume && interactive && options.sessionId) {
|
|
@@ -832,17 +532,6 @@ export function buildExecCommand(options) {
|
|
|
832
532
|
else if (resumeSpec && 'subcommand' in resumeSpec) {
|
|
833
533
|
cmd.push(resumeSpec.subcommand);
|
|
834
534
|
}
|
|
835
|
-
// Use versioned alias if a specific version was requested (e.g., claude@2.1.98).
|
|
836
|
-
// Resolve to the absolute path of the shim so spawn doesn't depend on PATH —
|
|
837
|
-
// on Linux installs where the shims dir isn't on PATH, spawning the bare
|
|
838
|
-
// versioned name fails with ENOENT even though `agents view` shows the agent.
|
|
839
|
-
//
|
|
840
|
-
// On Windows the alias is materialized as a `.cmd` only (see
|
|
841
|
-
// createVersionedAlias — a bash alias next to it would shadow the `.cmd` in
|
|
842
|
-
// cmd.exe/PowerShell name resolution); the extensionless existsSync branch
|
|
843
|
-
// below still matches a legacy install's bash alias. When no shim exists on
|
|
844
|
-
// disk we fall back to the bare versioned name, which spawnAgent() resolves
|
|
845
|
-
// via PATH (+ PATHEXT/shell on Windows).
|
|
846
535
|
if (options.version && cmd.length > 0) {
|
|
847
536
|
const versionedName = `${cmd[0]}@${options.version}`;
|
|
848
537
|
const absPath = path.join(getShimsDir(), versionedName);
|
|
@@ -853,23 +542,10 @@ export function buildExecCommand(options) {
|
|
|
853
542
|
cmd[0] = absPath;
|
|
854
543
|
}
|
|
855
544
|
else {
|
|
856
|
-
// No versioned shim on disk. Prefer the version's REAL launch binary
|
|
857
|
-
// (node_modules/.bin/<cli>) over the bare `<cli>@<version>` name — that
|
|
858
|
-
// literal is not on PATH and spawns as ENOENT (the `kimi@0.19.2` failure).
|
|
859
|
-
// Fall back to the literal only if the binary is absent (the run path's
|
|
860
|
-
// ensureAgentRunnable normally repairs/creates the alias before we reach here).
|
|
861
545
|
const realBinary = options.agent ? getBinaryPath(options.agent, options.version) : undefined;
|
|
862
546
|
cmd[0] = realBinary && fs.existsSync(realBinary) ? realBinary : versionedName;
|
|
863
547
|
}
|
|
864
548
|
}
|
|
865
|
-
// Resolve the model up front so the reasoning-flag block can honor a cost tier
|
|
866
|
-
// that maps to reasoning effort on a single-model harness (e.g. Grok, where the
|
|
867
|
-
// tier IS the effort dial). `modelVersion` is null when no version resolves;
|
|
868
|
-
// `tierModel` is the concrete model a tier resolved to (null => drop the flag).
|
|
869
|
-
// Prefer the user's explicit --model. Codex falls back to ~/.codex/config.toml
|
|
870
|
-
// (per-version CODEX_HOME may not carry that setting). OpenCode has no model
|
|
871
|
-
// env var — a custom-harness pin lives in OPENCODE_MODEL and must become
|
|
872
|
-
// `--model` here, or the host silently uses its configured default (PHNX-2577).
|
|
873
549
|
const effectiveModel = options.model
|
|
874
550
|
?? (options.agent === 'codex' ? readCodexConfiguredModel() : undefined)
|
|
875
551
|
?? (options.agent === 'opencode' ? options.env?.OPENCODE_MODEL : undefined);
|
|
@@ -879,41 +555,23 @@ export function buildExecCommand(options) {
|
|
|
879
555
|
const tierResolved = effectiveModel && modelVersion && isTierToken(effectiveModel)
|
|
880
556
|
? resolveTier(options.agent, modelVersion, effectiveModel)
|
|
881
557
|
: null;
|
|
882
|
-
// An explicit --effort wins; otherwise a single-model tier's effort applies.
|
|
883
558
|
const effortLevel = options.effort !== 'auto' ? options.effort : (tierResolved?.effort ?? options.effort);
|
|
884
|
-
// Add reasoning effort flags (before mode flags for codex -c positioning)
|
|
885
|
-
// For codex, -c must come before 'exec' subcommand, so we insert at position 1
|
|
886
559
|
if (effortLevel !== 'auto') {
|
|
887
560
|
const reasoningFlags = buildReasoningFlags(options.agent, effortLevel);
|
|
888
561
|
if (reasoningFlags.length > 0) {
|
|
889
562
|
if (options.agent === 'codex') {
|
|
890
|
-
// Insert after 'codex' (or 'codex@version') but before 'exec'
|
|
891
563
|
cmd.splice(1, 0, ...reasoningFlags);
|
|
892
564
|
}
|
|
893
565
|
else {
|
|
894
|
-
// For other agents, append after base
|
|
895
566
|
cmd.push(...reasoningFlags);
|
|
896
567
|
}
|
|
897
568
|
}
|
|
898
569
|
}
|
|
899
|
-
// Resolve the requested mode against the agent's capability table.
|
|
900
|
-
// - `auto` on an agent without auto support → silently degrades to `edit`
|
|
901
|
-
// - `plan` on an agent without a read-only mode → degrades to modes[0]
|
|
902
|
-
// - headless `plan` on an agent with headlessPlan:false (kimi, grok) →
|
|
903
|
-
// degrades to `auto` with a stderr warning (see resolveHeadlessMode)
|
|
904
|
-
// - `skip` on an unsupported agent → throws a clear error
|
|
905
|
-
// After resolution, the chosen mode is guaranteed to be in template.modeFlags.
|
|
906
570
|
const resolvedMode = resolveHeadlessMode(options.agent, normalizeMode(options.mode), interactive, options.modeWarningContext, options.modeWarningState);
|
|
907
571
|
const modeFlags = template.modeFlags[resolvedMode];
|
|
908
572
|
if (!modeFlags) {
|
|
909
|
-
// Defense in depth: would only fire if AGENTS.capabilities.modes and
|
|
910
|
-
// AGENT_COMMANDS.modeFlags drifted apart. Tests assert they agree.
|
|
911
573
|
throw new Error(`Internal error: ${options.agent} declares '${resolvedMode}' in capabilities.modes but has no entry in AGENT_COMMANDS.modeFlags.${resolvedMode}.`);
|
|
912
574
|
}
|
|
913
|
-
// Launch-arg quirks (the harness axis of Move 3): cursor's additive `--trust`
|
|
914
|
-
// and the codex/kimi mode-flag overrides move to the harness adapter, so the
|
|
915
|
-
// per-agent name-chain collapses to one dispatch. The generic resume-subcommand
|
|
916
|
-
// and modeFlags paths stay here — they are not per-harness.
|
|
917
575
|
const launchAdapter = resolveHarnessAdapter(options.agent);
|
|
918
576
|
const launchArgsCtx = {
|
|
919
577
|
resolvedMode,
|
|
@@ -931,41 +589,21 @@ export function buildExecCommand(options) {
|
|
|
931
589
|
}
|
|
932
590
|
else if (resumeSpec && 'subcommand' in resumeSpec) {
|
|
933
591
|
if (resolvedMode === 'skip') {
|
|
934
|
-
// skip = yolo on resume too; both `codex resume` (TUI) and
|
|
935
|
-
// `codex exec resume` accept the bypass flag.
|
|
936
592
|
cmd.push('--dangerously-bypass-approvals-and-sandbox');
|
|
937
593
|
}
|
|
938
594
|
else if (interactive) {
|
|
939
595
|
cmd.push(...modeFlags);
|
|
940
596
|
}
|
|
941
597
|
else {
|
|
942
|
-
// `codex exec resume` rejects `--sandbox <mode>` (verified against
|
|
943
|
-
// `codex exec resume --help` on 0.142.5), but takes -c config overrides —
|
|
944
|
-
// map the mode through sandbox_mode so a non-skip resume never gets the
|
|
945
|
-
// approval/sandbox bypass.
|
|
946
598
|
cmd.push(...modeFlags);
|
|
947
599
|
}
|
|
948
600
|
}
|
|
949
601
|
else {
|
|
950
602
|
cmd.push(...modeFlags);
|
|
951
603
|
}
|
|
952
|
-
// Add print/headless flags whenever the run RESOLVED headless -- gate on the
|
|
953
|
-
// resolved state (`!interactive`), not the raw `--headless` flag. Headless is
|
|
954
|
-
// inferred from prompt presence (resolveInteractive), and `--headless` defaults
|
|
955
|
-
// to `false` at the CLI layer, so gating on `options.headless` skipped these
|
|
956
|
-
// flags for a bare `agents run <agent> "prompt"`. For antigravity that meant
|
|
957
|
-
// `agy <prompt>` with no `--print`, launching the TUI and dying on `/dev/tty`
|
|
958
|
-
// in any non-terminal shell. `!interactive` is true for both an explicit
|
|
959
|
-
// `--headless` and a prompt-inferred headless run; an interactive run (no
|
|
960
|
-
// prompt, or `--interactive`) still skips them so the CLI opens its REPL.
|
|
961
604
|
if (!interactive && template.printFlags) {
|
|
962
605
|
cmd.push(...template.printFlags);
|
|
963
606
|
}
|
|
964
|
-
// Resume vs. create. With `resume`, emit the agent's NATIVE resume reference:
|
|
965
|
-
// `{ flag }` agents append `<flag> <id>` (claude `--resume <id>`); `{ subcommand }`
|
|
966
|
-
// agents (codex) already pushed the verb above, so the id is the first
|
|
967
|
-
// positional here — placed before the prompt positional appended later. Without
|
|
968
|
-
// `resume`, the legacy claude-only `--session-id` CREATES a session with that id.
|
|
969
607
|
if (options.resume && options.sessionId && resumeSpec && !museInteractiveResumeDone) {
|
|
970
608
|
if ('flag' in resumeSpec) {
|
|
971
609
|
const flag = interactive
|
|
@@ -980,14 +618,8 @@ export function buildExecCommand(options) {
|
|
|
980
618
|
else if (options.sessionId && options.agent === 'claude') {
|
|
981
619
|
cmd.push('--session-id', options.sessionId);
|
|
982
620
|
}
|
|
983
|
-
// Add model. `effectiveModel` already preferred --model, then Codex's
|
|
984
|
-
// configured default, then an OpenCode custom-harness pin (OPENCODE_MODEL).
|
|
985
621
|
if (effectiveModel && template.modelFlag) {
|
|
986
622
|
if (tierResolved) {
|
|
987
|
-
// Cost tier (cheap|default|best|ultra) -> a concrete model this harness+
|
|
988
|
-
// version actually ships. Covers `agents run` and `agents teams` (both
|
|
989
|
-
// funnel here). A null model means nothing resolved -> drop the flag and
|
|
990
|
-
// let the harness pick its default.
|
|
991
623
|
if (tierResolved.model) {
|
|
992
624
|
cmd.push(template.modelFlag, tierResolved.model);
|
|
993
625
|
if (tierResolved.note)
|
|
@@ -1008,35 +640,22 @@ export function buildExecCommand(options) {
|
|
|
1008
640
|
cmd.push(template.modelFlag, effectiveModel);
|
|
1009
641
|
}
|
|
1010
642
|
else {
|
|
1011
|
-
// Tier token but no version resolved -> forwarding the literal "best"/etc.
|
|
1012
|
-
// would be rejected by the CLI, so drop the flag (harness default).
|
|
1013
643
|
process.stderr.write(`[agents] cannot resolve tier "${effectiveModel}" without a version; using harness default\n`);
|
|
1014
644
|
}
|
|
1015
645
|
}
|
|
1016
|
-
// Add JSON output flags if requested
|
|
1017
646
|
if (options.json && template.jsonFlags) {
|
|
1018
647
|
cmd.push(...template.jsonFlags);
|
|
1019
648
|
}
|
|
1020
|
-
// Add verbose flag independently of JSON
|
|
1021
649
|
if (options.verbose && template.verboseFlag) {
|
|
1022
|
-
// Avoid duplicate if jsonFlags already included --verbose
|
|
1023
650
|
if (!(options.json && template.jsonFlags?.includes(template.verboseFlag))) {
|
|
1024
651
|
cmd.push(template.verboseFlag);
|
|
1025
652
|
}
|
|
1026
653
|
}
|
|
1027
|
-
// Add prompt when provided. In pure interactive mode (no prompt) we skip this
|
|
1028
|
-
// so the CLI launches its TUI. When --interactive is passed alongside a prompt
|
|
1029
|
-
// we still forward the prompt so the agent receives it as the first message.
|
|
1030
654
|
if (options.prompt !== undefined) {
|
|
1031
655
|
if (interactive && options.agent === 'opencode') {
|
|
1032
|
-
// The OpenCode TUI takes an initial prompt via --prompt; a bare positional
|
|
1033
|
-
// on the default command is parsed as a project path, not a message.
|
|
1034
656
|
cmd.push('--prompt', options.prompt);
|
|
1035
657
|
}
|
|
1036
658
|
else if (interactive && options.agent === 'claude') {
|
|
1037
|
-
// Claude's -p is --print, not a prompt-value flag. In an interactive run
|
|
1038
|
-
// the initial prompt is positional; emitting `-p /continue <id>` turns a
|
|
1039
|
-
// focus recovery into a one-shot print process that immediately exits.
|
|
1040
659
|
cmd.push(options.prompt);
|
|
1041
660
|
}
|
|
1042
661
|
else if (template.promptFlag === 'positional') {
|
|
@@ -1046,45 +665,9 @@ export function buildExecCommand(options) {
|
|
|
1046
665
|
cmd.push(template.promptFlag, options.prompt);
|
|
1047
666
|
}
|
|
1048
667
|
}
|
|
1049
|
-
// Project / --add-dir grants. Codex folds them into the named edit profile
|
|
1050
|
-
// above (workspace_roots); resume rejects the native --add-dir flag.
|
|
1051
|
-
// Everything else is strategy-driven in applyAddDirs:
|
|
1052
|
-
// native-flag — claude, kimi, cursor (`--add-dir`)
|
|
1053
|
-
// grok-sandbox — rules + project sandbox profile when sandboxed
|
|
1054
|
-
// none — ignored (no multi-root surface)
|
|
1055
|
-
//
|
|
1056
|
-
// `~` is expanded in normalizeAddDirs (via expandLocalHome), because no shell
|
|
1057
|
-
// does it for us: a forwarded grant crosses the SSH boundary single-quoted
|
|
1058
|
-
// (`shellQuote` in ssh-exec.ts), so the remote login shell leaves `~/…`
|
|
1059
|
-
// literal and the harness resolves it as a directory actually named `~`.
|
|
1060
|
-
// Expanding on the side that runs the harness is what lets one home-relative
|
|
1061
|
-
// grant re-root per machine.
|
|
1062
668
|
applyAddDirs(options.agent, cmd, options.addDirs, {
|
|
1063
669
|
cwd: options.cwd ?? process.cwd(),
|
|
1064
670
|
});
|
|
1065
|
-
// Claude-specific: workflow capability scoping. WORKFLOW.md frontmatter
|
|
1066
|
-
// `tools:` / `mcpServers:` is translated to the headless flags that ACTUALLY
|
|
1067
|
-
// restrict the run (verified against `claude --help` on the installed CLI):
|
|
1068
|
-
//
|
|
1069
|
-
// tools: -> `--tools <names...>` — restricts the AVAILABLE built-in
|
|
1070
|
-
// tool set. This is the security boundary: tools NOT named
|
|
1071
|
-
// here (e.g. Write, Bash, Edit) are unavailable for the whole
|
|
1072
|
-
// run. `--allowedTools` would only auto-approve without
|
|
1073
|
-
// restricting, so it is the WRONG flag for sandboxing.
|
|
1074
|
-
// We also emit `--allowedTools <names...>` for the same set so
|
|
1075
|
-
// the permitted tools don't prompt in headless `-p` mode.
|
|
1076
|
-
// mcpServers: -> `--mcp-config <path>` PLUS `--strict-mcp-config`. The
|
|
1077
|
-
// config flag alone ADDS servers to the existing set; only
|
|
1078
|
-
// `--strict-mcp-config` makes the run use *only* the named
|
|
1079
|
-
// servers, which is what scoping means.
|
|
1080
|
-
//
|
|
1081
|
-
// The command layer gates this behind the `allowlist` capability and assembles
|
|
1082
|
-
// the mcp-config file; buildExecCommand stays a pure string-builder.
|
|
1083
|
-
//
|
|
1084
|
-
// `<tools...>` is variadic. Emit the names as separate argv tokens. The flags
|
|
1085
|
-
// here are appended AFTER the positional prompt (added above), so the variadic
|
|
1086
|
-
// never swallows the prompt; the trailing `--allowedTools` / `--strict-mcp-config`
|
|
1087
|
-
// tokens also terminate the `--tools` variadic cleanly.
|
|
1088
671
|
if (options.agent === 'claude') {
|
|
1089
672
|
if (options.toolsRestrict && options.toolsRestrict.length > 0) {
|
|
1090
673
|
cmd.push('--tools', ...options.toolsRestrict);
|
|
@@ -1095,52 +678,25 @@ export function buildExecCommand(options) {
|
|
|
1095
678
|
cmd.push('--strict-mcp-config');
|
|
1096
679
|
}
|
|
1097
680
|
}
|
|
1098
|
-
// Forward arbitrary native flags supplied after `--` verbatim. Appended last
|
|
1099
|
-
// so they cannot be misinterpreted as values for earlier flags or as the prompt.
|
|
1100
681
|
if (options.passthroughArgs && options.passthroughArgs.length > 0) {
|
|
1101
682
|
cmd.push(...options.passthroughArgs);
|
|
1102
683
|
}
|
|
1103
684
|
return cmd;
|
|
1104
685
|
}
|
|
1105
|
-
/** Spawn an agent and return its exit code. Convenience wrapper over spawnAgent. */
|
|
1106
686
|
export async function execAgent(options) {
|
|
1107
687
|
const { exitCode } = await spawnAgent(options);
|
|
1108
688
|
return exitCode;
|
|
1109
689
|
}
|
|
1110
|
-
/**
|
|
1111
|
-
* Resolve how to spawn a shim target for a platform. Pure — testable on any host.
|
|
1112
|
-
*
|
|
1113
|
-
* POSIX always execs the binary directly (no shell). On Windows a bare
|
|
1114
|
-
* (non-absolute) name or a `.cmd` companion goes through the shell so cmd.exe
|
|
1115
|
-
* resolves it via PATHEXT — the common, `.cmd`-present path; an absolute `.cmd`
|
|
1116
|
-
* or extensionless path is exec'd through the shell / directly. npm always ships
|
|
1117
|
-
* a `<cmd>.cmd` companion on Windows, so the runnable target `execShimPassthrough`
|
|
1118
|
-
* hands us is the `.cmd` (never a bare `.ps1`).
|
|
1119
|
-
*/
|
|
1120
690
|
export function resolveShimSpawn(platform, binary, extraArgs) {
|
|
1121
691
|
if (platform === 'win32') {
|
|
1122
|
-
// Use win32 path semantics regardless of the host running this (the platform
|
|
1123
|
-
// is the parameter, not process.platform) so `C:\...` reads as absolute.
|
|
1124
692
|
const useShell = !path.win32.isAbsolute(binary) || binary.endsWith('.cmd');
|
|
1125
693
|
if (useShell) {
|
|
1126
|
-
// DEP0190-safe: hand cmd.exe ONE fully-quoted command line with an EMPTY
|
|
1127
|
-
// args array, so Node never concatenates `extraArgs` (which carry the
|
|
1128
|
-
// user's raw prompt/flags) into the shell line unescaped — that concat is
|
|
1129
|
-
// both the deprecation and a command-injection surface.
|
|
1130
694
|
return { command: composeWin32CommandLine(binary, extraArgs), args: [], shell: true };
|
|
1131
695
|
}
|
|
1132
696
|
return { command: binary, args: extraArgs, shell: false };
|
|
1133
697
|
}
|
|
1134
698
|
return { command: binary, args: extraArgs, shell: false };
|
|
1135
699
|
}
|
|
1136
|
-
/**
|
|
1137
|
-
* Transparent passthrough exec for generated shims — the node-side delegate that
|
|
1138
|
-
* Windows `.cmd` shims call. Resolves the active version (explicit pin, else
|
|
1139
|
-
* project/default) and execs the real binary with the user's RAW args and the
|
|
1140
|
-
* per-version env isolation, WITHOUT injecting mode/model/reasoning flags. This
|
|
1141
|
-
* mirrors what the POSIX bash shim does inline (`exec $BINARY $launchArgs "$@"`),
|
|
1142
|
-
* keeping version resolution in one place instead of reimplementing it in batch.
|
|
1143
|
-
*/
|
|
1144
700
|
export async function execShimPassthrough(agent, rawArgs, cwd, pinnedVersion) {
|
|
1145
701
|
const version = pinnedVersion ?? resolveVersion(agent, cwd) ?? undefined;
|
|
1146
702
|
if (!version || !isVersionInstalled(agent, version))
|
|
@@ -1155,50 +711,20 @@ async function execShimPassthroughLeased(agent, rawArgs, cwd, pinnedVersion) {
|
|
|
1155
711
|
}
|
|
1156
712
|
let binary = getBinaryPath(agent, version);
|
|
1157
713
|
if (process.platform === 'win32') {
|
|
1158
|
-
// npm ships <cmd>.cmd alongside the bare script on Windows; that's the runnable form.
|
|
1159
714
|
const cmdPath = binary + '.cmd';
|
|
1160
715
|
if (fs.existsSync(cmdPath))
|
|
1161
716
|
binary = cmdPath;
|
|
1162
717
|
}
|
|
1163
|
-
// Match the POSIX shim: direct Codex launches default to the safe writable
|
|
1164
|
-
// profile, while later user arguments can still override native settings.
|
|
1165
718
|
const launchArgs = agent === 'codex'
|
|
1166
719
|
? ['-c', 'check_for_update_on_startup=false', ...codexPolicyArgs('edit', codexEditWritableRoots(cwd))]
|
|
1167
720
|
: [];
|
|
1168
|
-
// Mint a launch id and export it as AGENT_LAUNCH_ID so the agent's SessionStart
|
|
1169
|
-
// hook records the same id — the join key that maps this launch to its exact
|
|
1170
|
-
// session even though the recorded pid here is the cmd.exe wrapper (Windows) or
|
|
1171
|
-
// a shell, while the hook runs under the agent descendant. This is the primary
|
|
1172
|
-
// attribution path on Windows (no lsof), so the launchId join matters most here.
|
|
1173
721
|
const launchId = randomUUID();
|
|
1174
|
-
// mode/effort are required by ExecOptions but do not affect the env buildExecEnv
|
|
1175
|
-
// derives; pass the agent's default to satisfy the type. Passing no prompt makes
|
|
1176
|
-
// this resolve INTERACTIVE, so the launch authenticates from the per-version
|
|
1177
|
-
// login rather than the headless `auth` setup-token (EXEC-2a) — right for the
|
|
1178
|
-
// common case, someone invoking the harness binary directly. Known limit: we do
|
|
1179
|
-
// not parse `rawArgs`, so a `-p "task"` passthrough is headless in fact and
|
|
1180
|
-
// interactive by this classification, and loses the token. Windows-only in
|
|
1181
|
-
// practice (POSIX uses the bash shim, which execs the binary and never reaches
|
|
1182
|
-
// buildExecEnv — `installations/shims.ts` generateShimScript).
|
|
1183
722
|
const env = buildExecEnv({ agent, version, cwd, mode: defaultModeFor(agent), effort: 'auto', env: { AGENT_LAUNCH_ID: launchId } });
|
|
1184
723
|
ensureVendorHomeDir(agent, getVersionHomePath(agent, version));
|
|
1185
724
|
const { command, args, shell } = resolveShimSpawn(process.platform, binary, [...launchArgs, ...rawArgs]);
|
|
1186
|
-
// Pre-launch marker for the SECOND live launch path: the Windows generated
|
|
1187
|
-
// `.cmd` shim delegates here and spawns the harness directly, so without this
|
|
1188
|
-
// a pinned, logged-out version launched via the shim would be invisible —
|
|
1189
|
-
// exactly the blind spot this event closes. Best-effort; re-derives the
|
|
1190
|
-
// signed-in verdict from the pinned version home (no rotated pick here).
|
|
1191
725
|
await emitRunLaunch({ agent, version, resolvedVia: 'shim' });
|
|
1192
726
|
return new Promise((resolve) => {
|
|
1193
|
-
// Register listeners in the same synchronous turn as spawn: awaiting a lock
|
|
1194
|
-
// release after spawn can miss a fast child's exit/error event.
|
|
1195
727
|
const child = spawn(command, args, { cwd, stdio: 'inherit', env, shell });
|
|
1196
|
-
// Record the launch so `ag sessions --active` can attribute the agent
|
|
1197
|
-
// process to its cwd (and exact session when the caller passed
|
|
1198
|
-
// --session-id). Vital on Windows, where there is no lsof to recover a
|
|
1199
|
-
// foreign process's cwd. On the shell path this pid is the cmd.exe
|
|
1200
|
-
// wrapper, not the agent binary — the active scan resolves that by
|
|
1201
|
-
// walking the candidate's ancestors (readAncestorSessionEntry).
|
|
1202
728
|
if (child.pid) {
|
|
1203
729
|
const passthroughSessionId = extractSessionIdArg(rawArgs);
|
|
1204
730
|
writePidSessionEntry({
|
|
@@ -1212,8 +738,6 @@ async function execShimPassthroughLeased(agent, rawArgs, cwd, pinnedVersion) {
|
|
|
1212
738
|
terminalId: launchIdentityEnv().AGENT_TERMINAL_ID,
|
|
1213
739
|
startedAtMs: Date.now(),
|
|
1214
740
|
});
|
|
1215
|
-
// Durable sessionId -> actor record (RUSH-2019) so the scanner can attribute
|
|
1216
|
-
// this session to a person after the pid dies. Best-effort; no-ops without id.
|
|
1217
741
|
if (passthroughSessionId) {
|
|
1218
742
|
writeSessionActorRecord({
|
|
1219
743
|
sessionId: passthroughSessionId,
|
|
@@ -1231,37 +755,9 @@ async function execShimPassthroughLeased(agent, rawArgs, cwd, pinnedVersion) {
|
|
|
1231
755
|
});
|
|
1232
756
|
});
|
|
1233
757
|
}
|
|
1234
|
-
/**
|
|
1235
|
-
* Whether a dead pane's failure should be recapped to stderr (RUSH-2185 / EXEC-23a).
|
|
1236
|
-
*
|
|
1237
|
-
* For headless runs only a nonzero exit is a failure worth surfacing — a
|
|
1238
|
-
* clean 0 means the agent finished the task before we could attach.
|
|
1239
|
-
* For interactive runs ANY exit (including 0) is a failure: an instant clean
|
|
1240
|
-
* exit means the harness has no bare REPL and the user would see only a mute
|
|
1241
|
-
* `[detached]` with no explanation.
|
|
1242
|
-
*/
|
|
1243
758
|
export function shouldRecapDeadPane(status, interactive) {
|
|
1244
759
|
return (status ?? 0) !== 0 || interactive;
|
|
1245
760
|
}
|
|
1246
|
-
/**
|
|
1247
|
-
* The exit code a tmux-wrapped run resolves with (RUSH-2185 / EXEC-23b).
|
|
1248
|
-
*
|
|
1249
|
-
* Three inputs, one rule: report success ONLY for an outcome tmux actually told
|
|
1250
|
-
* us about. A clean user detach (`knownAlive`) is 0; a dead pane reports the
|
|
1251
|
-
* status tmux read off it; everything else — pane unreadable because the server
|
|
1252
|
-
* or session went away, or dead with no status — is UNKNOWN and resolves to
|
|
1253
|
-
* {@link UNKNOWN_OUTCOME_EXIT_CODE}, never 0.
|
|
1254
|
-
*
|
|
1255
|
-
* Why this is not `status ?? 0`: an interactive run whose tmux server died mid-
|
|
1256
|
-
* work landed on exactly those unknown branches and returned 0, so `agents run`
|
|
1257
|
-
* printed a failure banner while handing its caller a success code. The same
|
|
1258
|
-
* "1 if unknown" rule already governs the `--device` follow path
|
|
1259
|
-
* (`docs/specifications.md` §Agent execution, exit-code table).
|
|
1260
|
-
*
|
|
1261
|
-
* @param pane What `paneExitStatus` read back for the agent pane.
|
|
1262
|
-
* @param knownAlive Positive proof the pane is still alive (see
|
|
1263
|
-
* {@link isPaneKnownAliveFromQueryResult}) — a clean detach.
|
|
1264
|
-
*/
|
|
1265
761
|
export function tmuxRunExitCode(pane, knownAlive) {
|
|
1266
762
|
if (knownAlive)
|
|
1267
763
|
return 0;
|
|
@@ -1269,70 +765,28 @@ export function tmuxRunExitCode(pane, knownAlive) {
|
|
|
1269
765
|
return pane.status;
|
|
1270
766
|
return UNKNOWN_OUTCOME_EXIT_CODE;
|
|
1271
767
|
}
|
|
1272
|
-
/**
|
|
1273
|
-
* True only when a `display-message #{pane_dead}` tmux query explicitly returned
|
|
1274
|
-
* "0" (pane alive). Used to distinguish "pane alive" from "query failed" in
|
|
1275
|
-
* situations where `paneExitStatus` conservatively returns `{dead: false}` for
|
|
1276
|
-
* both (RUSH-2185 / EXEC-23a / F3).
|
|
1277
|
-
*
|
|
1278
|
-
* @param code The exit code of the `tmux display-message` command.
|
|
1279
|
-
* @param stdout Its stdout (expected to be "0" when the pane is alive).
|
|
1280
|
-
*/
|
|
1281
768
|
export function isPaneKnownAliveFromQueryResult(code, stdout) {
|
|
1282
769
|
return code === 0 && stdout.trim() === '0';
|
|
1283
770
|
}
|
|
1284
|
-
/**
|
|
1285
|
-
* Tmux is opt-in except when a TTY-less remote launch would otherwise have no
|
|
1286
|
-
* interface. Explicit per-run opt-outs always win.
|
|
1287
|
-
*/
|
|
1288
771
|
export function resolveTmuxWrap(ctx) {
|
|
1289
|
-
// A headless `-p` run has no TTY to attach, Windows has no tmux path, and
|
|
1290
|
-
// nesting tmux-in-tmux is pointless.
|
|
1291
772
|
if (!ctx.interactive)
|
|
1292
773
|
return { kind: 'bare' };
|
|
1293
774
|
if (ctx.platform === 'win32')
|
|
1294
775
|
return { kind: 'bare' };
|
|
1295
776
|
if (ctx.inTmux)
|
|
1296
777
|
return { kind: 'bare' };
|
|
1297
|
-
// Explicit opt-outs win over every other rule: `--raw` exists precisely to
|
|
1298
|
-
// get the unwrapped process.
|
|
1299
778
|
if (ctx.raw)
|
|
1300
779
|
return { kind: 'bare' };
|
|
1301
780
|
if (ctx.noTmuxEnv)
|
|
1302
781
|
return { kind: 'bare' };
|
|
1303
|
-
// Local interactive with no TTY cannot attach. Wrapping anyway creates a
|
|
1304
|
-
// detached pane, attach returns immediately, and resolveAfterAttach treats
|
|
1305
|
-
// the still-alive pane as Ctrl-b d — the session-tracker test leak.
|
|
1306
782
|
if (!ctx.hasTty && !ctx.remoteDispatch)
|
|
1307
783
|
return { kind: 'bare' };
|
|
1308
|
-
// tmux.enabled gates the wrap for local AND followed remote runs. The one
|
|
1309
|
-
// exception: a followed remote run whose launcher has no TTY (CI, scripts)
|
|
1310
|
-
// gives the peer nothing to attach to — the detached pane is its only
|
|
1311
|
-
// interface, infrastructure rather than ergonomics.
|
|
1312
784
|
if (!ctx.configEnabled && !(ctx.remoteDispatch && !ctx.hasTty))
|
|
1313
785
|
return { kind: 'bare' };
|
|
1314
|
-
// Fail loud rather than launch a remote agent that a blink would kill: the
|
|
1315
|
-
// caller refuses the run instead of starting work that cannot be recovered.
|
|
1316
786
|
if (!ctx.tmuxAvailable)
|
|
1317
787
|
return ctx.remoteDispatch ? { kind: 'undurable' } : { kind: 'bare' };
|
|
1318
788
|
return { kind: 'wrap' };
|
|
1319
789
|
}
|
|
1320
|
-
/**
|
|
1321
|
-
* True when `options.sessionId` is an id the HARNESS actually received, and so a
|
|
1322
|
-
* real, resumable handle — rather than one the launcher generated for its own
|
|
1323
|
-
* bookkeeping and the agent never saw.
|
|
1324
|
-
*
|
|
1325
|
-
* Mirrors exactly the two branches in buildExecCommand that put the id on the
|
|
1326
|
-
* command line: a native resume (any harness with a `resume` spec) and claude's
|
|
1327
|
-
* create-with-`--session-id`. Everything else — `agents run codex --session-id X`
|
|
1328
|
-
* without `--resume`, or a fresh non-claude launch whose real id only shows up
|
|
1329
|
-
* later via the SessionStart hook — leaves the agent with an id of its own
|
|
1330
|
-
* choosing, so `options.sessionId` must not be published as if it were that id.
|
|
1331
|
-
*
|
|
1332
|
-
* Keep in lockstep with buildExecCommand's resume/create branches: a harness
|
|
1333
|
-
* that gains a forced-session-id flag must be reflected here in the SAME change,
|
|
1334
|
-
* or this reports a genuine id as fabricated.
|
|
1335
|
-
*/
|
|
1336
790
|
export function isHarnessKnownSessionId(agent, sessionId, resume) {
|
|
1337
791
|
if (!sessionId)
|
|
1338
792
|
return false;
|
|
@@ -1340,27 +794,12 @@ export function isHarnessKnownSessionId(agent, sessionId, resume) {
|
|
|
1340
794
|
return true;
|
|
1341
795
|
return agent === 'claude';
|
|
1342
796
|
}
|
|
1343
|
-
|
|
1344
|
-
* Build the pane command without inheriting stale tmux-server env. Redacted
|
|
1345
|
-
* copies keep secret values out of persisted SessionMeta commands.
|
|
1346
|
-
*/
|
|
797
|
+
// Resolved env values never enter tmux argv/metadata; source an exclusive 0600 file, unlink it, and abort if sourcing fails.
|
|
1347
798
|
export function buildTmuxAgentCommand(executable, args, env, opts = {}) {
|
|
1348
799
|
const agentCmd = [executable, ...args].map(shellQuote).join(' ');
|
|
1349
800
|
const absentIdentity = LAUNCH_IDENTITY_KEYS.filter(key => env[key] === undefined);
|
|
1350
|
-
// envFile: source the values instead of inlining them, so no VALUE ever lands
|
|
1351
|
-
// in the pane's argv. `exec env K=V …` put every resolved secret into the
|
|
1352
|
-
// process table, readable by any process of this user — on one fleet box six
|
|
1353
|
-
// live processes carried the secrets-store master passphrase, which decrypts
|
|
1354
|
-
// every file-backed bundle including the Claude OAuth tokens (RUSH-2100).
|
|
1355
|
-
// `set -a` exports what the file assigns; the file is unlinked before `exec`,
|
|
1356
|
-
// so it exists only for the sourcing itself. A missing file aborts the pane
|
|
1357
|
-
// rather than silently launching with a half-built env.
|
|
1358
801
|
if (opts.envFile) {
|
|
1359
802
|
const f = shellQuote(opts.envFile);
|
|
1360
|
-
// Remove the file whether or not sourcing succeeds — a bare `. f || exit 1`
|
|
1361
|
-
// strands the plaintext env (incl. the secrets-store master passphrase) on
|
|
1362
|
-
// disk on any source failure, worse than the argv leak this replaces
|
|
1363
|
-
// (RUSH-2100). Capture the source rc, unlink, then honor it.
|
|
1364
803
|
return `${absentIdentity.length ? `unset ${absentIdentity.join(' ')}; ` : ''}set -a; . ${f}; __agents_rc=$?; set +a; rm -f ${f}; [ "$__agents_rc" -eq 0 ] || exit 1; exec ${agentCmd}`;
|
|
1365
804
|
}
|
|
1366
805
|
const envPrefix = Object.entries(env)
|
|
@@ -1369,16 +808,6 @@ export function buildTmuxAgentCommand(executable, args, env, opts = {}) {
|
|
|
1369
808
|
.join(' ');
|
|
1370
809
|
return `exec env ${absentIdentity.map(key => `-u ${key}`).join(' ')} ${envPrefix} ${agentCmd}`;
|
|
1371
810
|
}
|
|
1372
|
-
/**
|
|
1373
|
-
* Serialize the pane env to a shell-sourceable file, created 0600 and exclusively
|
|
1374
|
-
* (`wx`) so it can never adopt a pre-existing file's mode or content.
|
|
1375
|
-
*
|
|
1376
|
-
* EVERY key goes in the file, not a curated "secret-bearing" subset: a denylist
|
|
1377
|
-
* has to be updated for each new credential and is wrong the moment someone
|
|
1378
|
-
* forgets, whereas routing all of it through the file makes the guarantee hold by
|
|
1379
|
-
* construction. Keys are filtered to valid shell identifiers for the same reason
|
|
1380
|
-
* `env` needed it — an exported function (`BASH_FUNC_x%%`) is not assignable.
|
|
1381
|
-
*/
|
|
1382
811
|
export function writeTmuxEnvFile(env, filePath) {
|
|
1383
812
|
const body = Object.entries(env)
|
|
1384
813
|
.filter(([k, v]) => v !== undefined && EXEC_ENV_KEY_PATTERN.test(k))
|
|
@@ -1393,13 +822,6 @@ export function writeTmuxEnvFile(env, filePath) {
|
|
|
1393
822
|
fs.closeSync(fd);
|
|
1394
823
|
}
|
|
1395
824
|
}
|
|
1396
|
-
/**
|
|
1397
|
-
* Trim a raw `tmux capture-pane` dump to its last `maxLines` non-empty lines
|
|
1398
|
-
* (right-stripping each). Used by runInTmux to recap a fast-failed agent's
|
|
1399
|
-
* output into the caller's shell so a launch crash (e.g. a gutted install that
|
|
1400
|
-
* dies with ENOENT the instant it spawns) isn't swallowed by the bare
|
|
1401
|
-
* `[detached]` the pane-died hook otherwise leaves behind.
|
|
1402
|
-
*/
|
|
1403
825
|
export function formatPaneTail(raw, maxLines = 30) {
|
|
1404
826
|
return raw
|
|
1405
827
|
.split('\n')
|
|
@@ -1408,28 +830,6 @@ export function formatPaneTail(raw, maxLines = 30) {
|
|
|
1408
830
|
.slice(-maxLines)
|
|
1409
831
|
.join('\n');
|
|
1410
832
|
}
|
|
1411
|
-
/**
|
|
1412
|
-
* Run an interactive agent inside a detached tmux session on the shared socket,
|
|
1413
|
-
* attach the current TTY, and propagate the wrapped agent's exit code.
|
|
1414
|
-
*
|
|
1415
|
-
* Lifecycle:
|
|
1416
|
-
* 1. createSession() launches `sh -c 'exec env … agent'` detached, remain-on-exit
|
|
1417
|
-
* on (global), and returns the pane id.
|
|
1418
|
-
* 2. A per-session `pane-died` hook tears the session down the instant the AGENT
|
|
1419
|
-
* pane exits: with a client attached it `detach-client`s so attach returns
|
|
1420
|
-
* instead of parking on a dead pane (then resolveAfterAttach reads the status
|
|
1421
|
-
* and kills); with no client attached it `kill-session`s outright, so a
|
|
1422
|
-
* wrapped agent that exits unattended can't leave a dead husk lingering on the
|
|
1423
|
-
* socket. The hook is guarded on `#{hook_pane}` so it fires ONLY for the agent
|
|
1424
|
-
* pane — user-created splits (Ctrl-b " / %) that the user exits are closed in
|
|
1425
|
-
* place (`kill-pane`) instead of tearing down the whole client, so exiting one
|
|
1426
|
-
* split leaves the agent running full-window rather than kicking you out.
|
|
1427
|
-
* 3. We record the agent pane's pid → session mapping (WITH the tmux pane) so the
|
|
1428
|
-
* headless active-scan attributes it, then attach the TTY (blocking).
|
|
1429
|
-
* 4. On return: if the pane is dead the agent exited — read its status, tear the
|
|
1430
|
-
* session down, return that code. If the pane is still alive the user detached
|
|
1431
|
-
* (Ctrl-b d) — return 0 and LEAVE the session for `agents focus` to re-attach.
|
|
1432
|
-
*/
|
|
1433
833
|
async function runInTmux(options, executable, args) {
|
|
1434
834
|
const { createSession, killSession, paneExitStatus, prepareSessionForResume, setSessionHook, slugifyName, agentPaneDiedHook, markSessionHookSchema } = await import('./tmux/session.js');
|
|
1435
835
|
const { getDefaultSocketPath } = await import('./tmux/paths.js');
|
|
@@ -1440,13 +840,6 @@ async function runInTmux(options, executable, args) {
|
|
|
1440
840
|
const name = slugifyName(`ag-${options.agent}-${idSeed}`);
|
|
1441
841
|
const RED = '\x1b[31m', GRAY = '\x1b[90m', OFF = '\x1b[0m';
|
|
1442
842
|
const NO_TMUX_TIP = `${GRAY} This run used the opt-in tmux wrap. Re-run with --no-tmux for a direct launch, or turn the wrap off: agents config set devices.${machineId()}.tmux off${OFF}\n\n`;
|
|
1443
|
-
// Read a dead pane's scrollback. Must run BEFORE killSession — capture-pane
|
|
1444
|
-
// needs the session still alive (remain-on-exit keeps the dead pane readable
|
|
1445
|
-
// until we tear it down). Best-effort: a missing/gone pane just yields ''.
|
|
1446
|
-
// Callers thread this into SpawnResult.stdout for a GENUINELY dead pane only
|
|
1447
|
-
// (positive proof from paneExitStatus) — never for the "still alive, user
|
|
1448
|
-
// detached" or "outcome unknown" paths below, so an interactive detach or an
|
|
1449
|
-
// unresolved tmux race can never masquerade as refusal evidence.
|
|
1450
843
|
const capturePaneTail = async (pane) => {
|
|
1451
844
|
if (!pane)
|
|
1452
845
|
return '';
|
|
@@ -1458,10 +851,6 @@ async function runInTmux(options, executable, args) {
|
|
|
1458
851
|
return '';
|
|
1459
852
|
}
|
|
1460
853
|
};
|
|
1461
|
-
// Recap a dead pane's tail into THIS shell's stderr. The pane-died hook
|
|
1462
|
-
// detaches the client the instant the agent exits, so a fast failure (a
|
|
1463
|
-
// gutted install that dies with ENOENT, a bad flag, a crash on startup) would
|
|
1464
|
-
// otherwise leave only a bare `[detached]` with no clue why.
|
|
1465
854
|
const surfacePaneFailure = async (pane, status, headline, tail) => {
|
|
1466
855
|
if (!pane)
|
|
1467
856
|
return;
|
|
@@ -1473,10 +862,6 @@ async function runInTmux(options, executable, args) {
|
|
|
1473
862
|
}
|
|
1474
863
|
process.stderr.write(NO_TMUX_TIP);
|
|
1475
864
|
};
|
|
1476
|
-
// F3 (RUSH-2185 / EXEC-23a): paneExitStatus returns {dead:false} for BOTH
|
|
1477
|
-
// "pane is alive" and "tmux query failed (race / pane already gone)". Require
|
|
1478
|
-
// POSITIVE proof before taking the keep-session path — a separate direct query
|
|
1479
|
-
// that only returns true when tmux explicitly confirms pane_dead=0.
|
|
1480
865
|
const checkPaneKnownAlive = async (p) => {
|
|
1481
866
|
try {
|
|
1482
867
|
const r = await runTmux({ socket, args: ['display-message', '-pt', p, '-p', '#{pane_dead}'], throwOnError: false });
|
|
@@ -1486,13 +871,6 @@ async function runInTmux(options, executable, args) {
|
|
|
1486
871
|
return false;
|
|
1487
872
|
}
|
|
1488
873
|
};
|
|
1489
|
-
/**
|
|
1490
|
-
* Resolve what an attach client's return actually means, for EVERY path that
|
|
1491
|
-
* attaches (the fresh wrapper below AND the resume-attach above). Asking tmux
|
|
1492
|
-
* is the only way to tell "the user detached" from "the agent exited" from
|
|
1493
|
-
* "the session went away underneath us", so an attach that skips this cannot
|
|
1494
|
-
* do better than assume success — which is exactly the defect EXEC-23b fixes.
|
|
1495
|
-
*/
|
|
1496
874
|
let paneLaunchBinding;
|
|
1497
875
|
const bindCompletedPane = () => {
|
|
1498
876
|
recordCompletedLaunch(paneLaunchBinding);
|
|
@@ -1501,44 +879,18 @@ async function runInTmux(options, executable, args) {
|
|
|
1501
879
|
const after = pane ? await paneExitStatus(pane, socket) : { found: false, dead: false, status: undefined };
|
|
1502
880
|
if (after.dead) {
|
|
1503
881
|
bindCompletedPane();
|
|
1504
|
-
// Positive proof of a genuinely completed pane (paneExitStatus confirmed
|
|
1505
|
-
// dead) — capture its scrollback as refusal evidence for the caller
|
|
1506
|
-
// (classifyClaudeRunRefusal etc.) BEFORE tearing the session down.
|
|
1507
|
-
// Deliberately not done for the "alive" (detach) or "unknown" branches
|
|
1508
|
-
// below: neither is a demonstrated completion, so neither may carry
|
|
1509
|
-
// evidence a caller could mistake for a real refusal or success.
|
|
1510
882
|
const tail = await capturePaneTail(pane);
|
|
1511
|
-
// Nonzero exit after attach → the agent crashed rather than the user
|
|
1512
|
-
// detaching cleanly (a clean detach leaves the pane ALIVE, handled below).
|
|
1513
|
-
// F2: for interactive runs, also recap a clean exit-0 — the harness exited
|
|
1514
|
-
// without error but without starting a REPL, which is still a failure.
|
|
1515
883
|
if (shouldRecapDeadPane(after.status, resolveInteractive(options))) {
|
|
1516
884
|
await surfacePaneFailure(pane, after.status, `${options.agent} exited`, tail);
|
|
1517
885
|
}
|
|
1518
886
|
await killSession(name, socket).catch(() => { });
|
|
1519
|
-
// A dead pane whose status tmux never reported is UNKNOWN, not success —
|
|
1520
|
-
// and surfacePaneFailure already printed `exit 1` for it, so the old
|
|
1521
|
-
// `?? 0` made the message and the returned code disagree (EXEC-23b).
|
|
1522
887
|
return { exitCode: tmuxRunExitCode(after, false), stderr: '', stdout: tail };
|
|
1523
888
|
}
|
|
1524
|
-
// after.dead===false, but that could be a stale/unreadable-pane result.
|
|
1525
|
-
// Require positive proof before keeping the session as "user detached".
|
|
1526
889
|
if (pane && await checkPaneKnownAlive(pane)) {
|
|
1527
|
-
// Confirmed alive: the user pressed Ctrl-b d; keep the session for `agents focus`.
|
|
1528
890
|
return { exitCode: tmuxRunExitCode(after, true), stderr: '', stdout: '' };
|
|
1529
891
|
}
|
|
1530
|
-
// F4 (EXEC-23b): the outcome is UNKNOWN — tmux could not tell us whether the
|
|
1531
|
-
// agent finished or was killed. MUST NOT be reported as success: a caller
|
|
1532
|
-
// scripting `agents run` would count a run killed mid-work as a clean
|
|
1533
|
-
// finish. Tear down so no orphan session is left, say so, and exit non-zero
|
|
1534
|
-
// — the same "1 if unknown" rule the `--device` follow path already uses.
|
|
1535
892
|
await killSession(name, socket).catch(() => { });
|
|
1536
|
-
// One computation feeds both the banner and the return value — printing a
|
|
1537
|
-
// code the caller does not receive is the same defect in miniature.
|
|
1538
893
|
const exitCode = tmuxRunExitCode(after, false);
|
|
1539
|
-
// Two distinct causes reach here, and the banner must not assert the wrong
|
|
1540
|
-
// one: a pane we HAD (the session went away under it) versus a run whose
|
|
1541
|
-
// pane id tmux never reported at creation, which had nothing to read from.
|
|
1542
894
|
const cause = pane
|
|
1543
895
|
? 'The tmux session went away before its exit status could be read, so this run may have been killed mid-work.'
|
|
1544
896
|
: 'This run had no readable tmux pane, so its exit status could never be read.';
|
|
@@ -1546,49 +898,27 @@ async function runInTmux(options, executable, args) {
|
|
|
1546
898
|
`${GRAY} ${cause}${OFF}\n` + NO_TMUX_TIP);
|
|
1547
899
|
return { exitCode, stderr: '', stdout: '' };
|
|
1548
900
|
};
|
|
1549
|
-
// A native resume must not create a competing wrapper for a live session.
|
|
1550
|
-
// A retained dead pane is reaped before the harness resumes normally.
|
|
1551
901
|
const resumePrep = options.resume ? await prepareSessionForResume(name, socket) : { decision: 'create' };
|
|
1552
902
|
if (resumePrep.decision === 'attach') {
|
|
1553
903
|
if (options.sessionId)
|
|
1554
904
|
writeSessionAliasRecord(options.sessionId, name);
|
|
1555
905
|
await attachTmux({ socket, args: ['attach-session', '-t', name] });
|
|
1556
|
-
// EXEC-23b: a resume-attach is an attach like any other — it must ask tmux
|
|
1557
|
-
// what happened rather than assume 0. Before this it returned a hardcoded
|
|
1558
|
-
// success, so a resumed run whose server died under it reported a clean
|
|
1559
|
-
// finish, the identical defect on the identical shape.
|
|
1560
906
|
return resolveAfterAttach(resumePrep.pane);
|
|
1561
907
|
}
|
|
1562
|
-
// SessionStart learns some harness IDs only after launch. Carry the wrapper
|
|
1563
|
-
// name into that hook so it can bind both identities durably.
|
|
1564
908
|
const execEnv = { ...buildExecEnv(options), AGENT_TMUX_SESSION_NAME: name };
|
|
1565
|
-
// The pane sources its env from a 0600 file it unlinks before exec, so no
|
|
1566
|
-
// resolved secret VALUE reaches the process table (RUSH-2100). SessionMeta.cmd
|
|
1567
|
-
// keeps the value-redacted inline form — the human-readable record of what ran,
|
|
1568
|
-
// which never carried real values anyway (RUSH-1758).
|
|
1569
909
|
const envFile = path.join(getRuntimeStateDir(), 'tmux-env', `${name}-${randomUUID().slice(0, 8)}.env`);
|
|
1570
910
|
writeTmuxEnvFile(execEnv, envFile);
|
|
1571
911
|
let cmd = buildTmuxAgentCommand(executable, args, execEnv, { envFile });
|
|
1572
912
|
const leaseVersion = options.version ?? resolveVersion(options.agent, cwd);
|
|
1573
913
|
if (leaseVersion && isVersionInstalled(options.agent, leaseVersion)) {
|
|
1574
914
|
const leaseCli = getCliLaunch(['__launch-lease', options.agent, leaseVersion], getAgentsBinPath());
|
|
1575
|
-
// The pane outlives a detached launcher. Lease its own exec-replaced shell
|
|
1576
|
-
// before launching, so detaching cannot open an unprotected launch gap.
|
|
1577
915
|
cmd = `${[leaseCli.command, ...leaseCli.args].map(shellQuote).join(' ')} "$$" || exit 1; ${cmd}`;
|
|
1578
916
|
}
|
|
1579
917
|
const metaCmd = buildTmuxAgentCommand(executable, args, execEnv, { redactEnvValues: true });
|
|
1580
918
|
const labels = { agent: options.agent };
|
|
1581
|
-
// Only publish an id the harness actually received. createSession turns this
|
|
1582
|
-
// label into the `@ag_session_id` tmux option that status bars read, and a
|
|
1583
|
-
// launcher-internal id displayed there looks exactly like a resumable one
|
|
1584
|
-
// while `ag focus <id>` rejects it.
|
|
1585
919
|
if (isHarnessKnownSessionId(options.agent, options.sessionId, options.resume)) {
|
|
1586
920
|
labels.sessionId = options.sessionId;
|
|
1587
921
|
}
|
|
1588
|
-
// Only a launched pane sources-and-unlinks the env file. If createSession
|
|
1589
|
-
// throws, the pane never runs, so the resolved secrets (incl. the master
|
|
1590
|
-
// passphrase) would linger on disk — remove it on that failure path
|
|
1591
|
-
// (RUSH-2100). On success the detached pane owns the unlink.
|
|
1592
922
|
let meta;
|
|
1593
923
|
try {
|
|
1594
924
|
meta = await createSession({ name, cmd, metaCmd, cwd, socket, source: 'cli', labels });
|
|
@@ -1597,34 +927,22 @@ async function runInTmux(options, executable, args) {
|
|
|
1597
927
|
try {
|
|
1598
928
|
fs.rmSync(envFile, { force: true });
|
|
1599
929
|
}
|
|
1600
|
-
catch {
|
|
930
|
+
catch { }
|
|
1601
931
|
throw err;
|
|
1602
932
|
}
|
|
1603
933
|
const pane = meta.pane;
|
|
1604
934
|
if (options.sessionId)
|
|
1605
935
|
writeSessionAliasRecord(options.sessionId, name);
|
|
1606
936
|
if (pane) {
|
|
1607
|
-
// When the AGENT pane dies, detach the client (don't kill) so the session
|
|
1608
|
-
// survives just long enough to read the dead pane's exit status below. The
|
|
1609
|
-
// `#{hook_pane}` guard scopes this to the agent pane only: if the user splits
|
|
1610
|
-
// the window and exits one of THEIR panes, the else-branch closes that split
|
|
1611
|
-
// in place instead of detaching everyone (`run-shell -C` executes the
|
|
1612
|
-
// targeted kill inside tmux's server command queue, avoiding a second
|
|
1613
|
-
// client racing the same socket under load, #965). Without the guard,
|
|
1614
|
-
// exiting any split kicked the user clean out of tmux.
|
|
1615
937
|
const hookInstalled = await setSessionHook(name, 'pane-died', agentPaneDiedHook(name, pane), socket);
|
|
1616
|
-
// Stamp the schema marker only after tmux accepted the hook. A failed
|
|
1617
|
-
// install stays unmarked so daemon reconciliation retries it later.
|
|
1618
938
|
if (hookInstalled)
|
|
1619
939
|
await markSessionHookSchema(name, socket);
|
|
1620
|
-
// Record the agent's OS pid (the pane leaf, thanks to `exec`) WITH its tmux
|
|
1621
|
-
// pane so the active-scan attributes it exactly and shows the %pane.
|
|
1622
940
|
let panePid = 0;
|
|
1623
941
|
try {
|
|
1624
942
|
const r = await runTmux({ socket, args: ['display-message', '-pt', pane, '-p', '#{pane_pid}'], throwOnError: false });
|
|
1625
943
|
panePid = parseInt(r.stdout.trim(), 10) || 0;
|
|
1626
944
|
}
|
|
1627
|
-
catch {
|
|
945
|
+
catch { }
|
|
1628
946
|
writePidSessionEntry({
|
|
1629
947
|
pid: panePid,
|
|
1630
948
|
agent: options.agent,
|
|
@@ -1633,10 +951,6 @@ async function runInTmux(options, executable, args) {
|
|
|
1633
951
|
cwd,
|
|
1634
952
|
actor: resolveActor().id,
|
|
1635
953
|
initiatedBy: resolveActor().kind,
|
|
1636
|
-
// spawnAgent injected AGENT_LAUNCH_ID into options.env before delegating
|
|
1637
|
-
// here; record the same id so the hook (running under the pane-leaf agent
|
|
1638
|
-
// pid) reconciles by launchId. This pane's pid usually IS the agent pid,
|
|
1639
|
-
// but the launchId join is robust even when it isn't.
|
|
1640
954
|
launchId: options.env?.AGENT_LAUNCH_ID,
|
|
1641
955
|
terminalId: launchIdentityEnv().AGENT_TERMINAL_ID,
|
|
1642
956
|
tmuxPane: pane,
|
|
@@ -1655,44 +969,20 @@ async function runInTmux(options, executable, args) {
|
|
|
1655
969
|
});
|
|
1656
970
|
}
|
|
1657
971
|
}
|
|
1658
|
-
// The agent could exit before we attach (fast failure). Don't attach to an
|
|
1659
|
-
// already-dead pane — surface its output + status directly and tear down.
|
|
1660
972
|
const before = pane ? await paneExitStatus(pane, socket) : { found: false, dead: false, status: undefined };
|
|
1661
973
|
if (before.dead) {
|
|
1662
974
|
bindCompletedPane();
|
|
1663
|
-
// Positive proof of a genuinely completed pane — capture scrollback as
|
|
1664
|
-
// refusal evidence before tearing the session down (see the matching
|
|
1665
|
-
// comment in resolveAfterAttach).
|
|
1666
975
|
const tail = await capturePaneTail(pane);
|
|
1667
|
-
// F2 (RUSH-2185 / EXEC-23a): for interactive runs, ALWAYS recap — a clean
|
|
1668
|
-
// exit-0 before attach means the harness has no interactive REPL and the
|
|
1669
|
-
// user would see only a bare `[detached]` with no clue why. For headless
|
|
1670
|
-
// runs the old quiet behaviour stands: exit-0 is a successful quick run.
|
|
1671
976
|
if (shouldRecapDeadPane(before.status, resolveInteractive(options))) {
|
|
1672
977
|
await surfacePaneFailure(pane, before.status, `${options.agent} exited before it could start`, tail);
|
|
1673
978
|
}
|
|
1674
979
|
await killSession(name, socket).catch(() => { });
|
|
1675
|
-
// A dead pane whose status tmux never reported is an UNKNOWN outcome, not a
|
|
1676
|
-
// success — and the banner one line up already printed `exit 1` for it, so
|
|
1677
|
-
// the old `?? 0` also made the message and the returned code disagree.
|
|
1678
980
|
return { exitCode: tmuxRunExitCode(before, false), stderr: '', stdout: tail };
|
|
1679
981
|
}
|
|
1680
982
|
await attachTmux({ socket, args: ['attach-session', '-t', name] });
|
|
1681
983
|
return resolveAfterAttach(pane);
|
|
1682
984
|
}
|
|
1683
|
-
|
|
1684
|
-
* Print the run's resolved session id as a one-line stdout sentinel so a `--device`
|
|
1685
|
-
* launcher can relate the remote-created session back to itself (see the
|
|
1686
|
-
* `emitSessionId` option and hosts/session-marker.ts).
|
|
1687
|
-
*
|
|
1688
|
-
* For Claude the id was forced up front (`options.sessionId`, wired as
|
|
1689
|
-
* `--session-id`), so it's authoritative with no lookup. Every other agent coined
|
|
1690
|
-
* its OWN id, which its SessionStart hook recorded under this run's launchId — the
|
|
1691
|
-
* exact join key `agents sessions --active` uses — so we read it back from the hook
|
|
1692
|
-
* index by launchId (falling back to the child pid the hook may have recorded
|
|
1693
|
-
* under). Nothing to emit when the hook hasn't landed an id (hookless harness):
|
|
1694
|
-
* the launcher simply keeps the un-mapped task, never a fabricated id.
|
|
1695
|
-
*/
|
|
985
|
+
// Publish only a session id supplied by the harness or joined through the shared launch id.
|
|
1696
986
|
function emitResolvedSessionId(options, launchId, childPid) {
|
|
1697
987
|
let sessionId = options.sessionId;
|
|
1698
988
|
if (!sessionId) {
|
|
@@ -1704,29 +994,16 @@ function emitResolvedSessionId(options, launchId, childPid) {
|
|
|
1704
994
|
});
|
|
1705
995
|
}
|
|
1706
996
|
catch {
|
|
1707
|
-
/* hook index unreadable — emit nothing rather than a guess */
|
|
1708
997
|
}
|
|
1709
998
|
}
|
|
1710
999
|
if (sessionId)
|
|
1711
1000
|
process.stdout.write(sessionIdMarkerLine(sessionId));
|
|
1712
1001
|
}
|
|
1713
|
-
/**
|
|
1714
|
-
* Build the `run.launch` event payload. Pure and exported so the signedIn ->
|
|
1715
|
-
* launchedLoggedOut mapping is unit-testable without spawning. Mirrors the
|
|
1716
|
-
* buildRotationDecisionEvent / emitRotationDecision split in rotate.ts.
|
|
1717
|
-
*
|
|
1718
|
-
* `launchedLoggedOut` is the headline flag — true ONLY when `signedIn` was
|
|
1719
|
-
* resolved to false (a launch into a logged-out version, the yosemite-m3 2.1.219
|
|
1720
|
-
* incident). An UNKNOWN verdict (`signedIn === null`) is never treated as
|
|
1721
|
-
* logged out.
|
|
1722
|
-
*/
|
|
1723
1002
|
export function buildRunLaunchPayload(input) {
|
|
1724
1003
|
return {
|
|
1725
1004
|
module: 'run',
|
|
1726
1005
|
agent: input.agent,
|
|
1727
1006
|
...(input.harnessName ? { harnessName: input.harnessName } : {}),
|
|
1728
|
-
// Omitted only when no version could be resolved at all — the typed `version`
|
|
1729
|
-
// field can't carry null, and an absent version is honest.
|
|
1730
1007
|
version: input.version,
|
|
1731
1008
|
strategy: input.strategy ?? null,
|
|
1732
1009
|
signedIn: input.signedIn,
|
|
@@ -1735,36 +1012,15 @@ export function buildRunLaunchPayload(input) {
|
|
|
1735
1012
|
...(input.resolvedVia ? { resolvedVia: input.resolvedVia } : {}),
|
|
1736
1013
|
};
|
|
1737
1014
|
}
|
|
1738
|
-
/**
|
|
1739
|
-
* Emit the pre-launch `run.launch` observability event just before the harness
|
|
1740
|
-
* child is spawned. Best-effort by construction — the whole point is that it can
|
|
1741
|
-
* NEVER break a launch, so every step (the signed-in probe, the emit itself) is
|
|
1742
|
-
* wrapped and a failure is swallowed. Mirrors the non-fatal pattern of
|
|
1743
|
-
* recordDispatchedRun and emitRotationDecision.
|
|
1744
|
-
*
|
|
1745
|
-
* The `signedIn` verdict is for the SPECIFIC launched version on THIS device, so
|
|
1746
|
-
* `launchedLoggedOut` catches a launch into a logged-out version that
|
|
1747
|
-
* `--device auto` readiness let through (the yosemite-m3 2.1.219 incident). It is
|
|
1748
|
-
* REUSED from `ctx.launchSignedIn` when the caller already computed it via the
|
|
1749
|
-
* identical gate (the rotated pick — no double fs read, no disagreement window),
|
|
1750
|
-
* and only otherwise re-derived via {@link isVersionLaunchableHere} (dynamically
|
|
1751
|
-
* imported so the spawn path takes on no static dependency on the accounting
|
|
1752
|
-
* layer).
|
|
1753
|
-
*/
|
|
1754
1015
|
async function emitRunLaunch(ctx) {
|
|
1755
1016
|
try {
|
|
1756
1017
|
let signedIn;
|
|
1757
1018
|
let email;
|
|
1758
1019
|
if (ctx.launchSignedIn !== undefined) {
|
|
1759
|
-
// Caller already computed the verdict for this exact version via the same
|
|
1760
|
-
// gate — reuse it verbatim.
|
|
1761
1020
|
signedIn = ctx.launchSignedIn;
|
|
1762
1021
|
email = ctx.launchEmail ?? null;
|
|
1763
1022
|
}
|
|
1764
1023
|
else {
|
|
1765
|
-
// Pinned-default / shim paths: probe the version home now. Without a
|
|
1766
|
-
// concrete version we cannot probe, so leave the verdict unknown (null)
|
|
1767
|
-
// rather than guess.
|
|
1768
1024
|
signedIn = null;
|
|
1769
1025
|
email = null;
|
|
1770
1026
|
if (ctx.version) {
|
|
@@ -1775,7 +1031,6 @@ async function emitRunLaunch(ctx) {
|
|
|
1775
1031
|
email = state.email;
|
|
1776
1032
|
}
|
|
1777
1033
|
catch {
|
|
1778
|
-
/* probe unavailable — record the launch without the signed-in verdict */
|
|
1779
1034
|
}
|
|
1780
1035
|
}
|
|
1781
1036
|
}
|
|
@@ -1790,7 +1045,6 @@ async function emitRunLaunch(ctx) {
|
|
|
1790
1045
|
}));
|
|
1791
1046
|
}
|
|
1792
1047
|
catch {
|
|
1793
|
-
/* observability must never break a launch */
|
|
1794
1048
|
}
|
|
1795
1049
|
}
|
|
1796
1050
|
async function spawnAgent(options) {
|
|
@@ -1836,10 +1090,10 @@ async function spawnAgent(options) {
|
|
|
1836
1090
|
else if (!row.isApiErrorMessage && row.message?.model && content.trim())
|
|
1837
1091
|
clearClaudeModelRefusal(modelKey, row.message.model);
|
|
1838
1092
|
}
|
|
1839
|
-
catch {
|
|
1093
|
+
catch { }
|
|
1840
1094
|
}
|
|
1841
1095
|
}
|
|
1842
|
-
catch {
|
|
1096
|
+
catch { }
|
|
1843
1097
|
};
|
|
1844
1098
|
const observer = transcript ? setInterval(observeTranscript, 2_000) : undefined;
|
|
1845
1099
|
observer?.unref();
|
|
@@ -1865,19 +1119,10 @@ async function spawnAgent(options) {
|
|
|
1865
1119
|
}
|
|
1866
1120
|
async function spawnAgentLeased(options) {
|
|
1867
1121
|
bootMark('spawn-agent:enter');
|
|
1868
|
-
// Assign a known session id up front for agents that accept one, so the
|
|
1869
|
-
// launcher can record an EXACT pid -> session mapping (see pid-registry) —
|
|
1870
|
-
// otherwise the headless `ag sessions --active` path can only guess
|
|
1871
|
-
// "newest .jsonl in the cwd" and collapses co-located agents onto one row.
|
|
1872
|
-
// Claude: `--session-id <uuid>` CREATES the session with that id (wired in
|
|
1873
|
-
// buildExecCommand). Skip on resume — the id is the one being resumed.
|
|
1874
1122
|
if (options.agent === 'claude' && !options.resume && !options.sessionId) {
|
|
1875
1123
|
options = { ...options, sessionId: randomUUID() };
|
|
1876
1124
|
}
|
|
1877
1125
|
ensureVendorHomeForSpawn(options);
|
|
1878
|
-
// Record the run's --name against its session id (when both are known at
|
|
1879
|
-
// launch) so `agents sessions <name>` resolves it. Best-effort; unnamed runs
|
|
1880
|
-
// and agents whose id isn't known up front simply skip this.
|
|
1881
1126
|
if (options.name && options.sessionId) {
|
|
1882
1127
|
recordRunName({ sessionId: options.sessionId, name: options.name, agent: options.agent, cwd: options.cwd });
|
|
1883
1128
|
}
|
|
@@ -1886,10 +1131,6 @@ async function spawnAgentLeased(options) {
|
|
|
1886
1131
|
const timeoutMs = options.timeout ? parseTimeout(options.timeout) : undefined;
|
|
1887
1132
|
const piped = !process.stdout.isTTY;
|
|
1888
1133
|
const interactive = resolveInteractive(options);
|
|
1889
|
-
// Fail loud before spawning a headless codex whose Linux sandbox can't start —
|
|
1890
|
-
// otherwise it burns a turn and lands zero tools (PHNX-3285). Cheap gate first
|
|
1891
|
-
// so the userns probe (one `unshare`) runs only for the exact case it applies to
|
|
1892
|
-
// (codex + Linux + headless + a sandboxed mode), never for every spawn.
|
|
1893
1134
|
if (options.agent === 'codex' && process.platform === 'linux' && !interactive) {
|
|
1894
1135
|
const codexMode = options.mode ? normalizeMode(options.mode) : defaultModeFor(options.agent);
|
|
1895
1136
|
if (codexMode !== 'skip') {
|
|
@@ -1907,18 +1148,9 @@ async function spawnAgentLeased(options) {
|
|
|
1907
1148
|
}
|
|
1908
1149
|
}
|
|
1909
1150
|
}
|
|
1910
|
-
//
|
|
1911
|
-
// credential falls through to Claude Code's "Select login method" screen — an
|
|
1912
|
-
// interactive OAuth on a headless box that never persists, the 10-minute
|
|
1913
|
-
// re-login loop (PHNX-3502 sibling). A worker authenticates from the
|
|
1914
|
-
// setup-token; when none resolves for the selected account, refuse with the
|
|
1915
|
-
// real fix instead of the useless login prompt. Headless already fails loud
|
|
1916
|
-
// (401), so the gate is interactive-only (the preflight enforces that).
|
|
1151
|
+
// Headed Claude uses native OAuth only; workers require the selected slot's durable setup token and never open interactive login.
|
|
1917
1152
|
if (options.agent === 'claude') {
|
|
1918
1153
|
const { versionHome } = resolveExecConfigHome(options);
|
|
1919
|
-
// A credential reaches the child if the worker setup-token resolves for the
|
|
1920
|
-
// selected account OR the caller passed an explicit --env override
|
|
1921
|
-
// (buildExecEnv merges options.env last, so it wins even the worker strip).
|
|
1922
1154
|
const hasWorkerCredential = Boolean(options.env?.CLAUDE_CODE_OAUTH_TOKEN) ||
|
|
1923
1155
|
(versionHome ? resolveClaudeSetupToken(versionHome) !== null : false);
|
|
1924
1156
|
const loginTrap = claudeWorkerLoginTrapPreflight({
|
|
@@ -1932,34 +1164,12 @@ async function spawnAgentLeased(options) {
|
|
|
1932
1164
|
process.stderr.write(`\x1b[31m${loginTrap}\x1b[0m\n`);
|
|
1933
1165
|
return { exitCode: 1, stdout: '', stderr: loginTrap };
|
|
1934
1166
|
}
|
|
1935
|
-
// A credentialed run on a worker never needs Claude Code's first-run
|
|
1936
|
-
// onboarding, and in a provider (setup-token) launch's shared version home
|
|
1937
|
-
// nothing else completes it: the tab opened on the theme picker instead of
|
|
1938
|
-
// the agent (yosemite-m1, 2026-09-28). A headed device keeps its own
|
|
1939
|
-
// onboarding; the person at it answers it.
|
|
1940
1167
|
if (hasWorkerCredential && versionHome && !isHeadedDeviceRole(selfConfiguredDeviceRole())) {
|
|
1941
1168
|
seedClaudeWorkerHomeIdentity(versionHome);
|
|
1942
1169
|
}
|
|
1943
1170
|
}
|
|
1944
|
-
// Budget live kill-switch (issue #346). For headless runs we incrementally
|
|
1945
|
-
// parse stream-json usage off stdout, accumulate cost, and kill the child the
|
|
1946
|
-
// moment a configured cap is crossed — exactly like the --timeout path, but
|
|
1947
|
-
// resolving with a DISTINCT exit code so CI/headless can tell budget-kill from
|
|
1948
|
-
// timeout. Spend is recorded to the shared ledger in the close handler. The
|
|
1949
|
-
// watcher is dormant (and zero-cost) when no caps are configured.
|
|
1950
1171
|
const cwd = options.cwd || process.cwd();
|
|
1951
|
-
//
|
|
1952
|
-
// exported to the child as AGENT_LAUNCH_ID, so the agent's SessionStart hook
|
|
1953
|
-
// records the SAME id in its own state file (terminals/sessions/<pid>.json).
|
|
1954
|
-
// That id is the join key that reconciles this launch's pid-registry entry
|
|
1955
|
-
// with the hook's authoritative session id even when the hook runs under a
|
|
1956
|
-
// different pid (tmux pane leaf / cmd.exe wrapper) — see pid-registry.ts and
|
|
1957
|
-
// session/hook-sessions.ts. ADOPT a launch id a `--device` launcher already
|
|
1958
|
-
// forwarded (via `--env AGENT_LAUNCH_ID=…`) so ONE correlation key spans the
|
|
1959
|
-
// SSH hop and the launcher can resolve this run's real session id for every
|
|
1960
|
-
// agent, not just Claude (RUSH-2034); mint a fresh one for every local run.
|
|
1961
|
-
// Injected into options.env so every downstream env build (the bare spawn
|
|
1962
|
-
// below AND the tmux env prefix in runInTmux) carries it.
|
|
1172
|
+
// One launch id joins SSH, tmux, hook, and tracker observations into the same run.
|
|
1963
1173
|
const launchId = resolveLaunchId(options.env?.AGENT_LAUNCH_ID);
|
|
1964
1174
|
const runId = launchId;
|
|
1965
1175
|
options = { ...options, env: { ...options.env, AGENT_LAUNCH_ID: launchId } };
|
|
@@ -1968,9 +1178,6 @@ async function spawnAgentLeased(options) {
|
|
|
1968
1178
|
agent: options.agent,
|
|
1969
1179
|
version: options.version,
|
|
1970
1180
|
cwd: options.cwd || process.cwd(),
|
|
1971
|
-
// The mode that ran, not the one requested — `agents run` passes the
|
|
1972
|
-
// requested mode so the resolver can warn, but telemetry must agree with
|
|
1973
|
-
// the audit log. See RUSH-2106 for removing that ambiguity at the source.
|
|
1974
1181
|
mode: resolveMode(options.agent, normalizeMode(options.mode)),
|
|
1975
1182
|
model: options.model,
|
|
1976
1183
|
interactive,
|
|
@@ -1979,11 +1186,6 @@ async function spawnAgentLeased(options) {
|
|
|
1979
1186
|
command: executable,
|
|
1980
1187
|
args: redactArgs(args.slice(0, 10)),
|
|
1981
1188
|
});
|
|
1982
|
-
// Interactive spawn-wrap: run the agent INSIDE a shared-socket tmux session
|
|
1983
|
-
// (then attach this TTY) so it gets a unique, addressable %pane. Opt-in via
|
|
1984
|
-
// this device's tmux.enabled, local and remote alike (PHNX-3316); a followed
|
|
1985
|
-
// remote run left bare relies on reconnect-and-resume, not a pane. Every
|
|
1986
|
-
// failed guard keeps the bare spawn below.
|
|
1987
1189
|
const tmuxWrap = resolveTmuxWrap({
|
|
1988
1190
|
interactive,
|
|
1989
1191
|
platform: process.platform,
|
|
@@ -1996,17 +1198,6 @@ async function spawnAgentLeased(options) {
|
|
|
1996
1198
|
hasTty: !!process.stdout.isTTY,
|
|
1997
1199
|
});
|
|
1998
1200
|
if (tmuxWrap.kind === 'undurable') {
|
|
1999
|
-
// Refuse rather than start work a blink would destroy. This is the ONLY
|
|
2000
|
-
// check — `ensureHostReady` gates a `--device` dispatch on the peer being
|
|
2001
|
-
// reachable and able to run the pinned agent, not on it having tmux, so
|
|
2002
|
-
// there is no launcher-side probe ahead of this one. Failing here still
|
|
2003
|
-
// fails before the agent starts, which is what matters; a pre-dispatch
|
|
2004
|
-
// probe would only move the message earlier, at the cost of a round trip on
|
|
2005
|
-
// every launch. Reached only when the wrap was wanted: the device opted in
|
|
2006
|
-
// via tmux.enabled, or a followed run whose launcher had no TTY (CI,
|
|
2007
|
-
// scripts) left the peer nothing to attach to, so the pane is its stdout.
|
|
2008
|
-
// The config tip uses the ssh form because tmux.enabled is machine-local:
|
|
2009
|
-
// setting it from the launcher throws (assertLocalTarget).
|
|
2010
1201
|
const msg = `agents: ${machineId()} has no tmux, so this --device run cannot get the pane it needs.\n`
|
|
2011
1202
|
+ ` install it: (apt|dnf|brew) install tmux\n`
|
|
2012
1203
|
+ ` or turn the wrap off: agents ssh ${machineId()} 'agents devices config ${machineId()} tmux.enabled off'\n`
|
|
@@ -2015,14 +1206,6 @@ async function spawnAgentLeased(options) {
|
|
|
2015
1206
|
timer.end({ exitCode: 1, status: 'failed', error: 'remote interactive run has no tmux for durability' });
|
|
2016
1207
|
return { exitCode: 1, stdout: '', stderr: msg };
|
|
2017
1208
|
}
|
|
2018
|
-
// Pre-launch marker (`run.launch`), fired on THIS device right before the
|
|
2019
|
-
// harness child is spawned — for BOTH the tmux-wrapped and bare paths below,
|
|
2020
|
-
// and only once the undurable refusal above has passed (a refused run never
|
|
2021
|
-
// spawns). Unlike `run.dispatched` (recordDispatchedRun, at FINALIZE), this
|
|
2022
|
-
// records a launch that then sits stuck at a login screen and never finalizes,
|
|
2023
|
-
// so a launch into a logged-out version is visible instead of silent. The
|
|
2024
|
-
// signed-in verdict is REUSED from the rotated pick when the command threaded
|
|
2025
|
-
// it (options.launchSignedIn), else re-derived from the version home.
|
|
2026
1209
|
await emitRunLaunch({
|
|
2027
1210
|
agent: options.agent,
|
|
2028
1211
|
harnessName: options.harnessName,
|
|
@@ -2046,23 +1229,10 @@ async function spawnAgentLeased(options) {
|
|
|
2046
1229
|
}
|
|
2047
1230
|
}
|
|
2048
1231
|
return new Promise((resolve, reject) => {
|
|
2049
|
-
// Interactive mode inherits all stdio so the CLI owns the TTY (TUI
|
|
2050
|
-
// rendering, raw-mode keystrokes, colored output). Headless mode pipes
|
|
2051
|
-
// stderr so we can scan for rate limits and feed fallback. stdout stays
|
|
2052
|
-
// inherited for TTY, piped when the caller pipes us downstream.
|
|
2053
|
-
// PIPE (and later tee) stdout whenever the live budget watcher must read it
|
|
2054
|
-
// — for ALL non-interactive runs when caps are active, regardless of TTY.
|
|
2055
|
-
// See shouldTapStdout() for the rationale (FIX 3, issue #346).
|
|
2056
1232
|
const tapStdout = shouldTapStdout(interactive, piped, watcherState !== null, options.captureStdoutTail);
|
|
2057
1233
|
const stdio = interactive
|
|
2058
1234
|
? ['inherit', 'inherit', 'inherit']
|
|
2059
1235
|
: ['inherit', tapStdout ? 'pipe' : 'inherit', 'pipe'];
|
|
2060
|
-
// On Windows, .cmd batch wrappers (npm-installed CLIs) require shell:true
|
|
2061
|
-
// whether addressed by name or absolute path. On that shell path, compose a
|
|
2062
|
-
// single fully-quoted command line and pass an EMPTY args array (see
|
|
2063
|
-
// composeWin32CommandLine) so Node never concatenates the args array — which
|
|
2064
|
-
// carries the user's prompt — into the cmd.exe line unescaped (DEP0190 +
|
|
2065
|
-
// command injection).
|
|
2066
1236
|
const useShell = process.platform === 'win32' && (!path.isAbsolute(executable) || executable.endsWith('.cmd'));
|
|
2067
1237
|
const spawnCommand = useShell ? composeWin32CommandLine(executable, args) : executable;
|
|
2068
1238
|
const spawnArgs = useShell ? [] : args;
|
|
@@ -2073,10 +1243,6 @@ async function spawnAgentLeased(options) {
|
|
|
2073
1243
|
env: buildExecEnv(options),
|
|
2074
1244
|
shell: useShell,
|
|
2075
1245
|
});
|
|
2076
|
-
// Record this launch so `ag sessions --active` can map the pid to its exact
|
|
2077
|
-
// session (sessionId is set for Claude above) instead of guessing the newest
|
|
2078
|
-
// .jsonl in the cwd — the collapse that made co-located agents indistinguishable.
|
|
2079
|
-
// Best-effort: pruned when the pid dies; a failed write just degrades to the heuristic.
|
|
2080
1246
|
writePidSessionEntry({
|
|
2081
1247
|
pid: child.pid ?? 0,
|
|
2082
1248
|
agent: options.agent,
|
|
@@ -2102,23 +1268,16 @@ async function spawnAgentLeased(options) {
|
|
|
2102
1268
|
startedAtMs: Date.now(),
|
|
2103
1269
|
});
|
|
2104
1270
|
}
|
|
2105
|
-
// Mark startup time (time from function call to process spawn)
|
|
2106
1271
|
timer.mark('startup');
|
|
2107
1272
|
let budgetKilled = false;
|
|
2108
1273
|
let budgetKillTimer;
|
|
2109
1274
|
let stdoutTail = '';
|
|
2110
1275
|
const STDOUT_TAIL_CAP = 16 * 1024;
|
|
2111
1276
|
if (!interactive && tapStdout && child.stdout) {
|
|
2112
|
-
// TEE the child's stdout back to the parent's so the user still sees
|
|
2113
|
-
// output (mirrors stdio:'inherit') while we tap the same stream for usage.
|
|
2114
1277
|
child.stdout.pipe(process.stdout);
|
|
2115
|
-
// Keep a rolling TAIL (billing refusals arrive at the very end of a run)
|
|
2116
|
-
// for the fallback chain's rate-limit scan.
|
|
2117
1278
|
child.stdout.on('data', (chunk) => {
|
|
2118
1279
|
stdoutTail = (stdoutTail + chunk.toString('utf-8')).slice(-STDOUT_TAIL_CAP);
|
|
2119
1280
|
});
|
|
2120
|
-
// Tap the same stream for budget usage events without consuming the pipe
|
|
2121
|
-
// (a 'data' listener and .pipe() both receive every chunk). Kill on breach.
|
|
2122
1281
|
if (watcherState) {
|
|
2123
1282
|
let pendingLine = '';
|
|
2124
1283
|
child.stdout.on('data', (chunk) => {
|
|
@@ -2165,31 +1324,19 @@ async function spawnAgentLeased(options) {
|
|
|
2165
1324
|
recordCompletedLaunch(launchBinding);
|
|
2166
1325
|
if (timeoutTimer)
|
|
2167
1326
|
clearTimeout(timeoutTimer);
|
|
2168
|
-
// Clear the budget-kill SIGKILL escalation timer (mirror the --timeout
|
|
2169
|
-
// timer cleanup) so a programmatic caller reusing execAgent (the #332 loop
|
|
2170
|
-
// driver) never sees a stray 5s kill event fire after the child has exited.
|
|
2171
1327
|
if (budgetKillTimer)
|
|
2172
1328
|
clearTimeout(budgetKillTimer);
|
|
2173
|
-
// Record final spend to the shared ledger (issue #346). Best-effort: a
|
|
2174
|
-
// ledger write must never mask the run's own outcome.
|
|
2175
1329
|
if (watcherState) {
|
|
2176
1330
|
try {
|
|
2177
1331
|
watcherState.finalize();
|
|
2178
1332
|
}
|
|
2179
|
-
catch {
|
|
2180
|
-
// Release the watcher's references / stop accepting events (symmetry).
|
|
1333
|
+
catch { }
|
|
2181
1334
|
try {
|
|
2182
1335
|
watcherState.watcher.dispose();
|
|
2183
1336
|
}
|
|
2184
|
-
catch {
|
|
1337
|
+
catch { }
|
|
2185
1338
|
}
|
|
2186
|
-
// Budget kill resolves with a DISTINCT non-zero exit so CI/headless and
|
|
2187
|
-
// teams/cloud can tell a budget termination apart from a normal failure.
|
|
2188
1339
|
const exitCode = budgetKilled ? BUDGET_KILL_EXIT_CODE : (code ?? 0);
|
|
2189
|
-
// Relate the session id back to a `--device` launcher (see the emitSessionId
|
|
2190
|
-
// doc). Claude's id is the one we forced; every other agent coined its own,
|
|
2191
|
-
// which the SessionStart hook recorded under this run's launchId — resolve
|
|
2192
|
-
// and print it as a one-line sentinel that rides the followed log home.
|
|
2193
1340
|
if (options.emitSessionId)
|
|
2194
1341
|
emitResolvedSessionId(options, launchId, child.pid);
|
|
2195
1342
|
timer.end({ exitCode, status: budgetKilled ? 'budget_killed' : code === 0 ? 'success' : 'failed' });
|
|
@@ -2197,21 +1344,8 @@ async function spawnAgentLeased(options) {
|
|
|
2197
1344
|
});
|
|
2198
1345
|
});
|
|
2199
1346
|
}
|
|
2200
|
-
/** Exit code spawnAgent resolves with when a run is killed for crossing a budget cap. */
|
|
2201
1347
|
export const BUDGET_KILL_EXIT_CODE = 7;
|
|
2202
|
-
/**
|
|
2203
|
-
* Exit code a tmux-wrapped run resolves with when tmux cannot tell us how the
|
|
2204
|
-
* agent finished — the pane is unreadable, or it is dead with no reported status
|
|
2205
|
-
* (EXEC-23b). Never 0: an unknown outcome reported as success is how a run killed
|
|
2206
|
-
* mid-work gets counted as a clean finish by whatever scripted it.
|
|
2207
|
-
*/
|
|
2208
1348
|
export const UNKNOWN_OUTCOME_EXIT_CODE = 1;
|
|
2209
|
-
/**
|
|
2210
|
-
* Resolve the budget watcher for a run. Returns null (watcher dormant) when no
|
|
2211
|
-
* caps are configured, so non-budget users pay nothing. When caps exist, builds
|
|
2212
|
-
* a live watcher seeded with the day/project spend already on the ledger, plus
|
|
2213
|
-
* a finalize() that appends this run's accumulated spend.
|
|
2214
|
-
*/
|
|
2215
1349
|
async function setupBudgetWatcher(options, cwd, runId) {
|
|
2216
1350
|
const interactive = resolveInteractive(options);
|
|
2217
1351
|
if (interactive)
|
|
@@ -2232,7 +1366,6 @@ async function setupBudgetWatcher(options, cwd, runId) {
|
|
|
2232
1366
|
agentDaySpend: { [options.agent]: ledger.spendForAgentDay(options.agent, today, entries) },
|
|
2233
1367
|
});
|
|
2234
1368
|
const watcher = makeLiveSpendWatcher({ caps, onBreach: () => { } });
|
|
2235
|
-
// Accumulate per-(model) usage for a clean final ledger record.
|
|
2236
1369
|
const seen = [];
|
|
2237
1370
|
const model = options.model ?? `${options.agent}-default`;
|
|
2238
1371
|
return {
|
|
@@ -2266,13 +1399,6 @@ async function setupBudgetWatcher(options, cwd, runId) {
|
|
|
2266
1399
|
},
|
|
2267
1400
|
};
|
|
2268
1401
|
}
|
|
2269
|
-
/**
|
|
2270
|
-
* Patterns that indicate a rate/usage limit. Matching is intentionally broad
|
|
2271
|
-
* because providers phrase these differently -- Anthropic uses "5-hour limit"
|
|
2272
|
-
* and "rate limit", OpenAI surfaces 429s, Google says "quota exceeded".
|
|
2273
|
-
* False positives here just trigger a fallback attempt; false negatives leave
|
|
2274
|
-
* the original error unhandled, which is worse.
|
|
2275
|
-
*/
|
|
2276
1402
|
export const RATE_LIMIT_PATTERNS = [
|
|
2277
1403
|
/rate[\s-]?limit/i,
|
|
2278
1404
|
/usage[\s-]?limit/i,
|
|
@@ -2282,23 +1408,12 @@ export const RATE_LIMIT_PATTERNS = [
|
|
|
2282
1408
|
/too many requests/i,
|
|
2283
1409
|
/api[\s_-]?overloaded/i,
|
|
2284
1410
|
/\boverloaded\b/i,
|
|
2285
|
-
// Claude billing refusals — "You've hit your org's monthly spend limit" and
|
|
2286
|
-
// "You're out of usage credits". Both end the run with exit 1 and are exactly
|
|
2287
|
-
// the condition a fallback chain exists to recover from. Printed to STDOUT,
|
|
2288
|
-
// hence the stdout tail in SpawnResult.
|
|
2289
1411
|
/spend[\s-]?limit/i,
|
|
2290
1412
|
/out of (?:usage )?credits/i,
|
|
2291
1413
|
];
|
|
2292
|
-
/** Return true if the text contains any known rate-limit or overload indicator. */
|
|
2293
1414
|
export function detectRateLimit(text) {
|
|
2294
1415
|
return RATE_LIMIT_PATTERNS.some(pattern => pattern.test(text));
|
|
2295
1416
|
}
|
|
2296
|
-
/**
|
|
2297
|
-
* Narrow detector for a BILLING exhaustion — tokens/credits run out or the
|
|
2298
|
-
* monthly spend cap is hit — as opposed to a time-window rate limit. This class
|
|
2299
|
-
* does NOT recover on a clock, so rotation must remember it per-account
|
|
2300
|
-
* (noteClaudeOutOfCredits) until a later successful run clears it.
|
|
2301
|
-
*/
|
|
2302
1417
|
const OUT_OF_CREDITS_PATTERNS = [
|
|
2303
1418
|
/out of (?:usage )?credits/i,
|
|
2304
1419
|
/spend[\s-]?limit/i,
|
|
@@ -2306,17 +1421,6 @@ const OUT_OF_CREDITS_PATTERNS = [
|
|
|
2306
1421
|
export function detectOutOfCredits(text) {
|
|
2307
1422
|
return OUT_OF_CREDITS_PATTERNS.some(pattern => pattern.test(text));
|
|
2308
1423
|
}
|
|
2309
|
-
/**
|
|
2310
|
-
* Classify a Claude run's output + exit code, model-limit refusal included.
|
|
2311
|
-
* Precedence: a session-limit reset first (it carries a clock), then a
|
|
2312
|
-
* clock-less billing exhaustion, then a MODEL-specific refusal ("You've
|
|
2313
|
-
* reached your Fable limit…") — checked BEFORE the exit-0 clear so a model
|
|
2314
|
-
* refusal that ends the run with exit 0 is never misread as a clean success
|
|
2315
|
-
* that clears every other stale marker on the account. A model refusal never
|
|
2316
|
-
* maps to `note_out_of_credits`/`note_session`: those are account-wide, this
|
|
2317
|
-
* names one model. Only a clean run with NO refusal text clears stale
|
|
2318
|
-
* markers; anything else leaves them untouched.
|
|
2319
|
-
*/
|
|
2320
1424
|
export function classifyClaudeRunRefusal(output, exitCode, model) {
|
|
2321
1425
|
const sessionLimitReset = parseClaudeSessionLimitReset(output);
|
|
2322
1426
|
if (sessionLimitReset)
|
|
@@ -2331,22 +1435,7 @@ export function classifyClaudeRunRefusal(output, exitCode, model) {
|
|
|
2331
1435
|
return { action: 'clear' };
|
|
2332
1436
|
return { action: 'none' };
|
|
2333
1437
|
}
|
|
2334
|
-
/**
|
|
2335
|
-
* Parse Codex's usage-limit refusal reset. Codex prints
|
|
2336
|
-
* `ERROR: You've hit your usage limit. … try again at Sep 12th, 2026 8:32 AM.`
|
|
2337
|
-
* (or `…try again at 8:32 AM.` for the 5-hour window). The reset is what makes
|
|
2338
|
-
* this a session-style limit that auto-clears on its clock rather than a
|
|
2339
|
-
* clock-less billing exhaustion. Ordinal suffixes (`12th`) are stripped so
|
|
2340
|
-
* `Date.parse` accepts the date; a time-only reset resolves against today/tomorrow.
|
|
2341
|
-
* Returns null when there is no future reset to parse (caller then leaves the
|
|
2342
|
-
* marker untouched rather than persisting a sticky one it cannot expire).
|
|
2343
|
-
*/
|
|
2344
1438
|
export function parseCodexUsageLimitReset(text, nowMs = Date.now()) {
|
|
2345
|
-
// Gate on the CLI's own refusal phrasing, NOT a bare "usage limit" substring:
|
|
2346
|
-
// this runs against a 16KB stdout tail of `codex exec`, which streams the whole
|
|
2347
|
-
// agent transcript, so a session that merely *discusses* usage-limit code would
|
|
2348
|
-
// otherwise false-positive and wrongly mark a HEALTHY account excluded. Mirrors
|
|
2349
|
-
// the narrow Claude convention (`hit your session limit`).
|
|
2350
1439
|
if (!/hit your usage limit/i.test(text))
|
|
2351
1440
|
return null;
|
|
2352
1441
|
const match = /try again (?:at|on)\s+([^.\n]+)/i.exec(text);
|
|
@@ -2355,14 +1444,8 @@ export function parseCodexUsageLimitReset(text, nowMs = Date.now()) {
|
|
|
2355
1444
|
const segment = match[1].trim().replace(/(\d{1,2})(st|nd|rd|th)\b/gi, '$1');
|
|
2356
1445
|
const absolute = Date.parse(segment);
|
|
2357
1446
|
if (!Number.isNaN(absolute)) {
|
|
2358
|
-
// A full date parsed — honor it only while still in the future; a past reset
|
|
2359
|
-
// means the window already recovered, so there is nothing to note. Do NOT
|
|
2360
|
-
// fall through to the clock path, which would understate the real date as
|
|
2361
|
-
// today/tomorrow.
|
|
2362
1447
|
return absolute > nowMs ? new Date(absolute) : null;
|
|
2363
1448
|
}
|
|
2364
|
-
// No date parsed — the 5-hour "try again at 8:32 AM" (time-only) form. Resolve
|
|
2365
|
-
// it against today, rolling to tomorrow when the clock has already passed.
|
|
2366
1449
|
const clock = /(\d{1,2})(?::(\d{2}))?\s*(am|pm)/i.exec(segment);
|
|
2367
1450
|
if (!clock)
|
|
2368
1451
|
return null;
|
|
@@ -2376,18 +1459,6 @@ export function parseCodexUsageLimitReset(text, nowMs = Date.now()) {
|
|
|
2376
1459
|
result.setDate(result.getDate() + 1);
|
|
2377
1460
|
return result;
|
|
2378
1461
|
}
|
|
2379
|
-
/**
|
|
2380
|
-
* Classify what a Codex run's output + exit code means for the account's
|
|
2381
|
-
* persisted refusal marker — the Codex sibling of {@link classifyClaudeRunRefusal}
|
|
2382
|
-
* (the `ClaudeRefusalAction` shape is harness-generic; the usage cache it drives
|
|
2383
|
-
* is identity-keyed and shared across harnesses). Codex's usage limit is
|
|
2384
|
-
* time-windowed and carries a reset ("try again at <date>"), so it is noted as a
|
|
2385
|
-
* clock-bearing session limit that auto-clears — NOT a clock-less out_of_credits,
|
|
2386
|
-
* which would stay sticky until a successful run the excluded account can never
|
|
2387
|
-
* get. A genuine credit/quota exhaustion IS clock-less. A clean run clears any
|
|
2388
|
-
* stale marker; a limit with no parseable reset is left untouched (the run still
|
|
2389
|
-
* cascades via detectRateLimit) rather than persisting an unexpirable marker.
|
|
2390
|
-
*/
|
|
2391
1462
|
export function classifyCodexRunRefusal(output, exitCode, nowMs = Date.now()) {
|
|
2392
1463
|
const reset = parseCodexUsageLimitReset(output, nowMs);
|
|
2393
1464
|
if (reset)
|
|
@@ -2420,11 +1491,6 @@ const AUTH_FAILURE_PATTERNS = [
|
|
|
2420
1491
|
/organization has (?:disabled|revoked) .*(?:subscription|access)/i,
|
|
2421
1492
|
/401\b[^\n]*(?:OAuth|authenticat|credential|Unauthorized)/i,
|
|
2422
1493
|
];
|
|
2423
|
-
/**
|
|
2424
|
-
* Return true if the text contains any known authentication-failure indicator.
|
|
2425
|
-
* Agent-agnostic: matches the user-visible error string wherever it surfaces
|
|
2426
|
-
* (stdout tail, a captured error message, a plain-text agent's output).
|
|
2427
|
-
*/
|
|
2428
1494
|
export function detectAuthFailure(text) {
|
|
2429
1495
|
return AUTH_FAILURE_PATTERNS.some(pattern => pattern.test(text));
|
|
2430
1496
|
}
|
|
@@ -2467,12 +1533,6 @@ export function detectAuthFailureEvent(logText, agent) {
|
|
|
2467
1533
|
}
|
|
2468
1534
|
return false;
|
|
2469
1535
|
}
|
|
2470
|
-
/**
|
|
2471
|
-
* Return the first human-readable auth-failure phrase found in the text, for use
|
|
2472
|
-
* as a stable, short run `errorMessage` reason. Falls back to null when the only
|
|
2473
|
-
* signal was the structural `error:"authentication_failed"` marker with no
|
|
2474
|
-
* user-visible string.
|
|
2475
|
-
*/
|
|
2476
1536
|
export function authFailureReason(text) {
|
|
2477
1537
|
for (const pattern of AUTH_FAILURE_PATTERNS) {
|
|
2478
1538
|
const m = text.match(pattern);
|
|
@@ -2481,20 +1541,6 @@ export function authFailureReason(text) {
|
|
|
2481
1541
|
}
|
|
2482
1542
|
return null;
|
|
2483
1543
|
}
|
|
2484
|
-
/**
|
|
2485
|
-
* Decide whether a run's stream-json log is an authentication failure. The
|
|
2486
|
-
* single source of truth for both the foreground and detached run paths.
|
|
2487
|
-
*
|
|
2488
|
-
* The structural marker (`detectAuthFailureEvent`, gated on `is_error:true`) is
|
|
2489
|
-
* authoritative and safe on ANY exit — it catches a logged-out Claude that exits
|
|
2490
|
-
* 0 (its `result` event carries `is_error:true` while `terminal_reason` is
|
|
2491
|
-
* "completed"). The raw user-visible string (`detectAuthFailure`) is only
|
|
2492
|
-
* consulted when the process actually FAILED, as a fallback for a run that died
|
|
2493
|
-
* mid-stream before emitting a `result` event. That gate is what prevents a
|
|
2494
|
-
* genuinely-completed run whose output merely *mentions* an auth phrase (e.g. a
|
|
2495
|
-
* routine documenting a login flow) from being misclassified and having its
|
|
2496
|
-
* legitimate report suppressed.
|
|
2497
|
-
*/
|
|
2498
1544
|
export function isAuthFailureFromLog(logText, agent, opts) {
|
|
2499
1545
|
if (detectAuthFailureEvent(logText, agent))
|
|
2500
1546
|
return true;
|
|
@@ -2502,16 +1548,6 @@ export function isAuthFailureFromLog(logText, agent, opts) {
|
|
|
2502
1548
|
return true;
|
|
2503
1549
|
return false;
|
|
2504
1550
|
}
|
|
2505
|
-
/**
|
|
2506
|
-
* Build the prompt handed to the fallback agent when the primary was stopped
|
|
2507
|
-
* mid-task by a rate limit.
|
|
2508
|
-
*
|
|
2509
|
-
* When the prior agent was Claude we pin its session ID via `--session-id` so
|
|
2510
|
-
* `prevSessionId` is always defined; for other primaries we pass undefined and
|
|
2511
|
-
* get a simpler retry-with-context prompt. Claude understands `/continue <id>`
|
|
2512
|
-
* via its shipped skill -- other agents fall through to an explicit instruction
|
|
2513
|
-
* that points at the version-agnostic `agents sessions <id>` reader.
|
|
2514
|
-
*/
|
|
2515
1551
|
export function buildFallbackPrompt(prevAgent, prevSessionId, nextAgent, originalPrompt) {
|
|
2516
1552
|
if (nextAgent === 'claude' && prevSessionId) {
|
|
2517
1553
|
return `/continue ${prevSessionId}`;
|
|
@@ -2525,20 +1561,7 @@ export function buildFallbackPrompt(prevAgent, prevSessionId, nextAgent, origina
|
|
|
2525
1561
|
lines.push(``, `Original request: ${originalPrompt}`, ``, `Continue from where the prior agent left off.`);
|
|
2526
1562
|
return lines.join('\n');
|
|
2527
1563
|
}
|
|
2528
|
-
|
|
2529
|
-
* Run an agent and, on rate-limit failure, cascade through the fallback chain.
|
|
2530
|
-
*
|
|
2531
|
-
* The primary agent gets the original prompt. Subsequent agents get a
|
|
2532
|
-
* `/continue <id>`-style handoff (see buildFallbackPrompt) when we can pin a
|
|
2533
|
-
* session ID -- which today means Claude as primary (supports `--session-id`).
|
|
2534
|
-
* For other primaries, fallbacks run with the original prompt plus a
|
|
2535
|
-
* retry-with-context note, since we can't deterministically resolve their
|
|
2536
|
-
* auto-generated session IDs.
|
|
2537
|
-
*
|
|
2538
|
-
* Only rate-limit failures cascade. Other errors (missing flag, auth failure,
|
|
2539
|
-
* compile error) bubble up from the primary so the caller sees the real cause
|
|
2540
|
-
* instead of an opaque "all agents failed" message.
|
|
2541
|
-
*/
|
|
1564
|
+
// Fallback preserves an explicit mode; only an implicit mode is re-resolved for the next harness.
|
|
2542
1565
|
export async function runWithFallback(options) {
|
|
2543
1566
|
const chain = [
|
|
2544
1567
|
{ agent: options.agent, version: options.version },
|
|
@@ -2546,11 +1569,6 @@ export async function runWithFallback(options) {
|
|
|
2546
1569
|
];
|
|
2547
1570
|
let prevAgent;
|
|
2548
1571
|
let prevSessionId;
|
|
2549
|
-
// Workflow capability scoping only takes effect on claude (buildExecCommand
|
|
2550
|
-
// guards `--tools` / `--mcp-config` / `--strict-mcp-config` on agent==='claude').
|
|
2551
|
-
// A fallback to any non-claude agent would run with NONE of that scoping — the
|
|
2552
|
-
// declared sandbox silently evaporates. Warn loudly so a rate-limit handoff to
|
|
2553
|
-
// an unscoped agent is never silent (issue #324 fail-open).
|
|
2554
1572
|
const scopingActive = (options.toolsRestrict && options.toolsRestrict.length > 0)
|
|
2555
1573
|
|| !!options.mcpConfigPath;
|
|
2556
1574
|
if (scopingActive) {
|
|
@@ -2563,25 +1581,18 @@ export async function runWithFallback(options) {
|
|
|
2563
1581
|
}
|
|
2564
1582
|
for (let i = 0; i < chain.length; i++) {
|
|
2565
1583
|
const { agent, version, envOverride } = chain[i];
|
|
2566
|
-
// Every fallback entry can target a different harness/version home. Sync
|
|
2567
|
-
// its active preset immediately before dispatch so entries 2..N cannot
|
|
2568
|
-
// inherit the stale rules file left by the primary entry.
|
|
2569
1584
|
const rulesVersion = version ?? resolveVersion(agent);
|
|
2570
1585
|
if (rulesVersion) {
|
|
2571
1586
|
applyActiveRulesPresetAtRun(agent, rulesVersion, getVersionHomePath(agent, rulesVersion));
|
|
2572
1587
|
applySystemResourcesAtRun(agent, rulesVersion, getVersionHomePath(agent, rulesVersion));
|
|
2573
1588
|
}
|
|
2574
|
-
// Record the entry we're about to attempt so the caller (audit log) sees the
|
|
2575
|
-
// agent+version that actually ran, even after a rate-limit handoff.
|
|
2576
1589
|
if (options.dispatchSink) {
|
|
2577
1590
|
options.dispatchSink.agent = agent;
|
|
2578
1591
|
options.dispatchSink.version = version;
|
|
2579
1592
|
}
|
|
2580
1593
|
const pinnedSessionId = agent === 'claude' ? randomUUID() : undefined;
|
|
2581
|
-
// Same-host retry (same agent+version as previous entry — used by profile
|
|
2582
|
-
// `fallback_model` swaps) keeps the original prompt: the model changed,
|
|
2583
|
-
// not the CLI, so a `/continue` handoff prompt would be misleading.
|
|
2584
1594
|
const prev = i > 0 ? chain[i - 1] : undefined;
|
|
1595
|
+
// Same-agent entries are account/model retries, not cross-harness transcript handoff.
|
|
2585
1596
|
const sameHostRetry = !!prev && prev.agent === agent && prev.version === version;
|
|
2586
1597
|
const prompt = prevAgent && !sameHostRetry
|
|
2587
1598
|
? buildFallbackPrompt(prevAgent, prevSessionId, agent, options.prompt)
|
|
@@ -2594,8 +1605,6 @@ export async function runWithFallback(options) {
|
|
|
2594
1605
|
prompt,
|
|
2595
1606
|
env: envOverride ? { ...(options.env ?? {}), ...envOverride } : options.env,
|
|
2596
1607
|
sessionId: pinnedSessionId ?? (i === 0 ? options.sessionId : undefined),
|
|
2597
|
-
// Claude prints billing refusals (spend limit / out of credits) to
|
|
2598
|
-
// stdout; tail it so the cascade check below can see them.
|
|
2599
1608
|
captureStdoutTail: true,
|
|
2600
1609
|
};
|
|
2601
1610
|
const label = version ? `${agent}@${version}` : agent;
|
|
@@ -2620,13 +1629,6 @@ export async function runWithFallback(options) {
|
|
|
2620
1629
|
throw err;
|
|
2621
1630
|
}
|
|
2622
1631
|
const output = `${result.stderr}\n${result.stdout}`;
|
|
2623
|
-
// Persist a per-account refusal marker so rotation stops re-picking a
|
|
2624
|
-
// known-dead account: a session/usage limit recovers on its clock, a billing
|
|
2625
|
-
// exhaustion (tokens/credits) recovers only on a later successful run, and a
|
|
2626
|
-
// clean run clears any stale marker. Claude and Codex both surface these as
|
|
2627
|
-
// run-ending text, and the usage cache is identity-keyed (shared across
|
|
2628
|
-
// harnesses), so one path notes either. Decisions extracted + unit-tested in
|
|
2629
|
-
// classify{Claude,Codex}RunRefusal.
|
|
2630
1632
|
const refusal = agent === 'claude'
|
|
2631
1633
|
? classifyClaudeRunRefusal(output, result.exitCode ?? 1, execOpts.model)
|
|
2632
1634
|
: agent === 'codex'
|
|
@@ -2634,12 +1636,6 @@ export async function runWithFallback(options) {
|
|
|
2634
1636
|
: null;
|
|
2635
1637
|
const sessionLimitReset = refusal?.action === 'note_session' ? refusal.resetsAt : null;
|
|
2636
1638
|
if (refusal && version && refusal.action !== 'none') {
|
|
2637
|
-
// Resolve the account from the HOME this attempt actually authenticated
|
|
2638
|
-
// from — execHome (a slot dir, PHNX-3940 T5) or configVersion wins over
|
|
2639
|
-
// the bare managed-binary version home. Reading `getVersionHomePath(agent,
|
|
2640
|
-
// version)` unconditionally attributed a refusal to the wrong account for
|
|
2641
|
-
// every account-slot / configVersion launch, since `version` there is the
|
|
2642
|
-
// BINARY, not the credential's home.
|
|
2643
1639
|
const { versionHome: refusalHome } = resolveExecConfigHome(execOpts);
|
|
2644
1640
|
const account = await getAccountInfo(agent, refusalHome ?? getVersionHomePath(agent, version));
|
|
2645
1641
|
const usageKey = getUsageLookupKey(account);
|
|
@@ -2652,16 +1648,13 @@ export async function runWithFallback(options) {
|
|
|
2652
1648
|
clearClaudeAccountRefusal(usageKey);
|
|
2653
1649
|
}
|
|
2654
1650
|
}
|
|
2655
|
-
// A model-limit refusal commonly ends the CLI turn with exit 0 (Claude
|
|
2656
|
-
// just refuses to keep going on that model rather than crashing) — so,
|
|
2657
|
-
// like a session-limit reset, it must not be read as a clean success that
|
|
2658
|
-
// short-circuits the cascade before the fallback chain ever runs.
|
|
2659
1651
|
const modelLimited = refusal?.action === 'note_model_limit';
|
|
2660
1652
|
if (result.exitCode === 0 && !sessionLimitReset && !modelLimited)
|
|
2661
1653
|
return 0;
|
|
2662
1654
|
const isLast = i === chain.length - 1;
|
|
2663
1655
|
if (isLast)
|
|
2664
1656
|
return result.exitCode || 1;
|
|
1657
|
+
// Authentication and ordinary failures never trigger provider fallback; only explicit capacity signals do.
|
|
2665
1658
|
if (!sessionLimitReset && !modelLimited && !detectRateLimit(result.stderr) && !detectRateLimit(result.stdout)) {
|
|
2666
1659
|
return result.exitCode;
|
|
2667
1660
|
}
|