@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
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shim generation, config symlink management, and versioned aliases for agent version switching.
|
|
3
|
-
*/
|
|
4
1
|
import * as fs from 'fs';
|
|
5
2
|
import * as path from 'path';
|
|
6
3
|
import * as os from 'os';
|
|
@@ -17,7 +14,6 @@ import { slotAwareConfigEnvBash } from '../harness/adapter.js';
|
|
|
17
14
|
import { randomUUID } from 'node:crypto';
|
|
18
15
|
import { captureProcessStartTime } from '../platform/process.js';
|
|
19
16
|
import { atomicWriteFileSync } from '../fs-atomic.js';
|
|
20
|
-
/** Files and directories to always skip during conflict detection and migration. */
|
|
21
17
|
const MIGRATION_IGNORE_LIST = new Set([
|
|
22
18
|
'node_modules',
|
|
23
19
|
'.git',
|
|
@@ -36,13 +32,9 @@ function shouldIgnore(name) {
|
|
|
36
32
|
return true;
|
|
37
33
|
return false;
|
|
38
34
|
}
|
|
39
|
-
// Launch leases are written under the shared launch/update gate BEFORE exec or
|
|
40
|
-
// spawn. A live launcher protects the gap until its child appears in ps; an
|
|
41
|
-
// exec-replacing shim keeps the same PID. A birth fingerprint defeats PID reuse.
|
|
42
35
|
function launchLeaseDir(agent, label) {
|
|
43
36
|
return path.join(getVersionsDir(), agent, label, '.launch-leases');
|
|
44
37
|
}
|
|
45
|
-
/** Record that `pid` is about to execute this installation's binary. Call right before handing off to it. */
|
|
46
38
|
export function recordLaunchLease(agent, label, pid) {
|
|
47
39
|
const dir = launchLeaseDir(agent, label);
|
|
48
40
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -51,7 +43,7 @@ export function recordLaunchLease(agent, label, pid) {
|
|
|
51
43
|
return () => { try {
|
|
52
44
|
fs.unlinkSync(file);
|
|
53
45
|
}
|
|
54
|
-
catch {
|
|
46
|
+
catch { } };
|
|
55
47
|
}
|
|
56
48
|
function pidAlive(pid) {
|
|
57
49
|
try {
|
|
@@ -62,7 +54,6 @@ function pidAlive(pid) {
|
|
|
62
54
|
return err.code !== 'ESRCH';
|
|
63
55
|
}
|
|
64
56
|
}
|
|
65
|
-
/** Read-only: stale leases cannot defer an update, and preview never deletes files. */
|
|
66
57
|
export function hasLiveLaunchLease(agent, label) {
|
|
67
58
|
const dir = launchLeaseDir(agent, label);
|
|
68
59
|
let entries;
|
|
@@ -88,17 +79,15 @@ export function hasLiveLaunchLease(agent, label) {
|
|
|
88
79
|
}
|
|
89
80
|
catch {
|
|
90
81
|
live = true;
|
|
91
|
-
}
|
|
82
|
+
}
|
|
92
83
|
}
|
|
93
84
|
return live;
|
|
94
85
|
}
|
|
95
|
-
/** Detect filenames that exist in both `src` and `dest`, excluding symlinks in `dest`. */
|
|
96
86
|
function detectConflicts(src, dest, prefix = '') {
|
|
97
87
|
const conflicts = [];
|
|
98
88
|
if (!fs.existsSync(src) || !fs.existsSync(dest)) {
|
|
99
89
|
return conflicts;
|
|
100
90
|
}
|
|
101
|
-
// Skip if dest is a symlink (managed resources)
|
|
102
91
|
try {
|
|
103
92
|
const destStat = fs.lstatSync(dest);
|
|
104
93
|
if (destStat.isSymbolicLink()) {
|
|
@@ -106,35 +95,29 @@ function detectConflicts(src, dest, prefix = '') {
|
|
|
106
95
|
}
|
|
107
96
|
}
|
|
108
97
|
catch {
|
|
109
|
-
/* dest not accessible, no conflicts to report */
|
|
110
98
|
return conflicts;
|
|
111
99
|
}
|
|
112
100
|
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
113
101
|
for (const entry of entries) {
|
|
114
|
-
// Skip files/directories that should never be migrated
|
|
115
102
|
if (shouldIgnore(entry.name)) {
|
|
116
103
|
continue;
|
|
117
104
|
}
|
|
118
105
|
const srcPath = path.join(src, entry.name);
|
|
119
106
|
const destPath = path.join(dest, entry.name);
|
|
120
107
|
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
121
|
-
// Skip if dest entry is a symlink (managed resource)
|
|
122
108
|
try {
|
|
123
109
|
const entryDestStat = fs.lstatSync(destPath);
|
|
124
110
|
if (entryDestStat.isSymbolicLink()) {
|
|
125
111
|
continue;
|
|
126
112
|
}
|
|
127
113
|
if (entry.isDirectory()) {
|
|
128
|
-
// Recurse into subdirectories
|
|
129
114
|
conflicts.push(...detectConflicts(srcPath, destPath, relativePath));
|
|
130
115
|
}
|
|
131
116
|
else {
|
|
132
|
-
// File exists in both - it's a conflict
|
|
133
117
|
conflicts.push(relativePath);
|
|
134
118
|
}
|
|
135
119
|
}
|
|
136
120
|
catch {
|
|
137
|
-
// dest entry doesn't exist, not a conflict
|
|
138
121
|
}
|
|
139
122
|
}
|
|
140
123
|
return conflicts;
|
|
@@ -142,19 +125,17 @@ function detectConflicts(src, dest, prefix = '') {
|
|
|
142
125
|
async function promptConflictStrategy(conflictInfos) {
|
|
143
126
|
const totalConflicts = conflictInfos.reduce((sum, info) => sum + info.conflicts.length, 0);
|
|
144
127
|
if (totalConflicts === 0) {
|
|
145
|
-
return null;
|
|
128
|
+
return null;
|
|
146
129
|
}
|
|
147
|
-
// Show what has conflicts with clear paths
|
|
148
130
|
console.log('\nFile conflicts detected:');
|
|
149
131
|
for (const info of conflictInfos) {
|
|
150
132
|
const agentConfig = AGENTS[info.agent];
|
|
151
|
-
const configDir = agentConfig.configDir;
|
|
133
|
+
const configDir = agentConfig.configDir;
|
|
152
134
|
console.log(` ${info.conflicts.length} file(s) conflict between:`);
|
|
153
135
|
console.log(` ~/${configDir}/ (your config)`);
|
|
154
136
|
console.log(` ${agentConfig.name}@${info.version} (managed version)`);
|
|
155
137
|
}
|
|
156
138
|
console.log();
|
|
157
|
-
// Build choice labels with agent info for clarity
|
|
158
139
|
const firstInfo = conflictInfos[0];
|
|
159
140
|
const firstAgent = AGENTS[firstInfo.agent];
|
|
160
141
|
const versionLabel = conflictInfos.length === 1
|
|
@@ -182,130 +163,11 @@ async function promptConflictStrategy(conflictInfos) {
|
|
|
182
163
|
});
|
|
183
164
|
return strategy;
|
|
184
165
|
}
|
|
185
|
-
/** Generate the shim script content for an agent. Resolves project/default version, auto-installs if missing, and execs the binary. */
|
|
186
|
-
/**
|
|
187
|
-
* Current shim schema version. Bump whenever `generateShimScript` changes
|
|
188
|
-
* in a way that requires existing on-disk shims to be regenerated (new
|
|
189
|
-
* flags, fixed argument parsing, new hooks, etc.). `isShimCurrent` reads
|
|
190
|
-
* this marker out of existing shims to decide whether to regenerate.
|
|
191
|
-
*
|
|
192
|
-
* History:
|
|
193
|
-
* v1 — initial shim (implicit, no marker).
|
|
194
|
-
* v2 — `--version=...` form in sync/refresh-rules calls; refresh-rules
|
|
195
|
-
* shim hook for non-@-capable agents.
|
|
196
|
-
* v3 — sync/refresh-rules flag renamed `--version` → `--agent-version`
|
|
197
|
-
* so it no longer collides with commander's top-level `--version`.
|
|
198
|
-
* v4 — project version marker changed from `.agents-version` to a
|
|
199
|
-
* root-level `agents.yaml`; shim now skips ~/.agents/agents.yaml
|
|
200
|
-
* when walking up for a project marker.
|
|
201
|
-
* v5 — emit CODEX_HOME for codex shims so the versioned config (permissions,
|
|
202
|
-
* sandbox_mode, rules/agents-deny.rules) is actually read by the codex
|
|
203
|
-
* binary instead of $HOME/.codex.
|
|
204
|
-
* v6 — hard-disable Codex startup update checks in the generated shims.
|
|
205
|
-
* v7 — rename `agents refresh-memory` invocation to `agents refresh-rules`
|
|
206
|
-
* and capability flag `memoryImports` → `rulesImports`.
|
|
207
|
-
* v8 — versions moved from ~/.agents-system/versions to ~/.agents/versions
|
|
208
|
-
* (two-repo split: system = shipped defaults, user = operational state).
|
|
209
|
-
* v9 — claude shim exports CLAUDE_CODE_OAUTH_TOKEN from per-version
|
|
210
|
-
* .oauth_token file on Linux (keychain-less sandbox fallback).
|
|
211
|
-
* v11 — when no default is set or the configured version is not installed,
|
|
212
|
-
* interactively propose the latest already-installed version.
|
|
213
|
-
* v12 — helper calls inside generated shims use the absolute agents-cli
|
|
214
|
-
* entrypoint instead of PATH-resolved `agents`.
|
|
215
|
-
* v13 — validate agents.yaml version strings before constructing binary paths.
|
|
216
|
-
* v14 — derive `configDirName` from `agentConfig.configDir` relative to $HOME
|
|
217
|
-
* instead of hardcoding `.${agent}`. Backwards-compatible for every
|
|
218
|
-
* existing agent (their configDir is `~/.{agent}`); enables nested
|
|
219
|
-
* layouts like Antigravity's `~/.gemini/antigravity-cli/`.
|
|
220
|
-
* v15 — remove foreground resource sync / rules refresh from launch shims.
|
|
221
|
-
* Version homes are reconciled by agents-cli management commands; the
|
|
222
|
-
* shim hot path only resolves a version and execs the agent binary.
|
|
223
|
-
* v16 — re-introduce project-scoped compile to the shim hot path via
|
|
224
|
-
* `agents sync --launch`. This stays fast (filesystem-only): compiles
|
|
225
|
-
* project rules, mirrors workspace resources, and synthesizes the
|
|
226
|
-
* scoped plugin marketplaces (agents-cli/agents-system/extras-<alias>/
|
|
227
|
-
* agents-project). Version-home reconciliation stays out of the hot
|
|
228
|
-
* path — management commands still own that.
|
|
229
|
-
* v17 — bash-side skip-fast sentinel under ~/.agents/.cache/launch-sync/.
|
|
230
|
-
* When the sentinel mtime is newer than every source dir, exec the
|
|
231
|
-
* agent binary directly without spawning node. Cuts steady-state
|
|
232
|
-
* hot-path latency from ~680ms (node startup + module init) to ~11ms
|
|
233
|
-
* (a few stat calls). Node writes the sentinel after each successful
|
|
234
|
-
* sync. Documented limitation: POSIX dir mtime only updates on
|
|
235
|
-
* top-level entry add/remove — deep edits to plugin contents won't
|
|
236
|
-
* trigger auto-resync, run `agents sync` for that.
|
|
237
|
-
*/
|
|
238
|
-
// v20 — stop treating kimi like grok/droid: it npm-installs into
|
|
239
|
-
// node_modules/.bin/kimi, so resolve it via the generic branch. The old
|
|
240
|
-
// ~/.kimi-code/bin special-case never existed for npm installs and
|
|
241
|
-
// re-exec-looped through `command -v kimi` (the dispatcher itself).
|
|
242
|
-
// v21 — guard grok's `command -v grok` fallback against resolving to our own
|
|
243
|
-
// shims dir (same infinite re-exec loop), mirroring droid.
|
|
244
|
-
// v22 — export DISABLE_AUTOUPDATER=1 for claude shims so a pinned per-version
|
|
245
|
-
// install can't self-mutate: Claude Code's background auto-updater would
|
|
246
|
-
// otherwise rewrite the pinned binary in place. Explicit user value wins.
|
|
247
|
-
// v25 — dispatcher self-recovery: if the baked AGENTS_BIN is gone (a removed/moved
|
|
248
|
-
// dev build that generated the shim), resolve `agents` on PATH instead of
|
|
249
|
-
// exiting 127, so a stale/vanished dev build can't brick every launch.
|
|
250
|
-
// v26 — grok resolves its binary from the versioned home's .grok/downloads first
|
|
251
|
-
// ($VERSION_DIR/home/.grok/downloads, where the binary lands when the
|
|
252
|
-
// installer runs with GROK_HOME set or grok self-updates under the shim),
|
|
253
|
-
// then falls back to the global ~/.grok/downloads for pre-fix installs.
|
|
254
|
-
// The old dispatcher checked only the global dir, so a pinned grok that
|
|
255
|
-
// installed into the versioned home fell through to the "not installed"
|
|
256
|
-
// error.
|
|
257
|
-
// v30 — RUSH-2459: two compounding grok binary-resolution bugs fixed. (1) The
|
|
258
|
-
// "exact version match" grep ran against `ls`'s FULL PATH output, and
|
|
259
|
-
// the versioned home's own path always contains the version string
|
|
260
|
-
// (.../versions/grok/<version>/...), so it matched every candidate
|
|
261
|
-
// unconditionally and silently degraded to "whatever ls sorts first" —
|
|
262
|
-
// now matched against each candidate's basename instead. (2) When no
|
|
263
|
-
// filename genuinely carries the version, the fallback no longer
|
|
264
|
-
// trusts whatever sorts first: it rejects any grok-* candidate under
|
|
265
|
-
// 1MB (real grok binaries are ~100MB+; a stray wrapper/alias script is
|
|
266
|
-
// a few hundred bytes) and prefers the most recently modified
|
|
267
|
-
// survivor. On yosemite-s0 both bugs fired together: a stale, unrelated
|
|
268
|
-
// grok-0.2.118-* file — a 99-byte wrapper that exec'd cursor-agent —
|
|
269
|
-
// sorted alphabetically before the real self-updated grok binary and
|
|
270
|
-
// was silently launched instead.
|
|
271
|
-
// v32 — every config-dir pin (claude, grok, opencode, kimi, muse, copilot) yields to
|
|
272
|
-
// an account-slot launch (AGENTS_EXEC_HOME from `agents run`), so a slot run
|
|
273
|
-
// reads and writes its own slot home instead of the shared version home.
|
|
274
166
|
export const SHIM_SCHEMA_VERSION = 33;
|
|
275
|
-
/** Internal marker string used to embed the schema version in shim scripts. */
|
|
276
167
|
const SHIM_VERSION_MARKER = 'agents-shim-version:';
|
|
277
168
|
function shellQuote(value) {
|
|
278
169
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
279
170
|
}
|
|
280
|
-
/**
|
|
281
|
-
* Bash function embedded in every generated grok binary-resolution block
|
|
282
|
-
* (the dispatcher shim's `generateShimScript` and the direct alias's
|
|
283
|
-
* `generateVersionedAliasScript`). Prints the path to use, or nothing.
|
|
284
|
-
*
|
|
285
|
-
* Prefers a `grok-*` FILENAME that carries the pinned version string —
|
|
286
|
-
* checked against `basename`, never the full path: `dir` is always
|
|
287
|
-
* `.../versions/grok/<version>/home/.grok/downloads`, so the version string
|
|
288
|
-
* is already a substring of every path in that directory regardless of the
|
|
289
|
-
* actual filename. The original `ls "$dir"/grok-* | grep -i "$version"`
|
|
290
|
-
* matched on the full line and so matched every candidate unconditionally,
|
|
291
|
-
* silently degrading to "whatever sorts first" — the versioned-home half of
|
|
292
|
-
* RUSH-2459, distinct from (and compounding) the missing-match fallback bug
|
|
293
|
-
* below.
|
|
294
|
-
*
|
|
295
|
-
* Grok self-updates its binary in place while running under the shim, so a
|
|
296
|
-
* version-home's downloads dir can accumulate several `grok-*` files whose
|
|
297
|
-
* names have drifted away from the version-home's pinned version — when no
|
|
298
|
-
* filename carries it, never trust whatever the directory listing returns
|
|
299
|
-
* first (RUSH-2459: a stale, unrelated 99-byte wrapper script matching the
|
|
300
|
-
* `grok-*` naming pattern sorted before the real ~127MB self-updated binary
|
|
301
|
-
* and was silently exec'd). Instead, reject anything under
|
|
302
|
-
* MIN_GROK_BINARY_BYTES — comfortably above any wrapper/alias artifact,
|
|
303
|
-
* comfortably below a real compiled binary — and among the survivors, pick
|
|
304
|
-
* the most recently modified: the file grok's self-updater actually wrote
|
|
305
|
-
* last. Mirrors the TS implementation, `resolveGrokFallbackBinary` in
|
|
306
|
-
* versions.ts (which reads bare filenames via `fs.readdirSync` and so never
|
|
307
|
-
* had the full-path-match bug).
|
|
308
|
-
*/
|
|
309
171
|
const GROK_RESOLVE_BINARY_FN = `_resolve_grok_current() {
|
|
310
172
|
local target
|
|
311
173
|
target=$(readlink -f "$1/bin/grok" 2>/dev/null) || return 0
|
|
@@ -340,24 +202,15 @@ _resolve_grok_binary() {
|
|
|
340
202
|
function getAgentsBinForGeneratedShim() {
|
|
341
203
|
return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'index.js');
|
|
342
204
|
}
|
|
343
|
-
/**
|
|
344
|
-
* Generate the full bash shim script for the given agent. The returned string
|
|
345
|
-
* is written to ~/.agents/shims/{cliCommand} and made executable.
|
|
346
|
-
*/
|
|
347
205
|
export function generateShimScript(agent) {
|
|
348
206
|
const agentConfig = AGENTS[agent];
|
|
349
207
|
const cliCommand = agentConfig.cliCommand;
|
|
350
|
-
// Derive the relative config-dir path from the registry. For most agents
|
|
351
|
-
// this is just `.${agent}` (e.g., `.claude`, `.codex`); for nested layouts
|
|
352
|
-
// like Antigravity (`~/.gemini/antigravity-cli`) it carries the full
|
|
353
|
-
// subpath so per-version HOME symlinks reach the right place.
|
|
354
208
|
const configDirName = path.relative(os.homedir(), agentConfig.configDir);
|
|
355
209
|
const agentsBin = shellQuote(getAgentsBinForGeneratedShim());
|
|
356
210
|
const managedEnv = resolveHarnessAdapter(agent).shimConfigEnvBash?.({ configDirName }) ?? '';
|
|
357
211
|
const launchArgs = resolveHarnessAdapter(agent).shimLaunchArgs?.() ?? '';
|
|
358
212
|
return `#!/bin/bash
|
|
359
213
|
# Auto-generated by agents-cli - do not edit
|
|
360
|
-
# Shim for ${agentConfig.name}
|
|
361
214
|
# ${SHIM_VERSION_MARKER} ${SHIM_SCHEMA_VERSION}
|
|
362
215
|
|
|
363
216
|
AGENTS_USER_DIR="\${AGENTS_USER_DIR:-$HOME/.agents}"
|
|
@@ -366,11 +219,6 @@ AGENT="${agent}"
|
|
|
366
219
|
CLI_COMMAND="${cliCommand}"
|
|
367
220
|
|
|
368
221
|
if [ -z "$AGENTS_BIN" ] || [ ! -x "$AGENTS_BIN" ]; then
|
|
369
|
-
# The baked dispatcher is gone — e.g. the build that generated this shim (often
|
|
370
|
-
# a dev build under ~/.local/agents-cli-dev) was removed, moved, or its version
|
|
371
|
-
# dir rotated. Self-recover to whatever 'agents' now resolves to on PATH instead
|
|
372
|
-
# of bricking every managed launch. 'agents' is the CLI itself, never a per-agent
|
|
373
|
-
# shim, so this cannot re-enter this dispatcher.
|
|
374
222
|
RECOVERED_BIN="$(command -v agents 2>/dev/null || true)"
|
|
375
223
|
if [ -n "$RECOVERED_BIN" ] && [ -x "$RECOVERED_BIN" ]; then
|
|
376
224
|
AGENTS_BIN="$RECOVERED_BIN"
|
|
@@ -381,27 +229,14 @@ if [ -z "$AGENTS_BIN" ] || [ ! -x "$AGENTS_BIN" ]; then
|
|
|
381
229
|
fi
|
|
382
230
|
fi
|
|
383
231
|
|
|
384
|
-
# When agents-cli "adopts" a harness's own launcher (symlinks the native binary
|
|
385
|
-
# in ~/.local/bin to this dispatcher so version management wins regardless of
|
|
386
|
-
# PATH order), it records the real original here. Durable (.history, not the
|
|
387
|
-
# regenerable .cache) so the reverse pointer survives a cache wipe. Line 1 is
|
|
388
|
-
# the original binary (what we fall through to); line 2 is the launcher path
|
|
389
|
-
# (used by --release). It is the only safe fall-through target: exec it by
|
|
390
|
-
# ABSOLUTE PATH so we never re-resolve through PATH (which now points back at
|
|
391
|
-
# this dispatcher → infinite re-exec loop).
|
|
392
232
|
ADOPTED_ORIGINAL="$AGENTS_USER_DIR/.history/adopted-launchers/$CLI_COMMAND"
|
|
393
|
-
# Print the recorded original binary iff it is an executable file, else nothing.
|
|
394
233
|
adopted_original_bin() {
|
|
395
234
|
[ -f "$ADOPTED_ORIGINAL" ] || return 1
|
|
396
235
|
local orig
|
|
397
|
-
# First line only — line 2 (launcher path) is for --release, not exec.
|
|
398
236
|
IFS= read -r orig < "$ADOPTED_ORIGINAL" 2>/dev/null || return 1
|
|
399
237
|
[ -n "$orig" ] && [ -x "$orig" ] || return 1
|
|
400
238
|
printf '%s' "$orig"
|
|
401
239
|
}
|
|
402
|
-
# Last-resort fall-through: if a managed version can't be resolved but we've
|
|
403
|
-
# adopted this command's native launcher, run the original so the user's command
|
|
404
|
-
# never breaks. Replaces the process; returns non-zero only when no usable record.
|
|
405
240
|
exec_adopted_original() {
|
|
406
241
|
local orig
|
|
407
242
|
orig=$(adopted_original_bin) || return 1
|
|
@@ -415,7 +250,6 @@ find_project_version() {
|
|
|
415
250
|
while [ "$dir" != "/" ]; do
|
|
416
251
|
local candidate="$dir/agents.yaml"
|
|
417
252
|
if [ -f "$candidate" ] && [ "$candidate" != "$user_agents_yaml" ]; then
|
|
418
|
-
# Parse agents: section — same shape as resolve_default_version()
|
|
419
253
|
local version
|
|
420
254
|
version=$(awk -v agent="$AGENT" '
|
|
421
255
|
/^agents:/ { in_agents=1; next }
|
|
@@ -432,7 +266,6 @@ find_project_version() {
|
|
|
432
266
|
return 1
|
|
433
267
|
}
|
|
434
268
|
|
|
435
|
-
# Parse the agents: default map of one agents.yaml for this AGENT's version.
|
|
436
269
|
parse_agents_default() {
|
|
437
270
|
local meta="$1"
|
|
438
271
|
[ -f "$meta" ] || return 0
|
|
@@ -443,18 +276,9 @@ parse_agents_default() {
|
|
|
443
276
|
' "$meta"
|
|
444
277
|
}
|
|
445
278
|
|
|
446
|
-
# Parse the pins JSON (~/.agents/.history/devices/pins-<machine>.json) for this
|
|
447
|
-
# AGENT's pinned version. The file is JSON.stringify(…, 2) output, so the
|
|
448
|
-
# "agents" map sits at 2-space indent and its entries at 4 — a stable shape the
|
|
449
|
-
# awk below scrapes without a JSON parser (shims must stay dependency-free).
|
|
450
279
|
parse_pins_default() {
|
|
451
280
|
local pins="$1"
|
|
452
281
|
[ -f "$pins" ] || return 0
|
|
453
|
-
# Scope carefully: enter ONLY on a line that opens the agents block
|
|
454
|
-
# ( "agents": {) — an inline-empty map ("agents": {}) must NOT enter,
|
|
455
|
-
# or the needle would leak into a following "isolatedAgents" block and an
|
|
456
|
-
# isolated pin would masquerade as the global default. Exit at the block's
|
|
457
|
-
# closing brace (a trailing comma is fine). Entries sit at exactly 4 spaces.
|
|
458
282
|
awk -v agent="$AGENT" '
|
|
459
283
|
/^ "agents": [{]$/ { in_agents=1; next }
|
|
460
284
|
in_agents && /^ }/ { exit }
|
|
@@ -469,23 +293,12 @@ parse_pins_default() {
|
|
|
469
293
|
' "$pins"
|
|
470
294
|
}
|
|
471
295
|
|
|
472
|
-
# This machine's device id — mirrors machineId()/normalizeHost() in
|
|
473
|
-
# src/lib/machine-id.ts: first hostname label, lowercased, non-[a-z0-9_-] -> '-'.
|
|
474
|
-
# MUST stay in sync or the shim reads the wrong device folder.
|
|
475
296
|
machine_id() {
|
|
476
297
|
local raw="\${AGENTS_SYNC_MACHINE_ID:-$(hostname 2>/dev/null)}"
|
|
477
|
-
# first label -> trim -> lowercase -> non-[a-z0-9_-] to '-' (matches normalizeHost order).
|
|
478
298
|
raw=$(printf '%s' "$raw" | cut -d. -f1 | sed 's/^[[:space:]]*//; s/[[:space:]]*$//' | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/-/g')
|
|
479
299
|
[ -n "$raw" ] && printf '%s' "$raw" || printf 'unknown'
|
|
480
300
|
}
|
|
481
301
|
|
|
482
|
-
# Resolve the default version. The agents: version pins are MACHINE-LOCAL runtime
|
|
483
|
-
# state at .history/devices/pins-<machine>.json (untracked — auto-written pins in
|
|
484
|
-
# the tracked device doc caused commit churn); read that first, then fall back to
|
|
485
|
-
# the tracked device doc (installs not yet migrated) and finally the central
|
|
486
|
-
# agents.yaml (pre-split installs). Must match readMeta()'s central+pins merge in
|
|
487
|
-
# state.ts -- reading only the central file (the old behavior) missed every device
|
|
488
|
-
# pin and made the shim re-prompt "no default set" on every launch.
|
|
489
302
|
resolve_default_version() {
|
|
490
303
|
local v
|
|
491
304
|
v=$(parse_pins_default "$AGENTS_USER_DIR/.history/devices/pins-$(machine_id).json")
|
|
@@ -494,8 +307,6 @@ resolve_default_version() {
|
|
|
494
307
|
printf '%s' "$v"
|
|
495
308
|
}
|
|
496
309
|
|
|
497
|
-
# Find the latest installed version by numeric component comparison.
|
|
498
|
-
# Handles both semver (2.1.138) and date-based (2026.5.7) version strings.
|
|
499
310
|
find_latest_installed() {
|
|
500
311
|
local versions_dir="$AGENTS_USER_DIR/.history/versions/$AGENT"
|
|
501
312
|
[ -d "$versions_dir" ] || return
|
|
@@ -519,7 +330,6 @@ find_latest_installed() {
|
|
|
519
330
|
'
|
|
520
331
|
}
|
|
521
332
|
|
|
522
|
-
# Try project version first, then global default
|
|
523
333
|
VERSION=$(find_project_version)
|
|
524
334
|
VERSION_SOURCE="project"
|
|
525
335
|
if [ -z "$VERSION" ]; then
|
|
@@ -552,8 +362,6 @@ if [ -z "$VERSION" ]; then
|
|
|
552
362
|
exit 1
|
|
553
363
|
fi
|
|
554
364
|
else
|
|
555
|
-
# No managed version at all. If we adopted this command's native launcher,
|
|
556
|
-
# run it so the command keeps working; otherwise report it's unconfigured.
|
|
557
365
|
exec_adopted_original "$@"
|
|
558
366
|
echo "agents: no version of $AGENT configured" >&2
|
|
559
367
|
echo " Run: agents add $AGENT@<version>" >&2
|
|
@@ -568,25 +376,13 @@ fi
|
|
|
568
376
|
|
|
569
377
|
VERSION_DIR="$AGENTS_USER_DIR/.history/versions/$AGENT/$VERSION"
|
|
570
378
|
|
|
571
|
-
# Grok special case: binary lives in the versioned home's .grok/downloads (or,
|
|
572
|
-
# for pre-fix installs, the global ~/.grok/downloads), not node_modules. We
|
|
573
|
-
# still use the agents-cli version dir purely for GROK_HOME isolation.
|
|
574
379
|
if [ "$AGENT" = "grok" ]; then
|
|
575
380
|
${GROK_RESOLVE_BINARY_FN}
|
|
576
|
-
# Check the versioned home first — this is where the binary lands when the
|
|
577
|
-
# installer runs with GROK_HOME set (i.e. via the shim or a correct
|
|
578
|
-
# \`agents add grok\`), or when grok self-updates from within the shim.
|
|
579
|
-
# \`bin/grok\` is grok's own current-release pointer, kept by its updater in
|
|
580
|
-
# both layouts (\`bin/grok -> ../downloads/grok-<v>-<arch>\` and the newer
|
|
581
|
-
# \`bin/grok -> grok-<v>\`); \`grok update\` never touches downloads/ in the
|
|
582
|
-
# newer one, so scanning downloads/ alone keeps exec'ing a dead release.
|
|
583
381
|
BINARY=$(_resolve_grok_current "$VERSION_DIR/home/.grok")
|
|
584
382
|
GROK_DOWNLOADS="$VERSION_DIR/home/.grok/downloads"
|
|
585
383
|
if [ -z "$BINARY" ] && [ -d "$GROK_DOWNLOADS" ]; then
|
|
586
384
|
BINARY=$(_resolve_grok_binary "$GROK_DOWNLOADS" "$VERSION")
|
|
587
385
|
fi
|
|
588
|
-
# Fall back to the global grok home (binary installed without GROK_HOME set,
|
|
589
|
-
# e.g. an earlier \`agents add grok@latest\` before this resolution fix).
|
|
590
386
|
if [ -z "$BINARY" ] || [ ! -x "$BINARY" ]; then
|
|
591
387
|
BINARY=$(_resolve_grok_current "$HOME/.grok")
|
|
592
388
|
fi
|
|
@@ -597,37 +393,15 @@ ${GROK_RESOLVE_BINARY_FN}
|
|
|
597
393
|
fi
|
|
598
394
|
fi
|
|
599
395
|
if [ -z "$BINARY" ] || [ ! -x "$BINARY" ]; then
|
|
600
|
-
# Last resort: the adopted native launcher (recorded absolute path) if we
|
|
601
|
-
# adopted grok, else whatever is on PATH. Prefer the adopted record — after
|
|
602
|
-
# adoption, "command -v grok" resolves to the ~/.local/bin symlink that now
|
|
603
|
-
# points at THIS dispatcher, so exec-ing it would re-enter and spin forever.
|
|
604
396
|
BINARY=$(adopted_original_bin || echo "")
|
|
605
397
|
if [ -z "$BINARY" ]; then
|
|
606
398
|
BINARY=$(command -v grok 2>/dev/null || echo "")
|
|
607
|
-
# Refuse anything that resolves into our own shims dir (the dispatcher).
|
|
608
399
|
case "$(command -v "$BINARY" 2>/dev/null; readlink -f "$BINARY" 2>/dev/null)" in
|
|
609
400
|
*"$AGENTS_USER_DIR/.cache/shims/"*) BINARY="" ;;
|
|
610
401
|
esac
|
|
611
402
|
fi
|
|
612
403
|
fi
|
|
613
|
-
# Kimi is a normal npm agent: "agents add kimi" npm-installs
|
|
614
|
-
# @moonshot-ai/kimi-code into the version dir and the binary lands at
|
|
615
|
-
# node_modules/.bin/kimi (a curl-installed kimi is symlinked to the same spot
|
|
616
|
-
# by installVersion). So kimi resolves via the generic node_modules branch
|
|
617
|
-
# below -- never a bespoke ~/.kimi-code/bin path that does not exist for npm
|
|
618
|
-
# installs and fell back to "command -v kimi", which resolves to THIS
|
|
619
|
-
# dispatcher (shims dir is ahead on PATH) and re-execs forever. Only
|
|
620
|
-
# KIMI_CODE_HOME (config isolation) stays special-cased, separately below.
|
|
621
|
-
# Droid (Factory AI) special case: the official installer drops a standalone
|
|
622
|
-
# native binary at ~/.local/bin/droid — there is no npm package and nothing
|
|
623
|
-
# lands in node_modules/.bin. Resolve the fixed install path directly. The
|
|
624
|
-
# PATH fallback explicitly refuses anything under our own shims dir: that path
|
|
625
|
-
# IS this dispatcher, so exec'ing it would re-enter and spin in an infinite
|
|
626
|
-
# re-exec loop (the bug this branch fixes).
|
|
627
404
|
elif [ "$AGENT" = "droid" ]; then
|
|
628
|
-
# Prefer the adopted record first: if droid's ~/.local/bin/droid launcher was
|
|
629
|
-
# adopted, that fixed path now points at THIS dispatcher, so using it directly
|
|
630
|
-
# would infinite-loop. The record holds the real original binary.
|
|
631
405
|
BINARY=$(adopted_original_bin || echo "")
|
|
632
406
|
if [ -z "$BINARY" ]; then
|
|
633
407
|
DROID_BINARY="$HOME/.local/bin/droid"
|
|
@@ -641,9 +415,6 @@ elif [ "$AGENT" = "droid" ]; then
|
|
|
641
415
|
fi
|
|
642
416
|
fi
|
|
643
417
|
elif [ "$AGENT" = "muse" ]; then
|
|
644
|
-
# Muse Code installs a self-updating launcher at ~/.local/bin/muse (curl
|
|
645
|
-
# installer from dev.meta.ai). No npm package. Same shims-dir re-exec guard
|
|
646
|
-
# as droid.
|
|
647
418
|
BINARY=$(adopted_original_bin || echo "")
|
|
648
419
|
if [ -z "$BINARY" ]; then
|
|
649
420
|
MUSE_BINARY="$HOME/.local/bin/muse"
|
|
@@ -657,9 +428,6 @@ elif [ "$AGENT" = "muse" ]; then
|
|
|
657
428
|
fi
|
|
658
429
|
fi
|
|
659
430
|
elif [ "$AGENT" = "warp" ]; then
|
|
660
|
-
# Warp Agent CLI installs a global, self-updating warp binary at
|
|
661
|
-
# ~/.local/bin/warp (curl installer) -- like droid/muse -- so resolve it from
|
|
662
|
-
# PATH with the same shims-dir re-exec guard as droid/muse.
|
|
663
431
|
BINARY=$(adopted_original_bin || echo "")
|
|
664
432
|
if [ -z "$BINARY" ]; then
|
|
665
433
|
BINARY=$(command -v warp 2>/dev/null || echo "")
|
|
@@ -671,10 +439,6 @@ else
|
|
|
671
439
|
BINARY="$VERSION_DIR/node_modules/.bin/$CLI_COMMAND"
|
|
672
440
|
fi
|
|
673
441
|
|
|
674
|
-
# A managed binary must never resolve back into this dispatcher. This can
|
|
675
|
-
# happen when an install-script launcher was imported before adoption and was
|
|
676
|
-
# later repointed at the agents shim. Use the durable native target recorded by
|
|
677
|
-
# adoption instead of recursively exec-ing this script.
|
|
678
442
|
if [ -x "$BINARY" ]; then
|
|
679
443
|
RESOLVED_BINARY=$(realpath "$BINARY" 2>/dev/null || readlink -f "$BINARY" 2>/dev/null || echo "")
|
|
680
444
|
RESOLVED_SHIM=$(realpath "$AGENTS_USER_DIR/.cache/shims/$CLI_COMMAND" 2>/dev/null || readlink -f "$AGENTS_USER_DIR/.cache/shims/$CLI_COMMAND" 2>/dev/null || echo "")
|
|
@@ -683,12 +447,10 @@ if [ -x "$BINARY" ]; then
|
|
|
683
447
|
fi
|
|
684
448
|
fi
|
|
685
449
|
|
|
686
|
-
# Auto-install if not present
|
|
687
450
|
if [ ! -x "$BINARY" ]; then
|
|
688
451
|
if [ "$VERSION_SOURCE" = "project" ]; then
|
|
689
452
|
echo "agents: $AGENT@$VERSION required by agents.yaml but not installed" >&2
|
|
690
453
|
|
|
691
|
-
# Spinner animation
|
|
692
454
|
spin() {
|
|
693
455
|
local pid=$1
|
|
694
456
|
local chars="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
|
|
@@ -700,7 +462,6 @@ if [ ! -x "$BINARY" ]; then
|
|
|
700
462
|
printf "\\r" >&2
|
|
701
463
|
}
|
|
702
464
|
|
|
703
|
-
# Run install in background with spinner
|
|
704
465
|
"$AGENTS_BIN" add "$AGENT@$VERSION" --yes >/dev/null 2>&1 &
|
|
705
466
|
install_pid=$!
|
|
706
467
|
spin $install_pid
|
|
@@ -750,18 +511,6 @@ fi
|
|
|
750
511
|
|
|
751
512
|
${managedEnv}
|
|
752
513
|
|
|
753
|
-
# Project-scoped compile (rules, workspace resources, scoped plugin marketplaces).
|
|
754
|
-
# Skip-fast: if a sentinel from the last sync exists and is newer than all
|
|
755
|
-
# source dirs (project .agents/, user plugins, system plugins), exec the
|
|
756
|
-
# agent binary directly without spawning node. Cuts steady-state hot-path
|
|
757
|
-
# latency from ~680ms (node startup + agents-cli module init) to ~11ms (a
|
|
758
|
-
# handful of stat calls). Never blocks launch on failure of the sync itself.
|
|
759
|
-
#
|
|
760
|
-
# Known limitation: POSIX dir mtime updates only on entry add/remove at that
|
|
761
|
-
# level. Deep edits to existing plugin contents (e.g. editing a SKILL.md
|
|
762
|
-
# inside a plugin) won't bump the parent dir's mtime — the marketplace copy
|
|
763
|
-
# stays stale until \`agents sync\` runs explicitly or a top-level entry
|
|
764
|
-
# changes. Advanced users hot-iterating on plugins know to run sync.
|
|
765
514
|
PROJECT_SLUG=\$(printf '%s' "\$PWD" | tr / _ | tr ' ' _)
|
|
766
515
|
LAUNCH_SENTINEL="\$AGENTS_USER_DIR/.cache/launch-sync/\${AGENT}@\${VERSION}@\${PROJECT_SLUG}"
|
|
767
516
|
LAUNCH_SKIP=0
|
|
@@ -778,17 +527,6 @@ if [ "\$LAUNCH_SKIP" = "0" ]; then
|
|
|
778
527
|
"\$AGENTS_BIN" sync --agent "\$AGENT" --agent-version "\$VERSION" --launch --cwd "\$PWD" --quiet 2>/dev/null || true
|
|
779
528
|
fi
|
|
780
529
|
|
|
781
|
-
# Register a launch lease for THIS pid before the exec below replaces this
|
|
782
|
-
# process image (PHNX-3940) — \$\$ survives exec, so the lease's pid matches
|
|
783
|
-
# the real running binary. Takes the SAME per-installation lock the automatic
|
|
784
|
-
# background update uses for its whole stage->commit transaction, so this
|
|
785
|
-
# call blocks here (never past the exec below) for as long as an update of
|
|
786
|
-
# this exact installation is actively in flight, and otherwise returns almost
|
|
787
|
-
# immediately. Unlike the sync call above, this is NOT best-effort: silently
|
|
788
|
-
# falling through on failure (a lock the updater is genuinely still holding,
|
|
789
|
-
# or any other error) would let this process exec straight into a binary an
|
|
790
|
-
# update could be mid-swap on — exactly the race this exists to close. Fail
|
|
791
|
-
# closed instead.
|
|
792
530
|
if ! "\$AGENTS_BIN" __launch-lease "\$AGENT" "\$VERSION" "\$\$"; then
|
|
793
531
|
echo "agents: could not safely coordinate this launch with a possibly in-progress update of \$AGENT@\$VERSION." >&2
|
|
794
532
|
echo " Check: agents update \$AGENT@\$VERSION --check Retry once any update finishes." >&2
|
|
@@ -798,23 +536,12 @@ fi
|
|
|
798
536
|
${resolveHarnessAdapter(agent).shimExecTail?.(launchArgs) ?? `exec "$BINARY"${launchArgs} "$@"`}
|
|
799
537
|
`;
|
|
800
538
|
}
|
|
801
|
-
/**
|
|
802
|
-
* Which shim files to materialize for a platform. Pure — testable on any host.
|
|
803
|
-
*
|
|
804
|
-
* POSIX writes the extensionless `#!/bin/bash` shim — the file PATH resolution
|
|
805
|
-
* execs. Windows writes only the `.cmd` companion: PATHEXT makes it the runnable
|
|
806
|
-
* form, and the bash file (mode 0o755 is a no-op there) is never executed — so
|
|
807
|
-
* emitting it is dead weight that only ever confuses `where agents`.
|
|
808
|
-
*/
|
|
809
539
|
export function shimTargetsFor(platform) {
|
|
810
540
|
if (platform === 'win32')
|
|
811
541
|
return { bash: false, cmd: true };
|
|
812
542
|
return { bash: true, cmd: false };
|
|
813
543
|
}
|
|
814
|
-
/** Create the shim(s) for an agent. */
|
|
815
544
|
export function createShim(agent) {
|
|
816
|
-
// A bare shim puts agents-cli first on PATH for this agent — the opposite of what
|
|
817
|
-
// an isolated-only install promises.
|
|
818
545
|
assertIsolationBoundary(agent, 'create the bare shim');
|
|
819
546
|
ensureAgentsDir();
|
|
820
547
|
const shimsDir = getShimsDir();
|
|
@@ -824,27 +551,15 @@ export function createShim(agent) {
|
|
|
824
551
|
if (targets.bash) {
|
|
825
552
|
fs.writeFileSync(shimPath, generateShimScript(agent), { mode: 0o755 });
|
|
826
553
|
}
|
|
827
|
-
// Windows can't execute the bash shim directly. Drop a `.cmd` companion — which
|
|
828
|
-
// delegates to the node-side transparent resolver (`agents __shim`) so version
|
|
829
|
-
// resolution stays single-sourced instead of reimplemented in batch — and skip
|
|
830
|
-
// the vestigial bash file entirely.
|
|
831
554
|
if (targets.cmd) {
|
|
832
555
|
writeWindowsCmdShim(shimPath + '.cmd', agentConfig.cliCommand);
|
|
833
556
|
}
|
|
834
557
|
return shimPath;
|
|
835
558
|
}
|
|
836
|
-
// ─── White-label brand shims ──────────────────────────────────────────────────
|
|
837
|
-
// A brand shim is a PURE pass-through: unlike an agent shim (which resolves a
|
|
838
|
-
// version and execs the agent binary) or an alias shim (which injects a fixed
|
|
839
|
-
// subcommand), it forwards argv verbatim to the agents-cli entrypoint with
|
|
840
|
-
// `AGENTS_BRAND` set, so `<brand> <any-verb>` behaves exactly like
|
|
841
|
-
// `agents <any-verb>` but presents under the brand's name. See lib/brand.ts.
|
|
842
559
|
const BRAND_SHIM_MARKER = '# Brand shim:';
|
|
843
|
-
/** The POSIX pass-through shim for a brand. */
|
|
844
560
|
export function generateBrandShim(name) {
|
|
845
561
|
const agentsBin = shellQuote(getAgentsBinForGeneratedShim());
|
|
846
562
|
return `#!/bin/sh
|
|
847
|
-
# Auto-generated by agents-cli - do not edit
|
|
848
563
|
${BRAND_SHIM_MARKER} ${name} -> agents-cli (white-label)
|
|
849
564
|
AGENTS_BIN=${agentsBin}
|
|
850
565
|
if [ -z "$AGENTS_BIN" ] || [ ! -x "$AGENTS_BIN" ]; then
|
|
@@ -855,7 +570,6 @@ export AGENTS_BRAND=${name}
|
|
|
855
570
|
exec "$AGENTS_BIN" "$@"
|
|
856
571
|
`;
|
|
857
572
|
}
|
|
858
|
-
/** Write a brand's pass-through shim(s) onto PATH; returns the shim path. */
|
|
859
573
|
export function createBrandShim(name) {
|
|
860
574
|
ensureAgentsDir();
|
|
861
575
|
const shimsDir = getShimsDir();
|
|
@@ -869,7 +583,6 @@ export function createBrandShim(name) {
|
|
|
869
583
|
}
|
|
870
584
|
return shimPath;
|
|
871
585
|
}
|
|
872
|
-
/** Windows `.cmd` pass-through: set AGENTS_BRAND then forward argv to the entrypoint. */
|
|
873
586
|
function writeWindowsBrandShim(cmdPath, name) {
|
|
874
587
|
const indexJs = getAgentsBinForGeneratedShim();
|
|
875
588
|
const content = `@echo off\r\n` +
|
|
@@ -879,7 +592,6 @@ function writeWindowsBrandShim(cmdPath, name) {
|
|
|
879
592
|
`node "${indexJs}" %*\r\n`;
|
|
880
593
|
fs.writeFileSync(cmdPath, content);
|
|
881
594
|
}
|
|
882
|
-
/** True when the file at the given path is an agents-cli brand shim. */
|
|
883
595
|
export function isBrandShim(filePath) {
|
|
884
596
|
try {
|
|
885
597
|
const head = fs.readFileSync(filePath, 'utf-8').slice(0, 300);
|
|
@@ -889,7 +601,6 @@ export function isBrandShim(filePath) {
|
|
|
889
601
|
return false;
|
|
890
602
|
}
|
|
891
603
|
}
|
|
892
|
-
/** Remove a brand's shim companions. Returns true if anything was removed. */
|
|
893
604
|
export function removeBrandShim(name) {
|
|
894
605
|
const shimsDir = getShimsDir();
|
|
895
606
|
const shimPath = path.join(shimsDir, name);
|
|
@@ -902,23 +613,11 @@ export function removeBrandShim(name) {
|
|
|
902
613
|
}
|
|
903
614
|
return removed;
|
|
904
615
|
}
|
|
905
|
-
// ── gh overload shim ────────────────────────────────────────────────────────
|
|
906
|
-
// A transparent interceptor for the ONE thing that keeps rate-limiting the fleet:
|
|
907
|
-
// agents' trained `gh pr checks`. It routes that (and only that) to REST via
|
|
908
|
-
// `agents __gh`, and execs the real gh for everything else. Agents keep their
|
|
909
|
-
// habit; we decide what it runs. See cli/src/lib/github/gh-overload.ts + PHNX-3501.
|
|
910
616
|
const GH_OVERLOAD_MARKER = '# gh overload shim:';
|
|
911
|
-
/**
|
|
912
|
-
* The POSIX gh overload shim. Self-healing by construction: it resolves the real
|
|
913
|
-
* gh (first `gh` on PATH that is not this shims dir) and execs it directly whenever
|
|
914
|
-
* agents-cli is gone, the sentinel is already set (recursion), or the verb is
|
|
915
|
-
* anything but `pr checks` — so a leftover/orphaned shim can never break `gh`.
|
|
916
|
-
*/
|
|
917
617
|
export function generateGhOverloadShim() {
|
|
918
618
|
const agentsBin = shellQuote(getAgentsBinForGeneratedShim());
|
|
919
619
|
const shimsDir = shellQuote(getShimsDir());
|
|
920
620
|
return `#!/bin/sh
|
|
921
|
-
# Auto-generated by agents-cli - do not edit
|
|
922
621
|
${GH_OVERLOAD_MARKER} routes 'gh pr checks' to REST via 'agents __gh' (GraphQL rate-limit escape)
|
|
923
622
|
AGENTS_BIN=${agentsBin}
|
|
924
623
|
SHIMS_DIR=${shimsDir}
|
|
@@ -931,15 +630,10 @@ find_real_gh() {
|
|
|
931
630
|
IFS=$_oldifs; return 1
|
|
932
631
|
}
|
|
933
632
|
REAL_GH=$(find_real_gh)
|
|
934
|
-
# No real gh on PATH: fail loud like "command not found" (127). NEVER fall back to
|
|
935
|
-
# the bare string 'gh' — on a gh-less box that resolves to THIS shim and loops.
|
|
936
633
|
if [ -z "$REAL_GH" ]; then
|
|
937
634
|
echo "gh: not found (agents-cli gh overload: no real gh on PATH)" >&2
|
|
938
635
|
exit 127
|
|
939
636
|
fi
|
|
940
|
-
# Self-heal + recursion guard: agents-cli missing, or already inside the overload,
|
|
941
|
-
# or any verb other than 'pr checks' -> just be plain gh. REAL_GH is always an
|
|
942
|
-
# absolute path here, so this can never re-enter the shim.
|
|
943
637
|
if [ -n "$AGENTS_GH_SHIM" ] || [ -z "$AGENTS_BIN" ] || [ ! -x "$AGENTS_BIN" ]; then
|
|
944
638
|
exec "$REAL_GH" "$@"
|
|
945
639
|
fi
|
|
@@ -949,7 +643,6 @@ fi
|
|
|
949
643
|
exec "$REAL_GH" "$@"
|
|
950
644
|
`;
|
|
951
645
|
}
|
|
952
|
-
/** True when the file is our gh overload shim (not a user's real gh). */
|
|
953
646
|
export function isGhOverloadShim(filePath) {
|
|
954
647
|
try {
|
|
955
648
|
return fs.readFileSync(filePath, 'utf-8').slice(0, 300).includes(GH_OVERLOAD_MARKER);
|
|
@@ -958,7 +651,6 @@ export function isGhOverloadShim(filePath) {
|
|
|
958
651
|
return false;
|
|
959
652
|
}
|
|
960
653
|
}
|
|
961
|
-
/** True when a REAL `gh` binary exists on PATH outside our shims dir. */
|
|
962
654
|
function hasRealGhOnPath() {
|
|
963
655
|
const shimsDir = path.resolve(getShimsDir());
|
|
964
656
|
for (const dir of (process.env.PATH || '').split(path.delimiter)) {
|
|
@@ -970,21 +662,10 @@ function hasRealGhOnPath() {
|
|
|
970
662
|
return true;
|
|
971
663
|
}
|
|
972
664
|
catch {
|
|
973
|
-
// not here / not executable — keep scanning
|
|
974
665
|
}
|
|
975
666
|
}
|
|
976
667
|
return false;
|
|
977
668
|
}
|
|
978
|
-
/**
|
|
979
|
-
* Create/refresh the gh overload shim so a user's `gh pr checks` transparently
|
|
980
|
-
* escapes the GraphQL rate limit. POSIX only in v1 (Windows keeps native gh —
|
|
981
|
-
* resolving the real gh without recursion needs a separate `.cmd` design).
|
|
982
|
-
*
|
|
983
|
-
* Skips (returns null) when there is no real `gh` to overload — shadowing a
|
|
984
|
-
* non-existent binary would only turn a clean "command not found" into shim
|
|
985
|
-
* output. Never clobbers a non-shim `gh` a user placed in the shims dir. If a real
|
|
986
|
-
* gh later disappears, the shim itself fails loud with 127 rather than looping.
|
|
987
|
-
*/
|
|
988
669
|
export function ensureGhOverloadShim() {
|
|
989
670
|
if (!shimTargetsFor(process.platform).bash)
|
|
990
671
|
return null;
|
|
@@ -997,7 +678,6 @@ export function ensureGhOverloadShim() {
|
|
|
997
678
|
fs.writeFileSync(shimPath, generateGhOverloadShim(), { mode: 0o755 });
|
|
998
679
|
return shimPath;
|
|
999
680
|
}
|
|
1000
|
-
/** Remove the gh overload shim — real gh returns immediately. Called on uninstall. */
|
|
1001
681
|
export function removeGhOverloadShim() {
|
|
1002
682
|
const shimPath = path.join(getShimsDir(), 'gh');
|
|
1003
683
|
if (fs.existsSync(shimPath) && isGhOverloadShim(shimPath)) {
|
|
@@ -1006,18 +686,6 @@ export function removeGhOverloadShim() {
|
|
|
1006
686
|
}
|
|
1007
687
|
return false;
|
|
1008
688
|
}
|
|
1009
|
-
/**
|
|
1010
|
-
* Generate a Windows `.cmd` launcher that delegates to `agents __shim <spec>`.
|
|
1011
|
-
* `spec` is the agent's cliCommand for the default-version shim, or
|
|
1012
|
-
* `cliCommand@version` for a versioned alias. node + the dist entrypoint are
|
|
1013
|
-
* resolved at generation time so the launcher does not depend on `agents`
|
|
1014
|
-
* already being on PATH.
|
|
1015
|
-
*
|
|
1016
|
-
* `extraMarkerLines` lets callers stamp additional schema markers into the
|
|
1017
|
-
* header — versioned aliases embed their own alias-schema marker so
|
|
1018
|
-
* readVersionedAliasSchemaVersion can stat the `.cmd` (the only Windows
|
|
1019
|
-
* artifact) the same way it reads the bash script on POSIX.
|
|
1020
|
-
*/
|
|
1021
689
|
function writeWindowsCmdShim(cmdPath, spec, extraMarkerLines = []) {
|
|
1022
690
|
const indexJs = getAgentsBinForGeneratedShim();
|
|
1023
691
|
const content = `@echo off\r\n` +
|
|
@@ -1027,15 +695,10 @@ function writeWindowsCmdShim(cmdPath, spec, extraMarkerLines = []) {
|
|
|
1027
695
|
`node "${indexJs}" __shim ${spec} %*\r\n`;
|
|
1028
696
|
fs.writeFileSync(cmdPath, content);
|
|
1029
697
|
}
|
|
1030
|
-
/** Remove the shim(s) for an agent. */
|
|
1031
698
|
export function removeShim(agent) {
|
|
1032
699
|
const shimsDir = getShimsDir();
|
|
1033
700
|
const agentConfig = AGENTS[agent];
|
|
1034
701
|
const shimPath = path.join(shimsDir, agentConfig.cliCommand);
|
|
1035
|
-
// Remove whichever companions exist: the extensionless script (POSIX, or a
|
|
1036
|
-
// legacy Windows install that wrote it) AND the `.cmd` (Windows). Keying only
|
|
1037
|
-
// off the extensionless path would orphan the `.cmd` on Windows, where
|
|
1038
|
-
// createShim now writes only the `.cmd`.
|
|
1039
702
|
let removed = false;
|
|
1040
703
|
for (const p of [shimPath, shimPath + '.cmd']) {
|
|
1041
704
|
if (fs.existsSync(p)) {
|
|
@@ -1045,129 +708,21 @@ export function removeShim(agent) {
|
|
|
1045
708
|
}
|
|
1046
709
|
return removed;
|
|
1047
710
|
}
|
|
1048
|
-
/**
|
|
1049
|
-
* Current versioned-alias schema. Bump whenever `generateVersionedAliasScript`
|
|
1050
|
-
* changes in a way that requires existing on-disk aliases to be regenerated.
|
|
1051
|
-
*
|
|
1052
|
-
* History:
|
|
1053
|
-
* v1 — implicit (no marker); no CLAUDE_CONFIG_DIR export, so direct
|
|
1054
|
-
* `claude@X` invocations leaked into ~/.claude (the default version's
|
|
1055
|
-
* symlinked home) and `agents view` never saw the login.
|
|
1056
|
-
* v2 — emit CLAUDE_CONFIG_DIR for claude aliases so each version has its
|
|
1057
|
-
* own isolated config/OAuth slot; stamp a version marker so stale
|
|
1058
|
-
* aliases can be detected and regenerated.
|
|
1059
|
-
* v3 — emit CODEX_HOME for codex aliases so direct `codex@X` invocations
|
|
1060
|
-
* read the versioned permissions/rules instead of $HOME/.codex.
|
|
1061
|
-
* v4 — direct aliases read binaries and config homes from ~/.agents-system.
|
|
1062
|
-
* v5 — hard-disable Codex startup update checks in versioned aliases.
|
|
1063
|
-
* v6 — versions moved from ~/.agents-system/versions to ~/.agents/versions
|
|
1064
|
-
* (two-repo split: system = shipped defaults, user = operational state).
|
|
1065
|
-
* v7 — runtime state split into ~/.agents/.history and ~/.agents/.cache.
|
|
1066
|
-
* v8 — resolve grok/kimi/droid binaries from their real install locations
|
|
1067
|
-
* (~/.grok/downloads, ~/.kimi-code/bin, ~/.local/bin) instead of the
|
|
1068
|
-
* hardcoded node_modules/.bin, which never exists for these three and
|
|
1069
|
-
* made every versioned alias (the path `agents teams` pins to) fail
|
|
1070
|
-
* with "<agent>@<version> not installed". Also emit GROK_HOME.
|
|
1071
|
-
* v9 — kimi was wrong in v8: it npm-installs @moonshot-ai/kimi-code into
|
|
1072
|
-
* node_modules/.bin/kimi (grok/droid ship native binaries elsewhere,
|
|
1073
|
-
* kimi does not). The ~/.kimi-code/bin path never existed for an npm
|
|
1074
|
-
* install and the `command -v kimi` fallback resolved to this alias's
|
|
1075
|
-
* sibling dispatcher shim, re-exec-looping forever. Resolve kimi via the
|
|
1076
|
-
* generic node_modules/.bin branch.
|
|
1077
|
-
* v10 — guard grok's `command -v grok` fallback against resolving to our own
|
|
1078
|
-
* shims dir (same infinite re-exec loop), mirroring droid.
|
|
1079
|
-
* v11 — export DISABLE_AUTOUPDATER=1 for claude aliases so a pinned per-version
|
|
1080
|
-
* install can't self-mutate via Claude Code's background auto-updater.
|
|
1081
|
-
* Explicit user value wins.
|
|
1082
|
-
* v12 — Windows: stop writing the extensionless bash alias next to the `.cmd`
|
|
1083
|
-
* (and delete a lingering one). The version suffix contains dots, so
|
|
1084
|
-
* cmd.exe and PowerShell treat `claude@2.1.201` as a complete filename
|
|
1085
|
-
* with extension `.201`, exact-match the bash script AHEAD of PATHEXT
|
|
1086
|
-
* probing, and ShellExecute it to the `.sh` editor association — the
|
|
1087
|
-
* editor opens the script and the agent never launches. The `.cmd` is
|
|
1088
|
-
* now the only Windows artifact and carries this alias marker so
|
|
1089
|
-
* staleness checks read it directly.
|
|
1090
|
-
* v13 — grok aliases resolve the binary from the versioned home's
|
|
1091
|
-
* .grok/downloads first, then fall back to the global ~/.grok/downloads.
|
|
1092
|
-
* The old template checked only the global dir, so a `grok@<version>`
|
|
1093
|
-
* alias failed with "not installed" whenever the binary was staged into
|
|
1094
|
-
* the versioned home (installer run with GROK_HOME set, or grok
|
|
1095
|
-
* self-update under the shim).
|
|
1096
|
-
* v16 — RUSH-2459: two compounding grok binary-resolution bugs fixed. (1) The
|
|
1097
|
-
* "exact version match" grep ran against `ls`'s FULL PATH output, and
|
|
1098
|
-
* the versioned home's own path always contains the version string
|
|
1099
|
-
* (.../versions/grok/<version>/...), so it matched every candidate
|
|
1100
|
-
* unconditionally and silently degraded to "whatever ls sorts first" —
|
|
1101
|
-
* now matched against each candidate's basename instead. (2) When no
|
|
1102
|
-
* filename genuinely carries the version, the fallback no longer
|
|
1103
|
-
* trusts whatever sorts first: it rejects any grok-* candidate under
|
|
1104
|
-
* 1MB (real grok binaries are ~100MB+; a stray wrapper/alias script is
|
|
1105
|
-
* a few hundred bytes) and prefers the most recently modified
|
|
1106
|
-
* survivor. On yosemite-s0 both bugs fired together: a stale, unrelated
|
|
1107
|
-
* grok-0.2.118-* file — a 99-byte wrapper that exec'd cursor-agent —
|
|
1108
|
-
* sorted alphabetically before the real self-updated grok binary and
|
|
1109
|
-
* was silently launched instead.
|
|
1110
|
-
*/
|
|
1111
|
-
// v17 — the claude alias env now reuses the adapter's shimConfigEnvBash (adds the
|
|
1112
|
-
// Linux .oauth_token setup-token fallback the hand-copied subset had dropped),
|
|
1113
|
-
// so existing alias shims must regenerate to pick it up.
|
|
1114
|
-
// v18 — Cursor aliases select the file credential store and swap HOME to the
|
|
1115
|
-
// version home because current Cursor writes auth.json under ~/.cursor
|
|
1116
|
-
// and ignores XDG_CONFIG_HOME for credential storage.
|
|
1117
|
-
// v21 — every alias config-dir pin (claude, grok, opencode, kimi, muse, copilot)
|
|
1118
|
-
// yields to an account-slot launch (AGENTS_EXEC_HOME from `agents run`). Before,
|
|
1119
|
-
// the alias re-pinned every slot launch onto the shared version home, so a worker
|
|
1120
|
-
// run picked as one account onboarded from scratch and kept its history in
|
|
1121
|
-
// another account's home.
|
|
1122
711
|
export const VERSIONED_ALIAS_SCHEMA_VERSION = 21;
|
|
1123
|
-
/** Internal marker string used to embed the schema version in versioned alias scripts. */
|
|
1124
712
|
const VERSIONED_ALIAS_VERSION_MARKER = 'agents-versioned-alias-version:';
|
|
1125
|
-
// The version string is interpolated into a generated bash script and into
|
|
1126
|
-
// a filename. parseAgentSpec / parseVersion already validates this upstream,
|
|
1127
|
-
// but generators are also called from internal code paths (e.g., re-emit on
|
|
1128
|
-
// schema bump), so re-check here. Mirrors VERSION_RE in versions.ts.
|
|
1129
713
|
const ALIAS_VERSION_RE = /^[A-Za-z0-9._+-]{1,64}$/;
|
|
1130
714
|
function assertSafeVersion(version) {
|
|
1131
715
|
if (!ALIAS_VERSION_RE.test(version)) {
|
|
1132
716
|
throw new Error(`Refusing to generate shim for unsafe version: ${JSON.stringify(version)}`);
|
|
1133
717
|
}
|
|
1134
718
|
}
|
|
1135
|
-
/**
|
|
1136
|
-
* Agents whose config directory can be relocated by an environment variable
|
|
1137
|
-
* (the per-agent `managedEnv` block in `generateVersionedAliasScript` below).
|
|
1138
|
-
*
|
|
1139
|
-
* Only these can be installed with `agents add --isolated`: the versioned alias
|
|
1140
|
-
* points that env var at the copy's private home, so the copy never reads or
|
|
1141
|
-
* writes the user's real `~/.<agent>`. Every other agent isolates ONLY by
|
|
1142
|
-
* adopting `~/.<agent>` via a symlink — which an isolated install deliberately
|
|
1143
|
-
* skips — so an isolated copy would silently fall back to (and mutate) the real
|
|
1144
|
-
* config dir. For those agents `--isolated` is refused up front.
|
|
1145
|
-
*
|
|
1146
|
-
* KEEP IN SYNC with the `managedEnv` switch in `generateVersionedAliasScript`.
|
|
1147
|
-
* The colocated test `shims.isolation-capability.test.ts` enforces this.
|
|
1148
|
-
*/
|
|
1149
719
|
export const CONFIG_ENV_ISOLATED_AGENTS = ['claude', 'codex', 'copilot', 'cursor', 'grok', 'kimi', 'opencode', 'muse'];
|
|
1150
|
-
/**
|
|
1151
|
-
* Whether an agent supports a clean `--isolated` install — i.e. its config
|
|
1152
|
-
* location can be redirected by an env var so the isolated copy stays fully
|
|
1153
|
-
* separate from the user's real `~/.<agent>`. See {@link CONFIG_ENV_ISOLATED_AGENTS}.
|
|
1154
|
-
*/
|
|
1155
720
|
export function supportsIsolatedInstall(agent) {
|
|
1156
721
|
return CONFIG_ENV_ISOLATED_AGENTS.includes(agent);
|
|
1157
722
|
}
|
|
1158
|
-
/**
|
|
1159
|
-
* Harnesses that isolate by symlink-adopting `~/.<config>` rather than a
|
|
1160
|
-
* config-dir env (PHNX-3940 T5). One active slot per device; `accounts default`
|
|
1161
|
-
* repoints the adopted symlink under the auth-op lock.
|
|
1162
|
-
*/
|
|
1163
723
|
export function isSymlinkAdoptedHarness(agent) {
|
|
1164
724
|
return !CONFIG_ENV_ISOLATED_AGENTS.includes(agent);
|
|
1165
725
|
}
|
|
1166
|
-
/**
|
|
1167
|
-
* Repoint this harness's adopted `~/.<config>` symlink at `home`'s config dir.
|
|
1168
|
-
* No-op for env-isolated harnesses. Fails loud when the adopted path is a real
|
|
1169
|
-
* directory rather than a symlink — adopting that is `agents use`, not default.
|
|
1170
|
-
*/
|
|
1171
726
|
export function repointAdoptedConfigToHome(agent, home) {
|
|
1172
727
|
if (!isSymlinkAdoptedHarness(agent))
|
|
1173
728
|
return { success: true };
|
|
@@ -1198,14 +753,11 @@ export function repointAdoptedConfigToHome(agent, home) {
|
|
|
1198
753
|
throw err;
|
|
1199
754
|
}
|
|
1200
755
|
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
1201
|
-
// Atomic retarget: create temp symlink, rename over existing (same pattern
|
|
1202
|
-
// as switchHomeFileSymlinks). A window of "path missing" would let a
|
|
1203
|
-
// harness process observe neither the old nor the new target.
|
|
1204
756
|
const tmpPath = `${configPath}.agents-tmp-${process.pid}`;
|
|
1205
757
|
try {
|
|
1206
758
|
fs.unlinkSync(tmpPath);
|
|
1207
759
|
}
|
|
1208
|
-
catch {
|
|
760
|
+
catch { }
|
|
1209
761
|
try {
|
|
1210
762
|
fs.symlinkSync(target, tmpPath, process.platform === 'win32' ? 'junction' : undefined);
|
|
1211
763
|
fs.renameSync(tmpPath, configPath);
|
|
@@ -1214,7 +766,7 @@ export function repointAdoptedConfigToHome(agent, home) {
|
|
|
1214
766
|
try {
|
|
1215
767
|
fs.unlinkSync(tmpPath);
|
|
1216
768
|
}
|
|
1217
|
-
catch {
|
|
769
|
+
catch { }
|
|
1218
770
|
throw err;
|
|
1219
771
|
}
|
|
1220
772
|
return { success: true };
|
|
@@ -1223,16 +775,10 @@ export function repointAdoptedConfigToHome(agent, home) {
|
|
|
1223
775
|
lock.release();
|
|
1224
776
|
}
|
|
1225
777
|
}
|
|
1226
|
-
/**
|
|
1227
|
-
* Generate a versioned alias script that directly execs a specific version.
|
|
1228
|
-
* e.g., claude@2.0.65 -> directly runs that version's binary
|
|
1229
|
-
*/
|
|
1230
778
|
export function generateVersionedAliasScript(agent, version) {
|
|
1231
779
|
assertSafeVersion(version);
|
|
1232
780
|
const agentConfig = AGENTS[agent];
|
|
1233
781
|
const agentsBin = shellQuote(getAgentsBinForGeneratedShim());
|
|
1234
|
-
// Same derivation as `generateShimScript` so nested layouts (e.g.,
|
|
1235
|
-
// Antigravity's `~/.gemini/antigravity-cli`) land in the right place.
|
|
1236
782
|
const configDirName = path.relative(os.homedir(), agentConfig.configDir);
|
|
1237
783
|
const managedEnv = agent === 'claude'
|
|
1238
784
|
? `
|
|
@@ -1297,19 +843,6 @@ export AGENT_CLI_CREDENTIAL_STORE="file"
|
|
|
1297
843
|
`
|
|
1298
844
|
: '';
|
|
1299
845
|
const launchArgs = resolveHarnessAdapter(agent).shimLaunchArgs?.() ?? '';
|
|
1300
|
-
// Resolve the binary the same way the main shim does (see generateShimScript).
|
|
1301
|
-
// Grok and Droid do NOT ship into node_modules/.bin — Grok downloads a native
|
|
1302
|
-
// binary to ~/.grok/downloads and Droid (Factory AI) installs a standalone
|
|
1303
|
-
// binary to ~/.local/bin. Hardcoding the node_modules path made every
|
|
1304
|
-
// versioned alias for those two fail with "<agent>@<version> not installed",
|
|
1305
|
-
// which is exactly the path `agents teams` takes once it pins a teammate's
|
|
1306
|
-
// version. Kimi is NOT one of them: `agents add kimi` npm-installs
|
|
1307
|
-
// @moonshot-ai/kimi-code so its binary is at node_modules/.bin/kimi (the
|
|
1308
|
-
// generic branch below). The old ~/.kimi-code/bin path never exists for an
|
|
1309
|
-
// npm install and fell back to `command -v kimi`, which resolves to this
|
|
1310
|
-
// alias's sibling dispatcher shim and re-execs forever.
|
|
1311
|
-
// This template is unix-only — on Windows the .cmd companion delegates to
|
|
1312
|
-
// "agents __shim" which resolves via getBinaryPath() instead.
|
|
1313
846
|
const versionDir = `$AGENTS_REAL_HOME/.agents/.history/versions/${agent}/${version}`;
|
|
1314
847
|
const binaryResolution = agent === 'grok'
|
|
1315
848
|
? `# Grok ships its native binary in the versioned home's .grok/downloads (or,
|
|
@@ -1375,14 +908,7 @@ esac`
|
|
|
1375
908
|
return `#!/bin/bash
|
|
1376
909
|
# Auto-generated by agents-cli - do not edit
|
|
1377
910
|
# ${VERSIONED_ALIAS_VERSION_MARKER} ${VERSIONED_ALIAS_SCHEMA_VERSION}
|
|
1378
|
-
# Direct alias for ${agentConfig.name}@${version}
|
|
1379
911
|
|
|
1380
|
-
# The real home. A spawner may have swapped HOME already — an account slot
|
|
1381
|
-
# launch (PHNX-3940 T5) sets HOME to the slot dir and leaves the real home in
|
|
1382
|
-
# AGENTS_REAL_HOME — so every agents-owned path below (the installation, the
|
|
1383
|
-
# version home, the shims dir) is anchored here, never on whatever HOME is now.
|
|
1384
|
-
# Anchoring on HOME made a slot launch of cursor#<name> answer "not installed"
|
|
1385
|
-
# and the launch lease fail with "No installation directory".
|
|
1386
912
|
export AGENTS_REAL_HOME="\${AGENTS_REAL_HOME:-$HOME}"
|
|
1387
913
|
|
|
1388
914
|
${binaryResolution}
|
|
@@ -1392,11 +918,6 @@ if [ -z "$BINARY" ] || [ ! -x "$BINARY" ]; then
|
|
|
1392
918
|
exit 1
|
|
1393
919
|
fi
|
|
1394
920
|
|
|
1395
|
-
# Register a launch lease for THIS pid before the exec below (PHNX-3940) — see
|
|
1396
|
-
# generateShimScript's identical call for what this closes and why it fails
|
|
1397
|
-
# closed rather than falling through on error. \$\$ survives exec. It runs
|
|
1398
|
-
# under the REAL home, before any harness HOME swap below: agents-cli's own
|
|
1399
|
-
# state root is $HOME/.agents, so a swapped HOME cannot find the installation.
|
|
1400
921
|
if ! HOME="$AGENTS_REAL_HOME" ${agentsBin} __launch-lease "${agent}" "${version}" "\$\$"; then
|
|
1401
922
|
echo "agents: could not safely coordinate this launch with a possibly in-progress update of ${agent}@${version}." >&2
|
|
1402
923
|
echo " Check: agents update ${agent}@${version} --check Retry once any update finishes." >&2
|
|
@@ -1407,10 +928,6 @@ ${managedEnv}
|
|
|
1407
928
|
${resolveHarnessAdapter(agent).shimExecTail?.(launchArgs) ?? `exec "$BINARY"${launchArgs} "$@"`}
|
|
1408
929
|
`;
|
|
1409
930
|
}
|
|
1410
|
-
/**
|
|
1411
|
-
* Read the schema version of an on-disk versioned alias. Returns null if the
|
|
1412
|
-
* alias doesn't exist or is a pre-v2 alias (no marker — treated as stale).
|
|
1413
|
-
*/
|
|
1414
931
|
export function readVersionedAliasSchemaVersion(agent, version) {
|
|
1415
932
|
const aliasPath = versionedAliasOnDiskPath(agent, version);
|
|
1416
933
|
if (!fs.existsSync(aliasPath))
|
|
@@ -1427,33 +944,18 @@ export function readVersionedAliasSchemaVersion(agent, version) {
|
|
|
1427
944
|
return null;
|
|
1428
945
|
}
|
|
1429
946
|
}
|
|
1430
|
-
/**
|
|
1431
|
-
* True if the on-disk versioned alias matches the current schema version.
|
|
1432
|
-
*/
|
|
1433
947
|
export function isVersionedAliasCurrent(agent, version) {
|
|
1434
948
|
return readVersionedAliasSchemaVersion(agent, version) === VERSIONED_ALIAS_SCHEMA_VERSION;
|
|
1435
949
|
}
|
|
1436
|
-
/**
|
|
1437
|
-
* Regenerate a versioned alias if missing or stale. Mirrors ensureShimCurrent
|
|
1438
|
-
* for the main shim — callers can surface a one-line notice when something
|
|
1439
|
-
* was upgraded.
|
|
1440
|
-
*/
|
|
1441
950
|
export function ensureVersionedAliasCurrent(agent, version) {
|
|
1442
951
|
if (!fs.existsSync(versionedAliasOnDiskPath(agent, version))) {
|
|
1443
952
|
createVersionedAlias(agent, version);
|
|
1444
953
|
return 'created';
|
|
1445
954
|
}
|
|
1446
|
-
// A lingering extensionless bash alias on Windows shadows the `.cmd` in both
|
|
1447
|
-
// cmd.exe and PowerShell (the dotted version reads as a file extension, and
|
|
1448
|
-
// an exact filename match beats PATHEXT probing), ShellExecuting the bash
|
|
1449
|
-
// script to the `.sh` editor association instead of launching the agent.
|
|
1450
|
-
// Regenerate regardless of the `.cmd`'s stamp so the shadow gets deleted.
|
|
1451
955
|
if (shimTargetsFor(process.platform).cmd && fs.existsSync(getVersionedAliasPath(agent, version))) {
|
|
1452
956
|
createVersionedAlias(agent, version);
|
|
1453
957
|
return 'updated';
|
|
1454
958
|
}
|
|
1455
|
-
// Upgrade-only (newest-wins), same rationale as ensureShimCurrent: never
|
|
1456
|
-
// downgrade an alias stamped by a newer install sharing the shims dir.
|
|
1457
959
|
const onDisk = readVersionedAliasSchemaVersion(agent, version);
|
|
1458
960
|
if (onDisk === null || onDisk < VERSIONED_ALIAS_SCHEMA_VERSION) {
|
|
1459
961
|
createVersionedAlias(agent, version);
|
|
@@ -1461,40 +963,16 @@ export function ensureVersionedAliasCurrent(agent, version) {
|
|
|
1461
963
|
}
|
|
1462
964
|
return 'current';
|
|
1463
965
|
}
|
|
1464
|
-
/**
|
|
1465
|
-
* Get the filesystem path for a versioned alias script — the logical
|
|
1466
|
-
* (extensionless) launch name. On Windows this is not a real file (see
|
|
1467
|
-
* versionedAliasOnDiskFile); stat/read checks must use the on-disk path.
|
|
1468
|
-
*/
|
|
1469
966
|
export function getVersionedAliasPath(agent, version) {
|
|
1470
967
|
return path.join(getShimsDir(), `${AGENTS[agent].cliCommand}@${version}`);
|
|
1471
968
|
}
|
|
1472
|
-
/**
|
|
1473
|
-
* The file createVersionedAlias actually materializes for a platform:
|
|
1474
|
-
* `<cmd>@<version>.cmd` on Windows, the bare bash script on POSIX. Pure —
|
|
1475
|
-
* testable on any host. Mirrors onDiskShimFile for the main shim.
|
|
1476
|
-
*/
|
|
1477
969
|
export function versionedAliasOnDiskFile(cliCommand, version, platform) {
|
|
1478
970
|
const name = `${cliCommand}@${version}`;
|
|
1479
971
|
return shimTargetsFor(platform).cmd ? `${name}.cmd` : name;
|
|
1480
972
|
}
|
|
1481
|
-
/** The on-disk versioned-alias path for the current platform. */
|
|
1482
973
|
function versionedAliasOnDiskPath(agent, version) {
|
|
1483
974
|
return path.join(getShimsDir(), versionedAliasOnDiskFile(AGENTS[agent].cliCommand, version, process.platform));
|
|
1484
975
|
}
|
|
1485
|
-
/**
|
|
1486
|
-
* Create a versioned alias for a specific agent version.
|
|
1487
|
-
* e.g., claude@2.0.65
|
|
1488
|
-
*
|
|
1489
|
-
* Same platform split as createShim (shimTargetsFor): POSIX writes the
|
|
1490
|
-
* extensionless bash script; Windows writes ONLY the `.cmd`. Unlike the main
|
|
1491
|
-
* shim — where the bash file was merely dead weight — a bash alias next to the
|
|
1492
|
-
* versioned `.cmd` is actively harmful: the dotted version suffix makes
|
|
1493
|
-
* cmd.exe/PowerShell treat `claude@2.1.201` as a complete filename (extension
|
|
1494
|
-
* `.201`), so the exact match wins over PATHEXT probing and the shell
|
|
1495
|
-
* ShellExecutes the bash script to the `.sh` editor association — the editor
|
|
1496
|
-
* opens, the agent never launches. Any legacy bash alias is deleted here.
|
|
1497
|
-
*/
|
|
1498
976
|
export function createVersionedAlias(agent, version) {
|
|
1499
977
|
assertSafeVersion(version);
|
|
1500
978
|
ensureAgentsDir();
|
|
@@ -1516,11 +994,6 @@ export function createVersionedAlias(agent, version) {
|
|
|
1516
994
|
}
|
|
1517
995
|
return aliasPath;
|
|
1518
996
|
}
|
|
1519
|
-
/**
|
|
1520
|
-
* Remove a versioned alias for a specific agent version. Removes whichever
|
|
1521
|
-
* companions exist — the extensionless script (POSIX, or a legacy Windows
|
|
1522
|
-
* install that wrote it) AND the `.cmd` (Windows) — mirroring removeShim.
|
|
1523
|
-
*/
|
|
1524
997
|
export function removeVersionedAlias(agent, version) {
|
|
1525
998
|
const aliasPath = getVersionedAliasPath(agent, version);
|
|
1526
999
|
let removed = false;
|
|
@@ -1532,40 +1005,18 @@ export function removeVersionedAlias(agent, version) {
|
|
|
1532
1005
|
}
|
|
1533
1006
|
return removed;
|
|
1534
1007
|
}
|
|
1535
|
-
/**
|
|
1536
|
-
* Check if a versioned alias exists (the on-disk artifact for this platform).
|
|
1537
|
-
*/
|
|
1538
1008
|
export function versionedAliasExists(agent, version) {
|
|
1539
1009
|
return fs.existsSync(versionedAliasOnDiskPath(agent, version));
|
|
1540
1010
|
}
|
|
1541
|
-
/** Get the agent's config directory path in HOME (e.g. ~/.claude). */
|
|
1542
1011
|
export function getAgentConfigPath(agent) {
|
|
1543
1012
|
const agentConfig = AGENTS[agent];
|
|
1544
1013
|
const home = process.env.AGENTS_REAL_HOME || os.homedir();
|
|
1545
1014
|
return agentConfig.configDir.replace(os.homedir(), home);
|
|
1546
1015
|
}
|
|
1547
|
-
/**
|
|
1548
|
-
* Read the user's configured Codex model from their active `~/.codex/config.toml`.
|
|
1549
|
-
*
|
|
1550
|
-
* Codex runs under a per-version `CODEX_HOME` (see `buildExecEnv`). A dispatch
|
|
1551
|
-
* pinned to a version whose home config lacks a top-level `model` key silently
|
|
1552
|
-
* falls back to Codex's built-in default (currently `gpt-5.3-codex`), which a
|
|
1553
|
-
* ChatGPT-tier account is not entitled to use — the run dies with HTTP 400
|
|
1554
|
-
* before doing any work. The user's model preference lives in whichever
|
|
1555
|
-
* version-home was active when they set it (`~/.codex` symlinks to it), so it is
|
|
1556
|
-
* NOT visible to a run pinned to a different version. Forwarding it via `--model`
|
|
1557
|
-
* keeps the user's "default model setup" regardless of the active version-home,
|
|
1558
|
-
* and is concurrency-safe (no file writes) when fanning out many parallel runs.
|
|
1559
|
-
*
|
|
1560
|
-
* Returns the top-level `model` only (ignores `[profile.*]` tables). Best-effort:
|
|
1561
|
-
* a missing/unreadable/unset config yields `undefined` (caller keeps prior behaviour).
|
|
1562
|
-
*/
|
|
1563
1016
|
export function readCodexConfiguredModel() {
|
|
1564
1017
|
try {
|
|
1565
1018
|
const cfg = path.join(getAgentConfigPath('codex'), 'config.toml');
|
|
1566
1019
|
const text = fs.readFileSync(cfg, 'utf-8');
|
|
1567
|
-
// Only trust keys before the first [table]; a `model` under [profile.x] is
|
|
1568
|
-
// not the default the CLI uses at top level.
|
|
1569
1020
|
const topLevel = text.split(/^\s*\[/m)[0];
|
|
1570
1021
|
return topLevel.match(/^\s*model\s*=\s*["']([^"']+)["']/m)?.[1];
|
|
1571
1022
|
}
|
|
@@ -1573,27 +1024,21 @@ export function readCodexConfiguredModel() {
|
|
|
1573
1024
|
return undefined;
|
|
1574
1025
|
}
|
|
1575
1026
|
}
|
|
1576
|
-
/** Get the version-home config directory path. */
|
|
1577
1027
|
function getVersionConfigPath(agent, version) {
|
|
1578
1028
|
const agentConfig = AGENTS[agent];
|
|
1579
1029
|
const versionsDir = getVersionsDir();
|
|
1580
|
-
// Use the agent's full configDir subpath so nested layouts (e.g. antigravity) work.
|
|
1581
1030
|
const configDirName = path.relative(os.homedir(), agentConfig.configDir);
|
|
1582
1031
|
return path.join(versionsDir, agent, version, 'home', configDirName);
|
|
1583
1032
|
}
|
|
1584
|
-
/** Detect conflicts between the current config directory and the target version home. */
|
|
1585
1033
|
function detectMigrationConflicts(agent, version) {
|
|
1586
1034
|
const configPath = getAgentConfigPath(agent);
|
|
1587
1035
|
const versionConfigPath = getVersionConfigPath(agent, version);
|
|
1588
1036
|
try {
|
|
1589
1037
|
const stat = fs.lstatSync(configPath);
|
|
1590
1038
|
if (stat.isSymbolicLink()) {
|
|
1591
|
-
// Already a symlink - no migration needed, no conflicts
|
|
1592
1039
|
return null;
|
|
1593
1040
|
}
|
|
1594
1041
|
else if (stat.isDirectory()) {
|
|
1595
|
-
// Real directory exists - would need migration
|
|
1596
|
-
// Detect conflicts between user's current config and version home
|
|
1597
1042
|
const conflicts = detectConflicts(configPath, versionConfigPath);
|
|
1598
1043
|
return {
|
|
1599
1044
|
agent,
|
|
@@ -1601,22 +1046,18 @@ function detectMigrationConflicts(agent, version) {
|
|
|
1601
1046
|
conflicts,
|
|
1602
1047
|
};
|
|
1603
1048
|
}
|
|
1604
|
-
// Not a directory or symlink - unusual, no conflicts to report
|
|
1605
1049
|
return null;
|
|
1606
1050
|
}
|
|
1607
1051
|
catch (err) {
|
|
1608
1052
|
if (err.code === 'ENOENT') {
|
|
1609
|
-
// Config path doesn't exist - no migration needed
|
|
1610
1053
|
return null;
|
|
1611
1054
|
}
|
|
1612
1055
|
return null;
|
|
1613
1056
|
}
|
|
1614
1057
|
}
|
|
1615
|
-
/** Best-effort account identity for a file-auth agent's credential directory; null when no decodable account claim exists. */
|
|
1616
1058
|
export function readAuthFileIdentity(agent, configDir) {
|
|
1617
1059
|
return readAuthAccountIdentity(agent, configDir);
|
|
1618
1060
|
}
|
|
1619
|
-
/** Carry the freshest existing account credential into `toConfigDir` so version switches don't log out file-auth agents. */
|
|
1620
1061
|
export function carryForwardAuthFiles(agent, toConfigDir) {
|
|
1621
1062
|
const authFiles = AGENTS[agent].authFiles;
|
|
1622
1063
|
if (!authFiles || authFiles.length === 0)
|
|
@@ -1630,18 +1071,10 @@ export function carryForwardAuthFiles(agent, toConfigDir) {
|
|
|
1630
1071
|
.map(v => path.join(versionsBase, v, 'home', configDirName));
|
|
1631
1072
|
}
|
|
1632
1073
|
catch {
|
|
1633
|
-
return;
|
|
1634
|
-
}
|
|
1635
|
-
// Account identity currently installed at the destination home (null when the
|
|
1636
|
-
// dest is empty or its credential can't be decoded). When it IS known, only a
|
|
1637
|
-
// source home whose credential decodes to the SAME account is eligible to
|
|
1638
|
-
// overwrite it — so a newer login for a DIFFERENT account sitting in another
|
|
1639
|
-
// version-home can't silently replace the account the user is signed into
|
|
1640
|
-
// (RUSH-1764). An empty destination still seeds from the freshest source (the
|
|
1641
|
-
// version-switch case). Identity is a per-DIR/account property, not per-file:
|
|
1642
|
-
// for droid it comes from decrypting auth.v2.file with auth.v2.key, so it must
|
|
1643
|
-
// gate BOTH files as a unit (never carry account B's key over account A's).
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1644
1076
|
const toResolved = path.resolve(toConfigDir);
|
|
1077
|
+
// When destination identity is known, carry credentials only from that same account.
|
|
1645
1078
|
const destIdentity = readAuthFileIdentity(agent, toConfigDir);
|
|
1646
1079
|
const identityCache = new Map();
|
|
1647
1080
|
const dirIdentity = (dir) => {
|
|
@@ -1653,12 +1086,10 @@ export function carryForwardAuthFiles(agent, toConfigDir) {
|
|
|
1653
1086
|
for (const rel of authFiles) {
|
|
1654
1087
|
const dest = path.join(toConfigDir, rel);
|
|
1655
1088
|
const destResolved = path.resolve(dest);
|
|
1656
|
-
// Newest existing source copy across all version homes (excluding dest),
|
|
1657
|
-
// constrained to the destination's account identity when it is known.
|
|
1658
1089
|
let newest = null;
|
|
1659
1090
|
for (const dir of sourceDirs) {
|
|
1660
1091
|
if (path.resolve(dir) === toResolved)
|
|
1661
|
-
continue;
|
|
1092
|
+
continue;
|
|
1662
1093
|
const src = path.join(dir, rel);
|
|
1663
1094
|
if (path.resolve(src) === destResolved)
|
|
1664
1095
|
continue;
|
|
@@ -1671,8 +1102,6 @@ export function carryForwardAuthFiles(agent, toConfigDir) {
|
|
|
1671
1102
|
}
|
|
1672
1103
|
if (!st.isFile())
|
|
1673
1104
|
continue;
|
|
1674
|
-
// Account-identity guard: never carry a different account's credential over
|
|
1675
|
-
// an existing login. Only enforced when the destination's identity is known.
|
|
1676
1105
|
if (destIdentity !== null && dirIdentity(dir) !== destIdentity)
|
|
1677
1106
|
continue;
|
|
1678
1107
|
if (!newest || st.mtimeMs > newest.mtimeMs)
|
|
@@ -1680,13 +1109,12 @@ export function carryForwardAuthFiles(agent, toConfigDir) {
|
|
|
1680
1109
|
}
|
|
1681
1110
|
if (!newest)
|
|
1682
1111
|
continue;
|
|
1683
|
-
// Skip when the target already has an at-least-as-fresh copy.
|
|
1684
1112
|
try {
|
|
1685
1113
|
const dstat = fs.statSync(dest);
|
|
1686
1114
|
if (dstat.mtimeMs >= newest.mtimeMs)
|
|
1687
1115
|
continue;
|
|
1688
1116
|
}
|
|
1689
|
-
catch {
|
|
1117
|
+
catch { }
|
|
1690
1118
|
try {
|
|
1691
1119
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
1692
1120
|
const srcStat = fs.statSync(newest.path);
|
|
@@ -1694,45 +1122,28 @@ export function carryForwardAuthFiles(agent, toConfigDir) {
|
|
|
1694
1122
|
fs.chmodSync(dest, (srcStat.mode & 0o777) || 0o600);
|
|
1695
1123
|
fs.utimesSync(dest, srcStat.atime, srcStat.mtime);
|
|
1696
1124
|
}
|
|
1697
|
-
catch {
|
|
1125
|
+
catch { }
|
|
1698
1126
|
}
|
|
1699
1127
|
}
|
|
1700
|
-
/** Switch the agent's config symlink to point at a specific version, backing up any real directory first. */
|
|
1701
1128
|
export async function switchConfigSymlink(agent, version) {
|
|
1702
|
-
// Moves the user's real ~/.<agent> aside and symlinks it into a version home.
|
|
1703
1129
|
assertIsolationBoundary(agent, 'repoint your real config directory');
|
|
1704
1130
|
const configPath = getAgentConfigPath(agent);
|
|
1705
1131
|
const versionConfigPath = getVersionConfigPath(agent, version);
|
|
1706
|
-
// Ensure version config directory exists
|
|
1707
1132
|
if (!fs.existsSync(versionConfigPath)) {
|
|
1708
1133
|
fs.mkdirSync(versionConfigPath, { recursive: true });
|
|
1709
1134
|
}
|
|
1710
|
-
// Carry the account credential into the version we're switching to. Droid /
|
|
1711
|
-
// antigravity / kimi store login as files INSIDE the per-version config home;
|
|
1712
|
-
// switching versions repoints the symlink to a home that was never logged in,
|
|
1713
|
-
// silently logging the CLI out. Sign-in is account-global, so seed the target
|
|
1714
|
-
// home with the freshest existing credential before we flip the symlink.
|
|
1715
1135
|
carryForwardAuthFiles(agent, versionConfigPath);
|
|
1716
1136
|
try {
|
|
1717
1137
|
const stat = fs.lstatSync(configPath);
|
|
1718
1138
|
if (stat.isSymbolicLink()) {
|
|
1719
|
-
// Already a symlink - check if it points to the correct target
|
|
1720
1139
|
const currentTarget = fs.readlinkSync(configPath);
|
|
1721
1140
|
const resolvedCurrent = path.resolve(path.dirname(configPath), currentTarget);
|
|
1722
1141
|
const resolvedTarget = path.resolve(versionConfigPath);
|
|
1723
1142
|
if (resolvedCurrent === resolvedTarget) {
|
|
1724
|
-
// Already pointing to correct target, no-op
|
|
1725
1143
|
return { success: true };
|
|
1726
1144
|
}
|
|
1727
|
-
// openclaw mixes user data (openclaw.json, openclaw.db, per-agent
|
|
1728
|
-
// workspaces under ~/.openclaw/{agentId}/, memory/) with the version
|
|
1729
|
-
// home — silently swapping the symlink to a fresh version home strips
|
|
1730
|
-
// every running agent's config + workspace + memory. Carry the user
|
|
1731
|
-
// data forward into the new version home before flipping the symlink
|
|
1732
|
-
// (keep-dest preserves anything the new version already shipped).
|
|
1733
|
-
// Other agents (Claude, Codex, etc.) keep user data outside the
|
|
1734
|
-
// version-home dir, so this is openclaw-only by design.
|
|
1735
1145
|
if (agent === 'openclaw') {
|
|
1146
|
+
// Copy workspace and memory before repointing the live symlink.
|
|
1736
1147
|
try {
|
|
1737
1148
|
if (fs.existsSync(resolvedCurrent) && fs.statSync(resolvedCurrent).isDirectory()) {
|
|
1738
1149
|
await copyDirContents(resolvedCurrent, versionConfigPath, 'keep-dest');
|
|
@@ -1744,30 +1155,18 @@ export async function switchConfigSymlink(agent, version) {
|
|
|
1744
1155
|
`at the old path; you can copy it manually if needed.`);
|
|
1745
1156
|
}
|
|
1746
1157
|
}
|
|
1747
|
-
// Different target - update it
|
|
1748
1158
|
fs.unlinkSync(configPath);
|
|
1749
1159
|
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
1750
1160
|
fs.symlinkSync(versionConfigPath, configPath, process.platform === 'win32' ? 'junction' : undefined);
|
|
1751
1161
|
return { success: true };
|
|
1752
1162
|
}
|
|
1753
1163
|
else if (stat.isDirectory()) {
|
|
1754
|
-
// Real directory exists - backup and replace with symlink
|
|
1755
1164
|
const timestamp = Date.now();
|
|
1756
|
-
// Move to backup location
|
|
1757
1165
|
const backupsDir = getBackupsDir();
|
|
1758
1166
|
const agentBackupDir = path.join(backupsDir, agent);
|
|
1759
1167
|
const finalBackupPath = path.join(agentBackupDir, String(timestamp));
|
|
1760
1168
|
fs.mkdirSync(agentBackupDir, { recursive: true });
|
|
1761
1169
|
fs.renameSync(configPath, finalBackupPath);
|
|
1762
|
-
// Session JSONLs that lived under the old configPath have just moved to
|
|
1763
|
-
// finalBackupPath on disk. Rewrite any DB rows pointing at the old prefix
|
|
1764
|
-
// so querySessions stops returning phantom rows (issue #136). The
|
|
1765
|
-
// discoverer at src/lib/session/discover.ts already scans backup dirs, so
|
|
1766
|
-
// future indexer runs will find the new files — this just keeps the
|
|
1767
|
-
// existing rows valid in the meantime.
|
|
1768
|
-
//
|
|
1769
|
-
// Dynamic import so loading shims.ts doesn't transitively open the
|
|
1770
|
-
// sessions DB — many tests partially mock state.js and would break.
|
|
1771
1170
|
try {
|
|
1772
1171
|
const { updateSessionFilePaths } = await import('../session/db.js');
|
|
1773
1172
|
updateSessionFilePaths(configPath, finalBackupPath);
|
|
@@ -1776,7 +1175,6 @@ export async function switchConfigSymlink(agent, version) {
|
|
|
1776
1175
|
console.error(`Warning: failed to update session file_paths after backing up ${configPath}: ` +
|
|
1777
1176
|
`${err.message}. Stale rows may appear in session listings until the next scan.`);
|
|
1778
1177
|
}
|
|
1779
|
-
// Create symlink (parent already exists since the dir we just moved was here)
|
|
1780
1178
|
fs.symlinkSync(versionConfigPath, configPath, process.platform === 'win32' ? 'junction' : undefined);
|
|
1781
1179
|
return { success: true, backupPath: finalBackupPath };
|
|
1782
1180
|
}
|
|
@@ -1786,9 +1184,6 @@ export async function switchConfigSymlink(agent, version) {
|
|
|
1786
1184
|
}
|
|
1787
1185
|
catch (err) {
|
|
1788
1186
|
if (err.code === 'ENOENT') {
|
|
1789
|
-
// Config path doesn't exist - create symlink.
|
|
1790
|
-
// For nested layouts (e.g., ~/.gemini/antigravity-cli) the parent dir
|
|
1791
|
-
// may also be missing if the parent agent (Gemini) is not installed.
|
|
1792
1187
|
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
1793
1188
|
fs.symlinkSync(versionConfigPath, configPath, process.platform === 'win32' ? 'junction' : undefined);
|
|
1794
1189
|
return { success: true };
|
|
@@ -1796,16 +1191,7 @@ export async function switchConfigSymlink(agent, version) {
|
|
|
1796
1191
|
return { success: false, error: err.message };
|
|
1797
1192
|
}
|
|
1798
1193
|
}
|
|
1799
|
-
/**
|
|
1800
|
-
* Switch home-level files (outside the config dir) to per-version symlinks.
|
|
1801
|
-
* e.g., ~/.claude.json -> ~/.agents/versions/claude/2.0.65/home/.claude.json
|
|
1802
|
-
*
|
|
1803
|
-
* Uses atomic rename to avoid data loss if another session is running.
|
|
1804
|
-
* On first migration (real file -> symlink), merges global auth into
|
|
1805
|
-
* ALL installed versions so they inherit the current account.
|
|
1806
|
-
*/
|
|
1807
1194
|
export function switchHomeFileSymlinks(agent, version) {
|
|
1808
|
-
// Same, for home-level files such as ~/.claude.json.
|
|
1809
1195
|
assertIsolationBoundary(agent, 'repoint your home-level config files');
|
|
1810
1196
|
const agentConfig = AGENTS[agent];
|
|
1811
1197
|
const homeFiles = agentConfig.homeFiles;
|
|
@@ -1815,10 +1201,6 @@ export function switchHomeFileSymlinks(agent, version) {
|
|
|
1815
1201
|
const versionsDir = getVersionsDir();
|
|
1816
1202
|
const switched = [];
|
|
1817
1203
|
const errors = [];
|
|
1818
|
-
// For Claude, Claude's binary reads CLAUDE_CONFIG_DIR/.claude.json (INSIDE
|
|
1819
|
-
// the per-version .claude dir) — not the home-level file this function
|
|
1820
|
-
// manages. Reconcile all installed Claude versions so INSIDE is a symlink
|
|
1821
|
-
// to OUTSIDE, making OUTSIDE the single source of truth.
|
|
1822
1204
|
if (agent === 'claude') {
|
|
1823
1205
|
const reconcile = ensureAllClaudeInsideSymlinks();
|
|
1824
1206
|
for (const e of reconcile.errors)
|
|
@@ -1828,7 +1210,6 @@ export function switchHomeFileSymlinks(agent, version) {
|
|
|
1828
1210
|
const globalPath = path.join(home, fileName);
|
|
1829
1211
|
const versionFilePath = path.join(versionsDir, agent, version, 'home', fileName);
|
|
1830
1212
|
try {
|
|
1831
|
-
// Ensure version home dir exists
|
|
1832
1213
|
const versionFileDir = path.dirname(versionFilePath);
|
|
1833
1214
|
if (!fs.existsSync(versionFileDir)) {
|
|
1834
1215
|
fs.mkdirSync(versionFileDir, { recursive: true });
|
|
@@ -1838,7 +1219,6 @@ export function switchHomeFileSymlinks(agent, version) {
|
|
|
1838
1219
|
stat = fs.lstatSync(globalPath);
|
|
1839
1220
|
}
|
|
1840
1221
|
catch {
|
|
1841
|
-
// File doesn't exist at global path — just create symlink
|
|
1842
1222
|
if (!fs.existsSync(versionFilePath)) {
|
|
1843
1223
|
fs.writeFileSync(versionFilePath, '{}');
|
|
1844
1224
|
}
|
|
@@ -1847,15 +1227,13 @@ export function switchHomeFileSymlinks(agent, version) {
|
|
|
1847
1227
|
continue;
|
|
1848
1228
|
}
|
|
1849
1229
|
if (stat.isSymbolicLink()) {
|
|
1850
|
-
// Already a symlink — retarget atomically
|
|
1851
1230
|
const currentTarget = fs.readlinkSync(globalPath);
|
|
1852
1231
|
const resolvedCurrent = path.resolve(path.dirname(globalPath), currentTarget);
|
|
1853
1232
|
const resolvedTarget = path.resolve(versionFilePath);
|
|
1854
1233
|
if (resolvedCurrent === resolvedTarget) {
|
|
1855
1234
|
switched.push(fileName);
|
|
1856
|
-
continue;
|
|
1235
|
+
continue;
|
|
1857
1236
|
}
|
|
1858
|
-
// Atomic retarget: create temp symlink, rename over existing
|
|
1859
1237
|
if (!fs.existsSync(versionFilePath)) {
|
|
1860
1238
|
fs.writeFileSync(versionFilePath, '{}');
|
|
1861
1239
|
}
|
|
@@ -1865,8 +1243,6 @@ export function switchHomeFileSymlinks(agent, version) {
|
|
|
1865
1243
|
switched.push(fileName);
|
|
1866
1244
|
}
|
|
1867
1245
|
else if (stat.isFile()) {
|
|
1868
|
-
// Real file — first-time migration
|
|
1869
|
-
// Read the global file content
|
|
1870
1246
|
let globalContent;
|
|
1871
1247
|
try {
|
|
1872
1248
|
globalContent = JSON.parse(fs.readFileSync(globalPath, 'utf-8'));
|
|
@@ -1875,7 +1251,6 @@ export function switchHomeFileSymlinks(agent, version) {
|
|
|
1875
1251
|
errors.push(`${fileName}: Could not parse ${globalPath}: ${err.message}`);
|
|
1876
1252
|
continue;
|
|
1877
1253
|
}
|
|
1878
|
-
// Merge auth into ALL installed version files for this agent
|
|
1879
1254
|
const agentVersionsDir = path.join(versionsDir, agent);
|
|
1880
1255
|
if (fs.existsSync(agentVersionsDir)) {
|
|
1881
1256
|
for (const ver of fs.readdirSync(agentVersionsDir)) {
|
|
@@ -1885,28 +1260,23 @@ export function switchHomeFileSymlinks(agent, version) {
|
|
|
1885
1260
|
fs.mkdirSync(verFileDir, { recursive: true });
|
|
1886
1261
|
}
|
|
1887
1262
|
if (fs.existsSync(verFilePath)) {
|
|
1888
|
-
// Merge: version-specific fields + global auth fields
|
|
1889
1263
|
try {
|
|
1890
1264
|
const verContent = JSON.parse(fs.readFileSync(verFilePath, 'utf-8'));
|
|
1891
1265
|
const merged = { ...globalContent, ...verContent };
|
|
1892
|
-
// Ensure auth from global always wins
|
|
1893
1266
|
if (globalContent.oauthAccount) {
|
|
1894
1267
|
merged.oauthAccount = globalContent.oauthAccount;
|
|
1895
1268
|
}
|
|
1896
1269
|
fs.writeFileSync(verFilePath, JSON.stringify(merged, null, 2));
|
|
1897
1270
|
}
|
|
1898
1271
|
catch {
|
|
1899
|
-
// If version file is invalid JSON, overwrite with global
|
|
1900
1272
|
fs.writeFileSync(verFilePath, JSON.stringify(globalContent, null, 2));
|
|
1901
1273
|
}
|
|
1902
1274
|
}
|
|
1903
1275
|
else {
|
|
1904
|
-
// No version file — copy global wholesale
|
|
1905
1276
|
fs.writeFileSync(verFilePath, JSON.stringify(globalContent, null, 2));
|
|
1906
1277
|
}
|
|
1907
1278
|
}
|
|
1908
1279
|
}
|
|
1909
|
-
// Atomic swap: create temp symlink to target version, rename over real file
|
|
1910
1280
|
const tmpPath = `${globalPath}.agents-tmp-${process.pid}`;
|
|
1911
1281
|
fs.symlinkSync(versionFilePath, tmpPath);
|
|
1912
1282
|
fs.renameSync(tmpPath, globalPath);
|
|
@@ -1919,32 +1289,13 @@ export function switchHomeFileSymlinks(agent, version) {
|
|
|
1919
1289
|
}
|
|
1920
1290
|
return { switched, errors };
|
|
1921
1291
|
}
|
|
1922
|
-
/**
|
|
1923
|
-
* Claude reads `.claude.json` at `$CLAUDE_CONFIG_DIR/.claude.json`. Our shim
|
|
1924
|
-
* points CLAUDE_CONFIG_DIR at `<ver>/home/.claude`, so Claude's real config
|
|
1925
|
-
* file lives at `<ver>/home/.claude/.claude.json` (INSIDE), while
|
|
1926
|
-
* `switchHomeFileSymlinks` manages `<ver>/home/.claude.json` (OUTSIDE).
|
|
1927
|
-
*
|
|
1928
|
-
* To keep both views consistent we make INSIDE a symlink to OUTSIDE. Claude's
|
|
1929
|
-
* atomic write (`Uf6`) resolves symlinks before the tmp+rename cycle, so the
|
|
1930
|
-
* symlink survives across writes and OUTSIDE remains the single source of
|
|
1931
|
-
* truth that agents-cli's home-file machinery already manages.
|
|
1932
|
-
*
|
|
1933
|
-
* This function idempotently reconciles one version:
|
|
1934
|
-
* - INSIDE missing: create symlink -> `../.claude.json` (create OUTSIDE if needed).
|
|
1935
|
-
* - INSIDE already symlink to OUTSIDE: no-op.
|
|
1936
|
-
* - INSIDE is a real file: it's the authoritative auth state (Claude was
|
|
1937
|
-
* writing to it). Move its content to OUTSIDE (merging with OUTSIDE,
|
|
1938
|
-
* INSIDE wins for `oauthAccount`), then replace INSIDE with the symlink.
|
|
1939
|
-
* - Symlink points elsewhere: replace it.
|
|
1940
|
-
*/
|
|
1941
1292
|
export function ensureClaudeInsideSymlink(version) {
|
|
1942
1293
|
const versionsDir = getVersionsDir();
|
|
1943
1294
|
const versionHome = path.join(versionsDir, 'claude', version, 'home');
|
|
1944
1295
|
const outsidePath = path.join(versionHome, '.claude.json');
|
|
1945
1296
|
const insideDir = path.join(versionHome, '.claude');
|
|
1946
1297
|
const insidePath = path.join(insideDir, '.claude.json');
|
|
1947
|
-
const linkTarget = '../.claude.json';
|
|
1298
|
+
const linkTarget = '../.claude.json';
|
|
1948
1299
|
if (!fs.existsSync(insideDir)) {
|
|
1949
1300
|
fs.mkdirSync(insideDir, { recursive: true });
|
|
1950
1301
|
}
|
|
@@ -1953,13 +1304,11 @@ export function ensureClaudeInsideSymlink(version) {
|
|
|
1953
1304
|
insideStat = fs.lstatSync(insidePath);
|
|
1954
1305
|
}
|
|
1955
1306
|
catch {
|
|
1956
|
-
/* INSIDE does not exist */
|
|
1957
1307
|
}
|
|
1958
1308
|
if (insideStat?.isSymbolicLink()) {
|
|
1959
1309
|
const currentTarget = fs.readlinkSync(insidePath);
|
|
1960
1310
|
if (currentTarget === linkTarget)
|
|
1961
1311
|
return;
|
|
1962
|
-
// Wrong target — replace.
|
|
1963
1312
|
if (!fs.existsSync(outsidePath))
|
|
1964
1313
|
fs.writeFileSync(outsidePath, '{}');
|
|
1965
1314
|
fs.unlinkSync(insidePath);
|
|
@@ -1967,15 +1316,11 @@ export function ensureClaudeInsideSymlink(version) {
|
|
|
1967
1316
|
return;
|
|
1968
1317
|
}
|
|
1969
1318
|
if (insideStat?.isFile()) {
|
|
1970
|
-
// INSIDE is the authoritative file — Claude has been reading/writing it.
|
|
1971
|
-
// Merge INSIDE into OUTSIDE, with INSIDE winning on every field, then
|
|
1972
|
-
// replace INSIDE with a symlink.
|
|
1973
1319
|
let insideContent = {};
|
|
1974
1320
|
try {
|
|
1975
1321
|
insideContent = JSON.parse(fs.readFileSync(insidePath, 'utf-8'));
|
|
1976
1322
|
}
|
|
1977
1323
|
catch {
|
|
1978
|
-
/* INSIDE corrupt — treat as empty; OUTSIDE preserved as-is */
|
|
1979
1324
|
}
|
|
1980
1325
|
let outsideContent = {};
|
|
1981
1326
|
if (fs.existsSync(outsidePath)) {
|
|
@@ -1983,7 +1328,6 @@ export function ensureClaudeInsideSymlink(version) {
|
|
|
1983
1328
|
outsideContent = JSON.parse(fs.readFileSync(outsidePath, 'utf-8'));
|
|
1984
1329
|
}
|
|
1985
1330
|
catch {
|
|
1986
|
-
/* OUTSIDE corrupt — drop it */
|
|
1987
1331
|
}
|
|
1988
1332
|
}
|
|
1989
1333
|
const merged = { ...outsideContent, ...insideContent };
|
|
@@ -1992,15 +1336,10 @@ export function ensureClaudeInsideSymlink(version) {
|
|
|
1992
1336
|
fs.symlinkSync(linkTarget, insidePath);
|
|
1993
1337
|
return;
|
|
1994
1338
|
}
|
|
1995
|
-
// INSIDE missing — ensure OUTSIDE exists, then create symlink.
|
|
1996
1339
|
if (!fs.existsSync(outsidePath))
|
|
1997
1340
|
fs.writeFileSync(outsidePath, '{}');
|
|
1998
1341
|
fs.symlinkSync(linkTarget, insidePath);
|
|
1999
1342
|
}
|
|
2000
|
-
/**
|
|
2001
|
-
* Apply `ensureClaudeInsideSymlink` to every installed Claude version.
|
|
2002
|
-
* Safe to call repeatedly; per-version calls are idempotent.
|
|
2003
|
-
*/
|
|
2004
1343
|
function ensureAllClaudeInsideSymlinks() {
|
|
2005
1344
|
const versionsDir = getVersionsDir();
|
|
2006
1345
|
const claudeVersionsDir = path.join(versionsDir, 'claude');
|
|
@@ -2021,9 +1360,6 @@ function ensureAllClaudeInsideSymlinks() {
|
|
|
2021
1360
|
}
|
|
2022
1361
|
return { migrated, errors };
|
|
2023
1362
|
}
|
|
2024
|
-
/**
|
|
2025
|
-
* Get the current config symlink target version, if any.
|
|
2026
|
-
*/
|
|
2027
1363
|
export function getConfigSymlinkVersion(agent) {
|
|
2028
1364
|
const configPath = getAgentConfigPath(agent);
|
|
2029
1365
|
try {
|
|
@@ -2031,60 +1367,40 @@ export function getConfigSymlinkVersion(agent) {
|
|
|
2031
1367
|
if (!stat.isSymbolicLink()) {
|
|
2032
1368
|
return null;
|
|
2033
1369
|
}
|
|
2034
|
-
// Normalize separators so this matches on Windows too — readlinkSync there
|
|
2035
|
-
// returns backslash paths, which the forward-slash-only regex never matched
|
|
2036
|
-
// (misclassifying an owned symlink as foreign, e.g. in `agents uninstall`).
|
|
2037
1370
|
const target = fs.readlinkSync(configPath).replace(/\\/g, '/');
|
|
2038
|
-
// Extract version from path like ~/.agents/versions/claude/2.0.65/home/.claude
|
|
2039
1371
|
const match = target.match(/versions\/[^/]+\/([^/]+)\/home/);
|
|
2040
1372
|
return match ? match[1] : null;
|
|
2041
1373
|
}
|
|
2042
1374
|
catch {
|
|
2043
|
-
/* config path not accessible or not a symlink */
|
|
2044
1375
|
return null;
|
|
2045
1376
|
}
|
|
2046
1377
|
}
|
|
2047
|
-
/**
|
|
2048
|
-
* Copy directory contents with configurable conflict strategy.
|
|
2049
|
-
* Skips when dest is a symlink (managed resources that shouldn't be overwritten).
|
|
2050
|
-
*
|
|
2051
|
-
* @param src - Source directory
|
|
2052
|
-
* @param dest - Destination directory
|
|
2053
|
-
* @param strategy - How to handle conflicts: 'keep-dest', 'overwrite', or 'ask-per-file'
|
|
2054
|
-
* @param context - Agent/version context for prompts (only used when strategy is 'ask-per-file')
|
|
2055
|
-
*/
|
|
2056
1378
|
async function copyDirContents(src, dest, strategy = 'keep-dest', context) {
|
|
2057
|
-
// If dest is a symlink, skip - these are managed resources (skills, commands, etc.)
|
|
2058
|
-
// that link to central ~/.agents/ and shouldn't be overwritten with local copies
|
|
2059
1379
|
try {
|
|
2060
1380
|
const destStat = fs.lstatSync(dest);
|
|
2061
1381
|
if (destStat.isSymbolicLink()) {
|
|
2062
|
-
return;
|
|
1382
|
+
return;
|
|
2063
1383
|
}
|
|
2064
1384
|
}
|
|
2065
1385
|
catch {
|
|
2066
|
-
// dest doesn't exist, that's fine
|
|
2067
1386
|
}
|
|
2068
1387
|
if (!fs.existsSync(dest)) {
|
|
2069
1388
|
fs.mkdirSync(dest, { recursive: true });
|
|
2070
1389
|
}
|
|
2071
1390
|
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
2072
1391
|
for (const entry of entries) {
|
|
2073
|
-
// Skip files/directories that should never be migrated
|
|
2074
1392
|
if (shouldIgnore(entry.name)) {
|
|
2075
1393
|
continue;
|
|
2076
1394
|
}
|
|
2077
1395
|
const srcPath = path.join(src, entry.name);
|
|
2078
1396
|
const destPath = path.join(dest, entry.name);
|
|
2079
|
-
// Skip if dest entry is a symlink (managed resource)
|
|
2080
1397
|
try {
|
|
2081
1398
|
const entryDestStat = fs.lstatSync(destPath);
|
|
2082
1399
|
if (entryDestStat.isSymbolicLink()) {
|
|
2083
|
-
continue;
|
|
1400
|
+
continue;
|
|
2084
1401
|
}
|
|
2085
1402
|
}
|
|
2086
1403
|
catch {
|
|
2087
|
-
// dest entry doesn't exist, that's fine
|
|
2088
1404
|
}
|
|
2089
1405
|
if (entry.isDirectory()) {
|
|
2090
1406
|
await copyDirContents(srcPath, destPath, strategy, context);
|
|
@@ -2097,31 +1413,25 @@ async function copyDirContents(src, dest, strategy = 'keep-dest', context) {
|
|
|
2097
1413
|
fs.symlinkSync(linkTarget, destPath);
|
|
2098
1414
|
}
|
|
2099
1415
|
else {
|
|
2100
|
-
// File - check for conflict
|
|
2101
1416
|
if (fs.existsSync(destPath)) {
|
|
2102
|
-
// Handle based on strategy
|
|
2103
1417
|
if (strategy === 'keep-dest') {
|
|
2104
|
-
// Keep existing file, skip copying
|
|
2105
1418
|
continue;
|
|
2106
1419
|
}
|
|
2107
1420
|
else if (strategy === 'overwrite') {
|
|
2108
|
-
// Back up and overwrite
|
|
2109
1421
|
fs.copyFileSync(destPath, `${destPath}.backup`);
|
|
2110
1422
|
}
|
|
2111
1423
|
else if (strategy === 'ask-per-file') {
|
|
2112
|
-
// Back up dest file
|
|
2113
1424
|
fs.copyFileSync(destPath, `${destPath}.backup`);
|
|
2114
|
-
// Ask user with context - use clear path-based terminology
|
|
2115
1425
|
const agentConfig = context ? AGENTS[context.agent] : null;
|
|
2116
1426
|
const versionLabel = agentConfig
|
|
2117
1427
|
? `${agentConfig.name}@${context.version}`
|
|
2118
1428
|
: 'version';
|
|
2119
1429
|
const useMyFile = await confirm({
|
|
2120
1430
|
message: `${entry.name}: Use your config file instead of ${versionLabel}?`,
|
|
2121
|
-
default: false,
|
|
1431
|
+
default: false,
|
|
2122
1432
|
});
|
|
2123
1433
|
if (!useMyFile) {
|
|
2124
|
-
continue;
|
|
1434
|
+
continue;
|
|
2125
1435
|
}
|
|
2126
1436
|
}
|
|
2127
1437
|
}
|
|
@@ -2129,25 +1439,20 @@ async function copyDirContents(src, dest, strategy = 'keep-dest', context) {
|
|
|
2129
1439
|
}
|
|
2130
1440
|
}
|
|
2131
1441
|
}
|
|
2132
|
-
/** The on-disk shim filename for a platform: `<cmd>.cmd` on Windows, bare `<cmd>` on POSIX. */
|
|
2133
1442
|
export function onDiskShimFile(cliCommand, platform) {
|
|
2134
1443
|
return shimTargetsFor(platform).cmd ? `${cliCommand}.cmd` : cliCommand;
|
|
2135
1444
|
}
|
|
2136
|
-
/** The actual on-disk shim path for the current platform. */
|
|
2137
1445
|
function onDiskShimPath(agent) {
|
|
2138
1446
|
return path.join(getShimsDir(), onDiskShimFile(AGENTS[agent].cliCommand, process.platform));
|
|
2139
1447
|
}
|
|
2140
|
-
/** Check whether the on-disk shim exists for an agent. */
|
|
2141
1448
|
export function shimExists(agent) {
|
|
2142
1449
|
return fs.existsSync(onDiskShimPath(agent));
|
|
2143
1450
|
}
|
|
2144
|
-
/** Read the schema version from the on-disk shim header, or null if missing/unreadable. */
|
|
2145
1451
|
function readShimSchemaVersion(agent) {
|
|
2146
1452
|
if (!shimExists(agent))
|
|
2147
1453
|
return null;
|
|
2148
1454
|
try {
|
|
2149
1455
|
const content = fs.readFileSync(onDiskShimPath(agent), 'utf8');
|
|
2150
|
-
// Look at the first ~10 lines only — the marker lives in the header.
|
|
2151
1456
|
const header = content.split('\n', 10).join('\n');
|
|
2152
1457
|
const match = header.match(new RegExp(SHIM_VERSION_MARKER + '\\s*(\\d+)'));
|
|
2153
1458
|
if (!match)
|
|
@@ -2158,12 +1463,10 @@ function readShimSchemaVersion(agent) {
|
|
|
2158
1463
|
return null;
|
|
2159
1464
|
}
|
|
2160
1465
|
}
|
|
2161
|
-
/** True when the on-disk shim's schema version matches the current schema. */
|
|
2162
1466
|
export function isShimCurrent(agent) {
|
|
2163
1467
|
const version = readShimSchemaVersion(agent);
|
|
2164
1468
|
return version === SHIM_SCHEMA_VERSION;
|
|
2165
1469
|
}
|
|
2166
|
-
/** Extract the baked `AGENTS_BIN='...'` value from a shim file, or null. */
|
|
2167
1470
|
function readAgentsBinFromShim(shimPath) {
|
|
2168
1471
|
try {
|
|
2169
1472
|
const header = fs.readFileSync(shimPath, 'utf8').split('\n', 12).join('\n');
|
|
@@ -2174,26 +1477,16 @@ function readAgentsBinFromShim(shimPath) {
|
|
|
2174
1477
|
return null;
|
|
2175
1478
|
}
|
|
2176
1479
|
}
|
|
2177
|
-
/**
|
|
2178
|
-
* True when the agent shim's baked `AGENTS_BIN` is fine to keep: it either already
|
|
2179
|
-
* points at the install we'd generate now, OR points at some OTHER install that
|
|
2180
|
-
* still exists on disk (leave it — regenerating could ping-pong two live installs
|
|
2181
|
-
* sharing the shims dir). Returns FALSE only when the shim points at a DIFFERENT,
|
|
2182
|
-
* now-removed install — the exact drift a deleted dev build (`~/.local/agents-cli-dev`),
|
|
2183
|
-
* an old npm-global (`/opt/homebrew`), or a rotated version dir leaves behind. A shim
|
|
2184
|
-
* can pass the schema check (`isShimCurrent`) yet still carry that stale path.
|
|
2185
|
-
*/
|
|
2186
1480
|
export function shimPointsAtLiveInstall(agent) {
|
|
2187
1481
|
if (!shimExists(agent))
|
|
2188
|
-
return true;
|
|
1482
|
+
return true;
|
|
2189
1483
|
const baked = readAgentsBinFromShim(onDiskShimPath(agent));
|
|
2190
1484
|
if (!baked)
|
|
2191
1485
|
return true;
|
|
2192
1486
|
if (baked === getAgentsBinForGeneratedShim())
|
|
2193
|
-
return true;
|
|
2194
|
-
return fs.existsSync(baked);
|
|
1487
|
+
return true;
|
|
1488
|
+
return fs.existsSync(baked);
|
|
2195
1489
|
}
|
|
2196
|
-
/** Shim files in the shims dir, excluding the hooks/ subdir and @-versioned aliases. */
|
|
2197
1490
|
export function listShimFileNames() {
|
|
2198
1491
|
try {
|
|
2199
1492
|
return fs
|
|
@@ -2205,32 +1498,8 @@ export function listShimFileNames() {
|
|
|
2205
1498
|
return [];
|
|
2206
1499
|
}
|
|
2207
1500
|
}
|
|
2208
|
-
/**
|
|
2209
|
-
* Legacy command shims that are wrong even when their baked install is alive.
|
|
2210
|
-
* `secrets` (PHNX-3989), `sessions` (PHNX-4012), `computer` (PHNX-4075) and
|
|
2211
|
-
* `browser` (PHNX-4101): the shim `exec`s `agents <name>`, which is a passthrough
|
|
2212
|
-
* to the STANDALONE binary — so the shim re-enters itself (the 1.22.85 fork
|
|
2213
|
-
* bomb) and, sitting first on PATH, shadows the real `@phnx-labs/<name>-cli`
|
|
2214
|
-
* binary a user types directly. Pruned unconditionally.
|
|
2215
|
-
*
|
|
2216
|
-
* `computer` and `browser` are the sharpest, because agents-cli USED to publish
|
|
2217
|
-
* (`computer`) or shim (`browser`) a bin of its own: a machine that installed an
|
|
2218
|
-
* older CLI has a real shim on PATH under the name the standalone engine now owns.
|
|
2219
|
-
*/
|
|
2220
1501
|
const LEGACY_SHIMS_ALWAYS_PRUNED = new Set(['secrets', 'sessions', 'computer', 'pty', 'browser']);
|
|
2221
|
-
/**
|
|
2222
|
-
* Prune a stale, orphaned shim: one that is NOT a managed agent shim and NOT a user
|
|
2223
|
-
* alias, whose baked `AGENTS_BIN` points at an install that no longer exists. These
|
|
2224
|
-
* are `exec "$AGENTS_BIN" <cmd>` command shims (browser/teams) that
|
|
2225
|
-
* `scripts/postinstall.js` writes for the LIVE install; one baked at a removed
|
|
2226
|
-
* install either dies with `exit 127` or shadows the real package bin on PATH.
|
|
2227
|
-
* Only removed when the baked target is gone, so a working shim is never touched —
|
|
2228
|
-
* except the `LEGACY_SHIMS_ALWAYS_PRUNED` set, which cannot work at all (and which
|
|
2229
|
-
* postinstall no longer writes).
|
|
2230
|
-
* Returns true if removed.
|
|
2231
|
-
*/
|
|
2232
1502
|
export function pruneOrphanedCommandShim(fileName) {
|
|
2233
|
-
// Never touch a shim that corresponds to a real agent — agents-cli manages those.
|
|
2234
1503
|
const isAgentCommand = Object.values(AGENTS).some((a) => a.cliCommand === fileName);
|
|
2235
1504
|
if (isAgentCommand)
|
|
2236
1505
|
return false;
|
|
@@ -2243,12 +1512,12 @@ export function pruneOrphanedCommandShim(fileName) {
|
|
|
2243
1512
|
return false;
|
|
2244
1513
|
}
|
|
2245
1514
|
if (content.includes('# Alias shim:'))
|
|
2246
|
-
return false;
|
|
1515
|
+
return false;
|
|
2247
1516
|
const bin = readAgentsBinFromShim(shimPath);
|
|
2248
1517
|
if (!bin)
|
|
2249
|
-
return false;
|
|
1518
|
+
return false;
|
|
2250
1519
|
if (fs.existsSync(bin) && !LEGACY_SHIMS_ALWAYS_PRUNED.has(fileName))
|
|
2251
|
-
return false;
|
|
1520
|
+
return false;
|
|
2252
1521
|
try {
|
|
2253
1522
|
fs.rmSync(shimPath);
|
|
2254
1523
|
return true;
|
|
@@ -2257,13 +1526,11 @@ export function pruneOrphanedCommandShim(fileName) {
|
|
|
2257
1526
|
return false;
|
|
2258
1527
|
}
|
|
2259
1528
|
}
|
|
2260
|
-
/** Regenerate the shim if missing or older than the current schema; never downgrade a newer on-disk shim. */
|
|
2261
1529
|
export function ensureShimCurrent(agent) {
|
|
2262
1530
|
if (!shimExists(agent)) {
|
|
2263
1531
|
createShim(agent);
|
|
2264
1532
|
return 'created';
|
|
2265
1533
|
}
|
|
2266
|
-
// Upgrade-only: avoid ping-pong between two installs sharing the shims dir.
|
|
2267
1534
|
const onDisk = readShimSchemaVersion(agent);
|
|
2268
1535
|
if (onDisk === null || onDisk < SHIM_SCHEMA_VERSION) {
|
|
2269
1536
|
createShim(agent);
|
|
@@ -2271,7 +1538,6 @@ export function ensureShimCurrent(agent) {
|
|
|
2271
1538
|
}
|
|
2272
1539
|
return 'current';
|
|
2273
1540
|
}
|
|
2274
|
-
/** Refresh only existing generated launchers before unattended binary changes. */
|
|
2275
1541
|
export function refreshOwnedLaunchers(agent, label) {
|
|
2276
1542
|
const owned = (file) => {
|
|
2277
1543
|
try {
|
|
@@ -2288,22 +1554,17 @@ export function refreshOwnedLaunchers(agent, label) {
|
|
|
2288
1554
|
if (owned(versionedAliasOnDiskPath(agent, label)))
|
|
2289
1555
|
ensureVersionedAliasCurrent(agent, label);
|
|
2290
1556
|
}
|
|
2291
|
-
/** Get the logical (extensionless) shim path for an agent. */
|
|
2292
1557
|
export function getShimPath(agent) {
|
|
2293
1558
|
const shimsDir = getShimsDir();
|
|
2294
1559
|
const agentConfig = AGENTS[agent];
|
|
2295
1560
|
return path.join(shimsDir, agentConfig.cliCommand);
|
|
2296
1561
|
}
|
|
2297
|
-
/** Return the first executable on PATH that would shadow the managed shim, excluding the shim itself and legacy pre-split files. */
|
|
2298
1562
|
export function getPathShadowingExecutable(agent, overrides) {
|
|
2299
1563
|
const pathDirs = overrides?.pathDirs ?? (process.env.PATH || '').split(path.delimiter).filter(Boolean);
|
|
2300
1564
|
const shimPath = path.resolve(overrides?.shimPath ?? getShimPath(agent));
|
|
2301
1565
|
const cliCommand = AGENTS[agent].cliCommand;
|
|
2302
1566
|
const legacyUserShim = path.resolve(path.join(os.homedir(), '.agents', 'shims', cliCommand));
|
|
2303
1567
|
const managedShimExists = fs.existsSync(shimPath);
|
|
2304
|
-
// The shim's own realpath — an adopted launcher is a symlink at a DIFFERENT
|
|
2305
|
-
// path that resolves here, so identity must be by resolved target, not the
|
|
2306
|
-
// literal path string.
|
|
2307
1568
|
const shimReal = managedShimExists ? canonicalOrNull(shimPath) : null;
|
|
2308
1569
|
for (const dir of pathDirs) {
|
|
2309
1570
|
const candidate = path.resolve(dir, cliCommand);
|
|
@@ -2312,80 +1573,45 @@ export function getPathShadowingExecutable(agent, overrides) {
|
|
|
2312
1573
|
}
|
|
2313
1574
|
if (candidate === shimPath)
|
|
2314
1575
|
return null;
|
|
2315
|
-
// Adopted launcher: a symlink we repointed at our shim. Its path differs
|
|
2316
|
-
// from shimPath but it resolves to the same file, so it is NOT a shadow —
|
|
2317
|
-
// otherwise every adopted default would be re-flagged forever, resurfacing
|
|
2318
|
-
// the false "runs a native binary" note this whole feature set out to kill.
|
|
2319
1576
|
if (shimReal && canonicalOrNull(candidate) === shimReal)
|
|
2320
1577
|
return null;
|
|
2321
1578
|
if (candidate === legacyUserShim && managedShimExists) {
|
|
2322
|
-
// Legacy file from the pre-split layout. Don't treat as shadow — the
|
|
2323
|
-
// repair flow deletes it via removeLegacyUserShim instead. Continue
|
|
2324
|
-
// scanning so a real binary later in PATH is still detected.
|
|
2325
1579
|
continue;
|
|
2326
1580
|
}
|
|
2327
1581
|
return candidate;
|
|
2328
1582
|
}
|
|
2329
1583
|
return null;
|
|
2330
1584
|
}
|
|
2331
|
-
/**
|
|
2332
|
-
* Delete the legacy ~/.agents/shims/<cli> file if it exists, returning whether
|
|
2333
|
-
* anything was removed. Pre-split installs put shims under ~/.agents/shims/;
|
|
2334
|
-
* the new layout uses ~/.agents-system/shims/. The leftover file causes the
|
|
2335
|
-
* repair-prompt loop reported in PROJ-789 — `getPathShadowingExecutable` flags
|
|
2336
|
-
* it as a shadow but `addShimsToPath` only edits rc files, never the file
|
|
2337
|
-
* itself. Removing it ends the loop.
|
|
2338
|
-
*/
|
|
2339
1585
|
export function removeLegacyUserShim(agent, overrides) {
|
|
2340
1586
|
const cliCommand = AGENTS[agent].cliCommand;
|
|
2341
1587
|
const homeDir = overrides?.homeDir || os.homedir();
|
|
2342
1588
|
const legacyPath = path.join(homeDir, '.agents', 'shims', cliCommand);
|
|
2343
1589
|
if (!fs.existsSync(legacyPath))
|
|
2344
1590
|
return false;
|
|
2345
|
-
// Belt-and-suspenders: only remove if the current managed shim location is
|
|
2346
|
-
// different (it always should be — getShimsDir() returns the system dir —
|
|
2347
|
-
// but guard against future refactors that might collapse the two).
|
|
2348
1591
|
const currentShim = path.resolve(getShimPath(agent));
|
|
2349
1592
|
if (path.resolve(legacyPath) === currentShim)
|
|
2350
1593
|
return false;
|
|
2351
1594
|
try {
|
|
2352
1595
|
fs.unlinkSync(legacyPath);
|
|
2353
|
-
// Best-effort: clean up the legacy shims dir if empty.
|
|
2354
1596
|
try {
|
|
2355
1597
|
const legacyDir = path.dirname(legacyPath);
|
|
2356
1598
|
if (fs.readdirSync(legacyDir).length === 0)
|
|
2357
1599
|
fs.rmdirSync(legacyDir);
|
|
2358
1600
|
}
|
|
2359
|
-
catch {
|
|
1601
|
+
catch { }
|
|
2360
1602
|
return true;
|
|
2361
1603
|
}
|
|
2362
1604
|
catch {
|
|
2363
1605
|
return false;
|
|
2364
1606
|
}
|
|
2365
1607
|
}
|
|
2366
|
-
/**
|
|
2367
|
-
* Where an adopted launcher's provenance is recorded. Lives under durable
|
|
2368
|
-
* `.history` (NOT the regenerable `.cache`) so the reverse pointer to the native
|
|
2369
|
-
* binary survives a cache wipe — the shim reads it to fall through to the native
|
|
2370
|
-
* binary by absolute path when no managed version resolves. Two lines:
|
|
2371
|
-
* line 1 = original binary, line 2 = launcher path (for `--release`).
|
|
2372
|
-
*/
|
|
2373
1608
|
export function getAdoptedRecordPath(agent, historyDir = getHistoryDir()) {
|
|
2374
1609
|
return path.join(historyDir, 'adopted-launchers', AGENTS[agent].cliCommand);
|
|
2375
1610
|
}
|
|
2376
|
-
/**
|
|
2377
|
-
* The launcher a harness's own installer drops in an early-PATH dir. Detection
|
|
2378
|
-
* for adoption keys on the launcher *existing as a symlink resolving outside our
|
|
2379
|
-
* shims dir* — NOT on current PATH order. That's deliberate: the shim only loses
|
|
2380
|
-
* PATH races in non-interactive / GUI-launched shells, which an interactive
|
|
2381
|
-
* `agents` run can't observe via its own PATH. Keying on the durable symlink lets
|
|
2382
|
-
* auto-adoption fire for those users too. Returns the launcher path or null.
|
|
2383
|
-
*/
|
|
2384
1611
|
export function findAdoptableLauncher(agent, overrides) {
|
|
2385
1612
|
const cliCommand = AGENTS[agent].cliCommand;
|
|
2386
1613
|
const homeDir = overrides?.homeDir ?? os.homedir();
|
|
2387
1614
|
const shimsDirReal = canonical(overrides?.shimsDir ?? getShimsDir());
|
|
2388
|
-
// ~/.local/bin is where grok/kimi/antigravity/claude/codex/droid self-install.
|
|
2389
1615
|
const candidate = path.join(homeDir, '.local', 'bin', cliCommand);
|
|
2390
1616
|
let stat;
|
|
2391
1617
|
try {
|
|
@@ -2395,21 +1621,18 @@ export function findAdoptableLauncher(agent, overrides) {
|
|
|
2395
1621
|
return null;
|
|
2396
1622
|
}
|
|
2397
1623
|
if (!stat.isSymbolicLink())
|
|
2398
|
-
return null;
|
|
1624
|
+
return null;
|
|
2399
1625
|
let resolved;
|
|
2400
1626
|
try {
|
|
2401
|
-
resolved = fs.realpathSync(candidate);
|
|
1627
|
+
resolved = fs.realpathSync(candidate);
|
|
2402
1628
|
}
|
|
2403
1629
|
catch {
|
|
2404
1630
|
return null;
|
|
2405
1631
|
}
|
|
2406
|
-
// Already ours, or resolves into our shims dir → not adoptable.
|
|
2407
1632
|
if (resolved === shimsDirReal || resolved.startsWith(shimsDirReal + path.sep))
|
|
2408
1633
|
return null;
|
|
2409
1634
|
return candidate;
|
|
2410
1635
|
}
|
|
2411
|
-
/** Canonical path for identity comparison — realpath when it exists (resolves
|
|
2412
|
-
* symlinks AND platform aliases like macOS /var → /private/var), else resolve. */
|
|
2413
1636
|
function canonical(p) {
|
|
2414
1637
|
try {
|
|
2415
1638
|
return fs.realpathSync(p);
|
|
@@ -2418,8 +1641,6 @@ function canonical(p) {
|
|
|
2418
1641
|
return path.resolve(p);
|
|
2419
1642
|
}
|
|
2420
1643
|
}
|
|
2421
|
-
/** Like canonical(), but null when the path can't be resolved (broken/racy
|
|
2422
|
-
* symlink) — used where a failed resolve must NOT collapse to the input path. */
|
|
2423
1644
|
function canonicalOrNull(p) {
|
|
2424
1645
|
try {
|
|
2425
1646
|
return fs.realpathSync(p);
|
|
@@ -2428,29 +1649,7 @@ function canonicalOrNull(p) {
|
|
|
2428
1649
|
return null;
|
|
2429
1650
|
}
|
|
2430
1651
|
}
|
|
2431
|
-
/**
|
|
2432
|
-
* Adopt the harness's own launcher that shadows our shim on PATH.
|
|
2433
|
-
*
|
|
2434
|
-
* PATH-ordering fixes (editing rc files) can never reliably win: `~/.local/bin`
|
|
2435
|
-
* (where grok/droid/etc. self-install) is prepended in `.zshenv`/`.zprofile`
|
|
2436
|
-
* for *every* shell, while our shims prepend only lands in `.zshrc`
|
|
2437
|
-
* (interactive). No single rc file guarantees "last prepend wins" across zsh's
|
|
2438
|
-
* whole sourcing chain, so the shim loses in non-interactive / GUI-launched
|
|
2439
|
-
* contexts. Instead of fighting PATH order, we *become* the launcher: replace
|
|
2440
|
-
* the shadowing symlink with one pointing at our shim, and record the real
|
|
2441
|
-
* original so the shim falls through to it when no managed version is selected.
|
|
2442
|
-
*
|
|
2443
|
-
* Regression bounds:
|
|
2444
|
-
* - Only ever touches a **symlink** (never renames/deletes a real binary).
|
|
2445
|
-
* - Records the resolved original + launcher path for lossless restore
|
|
2446
|
-
* (`releaseAdoptedLauncher`), in durable `.history` so a cache wipe can't
|
|
2447
|
-
* orphan the reverse pointer.
|
|
2448
|
-
* - Idempotent: a no-op once the launcher already points at our shim.
|
|
2449
|
-
* - Never records our own shim as the "original" (would loop).
|
|
2450
|
-
*/
|
|
2451
1652
|
export function adoptShadowingLauncher(agent, overrides) {
|
|
2452
|
-
// Repoints the user's OWN launcher symlink at our shim — the most invasive thing
|
|
2453
|
-
// in the codebase, and the one with no isolated-scoped equivalent at all.
|
|
2454
1653
|
assertIsolationBoundary(agent, 'adopt your launcher');
|
|
2455
1654
|
const shimsDir = overrides?.shimsDir ?? getShimsDir();
|
|
2456
1655
|
const shimPath = path.join(shimsDir, AGENTS[agent].cliCommand);
|
|
@@ -2466,33 +1665,20 @@ export function adoptShadowingLauncher(agent, overrides) {
|
|
|
2466
1665
|
catch {
|
|
2467
1666
|
return { adopted: false, reason: 'error', launcher };
|
|
2468
1667
|
}
|
|
2469
|
-
// Only adopt symlinks. A real binary in an early-PATH dir is left untouched —
|
|
2470
|
-
// renaming a multi-hundred-MB native binary is exactly the kind of surprise
|
|
2471
|
-
// this feature must avoid. (Its shim stays reachable via the versioned name.)
|
|
2472
1668
|
if (!stat.isSymbolicLink()) {
|
|
2473
1669
|
return { adopted: false, reason: 'not-a-symlink', launcher };
|
|
2474
1670
|
}
|
|
2475
1671
|
const resolved = canonical(launcher);
|
|
2476
|
-
// Already ours → nothing to do.
|
|
2477
1672
|
if (resolved === shimReal) {
|
|
2478
1673
|
return { adopted: false, reason: 'already-adopted', launcher };
|
|
2479
1674
|
}
|
|
2480
|
-
// Never record a target that resolves back into our shims dir: exec-ing it
|
|
2481
|
-
// from the shim would re-enter this dispatcher and spin forever.
|
|
2482
1675
|
if (resolved === shimsDirReal || resolved.startsWith(shimsDirReal + path.sep)) {
|
|
2483
1676
|
return { adopted: false, reason: 'unsafe-target', launcher };
|
|
2484
1677
|
}
|
|
2485
1678
|
try {
|
|
2486
1679
|
const recordPath = getAdoptedRecordPath(agent, overrides?.historyDir);
|
|
2487
1680
|
fs.mkdirSync(path.dirname(recordPath), { recursive: true });
|
|
2488
|
-
// Line 1: original binary (shim fall-through target). Line 2: launcher path
|
|
2489
|
-
// (release restores this exact symlink, independent of PATH order at release
|
|
2490
|
-
// time — the M3 fix). Absolute launcher path so release never has to
|
|
2491
|
-
// re-derive it from a PATH scan that may miss.
|
|
2492
1681
|
fs.writeFileSync(recordPath, `${resolved}\n${path.resolve(launcher)}\n`, 'utf-8');
|
|
2493
|
-
// Repoint the launcher at our shim. rm + symlink (not atomic rename) is fine
|
|
2494
|
-
// here: the record is already written, so a crash between the two leaves a
|
|
2495
|
-
// recoverable state and the next run re-adopts idempotently.
|
|
2496
1682
|
fs.rmSync(launcher);
|
|
2497
1683
|
fs.symlinkSync(shimPath, launcher);
|
|
2498
1684
|
return { adopted: true, launcher, original: resolved };
|
|
@@ -2501,12 +1687,6 @@ export function adoptShadowingLauncher(agent, overrides) {
|
|
|
2501
1687
|
return { adopted: false, reason: 'error', launcher };
|
|
2502
1688
|
}
|
|
2503
1689
|
}
|
|
2504
|
-
/**
|
|
2505
|
-
* Undo `adoptShadowingLauncher`: repoint the launcher back at the recorded
|
|
2506
|
-
* original and drop the record. Reversible escape hatch for users who want the
|
|
2507
|
-
* native launcher to win. Returns the restored original path, or null if there
|
|
2508
|
-
* was nothing to release.
|
|
2509
|
-
*/
|
|
2510
1690
|
export function releaseAdoptedLauncher(agent, overrides) {
|
|
2511
1691
|
const shimsDir = overrides?.shimsDir ?? getShimsDir();
|
|
2512
1692
|
const recordPath = getAdoptedRecordPath(agent, overrides?.historyDir);
|
|
@@ -2520,16 +1700,10 @@ export function releaseAdoptedLauncher(agent, overrides) {
|
|
|
2520
1700
|
const original = lines[0] ?? '';
|
|
2521
1701
|
if (!original)
|
|
2522
1702
|
return null;
|
|
2523
|
-
// Line 2 is the exact launcher we rewrote at adopt time. Restoring it directly
|
|
2524
|
-
// (rather than re-deriving from PATH) means release works regardless of the
|
|
2525
|
-
// current shell's PATH order — the M3 fix. Fall back to a PATH scan only for
|
|
2526
|
-
// records written before this format existed.
|
|
2527
1703
|
const launcher = lines[1] || getPathShadowingExecutable(agent) || original;
|
|
2528
1704
|
const shimReal = canonical(path.join(shimsDir, AGENTS[agent].cliCommand));
|
|
2529
1705
|
const shimPath = path.resolve(path.join(shimsDir, AGENTS[agent].cliCommand));
|
|
2530
1706
|
try {
|
|
2531
|
-
// Only rewrite the launcher if it currently points at our shim (i.e. we own
|
|
2532
|
-
// it). If the user has since replaced it themselves, leave it alone.
|
|
2533
1707
|
let pointsAtShim = false;
|
|
2534
1708
|
try {
|
|
2535
1709
|
const stat = fs.lstatSync(launcher);
|
|
@@ -2539,7 +1713,7 @@ export function releaseAdoptedLauncher(agent, overrides) {
|
|
|
2539
1713
|
pointsAtShim = canonicalOrNull(launcher) === shimReal || absoluteTarget === shimPath;
|
|
2540
1714
|
}
|
|
2541
1715
|
}
|
|
2542
|
-
catch {
|
|
1716
|
+
catch { }
|
|
2543
1717
|
if (pointsAtShim || !fs.existsSync(launcher)) {
|
|
2544
1718
|
try {
|
|
2545
1719
|
if (fs.lstatSync(launcher).isSymbolicLink()) {
|
|
@@ -2549,7 +1723,7 @@ export function releaseAdoptedLauncher(agent, overrides) {
|
|
|
2549
1723
|
fs.rmSync(launcher, { force: true });
|
|
2550
1724
|
}
|
|
2551
1725
|
}
|
|
2552
|
-
catch {
|
|
1726
|
+
catch { }
|
|
2553
1727
|
fs.symlinkSync(original, launcher);
|
|
2554
1728
|
}
|
|
2555
1729
|
fs.rmSync(recordPath);
|
|
@@ -2559,23 +1733,9 @@ export function releaseAdoptedLauncher(agent, overrides) {
|
|
|
2559
1733
|
return null;
|
|
2560
1734
|
}
|
|
2561
1735
|
}
|
|
2562
|
-
/**
|
|
2563
|
-
* Check if the agent's CLI command is shadowed by a shell alias.
|
|
2564
|
-
*
|
|
2565
|
-
* Shell aliases live in the user's session and aren't visible from a Node.js
|
|
2566
|
-
* child process. We do a best-effort scan of common RC files for `alias
|
|
2567
|
-
* <command>=` patterns. Returns false when detection is inconclusive.
|
|
2568
|
-
*
|
|
2569
|
-
* Tracks the LAST `alias` / `unalias` action for this command per rc file —
|
|
2570
|
-
* a trailing `unalias codex` cancels an earlier `alias codex=...`, and
|
|
2571
|
-
* `unalias` can name multiple commands on one line. Without this, an
|
|
2572
|
-
* `alias` line elsewhere in the file would surface as a false positive
|
|
2573
|
-
* (e.g. seen in zshrc setups that conditionally clear an alias later).
|
|
2574
|
-
*/
|
|
2575
1736
|
function escapeRegex(value) {
|
|
2576
1737
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
2577
1738
|
}
|
|
2578
|
-
/** Walk rc lines in order; a later `unalias` clears an earlier `alias`. */
|
|
2579
1739
|
function isAliasActiveInRcContent(content, cliCommand) {
|
|
2580
1740
|
let active = false;
|
|
2581
1741
|
const aliasPattern = new RegExp(`^\\s*alias\\s+${escapeRegex(cliCommand)}\\s*=`);
|
|
@@ -2615,14 +1775,10 @@ export function hasAliasShadowingShim(agent, overrides) {
|
|
|
2615
1775
|
return true;
|
|
2616
1776
|
}
|
|
2617
1777
|
catch {
|
|
2618
|
-
// unreadable rc file — skip
|
|
2619
1778
|
}
|
|
2620
1779
|
}
|
|
2621
1780
|
return false;
|
|
2622
1781
|
}
|
|
2623
|
-
/**
|
|
2624
|
-
* Check if shims directory is in PATH.
|
|
2625
|
-
*/
|
|
2626
1782
|
export function isShimsInPath() {
|
|
2627
1783
|
const shimsDir = getShimsDir();
|
|
2628
1784
|
const pathDirs = (process.env.PATH || '').split(path.delimiter);
|
|
@@ -2674,9 +1830,6 @@ export function stripShimPathLines(content, shimsDir) {
|
|
|
2674
1830
|
}
|
|
2675
1831
|
return kept.join('\n').replace(/\n{3,}/g, '\n\n');
|
|
2676
1832
|
}
|
|
2677
|
-
/**
|
|
2678
|
-
* Get the shell rc file path for the current shell.
|
|
2679
|
-
*/
|
|
2680
1833
|
function getShellRcFile(overrides) {
|
|
2681
1834
|
const shell = overrides?.shell || process.env.SHELL || '/bin/bash';
|
|
2682
1835
|
const shellName = path.basename(shell);
|
|
@@ -2699,9 +1852,6 @@ function getShellRcFile(overrides) {
|
|
|
2699
1852
|
shell: shellName,
|
|
2700
1853
|
};
|
|
2701
1854
|
}
|
|
2702
|
-
/**
|
|
2703
|
-
* Get shell configuration instructions for adding shims to PATH.
|
|
2704
|
-
*/
|
|
2705
1855
|
export function getPathSetupInstructions() {
|
|
2706
1856
|
const shimsDir = getShimsDir();
|
|
2707
1857
|
const { rcFile, shell } = getShellRcFile();
|
|
@@ -2717,20 +1867,12 @@ IMPORTANT: Shims must be the last PATH prepend in your shell config to override
|
|
|
2717
1867
|
Then restart your shell or run:
|
|
2718
1868
|
source ~/${rcFile}`;
|
|
2719
1869
|
}
|
|
2720
|
-
/**
|
|
2721
|
-
* Add the shims directory to PATH: edits the shell rc file on POSIX, or registers
|
|
2722
|
-
* it on the Windows User PATH (registry + WM_SETTINGCHANGE). Idempotent.
|
|
2723
|
-
*/
|
|
2724
1870
|
export function addShimsToPath(overrides) {
|
|
2725
|
-
// Windows has no shell rc file to edit. Register the shims dir on the User PATH
|
|
2726
|
-
// via the platform-native mechanism instead. (The `shell` override is the test
|
|
2727
|
-
// hook for exercising the POSIX path, so it bypasses this branch.)
|
|
2728
1871
|
if (IS_WINDOWS && !overrides?.shell) {
|
|
2729
1872
|
return addShimsToWindowsUserPath(overrides?.shimsDir || getShimsDir());
|
|
2730
1873
|
}
|
|
2731
1874
|
const shimsDir = overrides?.shimsDir || getShimsDir();
|
|
2732
1875
|
const { rcFile, rcPath, shell } = getShellRcFile(overrides);
|
|
2733
|
-
// Read current rc file content
|
|
2734
1876
|
let content = '';
|
|
2735
1877
|
try {
|
|
2736
1878
|
if (fs.existsSync(rcPath)) {
|
|
@@ -2740,7 +1882,6 @@ export function addShimsToPath(overrides) {
|
|
|
2740
1882
|
catch (err) {
|
|
2741
1883
|
return { success: false, error: `Could not read ${rcFile}: ${err.message}` };
|
|
2742
1884
|
}
|
|
2743
|
-
// Generate the canonical PATH block.
|
|
2744
1885
|
let exportBlock;
|
|
2745
1886
|
if (shell === 'fish') {
|
|
2746
1887
|
exportBlock = `# agents-cli: version-managed agent CLIs\nfish_add_path ${shimsDir}\n`;
|
|
@@ -2749,14 +1890,11 @@ export function addShimsToPath(overrides) {
|
|
|
2749
1890
|
exportBlock = `# agents-cli: version-managed agent CLIs\nexport PATH="${shimsDir}:$PATH"\n`;
|
|
2750
1891
|
}
|
|
2751
1892
|
const contentWithoutShimLines = stripShimPathLines(content, shimsDir);
|
|
2752
|
-
// Write the updated content
|
|
2753
1893
|
try {
|
|
2754
|
-
// Ensure parent directories exist (especially for fish: ~/.config/fish/)
|
|
2755
1894
|
const rcDir = path.dirname(rcPath);
|
|
2756
1895
|
if (!fs.existsSync(rcDir)) {
|
|
2757
1896
|
fs.mkdirSync(rcDir, { recursive: true });
|
|
2758
1897
|
}
|
|
2759
|
-
// Append at EOF so later installer PATH prepends cannot shadow the shims.
|
|
2760
1898
|
const separator = contentWithoutShimLines.length > 0 && !contentWithoutShimLines.endsWith('\n') ? '\n' : '';
|
|
2761
1899
|
let newContent = contentWithoutShimLines + separator + exportBlock;
|
|
2762
1900
|
newContent = newContent.replace(/\n{2,}$/g, '\n');
|
|
@@ -2772,15 +1910,6 @@ export function addShimsToPath(overrides) {
|
|
|
2772
1910
|
return { success: false, error: `Could not write ${rcFile}: ${err.message}` };
|
|
2773
1911
|
}
|
|
2774
1912
|
}
|
|
2775
|
-
/**
|
|
2776
|
-
* Register the shims dir on the Windows User PATH via the .NET environment API,
|
|
2777
|
-
* which writes the registry AND broadcasts WM_SETTINGCHANGE — the correct analog
|
|
2778
|
-
* of editing a shell rc file (no `setx` truncation, no manual step). Idempotent:
|
|
2779
|
-
* a no-op when the shims dir is already first in the User PATH. Moves it to the
|
|
2780
|
-
* front when it exists but is in the wrong position (e.g. appended by an old
|
|
2781
|
-
* install) so it overrides any npm/global installs that appear later. The shims
|
|
2782
|
-
* dir is passed via an env var so it is never interpolated into the script text.
|
|
2783
|
-
*/
|
|
2784
1913
|
function addShimsToWindowsUserPath(shimsDir) {
|
|
2785
1914
|
const r = prependToWindowsUserPath(shimsDir);
|
|
2786
1915
|
if (!r.success) {
|
|
@@ -2807,12 +1936,6 @@ export function listAgentsWithInstalledVersions() {
|
|
|
2807
1936
|
function isInstalledVersionIsolated(agent, version) {
|
|
2808
1937
|
return fs.existsSync(path.join(getVersionsDir(), agent, version, '.isolated'));
|
|
2809
1938
|
}
|
|
2810
|
-
/**
|
|
2811
|
-
* Thrown when an operation would carry an isolated-only agent across the isolation
|
|
2812
|
-
* boundary. Callers that can explain the situation catch it and print guidance; the
|
|
2813
|
-
* throw is what makes the boundary a property of the code rather than a convention
|
|
2814
|
-
* every future call site has to remember.
|
|
2815
|
-
*/
|
|
2816
1939
|
export class IsolationBoundaryError extends Error {
|
|
2817
1940
|
agent;
|
|
2818
1941
|
operation;
|
|
@@ -2823,18 +1946,6 @@ export class IsolationBoundaryError extends Error {
|
|
|
2823
1946
|
this.name = 'IsolationBoundaryError';
|
|
2824
1947
|
}
|
|
2825
1948
|
}
|
|
2826
|
-
/**
|
|
2827
|
-
* True when EVERY installed version of `agent` is isolated (and at least one is).
|
|
2828
|
-
*
|
|
2829
|
-
* This is the switch: installing with `--isolated` is itself the act of opting in,
|
|
2830
|
-
* so there is no mode to set and none to forget. It is per-agent, so an isolated
|
|
2831
|
-
* codex constrains nothing about claude. And the escape hatch is inherent — remove
|
|
2832
|
-
* the isolated copies and the agent is ordinary again, which means the state that
|
|
2833
|
-
* grants protection is the same state you delete to drop it.
|
|
2834
|
-
*
|
|
2835
|
-
* An agent with any NORMAL version is not protected: that install already owns the
|
|
2836
|
-
* launcher and the real `~/.<agent>`, so there is no boundary left to defend.
|
|
2837
|
-
*/
|
|
2838
1949
|
export function isIsolationProtected(agent) {
|
|
2839
1950
|
const agentVersionsDir = path.join(getVersionsDir(), agent);
|
|
2840
1951
|
let dirs;
|
|
@@ -2846,12 +1957,6 @@ export function isIsolationProtected(agent) {
|
|
|
2846
1957
|
catch {
|
|
2847
1958
|
return false;
|
|
2848
1959
|
}
|
|
2849
|
-
// Count only directories that are actually an install. A bare version dir is
|
|
2850
|
-
// scaffolding, not a non-isolated version — and treating it as one would disable
|
|
2851
|
-
// protection at exactly the wrong moment: an adopting path that does
|
|
2852
|
-
// `mkdirSync(<version>/home)` before adopting would flip this to false with its own
|
|
2853
|
-
// first line and then walk straight through the gates. Ignoring scaffolding biases
|
|
2854
|
-
// the predicate toward protecting, which is the safe direction to fail in.
|
|
2855
1960
|
const installed = dirs.filter((v) => {
|
|
2856
1961
|
const dir = path.join(agentVersionsDir, v);
|
|
2857
1962
|
return fs.existsSync(path.join(dir, 'node_modules')) || fs.existsSync(path.join(dir, 'package.json'));
|
|
@@ -2860,7 +1965,6 @@ export function isIsolationProtected(agent) {
|
|
|
2860
1965
|
return false;
|
|
2861
1966
|
return installed.every((v) => isInstalledVersionIsolated(agent, v));
|
|
2862
1967
|
}
|
|
2863
|
-
/** Refuse `operation` when `agent` is isolated-only. */
|
|
2864
1968
|
export function assertIsolationBoundary(agent, operation) {
|
|
2865
1969
|
if (isIsolationProtected(agent))
|
|
2866
1970
|
throw new IsolationBoundaryError(agent, operation);
|
|
@@ -2880,9 +1984,6 @@ export function listAgentsWithNonIsolatedInstalledVersions() {
|
|
|
2880
1984
|
.some((entry) => entry.isDirectory() && !isInstalledVersionIsolated(agent, entry.name));
|
|
2881
1985
|
});
|
|
2882
1986
|
}
|
|
2883
|
-
/**
|
|
2884
|
-
* Create shims for all installed agents.
|
|
2885
|
-
*/
|
|
2886
1987
|
function ensureAllShims() {
|
|
2887
1988
|
const versionsDir = getVersionsDir();
|
|
2888
1989
|
if (!fs.existsSync(versionsDir)) {
|
|
@@ -2901,10 +2002,6 @@ function ensureAllShims() {
|
|
|
2901
2002
|
}
|
|
2902
2003
|
}
|
|
2903
2004
|
}
|
|
2904
|
-
/**
|
|
2905
|
-
* Compare resources between two versions.
|
|
2906
|
-
* Returns resources that exist in currentVersion but not in targetVersion.
|
|
2907
|
-
*/
|
|
2908
2005
|
function compareVersionResources(agent, currentVersion, targetVersion) {
|
|
2909
2006
|
const agentConfig = AGENTS[agent];
|
|
2910
2007
|
const currentPath = getVersionConfigPath(agent, currentVersion);
|
|
@@ -2916,7 +2013,6 @@ function compareVersionResources(agent, currentVersion, targetVersion) {
|
|
|
2916
2013
|
memory: [],
|
|
2917
2014
|
mcp: [],
|
|
2918
2015
|
};
|
|
2919
|
-
// Helper to list directory contents (names only)
|
|
2920
2016
|
const listDir = (dir) => {
|
|
2921
2017
|
if (!fs.existsSync(dir))
|
|
2922
2018
|
return [];
|
|
@@ -2924,11 +2020,9 @@ function compareVersionResources(agent, currentVersion, targetVersion) {
|
|
|
2924
2020
|
return fs.readdirSync(dir).filter(f => !f.startsWith('.'));
|
|
2925
2021
|
}
|
|
2926
2022
|
catch {
|
|
2927
|
-
/* directory not readable */
|
|
2928
2023
|
return [];
|
|
2929
2024
|
}
|
|
2930
2025
|
};
|
|
2931
|
-
// Helper to count lines in a file
|
|
2932
2026
|
const countLines = (filePath) => {
|
|
2933
2027
|
if (!fs.existsSync(filePath))
|
|
2934
2028
|
return 0;
|
|
@@ -2936,23 +2030,18 @@ function compareVersionResources(agent, currentVersion, targetVersion) {
|
|
|
2936
2030
|
return fs.readFileSync(filePath, 'utf-8').split('\n').length;
|
|
2937
2031
|
}
|
|
2938
2032
|
catch {
|
|
2939
|
-
/* file not readable */
|
|
2940
2033
|
return 0;
|
|
2941
2034
|
}
|
|
2942
2035
|
};
|
|
2943
|
-
// Compare commands
|
|
2944
2036
|
const currentCommands = listDir(path.join(currentPath, agentConfig.commandsSubdir));
|
|
2945
2037
|
const targetCommands = new Set(listDir(path.join(targetPath, agentConfig.commandsSubdir)));
|
|
2946
2038
|
diff.commands = currentCommands.filter(c => !targetCommands.has(c)).map(c => c.replace(/\.(md|toml)$/, ''));
|
|
2947
|
-
// Compare skills
|
|
2948
2039
|
const currentSkills = listDir(path.join(currentPath, 'skills'));
|
|
2949
2040
|
const targetSkills = new Set(listDir(path.join(targetPath, 'skills')));
|
|
2950
2041
|
diff.skills = currentSkills.filter(s => !targetSkills.has(s));
|
|
2951
|
-
// Compare hooks
|
|
2952
2042
|
const currentHooks = listDir(path.join(currentPath, 'hooks'));
|
|
2953
2043
|
const targetHooks = new Set(listDir(path.join(targetPath, 'hooks')));
|
|
2954
2044
|
diff.hooks = currentHooks.filter(h => !targetHooks.has(h));
|
|
2955
|
-
// Compare memory files (instructionsFile like CLAUDE.md)
|
|
2956
2045
|
const memoryFile = agentConfig.instructionsFile;
|
|
2957
2046
|
const currentMemoryPath = path.join(currentPath, memoryFile);
|
|
2958
2047
|
const targetMemoryPath = path.join(targetPath, memoryFile);
|
|
@@ -2961,7 +2050,6 @@ function compareVersionResources(agent, currentVersion, targetVersion) {
|
|
|
2961
2050
|
if (currentLines > 0 && currentLines !== targetLines) {
|
|
2962
2051
|
diff.memory.push({ file: memoryFile, currentLines, targetLines });
|
|
2963
2052
|
}
|
|
2964
|
-
// Compare MCP servers (from settings.json)
|
|
2965
2053
|
const readMcpServers = (configPath) => {
|
|
2966
2054
|
const settingsPath = path.join(configPath, 'settings.json');
|
|
2967
2055
|
if (!fs.existsSync(settingsPath))
|
|
@@ -2971,7 +2059,6 @@ function compareVersionResources(agent, currentVersion, targetVersion) {
|
|
|
2971
2059
|
return Object.keys(settings.mcpServers || {});
|
|
2972
2060
|
}
|
|
2973
2061
|
catch {
|
|
2974
|
-
/* settings.json corrupt or unreadable */
|
|
2975
2062
|
return [];
|
|
2976
2063
|
}
|
|
2977
2064
|
};
|
|
@@ -2980,9 +2067,6 @@ function compareVersionResources(agent, currentVersion, targetVersion) {
|
|
|
2980
2067
|
diff.mcp = currentMcp.filter(m => !targetMcp.has(m));
|
|
2981
2068
|
return diff;
|
|
2982
2069
|
}
|
|
2983
|
-
/**
|
|
2984
|
-
* Check if a ResourceDiff has any differences.
|
|
2985
|
-
*/
|
|
2986
2070
|
export function hasResourceDiff(diff) {
|
|
2987
2071
|
return (diff.commands.length > 0 ||
|
|
2988
2072
|
diff.skills.length > 0 ||
|
|
@@ -2990,15 +2074,10 @@ export function hasResourceDiff(diff) {
|
|
|
2990
2074
|
diff.memory.length > 0 ||
|
|
2991
2075
|
diff.mcp.length > 0);
|
|
2992
2076
|
}
|
|
2993
|
-
/**
|
|
2994
|
-
* Copy resources from one version to another.
|
|
2995
|
-
* Only copies resources listed in the diff (i.e., ones missing in target).
|
|
2996
|
-
*/
|
|
2997
2077
|
function copyResourcesToVersion(agent, fromVersion, toVersion, diff) {
|
|
2998
2078
|
const agentConfig = AGENTS[agent];
|
|
2999
2079
|
const fromPath = getVersionConfigPath(agent, fromVersion);
|
|
3000
2080
|
const toPath = getVersionConfigPath(agent, toVersion);
|
|
3001
|
-
// Helper to copy a file or directory
|
|
3002
2081
|
const copyItem = (srcDir, destDir, name) => {
|
|
3003
2082
|
const srcPath = path.join(srcDir, name);
|
|
3004
2083
|
const destPath = path.join(destDir, name);
|
|
@@ -3013,21 +2092,17 @@ function copyResourcesToVersion(agent, fromVersion, toVersion, diff) {
|
|
|
3013
2092
|
fs.copyFileSync(srcPath, destPath);
|
|
3014
2093
|
}
|
|
3015
2094
|
};
|
|
3016
|
-
// Copy missing commands
|
|
3017
2095
|
const commandsSubdir = agentConfig.commandsSubdir;
|
|
3018
2096
|
const ext = agentConfig.format === 'toml' ? '.toml' : '.md';
|
|
3019
2097
|
for (const cmd of diff.commands) {
|
|
3020
2098
|
copyItem(path.join(fromPath, commandsSubdir), path.join(toPath, commandsSubdir), `${cmd}${ext}`);
|
|
3021
2099
|
}
|
|
3022
|
-
// Copy missing skills
|
|
3023
2100
|
for (const skill of diff.skills) {
|
|
3024
2101
|
copyItem(path.join(fromPath, 'skills'), path.join(toPath, 'skills'), skill);
|
|
3025
2102
|
}
|
|
3026
|
-
// Copy missing hooks
|
|
3027
2103
|
for (const hook of diff.hooks) {
|
|
3028
2104
|
copyItem(path.join(fromPath, 'hooks'), path.join(toPath, 'hooks'), hook);
|
|
3029
2105
|
}
|
|
3030
|
-
// Copy memory file if different
|
|
3031
2106
|
for (const mem of diff.memory) {
|
|
3032
2107
|
const srcPath = path.join(fromPath, mem.file);
|
|
3033
2108
|
const destPath = path.join(toPath, mem.file);
|
|
@@ -3035,7 +2110,6 @@ function copyResourcesToVersion(agent, fromVersion, toVersion, diff) {
|
|
|
3035
2110
|
fs.copyFileSync(srcPath, destPath);
|
|
3036
2111
|
}
|
|
3037
2112
|
}
|
|
3038
|
-
// Merge MCP servers into target settings.json
|
|
3039
2113
|
if (diff.mcp.length > 0) {
|
|
3040
2114
|
const fromSettingsPath = path.join(fromPath, 'settings.json');
|
|
3041
2115
|
const toSettingsPath = path.join(toPath, 'settings.json');
|
|
@@ -3057,7 +2131,6 @@ function copyResourcesToVersion(agent, fromVersion, toVersion, diff) {
|
|
|
3057
2131
|
fs.writeFileSync(toSettingsPath, JSON.stringify(toSettings, null, 2));
|
|
3058
2132
|
}
|
|
3059
2133
|
catch {
|
|
3060
|
-
/* settings.json parse error, skip MCP merge */
|
|
3061
2134
|
}
|
|
3062
2135
|
}
|
|
3063
2136
|
}
|