@swarmify/agents-cli 1.13.3 → 1.14.0
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/README.md +2 -319
- package/bin/agents.js +2 -0
- package/package.json +13 -79
- package/scripts/postinstall.js +4 -71
- package/CHANGELOG.md +0 -316
- package/LICENSE +0 -21
- package/dist/commands/__tests__/sessions-tail.test.d.ts +0 -2
- package/dist/commands/__tests__/sessions-tail.test.d.ts.map +0 -1
- package/dist/commands/__tests__/sessions-tail.test.js +0 -108
- package/dist/commands/__tests__/sessions-tail.test.js.map +0 -1
- package/dist/commands/__tests__/sessions.test.d.ts +0 -2
- package/dist/commands/__tests__/sessions.test.d.ts.map +0 -1
- package/dist/commands/__tests__/sessions.test.js +0 -636
- package/dist/commands/__tests__/sessions.test.js.map +0 -1
- package/dist/commands/cloud.d.ts +0 -11
- package/dist/commands/cloud.d.ts.map +0 -1
- package/dist/commands/cloud.js +0 -363
- package/dist/commands/cloud.js.map +0 -1
- package/dist/commands/commands.d.ts +0 -12
- package/dist/commands/commands.d.ts.map +0 -1
- package/dist/commands/commands.js +0 -629
- package/dist/commands/commands.js.map +0 -1
- package/dist/commands/daemon.d.ts +0 -11
- package/dist/commands/daemon.d.ts.map +0 -1
- package/dist/commands/daemon.js +0 -119
- package/dist/commands/daemon.js.map +0 -1
- package/dist/commands/drive.d.ts +0 -11
- package/dist/commands/drive.d.ts.map +0 -1
- package/dist/commands/drive.js +0 -175
- package/dist/commands/drive.js.map +0 -1
- package/dist/commands/exec.d.ts +0 -11
- package/dist/commands/exec.d.ts.map +0 -1
- package/dist/commands/exec.js +0 -251
- package/dist/commands/exec.js.map +0 -1
- package/dist/commands/factory.d.ts +0 -11
- package/dist/commands/factory.d.ts.map +0 -1
- package/dist/commands/factory.js +0 -445
- package/dist/commands/factory.js.map +0 -1
- package/dist/commands/fork.d.ts +0 -11
- package/dist/commands/fork.d.ts.map +0 -1
- package/dist/commands/fork.js +0 -147
- package/dist/commands/fork.js.map +0 -1
- package/dist/commands/hooks.d.ts +0 -12
- package/dist/commands/hooks.d.ts.map +0 -1
- package/dist/commands/hooks.js +0 -690
- package/dist/commands/hooks.js.map +0 -1
- package/dist/commands/init.d.ts +0 -15
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -137
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/mcp.d.ts +0 -12
- package/dist/commands/mcp.d.ts.map +0 -1
- package/dist/commands/mcp.js +0 -583
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/models.d.ts +0 -11
- package/dist/commands/models.d.ts.map +0 -1
- package/dist/commands/models.js +0 -170
- package/dist/commands/models.js.map +0 -1
- package/dist/commands/packages.d.ts +0 -11
- package/dist/commands/packages.d.ts.map +0 -1
- package/dist/commands/packages.js +0 -551
- package/dist/commands/packages.js.map +0 -1
- package/dist/commands/permissions.d.ts +0 -12
- package/dist/commands/permissions.d.ts.map +0 -1
- package/dist/commands/permissions.js +0 -724
- package/dist/commands/permissions.js.map +0 -1
- package/dist/commands/plugins.d.ts +0 -11
- package/dist/commands/plugins.d.ts.map +0 -1
- package/dist/commands/plugins.js +0 -393
- package/dist/commands/plugins.js.map +0 -1
- package/dist/commands/profiles.d.ts +0 -12
- package/dist/commands/profiles.d.ts.map +0 -1
- package/dist/commands/profiles.js +0 -255
- package/dist/commands/profiles.js.map +0 -1
- package/dist/commands/pty.d.ts +0 -21
- package/dist/commands/pty.d.ts.map +0 -1
- package/dist/commands/pty.js +0 -391
- package/dist/commands/pty.js.map +0 -1
- package/dist/commands/pull.d.ts +0 -11
- package/dist/commands/pull.d.ts.map +0 -1
- package/dist/commands/pull.js +0 -456
- package/dist/commands/pull.js.map +0 -1
- package/dist/commands/push.d.ts +0 -11
- package/dist/commands/push.d.ts.map +0 -1
- package/dist/commands/push.js +0 -188
- package/dist/commands/push.js.map +0 -1
- package/dist/commands/refresh-memory.d.ts +0 -16
- package/dist/commands/refresh-memory.d.ts.map +0 -1
- package/dist/commands/refresh-memory.js +0 -52
- package/dist/commands/refresh-memory.js.map +0 -1
- package/dist/commands/resource-view.d.ts +0 -39
- package/dist/commands/resource-view.d.ts.map +0 -1
- package/dist/commands/resource-view.js +0 -197
- package/dist/commands/resource-view.js.map +0 -1
- package/dist/commands/routines.d.ts +0 -11
- package/dist/commands/routines.d.ts.map +0 -1
- package/dist/commands/routines.js +0 -590
- package/dist/commands/routines.js.map +0 -1
- package/dist/commands/rules.d.ts +0 -12
- package/dist/commands/rules.d.ts.map +0 -1
- package/dist/commands/rules.js +0 -489
- package/dist/commands/rules.js.map +0 -1
- package/dist/commands/secrets.d.ts +0 -11
- package/dist/commands/secrets.d.ts.map +0 -1
- package/dist/commands/secrets.js +0 -352
- package/dist/commands/secrets.js.map +0 -1
- package/dist/commands/sessions-picker.d.ts +0 -18
- package/dist/commands/sessions-picker.d.ts.map +0 -1
- package/dist/commands/sessions-picker.js +0 -265
- package/dist/commands/sessions-picker.js.map +0 -1
- package/dist/commands/sessions-tail.d.ts +0 -20
- package/dist/commands/sessions-tail.d.ts.map +0 -1
- package/dist/commands/sessions-tail.js +0 -236
- package/dist/commands/sessions-tail.js.map +0 -1
- package/dist/commands/sessions.d.ts +0 -18
- package/dist/commands/sessions.d.ts.map +0 -1
- package/dist/commands/sessions.js +0 -1173
- package/dist/commands/sessions.js.map +0 -1
- package/dist/commands/skills.d.ts +0 -12
- package/dist/commands/skills.d.ts.map +0 -1
- package/dist/commands/skills.js +0 -717
- package/dist/commands/skills.js.map +0 -1
- package/dist/commands/status.d.ts +0 -10
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js +0 -26
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/subagents.d.ts +0 -11
- package/dist/commands/subagents.d.ts.map +0 -1
- package/dist/commands/subagents.js +0 -361
- package/dist/commands/subagents.js.map +0 -1
- package/dist/commands/sync.d.ts +0 -11
- package/dist/commands/sync.d.ts.map +0 -1
- package/dist/commands/sync.js +0 -70
- package/dist/commands/sync.js.map +0 -1
- package/dist/commands/teams-picker.d.ts +0 -18
- package/dist/commands/teams-picker.d.ts.map +0 -1
- package/dist/commands/teams-picker.js +0 -290
- package/dist/commands/teams-picker.js.map +0 -1
- package/dist/commands/teams.d.ts +0 -18
- package/dist/commands/teams.d.ts.map +0 -1
- package/dist/commands/teams.js +0 -1144
- package/dist/commands/teams.js.map +0 -1
- package/dist/commands/utils.d.ts +0 -45
- package/dist/commands/utils.d.ts.map +0 -1
- package/dist/commands/utils.js +0 -106
- package/dist/commands/utils.js.map +0 -1
- package/dist/commands/versions.d.ts +0 -11
- package/dist/commands/versions.d.ts.map +0 -1
- package/dist/commands/versions.js +0 -701
- package/dist/commands/versions.js.map +0 -1
- package/dist/commands/view.d.ts +0 -43
- package/dist/commands/view.d.ts.map +0 -1
- package/dist/commands/view.js +0 -894
- package/dist/commands/view.js.map +0 -1
- package/dist/index.d.ts +0 -9
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -496
- package/dist/index.js.map +0 -1
- package/dist/lib/__tests__/bugfixes.test.d.ts +0 -2
- package/dist/lib/__tests__/bugfixes.test.d.ts.map +0 -1
- package/dist/lib/__tests__/bugfixes.test.js +0 -192
- package/dist/lib/__tests__/bugfixes.test.js.map +0 -1
- package/dist/lib/__tests__/exec.test.d.ts +0 -2
- package/dist/lib/__tests__/exec.test.d.ts.map +0 -1
- package/dist/lib/__tests__/exec.test.js +0 -446
- package/dist/lib/__tests__/exec.test.js.map +0 -1
- package/dist/lib/__tests__/git-sync.test.d.ts +0 -2
- package/dist/lib/__tests__/git-sync.test.d.ts.map +0 -1
- package/dist/lib/__tests__/git-sync.test.js +0 -138
- package/dist/lib/__tests__/git-sync.test.js.map +0 -1
- package/dist/lib/__tests__/hooks.test.d.ts +0 -2
- package/dist/lib/__tests__/hooks.test.d.ts.map +0 -1
- package/dist/lib/__tests__/hooks.test.js +0 -203
- package/dist/lib/__tests__/hooks.test.js.map +0 -1
- package/dist/lib/__tests__/memory-compile.test.d.ts +0 -2
- package/dist/lib/__tests__/memory-compile.test.d.ts.map +0 -1
- package/dist/lib/__tests__/memory-compile.test.js +0 -95
- package/dist/lib/__tests__/memory-compile.test.js.map +0 -1
- package/dist/lib/__tests__/models.test.d.ts +0 -2
- package/dist/lib/__tests__/models.test.d.ts.map +0 -1
- package/dist/lib/__tests__/models.test.js +0 -239
- package/dist/lib/__tests__/models.test.js.map +0 -1
- package/dist/lib/__tests__/rotate.test.d.ts +0 -2
- package/dist/lib/__tests__/rotate.test.d.ts.map +0 -1
- package/dist/lib/__tests__/rotate.test.js +0 -80
- package/dist/lib/__tests__/rotate.test.js.map +0 -1
- package/dist/lib/__tests__/secrets-bundles.test.d.ts +0 -2
- package/dist/lib/__tests__/secrets-bundles.test.d.ts.map +0 -1
- package/dist/lib/__tests__/secrets-bundles.test.js +0 -104
- package/dist/lib/__tests__/secrets-bundles.test.js.map +0 -1
- package/dist/lib/__tests__/secrets.test.d.ts +0 -2
- package/dist/lib/__tests__/secrets.test.d.ts.map +0 -1
- package/dist/lib/__tests__/secrets.test.js +0 -90
- package/dist/lib/__tests__/secrets.test.js.map +0 -1
- package/dist/lib/__tests__/shims.test.d.ts +0 -2
- package/dist/lib/__tests__/shims.test.d.ts.map +0 -1
- package/dist/lib/__tests__/shims.test.js +0 -57
- package/dist/lib/__tests__/shims.test.js.map +0 -1
- package/dist/lib/__tests__/usage.test.d.ts +0 -2
- package/dist/lib/__tests__/usage.test.d.ts.map +0 -1
- package/dist/lib/__tests__/usage.test.js +0 -220
- package/dist/lib/__tests__/usage.test.js.map +0 -1
- package/dist/lib/__tests__/versions.test.d.ts +0 -2
- package/dist/lib/__tests__/versions.test.d.ts.map +0 -1
- package/dist/lib/__tests__/versions.test.js +0 -63
- package/dist/lib/__tests__/versions.test.js.map +0 -1
- package/dist/lib/agents.d.ts +0 -158
- package/dist/lib/agents.d.ts.map +0 -1
- package/dist/lib/agents.js +0 -1159
- package/dist/lib/agents.js.map +0 -1
- package/dist/lib/artifact-actions.d.ts +0 -27
- package/dist/lib/artifact-actions.d.ts.map +0 -1
- package/dist/lib/artifact-actions.js +0 -58
- package/dist/lib/artifact-actions.js.map +0 -1
- package/dist/lib/cloud/codex.d.ts +0 -26
- package/dist/lib/cloud/codex.d.ts.map +0 -1
- package/dist/lib/cloud/codex.js +0 -237
- package/dist/lib/cloud/codex.js.map +0 -1
- package/dist/lib/cloud/factory.d.ts +0 -32
- package/dist/lib/cloud/factory.d.ts.map +0 -1
- package/dist/lib/cloud/factory.js +0 -43
- package/dist/lib/cloud/factory.js.map +0 -1
- package/dist/lib/cloud/registry.d.ts +0 -16
- package/dist/lib/cloud/registry.d.ts.map +0 -1
- package/dist/lib/cloud/registry.js +0 -68
- package/dist/lib/cloud/registry.js.map +0 -1
- package/dist/lib/cloud/rush.d.ts +0 -37
- package/dist/lib/cloud/rush.d.ts.map +0 -1
- package/dist/lib/cloud/rush.js +0 -230
- package/dist/lib/cloud/rush.js.map +0 -1
- package/dist/lib/cloud/rush.test.d.ts +0 -2
- package/dist/lib/cloud/rush.test.d.ts.map +0 -1
- package/dist/lib/cloud/rush.test.js +0 -63
- package/dist/lib/cloud/rush.test.js.map +0 -1
- package/dist/lib/cloud/store.d.ts +0 -23
- package/dist/lib/cloud/store.d.ts.map +0 -1
- package/dist/lib/cloud/store.js +0 -116
- package/dist/lib/cloud/store.js.map +0 -1
- package/dist/lib/cloud/stream.d.ts +0 -24
- package/dist/lib/cloud/stream.d.ts.map +0 -1
- package/dist/lib/cloud/stream.js +0 -145
- package/dist/lib/cloud/stream.js.map +0 -1
- package/dist/lib/cloud/types.d.ts +0 -109
- package/dist/lib/cloud/types.d.ts.map +0 -1
- package/dist/lib/cloud/types.js +0 -33
- package/dist/lib/cloud/types.js.map +0 -1
- package/dist/lib/cloud/types.test.d.ts +0 -2
- package/dist/lib/cloud/types.test.d.ts.map +0 -1
- package/dist/lib/cloud/types.test.js +0 -41
- package/dist/lib/cloud/types.test.js.map +0 -1
- package/dist/lib/commands.d.ts +0 -141
- package/dist/lib/commands.d.ts.map +0 -1
- package/dist/lib/commands.js +0 -514
- package/dist/lib/commands.js.map +0 -1
- package/dist/lib/convert.d.ts +0 -21
- package/dist/lib/convert.d.ts.map +0 -1
- package/dist/lib/convert.js +0 -54
- package/dist/lib/convert.js.map +0 -1
- package/dist/lib/daemon.d.ts +0 -43
- package/dist/lib/daemon.d.ts.map +0 -1
- package/dist/lib/daemon.js +0 -332
- package/dist/lib/daemon.js.map +0 -1
- package/dist/lib/drive-sync.d.ts +0 -46
- package/dist/lib/drive-sync.d.ts.map +0 -1
- package/dist/lib/drive-sync.js +0 -209
- package/dist/lib/drive-sync.js.map +0 -1
- package/dist/lib/exec.d.ts +0 -101
- package/dist/lib/exec.d.ts.map +0 -1
- package/dist/lib/exec.js +0 -450
- package/dist/lib/exec.js.map +0 -1
- package/dist/lib/factory/__tests__/config.test.d.ts +0 -2
- package/dist/lib/factory/__tests__/config.test.d.ts.map +0 -1
- package/dist/lib/factory/__tests__/config.test.js +0 -128
- package/dist/lib/factory/__tests__/config.test.js.map +0 -1
- package/dist/lib/factory/config.d.ts +0 -49
- package/dist/lib/factory/config.d.ts.map +0 -1
- package/dist/lib/factory/config.js +0 -127
- package/dist/lib/factory/config.js.map +0 -1
- package/dist/lib/factory.d.ts +0 -57
- package/dist/lib/factory.d.ts.map +0 -1
- package/dist/lib/factory.js +0 -107
- package/dist/lib/factory.js.map +0 -1
- package/dist/lib/git.d.ts +0 -157
- package/dist/lib/git.d.ts.map +0 -1
- package/dist/lib/git.js +0 -647
- package/dist/lib/git.js.map +0 -1
- package/dist/lib/help.d.ts +0 -10
- package/dist/lib/help.d.ts.map +0 -1
- package/dist/lib/help.js +0 -66
- package/dist/lib/help.js.map +0 -1
- package/dist/lib/hooks.d.ts +0 -125
- package/dist/lib/hooks.d.ts.map +0 -1
- package/dist/lib/hooks.js +0 -846
- package/dist/lib/hooks.js.map +0 -1
- package/dist/lib/ledger/__tests__/local.test.d.ts +0 -2
- package/dist/lib/ledger/__tests__/local.test.d.ts.map +0 -1
- package/dist/lib/ledger/__tests__/local.test.js +0 -177
- package/dist/lib/ledger/__tests__/local.test.js.map +0 -1
- package/dist/lib/ledger/__tests__/sync.test.d.ts +0 -2
- package/dist/lib/ledger/__tests__/sync.test.d.ts.map +0 -1
- package/dist/lib/ledger/__tests__/sync.test.js +0 -117
- package/dist/lib/ledger/__tests__/sync.test.js.map +0 -1
- package/dist/lib/ledger/index.d.ts +0 -18
- package/dist/lib/ledger/index.d.ts.map +0 -1
- package/dist/lib/ledger/index.js +0 -32
- package/dist/lib/ledger/index.js.map +0 -1
- package/dist/lib/ledger/local.d.ts +0 -22
- package/dist/lib/ledger/local.d.ts.map +0 -1
- package/dist/lib/ledger/local.js +0 -333
- package/dist/lib/ledger/local.js.map +0 -1
- package/dist/lib/ledger/r2.d.ts +0 -41
- package/dist/lib/ledger/r2.d.ts.map +0 -1
- package/dist/lib/ledger/r2.js +0 -335
- package/dist/lib/ledger/r2.js.map +0 -1
- package/dist/lib/ledger/sync.d.ts +0 -33
- package/dist/lib/ledger/sync.d.ts.map +0 -1
- package/dist/lib/ledger/sync.js +0 -106
- package/dist/lib/ledger/sync.js.map +0 -1
- package/dist/lib/ledger/types.d.ts +0 -100
- package/dist/lib/ledger/types.d.ts.map +0 -1
- package/dist/lib/ledger/types.js +0 -21
- package/dist/lib/ledger/types.js.map +0 -1
- package/dist/lib/manifest.d.ts +0 -14
- package/dist/lib/manifest.d.ts.map +0 -1
- package/dist/lib/manifest.js +0 -48
- package/dist/lib/manifest.js.map +0 -1
- package/dist/lib/markdown.d.ts +0 -5
- package/dist/lib/markdown.d.ts.map +0 -1
- package/dist/lib/markdown.js +0 -17
- package/dist/lib/markdown.js.map +0 -1
- package/dist/lib/mcp.d.ts +0 -64
- package/dist/lib/mcp.d.ts.map +0 -1
- package/dist/lib/mcp.js +0 -327
- package/dist/lib/mcp.js.map +0 -1
- package/dist/lib/memory-compile.d.ts +0 -65
- package/dist/lib/memory-compile.d.ts.map +0 -1
- package/dist/lib/memory-compile.js +0 -174
- package/dist/lib/memory-compile.js.map +0 -1
- package/dist/lib/memory.d.ts +0 -64
- package/dist/lib/memory.d.ts.map +0 -1
- package/dist/lib/memory.js +0 -275
- package/dist/lib/memory.js.map +0 -1
- package/dist/lib/models.d.ts +0 -98
- package/dist/lib/models.d.ts.map +0 -1
- package/dist/lib/models.js +0 -728
- package/dist/lib/models.js.map +0 -1
- package/dist/lib/permissions.d.ts +0 -227
- package/dist/lib/permissions.d.ts.map +0 -1
- package/dist/lib/permissions.js +0 -1071
- package/dist/lib/permissions.js.map +0 -1
- package/dist/lib/picker.d.ts +0 -27
- package/dist/lib/picker.d.ts.map +0 -1
- package/dist/lib/picker.js +0 -110
- package/dist/lib/picker.js.map +0 -1
- package/dist/lib/plugins.d.ts +0 -80
- package/dist/lib/plugins.d.ts.map +0 -1
- package/dist/lib/plugins.js +0 -556
- package/dist/lib/plugins.js.map +0 -1
- package/dist/lib/profiles-keychain.d.ts +0 -11
- package/dist/lib/profiles-keychain.d.ts.map +0 -1
- package/dist/lib/profiles-keychain.js +0 -14
- package/dist/lib/profiles-keychain.js.map +0 -1
- package/dist/lib/profiles-presets.d.ts +0 -25
- package/dist/lib/profiles-presets.d.ts.map +0 -1
- package/dist/lib/profiles-presets.js +0 -104
- package/dist/lib/profiles-presets.js.map +0 -1
- package/dist/lib/profiles.d.ts +0 -70
- package/dist/lib/profiles.d.ts.map +0 -1
- package/dist/lib/profiles.js +0 -145
- package/dist/lib/profiles.js.map +0 -1
- package/dist/lib/pty-client.d.ts +0 -23
- package/dist/lib/pty-client.d.ts.map +0 -1
- package/dist/lib/pty-client.js +0 -181
- package/dist/lib/pty-client.js.map +0 -1
- package/dist/lib/pty-server.d.ts +0 -21
- package/dist/lib/pty-server.d.ts.map +0 -1
- package/dist/lib/pty-server.js +0 -427
- package/dist/lib/pty-server.js.map +0 -1
- package/dist/lib/registry.d.ts +0 -45
- package/dist/lib/registry.d.ts.map +0 -1
- package/dist/lib/registry.js +0 -220
- package/dist/lib/registry.js.map +0 -1
- package/dist/lib/resources.d.ts +0 -55
- package/dist/lib/resources.d.ts.map +0 -1
- package/dist/lib/resources.js +0 -103
- package/dist/lib/resources.js.map +0 -1
- package/dist/lib/rotate.d.ts +0 -58
- package/dist/lib/rotate.d.ts.map +0 -1
- package/dist/lib/rotate.js +0 -93
- package/dist/lib/rotate.js.map +0 -1
- package/dist/lib/routines.d.ts +0 -99
- package/dist/lib/routines.d.ts.map +0 -1
- package/dist/lib/routines.js +0 -352
- package/dist/lib/routines.js.map +0 -1
- package/dist/lib/runner.d.ts +0 -26
- package/dist/lib/runner.d.ts.map +0 -1
- package/dist/lib/runner.js +0 -325
- package/dist/lib/runner.js.map +0 -1
- package/dist/lib/sandbox.d.ts +0 -26
- package/dist/lib/sandbox.d.ts.map +0 -1
- package/dist/lib/sandbox.js +0 -218
- package/dist/lib/sandbox.js.map +0 -1
- package/dist/lib/scheduler.d.ts +0 -26
- package/dist/lib/scheduler.d.ts.map +0 -1
- package/dist/lib/scheduler.js +0 -77
- package/dist/lib/scheduler.js.map +0 -1
- package/dist/lib/secrets-bundles.d.ts +0 -38
- package/dist/lib/secrets-bundles.d.ts.map +0 -1
- package/dist/lib/secrets-bundles.js +0 -176
- package/dist/lib/secrets-bundles.js.map +0 -1
- package/dist/lib/secrets.d.ts +0 -53
- package/dist/lib/secrets.d.ts.map +0 -1
- package/dist/lib/secrets.js +0 -140
- package/dist/lib/secrets.js.map +0 -1
- package/dist/lib/session/__tests__/db.test.d.ts +0 -2
- package/dist/lib/session/__tests__/db.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/db.test.js +0 -54
- package/dist/lib/session/__tests__/db.test.js.map +0 -1
- package/dist/lib/session/__tests__/discover.test.d.ts +0 -2
- package/dist/lib/session/__tests__/discover.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/discover.test.js +0 -63
- package/dist/lib/session/__tests__/discover.test.js.map +0 -1
- package/dist/lib/session/__tests__/prompt.test.d.ts +0 -2
- package/dist/lib/session/__tests__/prompt.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/prompt.test.js +0 -44
- package/dist/lib/session/__tests__/prompt.test.js.map +0 -1
- package/dist/lib/session/__tests__/render.test.d.ts +0 -2
- package/dist/lib/session/__tests__/render.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/render.test.js +0 -602
- package/dist/lib/session/__tests__/render.test.js.map +0 -1
- package/dist/lib/session/active.d.ts +0 -44
- package/dist/lib/session/active.d.ts.map +0 -1
- package/dist/lib/session/active.js +0 -379
- package/dist/lib/session/active.js.map +0 -1
- package/dist/lib/session/artifacts.d.ts +0 -15
- package/dist/lib/session/artifacts.d.ts.map +0 -1
- package/dist/lib/session/artifacts.js +0 -86
- package/dist/lib/session/artifacts.js.map +0 -1
- package/dist/lib/session/db.d.ts +0 -140
- package/dist/lib/session/db.d.ts.map +0 -1
- package/dist/lib/session/db.js +0 -599
- package/dist/lib/session/db.js.map +0 -1
- package/dist/lib/session/discover.d.ts +0 -72
- package/dist/lib/session/discover.d.ts.map +0 -1
- package/dist/lib/session/discover.js +0 -1315
- package/dist/lib/session/discover.js.map +0 -1
- package/dist/lib/session/parse.d.ts +0 -34
- package/dist/lib/session/parse.d.ts.map +0 -1
- package/dist/lib/session/parse.js +0 -663
- package/dist/lib/session/parse.js.map +0 -1
- package/dist/lib/session/prompt.d.ts +0 -13
- package/dist/lib/session/prompt.d.ts.map +0 -1
- package/dist/lib/session/prompt.js +0 -79
- package/dist/lib/session/prompt.js.map +0 -1
- package/dist/lib/session/prompt.test.d.ts +0 -2
- package/dist/lib/session/prompt.test.d.ts.map +0 -1
- package/dist/lib/session/prompt.test.js +0 -57
- package/dist/lib/session/prompt.test.js.map +0 -1
- package/dist/lib/session/render.d.ts +0 -103
- package/dist/lib/session/render.d.ts.map +0 -1
- package/dist/lib/session/render.js +0 -798
- package/dist/lib/session/render.js.map +0 -1
- package/dist/lib/session/team-filter.d.ts +0 -35
- package/dist/lib/session/team-filter.d.ts.map +0 -1
- package/dist/lib/session/team-filter.js +0 -75
- package/dist/lib/session/team-filter.js.map +0 -1
- package/dist/lib/session/team-filter.test.d.ts +0 -2
- package/dist/lib/session/team-filter.test.d.ts.map +0 -1
- package/dist/lib/session/team-filter.test.js +0 -157
- package/dist/lib/session/team-filter.test.js.map +0 -1
- package/dist/lib/session/types.d.ts +0 -84
- package/dist/lib/session/types.d.ts.map +0 -1
- package/dist/lib/session/types.js +0 -11
- package/dist/lib/session/types.js.map +0 -1
- package/dist/lib/shims.d.ts +0 -272
- package/dist/lib/shims.d.ts.map +0 -1
- package/dist/lib/shims.js +0 -1322
- package/dist/lib/shims.js.map +0 -1
- package/dist/lib/skills.d.ts +0 -142
- package/dist/lib/skills.d.ts.map +0 -1
- package/dist/lib/skills.js +0 -791
- package/dist/lib/skills.js.map +0 -1
- package/dist/lib/state.d.ts +0 -87
- package/dist/lib/state.d.ts.map +0 -1
- package/dist/lib/state.js +0 -333
- package/dist/lib/state.js.map +0 -1
- package/dist/lib/subagents.d.ts +0 -84
- package/dist/lib/subagents.d.ts.map +0 -1
- package/dist/lib/subagents.js +0 -410
- package/dist/lib/subagents.js.map +0 -1
- package/dist/lib/teams/__tests__/oracle.test.d.ts +0 -2
- package/dist/lib/teams/__tests__/oracle.test.d.ts.map +0 -1
- package/dist/lib/teams/__tests__/oracle.test.js +0 -89
- package/dist/lib/teams/__tests__/oracle.test.js.map +0 -1
- package/dist/lib/teams/__tests__/supervisor.test.d.ts +0 -2
- package/dist/lib/teams/__tests__/supervisor.test.d.ts.map +0 -1
- package/dist/lib/teams/__tests__/supervisor.test.js +0 -179
- package/dist/lib/teams/__tests__/supervisor.test.js.map +0 -1
- package/dist/lib/teams/agents.d.ts +0 -247
- package/dist/lib/teams/agents.d.ts.map +0 -1
- package/dist/lib/teams/agents.js +0 -1244
- package/dist/lib/teams/agents.js.map +0 -1
- package/dist/lib/teams/api.d.ts +0 -91
- package/dist/lib/teams/api.d.ts.map +0 -1
- package/dist/lib/teams/api.js +0 -239
- package/dist/lib/teams/api.js.map +0 -1
- package/dist/lib/teams/cloud.d.ts +0 -11
- package/dist/lib/teams/cloud.d.ts.map +0 -1
- package/dist/lib/teams/cloud.js +0 -169
- package/dist/lib/teams/cloud.js.map +0 -1
- package/dist/lib/teams/debug.d.ts +0 -8
- package/dist/lib/teams/debug.d.ts.map +0 -1
- package/dist/lib/teams/debug.js +0 -12
- package/dist/lib/teams/debug.js.map +0 -1
- package/dist/lib/teams/file_ops.d.ts +0 -13
- package/dist/lib/teams/file_ops.d.ts.map +0 -1
- package/dist/lib/teams/file_ops.js +0 -66
- package/dist/lib/teams/file_ops.js.map +0 -1
- package/dist/lib/teams/index.d.ts +0 -16
- package/dist/lib/teams/index.d.ts.map +0 -1
- package/dist/lib/teams/index.js +0 -15
- package/dist/lib/teams/index.js.map +0 -1
- package/dist/lib/teams/oracle.d.ts +0 -20
- package/dist/lib/teams/oracle.d.ts.map +0 -1
- package/dist/lib/teams/oracle.js +0 -59
- package/dist/lib/teams/oracle.js.map +0 -1
- package/dist/lib/teams/parsers.d.ts +0 -9
- package/dist/lib/teams/parsers.d.ts.map +0 -1
- package/dist/lib/teams/parsers.js +0 -837
- package/dist/lib/teams/parsers.js.map +0 -1
- package/dist/lib/teams/persistence.d.ts +0 -43
- package/dist/lib/teams/persistence.d.ts.map +0 -1
- package/dist/lib/teams/persistence.js +0 -299
- package/dist/lib/teams/persistence.js.map +0 -1
- package/dist/lib/teams/ralph.d.ts +0 -8
- package/dist/lib/teams/ralph.d.ts.map +0 -1
- package/dist/lib/teams/ralph.js +0 -59
- package/dist/lib/teams/ralph.js.map +0 -1
- package/dist/lib/teams/registry.d.ts +0 -18
- package/dist/lib/teams/registry.d.ts.map +0 -1
- package/dist/lib/teams/registry.js +0 -68
- package/dist/lib/teams/registry.js.map +0 -1
- package/dist/lib/teams/summarizer.d.ts +0 -73
- package/dist/lib/teams/summarizer.d.ts.map +0 -1
- package/dist/lib/teams/summarizer.js +0 -780
- package/dist/lib/teams/summarizer.js.map +0 -1
- package/dist/lib/teams/supervisor.d.ts +0 -49
- package/dist/lib/teams/supervisor.d.ts.map +0 -1
- package/dist/lib/teams/supervisor.js +0 -74
- package/dist/lib/teams/supervisor.js.map +0 -1
- package/dist/lib/template.d.ts +0 -27
- package/dist/lib/template.d.ts.map +0 -1
- package/dist/lib/template.js +0 -60
- package/dist/lib/template.js.map +0 -1
- package/dist/lib/types.d.ts +0 -331
- package/dist/lib/types.d.ts.map +0 -1
- package/dist/lib/types.js +0 -29
- package/dist/lib/types.js.map +0 -1
- package/dist/lib/usage.d.ts +0 -105
- package/dist/lib/usage.d.ts.map +0 -1
- package/dist/lib/usage.js +0 -686
- package/dist/lib/usage.js.map +0 -1
- package/dist/lib/versions.d.ts +0 -253
- package/dist/lib/versions.d.ts.map +0 -1
- package/dist/lib/versions.js +0 -1796
- package/dist/lib/versions.js.map +0 -1
- package/scripts/rebuild-sqlite.sh +0 -46
package/dist/lib/shims.js
DELETED
|
@@ -1,1322 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shim generation and config symlink management for agent version switching.
|
|
3
|
-
*
|
|
4
|
-
* Shims are small shell scripts placed in ~/.agents/shims/ that resolve the
|
|
5
|
-
* active agent version (project-level or user-default), then exec the real
|
|
6
|
-
* binary. Config isolation is achieved by symlinking ~/.{agent} into the
|
|
7
|
-
* per-version home directory. This module also handles versioned aliases
|
|
8
|
-
* (e.g., claude@2.0.65), PATH setup, conflict detection during migration,
|
|
9
|
-
* and resource diffing between versions.
|
|
10
|
-
*/
|
|
11
|
-
import * as fs from 'fs';
|
|
12
|
-
import * as path from 'path';
|
|
13
|
-
import * as os from 'os';
|
|
14
|
-
import { confirm, select } from '@inquirer/prompts';
|
|
15
|
-
import { getShimsDir, getVersionsDir, getBackupsDir, ensureAgentsDir } from './state.js';
|
|
16
|
-
export { getShimsDir };
|
|
17
|
-
import { AGENTS } from './agents.js';
|
|
18
|
-
/**
|
|
19
|
-
* Files and directories to always skip during conflict detection and migration.
|
|
20
|
-
* These are never user config that should be migrated.
|
|
21
|
-
*/
|
|
22
|
-
const MIGRATION_IGNORE_LIST = new Set([
|
|
23
|
-
'node_modules',
|
|
24
|
-
'.git',
|
|
25
|
-
'bun.lock',
|
|
26
|
-
'bun.lockb',
|
|
27
|
-
'package-lock.json',
|
|
28
|
-
'yarn.lock',
|
|
29
|
-
'pnpm-lock.yaml',
|
|
30
|
-
'.DS_Store',
|
|
31
|
-
'Thumbs.db',
|
|
32
|
-
]);
|
|
33
|
-
/**
|
|
34
|
-
* Check if a file/directory should be ignored during migration.
|
|
35
|
-
*/
|
|
36
|
-
function shouldIgnore(name) {
|
|
37
|
-
if (MIGRATION_IGNORE_LIST.has(name))
|
|
38
|
-
return true;
|
|
39
|
-
if (name.endsWith('.backup'))
|
|
40
|
-
return true;
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Detect conflicting files between source and destination directories.
|
|
45
|
-
* Returns list of filenames that exist in both locations (excluding symlinks in dest).
|
|
46
|
-
*/
|
|
47
|
-
export function detectConflicts(src, dest, prefix = '') {
|
|
48
|
-
const conflicts = [];
|
|
49
|
-
if (!fs.existsSync(src) || !fs.existsSync(dest)) {
|
|
50
|
-
return conflicts;
|
|
51
|
-
}
|
|
52
|
-
// Skip if dest is a symlink (managed resources)
|
|
53
|
-
try {
|
|
54
|
-
const destStat = fs.lstatSync(dest);
|
|
55
|
-
if (destStat.isSymbolicLink()) {
|
|
56
|
-
return conflicts;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
/* dest not accessible, no conflicts to report */
|
|
61
|
-
return conflicts;
|
|
62
|
-
}
|
|
63
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
64
|
-
for (const entry of entries) {
|
|
65
|
-
// Skip files/directories that should never be migrated
|
|
66
|
-
if (shouldIgnore(entry.name)) {
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const srcPath = path.join(src, entry.name);
|
|
70
|
-
const destPath = path.join(dest, entry.name);
|
|
71
|
-
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
72
|
-
// Skip if dest entry is a symlink (managed resource)
|
|
73
|
-
try {
|
|
74
|
-
const entryDestStat = fs.lstatSync(destPath);
|
|
75
|
-
if (entryDestStat.isSymbolicLink()) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
if (entry.isDirectory()) {
|
|
79
|
-
// Recurse into subdirectories
|
|
80
|
-
conflicts.push(...detectConflicts(srcPath, destPath, relativePath));
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
// File exists in both - it's a conflict
|
|
84
|
-
conflicts.push(relativePath);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
// dest entry doesn't exist, not a conflict
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return conflicts;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Prompt user for conflict resolution strategy.
|
|
95
|
-
*/
|
|
96
|
-
export async function promptConflictStrategy(conflictInfos) {
|
|
97
|
-
const totalConflicts = conflictInfos.reduce((sum, info) => sum + info.conflicts.length, 0);
|
|
98
|
-
if (totalConflicts === 0) {
|
|
99
|
-
return null; // No conflicts, no prompt needed
|
|
100
|
-
}
|
|
101
|
-
// Show what has conflicts with clear paths
|
|
102
|
-
console.log('\nFile conflicts detected:');
|
|
103
|
-
for (const info of conflictInfos) {
|
|
104
|
-
const agentConfig = AGENTS[info.agent];
|
|
105
|
-
const configDir = agentConfig.configDir; // e.g., ".opencode"
|
|
106
|
-
console.log(` ${info.conflicts.length} file(s) conflict between:`);
|
|
107
|
-
console.log(` ~/${configDir}/ (your config)`);
|
|
108
|
-
console.log(` ${agentConfig.name}@${info.version} (managed version)`);
|
|
109
|
-
}
|
|
110
|
-
console.log();
|
|
111
|
-
// Build choice labels with agent info for clarity
|
|
112
|
-
const firstInfo = conflictInfos[0];
|
|
113
|
-
const firstAgent = AGENTS[firstInfo.agent];
|
|
114
|
-
const versionLabel = conflictInfos.length === 1
|
|
115
|
-
? `${firstAgent.name}@${firstInfo.version}`
|
|
116
|
-
: 'version';
|
|
117
|
-
const strategy = await select({
|
|
118
|
-
message: 'Which files should be kept?',
|
|
119
|
-
choices: [
|
|
120
|
-
{
|
|
121
|
-
value: 'keep-dest',
|
|
122
|
-
name: `Keep ${versionLabel} files (recommended)`,
|
|
123
|
-
},
|
|
124
|
-
{
|
|
125
|
-
value: 'overwrite',
|
|
126
|
-
name: conflictInfos.length === 1
|
|
127
|
-
? `Keep ~/${firstAgent.configDir}/ files`
|
|
128
|
-
: 'Keep my config files',
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
value: 'ask-per-file',
|
|
132
|
-
name: `Decide per file (${totalConflicts} file${totalConflicts === 1 ? '' : 's'})`,
|
|
133
|
-
},
|
|
134
|
-
],
|
|
135
|
-
default: 'keep-dest',
|
|
136
|
-
});
|
|
137
|
-
return strategy;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Generate the shim script content for an agent.
|
|
141
|
-
*
|
|
142
|
-
* The shim resolves the version in order:
|
|
143
|
-
* 1. agents.yaml in project root (walk up from $PWD, skip ~/.agents/agents.yaml)
|
|
144
|
-
* 2. ~/.agents/agents.yaml default
|
|
145
|
-
*
|
|
146
|
-
* If version is specified but not installed, auto-installs it.
|
|
147
|
-
*
|
|
148
|
-
* Config isolation is handled via symlinks:
|
|
149
|
-
* ~/.{agent} -> ~/.agents/versions/{agent}/{version}/home/.{agent}/
|
|
150
|
-
*/
|
|
151
|
-
/**
|
|
152
|
-
* Current shim schema version. Bump whenever `generateShimScript` changes
|
|
153
|
-
* in a way that requires existing on-disk shims to be regenerated (new
|
|
154
|
-
* flags, fixed argument parsing, new hooks, etc.). `isShimCurrent` reads
|
|
155
|
-
* this marker out of existing shims to decide whether to regenerate.
|
|
156
|
-
*
|
|
157
|
-
* History:
|
|
158
|
-
* v1 — initial shim (implicit, no marker).
|
|
159
|
-
* v2 — `--version=...` form in sync/refresh-memory calls; refresh-memory
|
|
160
|
-
* shim hook for non-@-capable agents.
|
|
161
|
-
* v3 — sync/refresh-memory flag renamed `--version` → `--agent-version`
|
|
162
|
-
* so it no longer collides with commander's top-level `--version`.
|
|
163
|
-
* v4 — project version marker changed from `.agents-version` to a
|
|
164
|
-
* root-level `agents.yaml`; shim now skips ~/.agents/agents.yaml
|
|
165
|
-
* when walking up for a project marker.
|
|
166
|
-
* v5 — emit CODEX_HOME for codex shims so the versioned config (permissions,
|
|
167
|
-
* sandbox_mode, rules/agents-deny.rules) is actually read by the codex
|
|
168
|
-
* binary instead of $HOME/.codex.
|
|
169
|
-
*/
|
|
170
|
-
export const SHIM_SCHEMA_VERSION = 5;
|
|
171
|
-
/** Internal marker string used to embed the schema version in shim scripts. */
|
|
172
|
-
const SHIM_VERSION_MARKER = 'agents-shim-version:';
|
|
173
|
-
/**
|
|
174
|
-
* Generate the full bash shim script for the given agent. The returned string
|
|
175
|
-
* is written to ~/.agents/shims/{cliCommand} and made executable.
|
|
176
|
-
*/
|
|
177
|
-
export function generateShimScript(agent) {
|
|
178
|
-
const agentConfig = AGENTS[agent];
|
|
179
|
-
const cliCommand = agentConfig.cliCommand;
|
|
180
|
-
const configDirName = `.${agent}`;
|
|
181
|
-
const managedEnv = agent === 'claude'
|
|
182
|
-
? `
|
|
183
|
-
# Claude stores OAuth credentials in the macOS keychain. Scope them to the
|
|
184
|
-
# selected version's config directory so switching versions also switches the
|
|
185
|
-
# live Claude account.
|
|
186
|
-
export CLAUDE_CONFIG_DIR="$VERSION_DIR/home/${configDirName}"
|
|
187
|
-
`
|
|
188
|
-
: agent === 'codex'
|
|
189
|
-
? `
|
|
190
|
-
# Codex reads its config (approval_policy, sandbox_mode, MCP servers, rules)
|
|
191
|
-
# from CODEX_HOME. Point it at the versioned home so permissions/rules
|
|
192
|
-
# written by agents-cli actually take effect.
|
|
193
|
-
export CODEX_HOME="$VERSION_DIR/home/${configDirName}"
|
|
194
|
-
`
|
|
195
|
-
: '';
|
|
196
|
-
// Agents that don't natively resolve @-imports in their memory file need
|
|
197
|
-
// agents-cli to recompile when the user edits a rule/preset file. The
|
|
198
|
-
// check is fast (sha256 of ~8 small files) and skips the recompile when
|
|
199
|
-
// sources haven't changed.
|
|
200
|
-
const refreshMemoryCall = !agentConfig.capabilities.memoryImports
|
|
201
|
-
? `
|
|
202
|
-
# Recompile memory if any rule/preset source has changed since last sync.
|
|
203
|
-
# Fast-path check (~10-20ms) when nothing changed; full recompile only on
|
|
204
|
-
# actual diff. Non-blocking failure — if the refresh errors, we still launch.
|
|
205
|
-
agents refresh-memory --agent "$AGENT" --agent-version "$VERSION" --quiet 2>/dev/null || true
|
|
206
|
-
`
|
|
207
|
-
: '';
|
|
208
|
-
return `#!/bin/bash
|
|
209
|
-
# Auto-generated by agents-cli - do not edit
|
|
210
|
-
# Shim for ${agentConfig.name}
|
|
211
|
-
# ${SHIM_VERSION_MARKER} ${SHIM_SCHEMA_VERSION}
|
|
212
|
-
|
|
213
|
-
AGENTS_DIR="$HOME/.agents"
|
|
214
|
-
AGENT="${agent}"
|
|
215
|
-
CLI_COMMAND="${cliCommand}"
|
|
216
|
-
|
|
217
|
-
# Find project agents.yaml walking up from cwd (skip ~/.agents/agents.yaml)
|
|
218
|
-
find_project_version() {
|
|
219
|
-
local dir="$PWD"
|
|
220
|
-
local user_agents_yaml="$HOME/.agents/agents.yaml"
|
|
221
|
-
while [ "$dir" != "/" ]; do
|
|
222
|
-
local candidate="$dir/agents.yaml"
|
|
223
|
-
if [ -f "$candidate" ] && [ "$candidate" != "$user_agents_yaml" ]; then
|
|
224
|
-
# Parse agents: section — same shape as resolve_default_version()
|
|
225
|
-
local version
|
|
226
|
-
version=$(awk -v agent="$AGENT" '
|
|
227
|
-
/^agents:/ { in_agents=1; next }
|
|
228
|
-
in_agents && /^[^ ]/ { in_agents=0 }
|
|
229
|
-
in_agents && $0 ~ "^ " agent ":" { gsub(/.*:[[:space:]]*["'"'"']?|["'"'"']?[[:space:]]*$/, ""); print; exit }
|
|
230
|
-
' "$candidate")
|
|
231
|
-
if [ -n "$version" ]; then
|
|
232
|
-
echo "$version"
|
|
233
|
-
return 0
|
|
234
|
-
fi
|
|
235
|
-
fi
|
|
236
|
-
dir=$(dirname "$dir")
|
|
237
|
-
done
|
|
238
|
-
return 1
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
# Resolve version from agents.yaml (user default)
|
|
242
|
-
resolve_default_version() {
|
|
243
|
-
local meta="$AGENTS_DIR/agents.yaml"
|
|
244
|
-
if [ -f "$meta" ]; then
|
|
245
|
-
awk -v agent="$AGENT" '
|
|
246
|
-
/^agents:/ { in_agents=1; next }
|
|
247
|
-
in_agents && /^[^ ]/ { in_agents=0 }
|
|
248
|
-
in_agents && $0 ~ "^ " agent ":" { gsub(/.*:[[:space:]]*["'"'"']?|["'"'"']?[[:space:]]*$/, ""); print; exit }
|
|
249
|
-
' "$meta"
|
|
250
|
-
fi
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
# Find project-scoped .agents directory (stop at agents.yaml or .git)
|
|
254
|
-
find_project_agents_dir() {
|
|
255
|
-
local dir="$PWD"
|
|
256
|
-
while [ "$dir" != "/" ]; do
|
|
257
|
-
if [ -d "$dir/.agents" ]; then
|
|
258
|
-
echo "$dir/.agents"
|
|
259
|
-
return 0
|
|
260
|
-
fi
|
|
261
|
-
if [ -f "$dir/agents.yaml" ] || [ -d "$dir/.git" ] || [ -f "$dir/.git" ]; then
|
|
262
|
-
break
|
|
263
|
-
fi
|
|
264
|
-
dir=$(dirname "$dir")
|
|
265
|
-
done
|
|
266
|
-
return 1
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
# Try project version first, then global default
|
|
270
|
-
VERSION=$(find_project_version)
|
|
271
|
-
VERSION_SOURCE="project"
|
|
272
|
-
if [ -z "$VERSION" ]; then
|
|
273
|
-
VERSION=$(resolve_default_version)
|
|
274
|
-
VERSION_SOURCE="default"
|
|
275
|
-
fi
|
|
276
|
-
|
|
277
|
-
if [ -z "$VERSION" ]; then
|
|
278
|
-
echo "agents: no version of $AGENT configured" >&2
|
|
279
|
-
echo "Run: agents add $AGENT@<version>" >&2
|
|
280
|
-
exit 1
|
|
281
|
-
fi
|
|
282
|
-
|
|
283
|
-
VERSION_DIR="$AGENTS_DIR/versions/$AGENT/$VERSION"
|
|
284
|
-
BINARY="$VERSION_DIR/node_modules/.bin/$CLI_COMMAND"
|
|
285
|
-
|
|
286
|
-
# Auto-install if not present
|
|
287
|
-
if [ ! -x "$BINARY" ]; then
|
|
288
|
-
if [ "$VERSION_SOURCE" = "project" ]; then
|
|
289
|
-
echo "agents: $AGENT@$VERSION required by agents.yaml but not installed" >&2
|
|
290
|
-
|
|
291
|
-
# Spinner animation
|
|
292
|
-
spin() {
|
|
293
|
-
local pid=$1
|
|
294
|
-
local chars="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
|
|
295
|
-
local i=0
|
|
296
|
-
while kill -0 "$pid" 2>/dev/null; do
|
|
297
|
-
printf "\\r %s Installing $AGENT@$VERSION..." "\${chars:i++%\${#chars}:1}" >&2
|
|
298
|
-
sleep 0.1
|
|
299
|
-
done
|
|
300
|
-
printf "\\r" >&2
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
# Run install in background with spinner
|
|
304
|
-
agents add "$AGENT@$VERSION" --yes >/dev/null 2>&1 &
|
|
305
|
-
install_pid=$!
|
|
306
|
-
spin $install_pid
|
|
307
|
-
wait $install_pid
|
|
308
|
-
install_status=$?
|
|
309
|
-
|
|
310
|
-
if [ $install_status -eq 0 ]; then
|
|
311
|
-
echo " ✔ Installed $AGENT@$VERSION" >&2
|
|
312
|
-
else
|
|
313
|
-
echo " ✗ Failed to install $AGENT@$VERSION" >&2
|
|
314
|
-
exit 1
|
|
315
|
-
fi
|
|
316
|
-
else
|
|
317
|
-
echo "agents: $AGENT@$VERSION not installed" >&2
|
|
318
|
-
echo "Run: agents add $AGENT@$VERSION" >&2
|
|
319
|
-
exit 1
|
|
320
|
-
fi
|
|
321
|
-
fi
|
|
322
|
-
|
|
323
|
-
# Sync project-scoped resources into version home if a project .agents/ is present
|
|
324
|
-
PROJECT_AGENTS_DIR=$(find_project_agents_dir)
|
|
325
|
-
if [ -n "$PROJECT_AGENTS_DIR" ]; then
|
|
326
|
-
agents sync --agent "$AGENT" --agent-version "$VERSION" --project-dir "$PROJECT_AGENTS_DIR" --quiet >/dev/null 2>&1
|
|
327
|
-
fi
|
|
328
|
-
${refreshMemoryCall}${managedEnv}
|
|
329
|
-
|
|
330
|
-
exec "$BINARY" "$@"
|
|
331
|
-
`;
|
|
332
|
-
}
|
|
333
|
-
/**
|
|
334
|
-
* Create a shim for an agent.
|
|
335
|
-
*/
|
|
336
|
-
export function createShim(agent) {
|
|
337
|
-
ensureAgentsDir();
|
|
338
|
-
const shimsDir = getShimsDir();
|
|
339
|
-
const agentConfig = AGENTS[agent];
|
|
340
|
-
const shimPath = path.join(shimsDir, agentConfig.cliCommand);
|
|
341
|
-
const script = generateShimScript(agent);
|
|
342
|
-
fs.writeFileSync(shimPath, script, { mode: 0o755 });
|
|
343
|
-
return shimPath;
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Remove the shim for an agent.
|
|
347
|
-
*/
|
|
348
|
-
export function removeShim(agent) {
|
|
349
|
-
const shimsDir = getShimsDir();
|
|
350
|
-
const agentConfig = AGENTS[agent];
|
|
351
|
-
const shimPath = path.join(shimsDir, agentConfig.cliCommand);
|
|
352
|
-
if (fs.existsSync(shimPath)) {
|
|
353
|
-
fs.unlinkSync(shimPath);
|
|
354
|
-
return true;
|
|
355
|
-
}
|
|
356
|
-
return false;
|
|
357
|
-
}
|
|
358
|
-
/**
|
|
359
|
-
* Current versioned-alias schema. Bump whenever `generateVersionedAliasScript`
|
|
360
|
-
* changes in a way that requires existing on-disk aliases to be regenerated.
|
|
361
|
-
*
|
|
362
|
-
* History:
|
|
363
|
-
* v1 — implicit (no marker); no CLAUDE_CONFIG_DIR export, so direct
|
|
364
|
-
* `claude@X` invocations leaked into ~/.claude (the default version's
|
|
365
|
-
* symlinked home) and `agents view` never saw the login.
|
|
366
|
-
* v2 — emit CLAUDE_CONFIG_DIR for claude aliases so each version has its
|
|
367
|
-
* own isolated config/OAuth slot; stamp a version marker so stale
|
|
368
|
-
* aliases can be detected and regenerated.
|
|
369
|
-
* v3 — emit CODEX_HOME for codex aliases so direct `codex@X` invocations
|
|
370
|
-
* read the versioned permissions/rules instead of $HOME/.codex.
|
|
371
|
-
*/
|
|
372
|
-
export const VERSIONED_ALIAS_SCHEMA_VERSION = 3;
|
|
373
|
-
/** Internal marker string used to embed the schema version in versioned alias scripts. */
|
|
374
|
-
const VERSIONED_ALIAS_VERSION_MARKER = 'agents-versioned-alias-version:';
|
|
375
|
-
/**
|
|
376
|
-
* Generate a versioned alias script that directly execs a specific version.
|
|
377
|
-
* e.g., claude@2.0.65 -> directly runs that version's binary
|
|
378
|
-
*/
|
|
379
|
-
export function generateVersionedAliasScript(agent, version) {
|
|
380
|
-
const agentConfig = AGENTS[agent];
|
|
381
|
-
const configDirName = `.${agent}`;
|
|
382
|
-
const managedEnv = agent === 'claude'
|
|
383
|
-
? `
|
|
384
|
-
# Claude stores OAuth credentials in the macOS keychain. Scope them to this
|
|
385
|
-
# version's config directory so direct aliases also switch the live account.
|
|
386
|
-
export CLAUDE_CONFIG_DIR="$HOME/.agents/versions/${agent}/${version}/home/${configDirName}"
|
|
387
|
-
`
|
|
388
|
-
: agent === 'codex'
|
|
389
|
-
? `
|
|
390
|
-
# Codex reads its config (approval_policy, sandbox_mode, MCP servers, rules)
|
|
391
|
-
# from CODEX_HOME. Point direct aliases at the versioned home so permissions
|
|
392
|
-
# and rules written by agents-cli actually take effect.
|
|
393
|
-
export CODEX_HOME="$HOME/.agents/versions/${agent}/${version}/home/${configDirName}"
|
|
394
|
-
`
|
|
395
|
-
: '';
|
|
396
|
-
return `#!/bin/bash
|
|
397
|
-
# Auto-generated by agents-cli - do not edit
|
|
398
|
-
# ${VERSIONED_ALIAS_VERSION_MARKER} ${VERSIONED_ALIAS_SCHEMA_VERSION}
|
|
399
|
-
# Direct alias for ${agentConfig.name}@${version}
|
|
400
|
-
|
|
401
|
-
BINARY="$HOME/.agents/versions/${agent}/${version}/node_modules/.bin/${agentConfig.cliCommand}"
|
|
402
|
-
|
|
403
|
-
if [ ! -x "$BINARY" ]; then
|
|
404
|
-
echo "agents: ${agent}@${version} not installed" >&2
|
|
405
|
-
exit 1
|
|
406
|
-
fi
|
|
407
|
-
${managedEnv}
|
|
408
|
-
|
|
409
|
-
exec "$BINARY" "$@"
|
|
410
|
-
`;
|
|
411
|
-
}
|
|
412
|
-
/**
|
|
413
|
-
* Read the schema version of an on-disk versioned alias. Returns null if the
|
|
414
|
-
* alias doesn't exist or is a pre-v2 alias (no marker — treated as stale).
|
|
415
|
-
*/
|
|
416
|
-
export function readVersionedAliasSchemaVersion(agent, version) {
|
|
417
|
-
const aliasPath = getVersionedAliasPath(agent, version);
|
|
418
|
-
if (!fs.existsSync(aliasPath))
|
|
419
|
-
return null;
|
|
420
|
-
try {
|
|
421
|
-
const content = fs.readFileSync(aliasPath, 'utf8');
|
|
422
|
-
const header = content.split('\n', 10).join('\n');
|
|
423
|
-
const match = header.match(new RegExp(VERSIONED_ALIAS_VERSION_MARKER + '\\s*(\\d+)'));
|
|
424
|
-
if (!match)
|
|
425
|
-
return null;
|
|
426
|
-
return Number(match[1]);
|
|
427
|
-
}
|
|
428
|
-
catch {
|
|
429
|
-
return null;
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
/**
|
|
433
|
-
* True if the on-disk versioned alias matches the current schema version.
|
|
434
|
-
*/
|
|
435
|
-
export function isVersionedAliasCurrent(agent, version) {
|
|
436
|
-
return readVersionedAliasSchemaVersion(agent, version) === VERSIONED_ALIAS_SCHEMA_VERSION;
|
|
437
|
-
}
|
|
438
|
-
/**
|
|
439
|
-
* Regenerate a versioned alias if missing or stale. Mirrors ensureShimCurrent
|
|
440
|
-
* for the main shim — callers can surface a one-line notice when something
|
|
441
|
-
* was upgraded.
|
|
442
|
-
*/
|
|
443
|
-
export function ensureVersionedAliasCurrent(agent, version) {
|
|
444
|
-
const aliasPath = getVersionedAliasPath(agent, version);
|
|
445
|
-
if (!fs.existsSync(aliasPath)) {
|
|
446
|
-
createVersionedAlias(agent, version);
|
|
447
|
-
return 'created';
|
|
448
|
-
}
|
|
449
|
-
if (!isVersionedAliasCurrent(agent, version)) {
|
|
450
|
-
createVersionedAlias(agent, version);
|
|
451
|
-
return 'updated';
|
|
452
|
-
}
|
|
453
|
-
return 'current';
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* Get the filesystem path for a versioned alias script.
|
|
457
|
-
*/
|
|
458
|
-
export function getVersionedAliasPath(agent, version) {
|
|
459
|
-
return path.join(getShimsDir(), `${AGENTS[agent].cliCommand}@${version}`);
|
|
460
|
-
}
|
|
461
|
-
/**
|
|
462
|
-
* Create a versioned alias for a specific agent version.
|
|
463
|
-
* e.g., claude@2.0.65
|
|
464
|
-
*/
|
|
465
|
-
export function createVersionedAlias(agent, version) {
|
|
466
|
-
ensureAgentsDir();
|
|
467
|
-
const shimsDir = getShimsDir();
|
|
468
|
-
const agentConfig = AGENTS[agent];
|
|
469
|
-
const aliasPath = path.join(shimsDir, `${agentConfig.cliCommand}@${version}`);
|
|
470
|
-
const script = generateVersionedAliasScript(agent, version);
|
|
471
|
-
fs.writeFileSync(aliasPath, script, { mode: 0o755 });
|
|
472
|
-
return aliasPath;
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Remove a versioned alias for a specific agent version.
|
|
476
|
-
*/
|
|
477
|
-
export function removeVersionedAlias(agent, version) {
|
|
478
|
-
const shimsDir = getShimsDir();
|
|
479
|
-
const agentConfig = AGENTS[agent];
|
|
480
|
-
const aliasPath = path.join(shimsDir, `${agentConfig.cliCommand}@${version}`);
|
|
481
|
-
if (fs.existsSync(aliasPath)) {
|
|
482
|
-
fs.unlinkSync(aliasPath);
|
|
483
|
-
return true;
|
|
484
|
-
}
|
|
485
|
-
return false;
|
|
486
|
-
}
|
|
487
|
-
/**
|
|
488
|
-
* Check if a versioned alias exists.
|
|
489
|
-
*/
|
|
490
|
-
export function versionedAliasExists(agent, version) {
|
|
491
|
-
const shimsDir = getShimsDir();
|
|
492
|
-
const agentConfig = AGENTS[agent];
|
|
493
|
-
const aliasPath = path.join(shimsDir, `${agentConfig.cliCommand}@${version}`);
|
|
494
|
-
return fs.existsSync(aliasPath);
|
|
495
|
-
}
|
|
496
|
-
/**
|
|
497
|
-
* Get the path to the agent's config directory in HOME.
|
|
498
|
-
* e.g., ~/.claude for claude, ~/.codex for codex
|
|
499
|
-
*/
|
|
500
|
-
function getAgentConfigPath(agent) {
|
|
501
|
-
const agentConfig = AGENTS[agent];
|
|
502
|
-
const home = process.env.AGENTS_REAL_HOME || os.homedir();
|
|
503
|
-
return agentConfig.configDir.replace(os.homedir(), home);
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* Get the path to the version's config directory.
|
|
507
|
-
* e.g., ~/.agents/versions/claude/2.0.65/home/.claude/
|
|
508
|
-
*/
|
|
509
|
-
function getVersionConfigPath(agent, version) {
|
|
510
|
-
const agentConfig = AGENTS[agent];
|
|
511
|
-
const versionsDir = getVersionsDir();
|
|
512
|
-
const configDirName = `.${agent}`; // .claude, .codex, etc.
|
|
513
|
-
return path.join(versionsDir, agent, version, 'home', configDirName);
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* Detect conflicts that would occur when switching config symlink for an agent/version.
|
|
517
|
-
* This allows collecting conflicts upfront before prompting for a strategy.
|
|
518
|
-
*
|
|
519
|
-
* Returns null if no migration is needed (already symlink or doesn't exist),
|
|
520
|
-
* or ConflictInfo with the list of conflicting files.
|
|
521
|
-
*/
|
|
522
|
-
export function detectMigrationConflicts(agent, version) {
|
|
523
|
-
const configPath = getAgentConfigPath(agent);
|
|
524
|
-
const versionConfigPath = getVersionConfigPath(agent, version);
|
|
525
|
-
try {
|
|
526
|
-
const stat = fs.lstatSync(configPath);
|
|
527
|
-
if (stat.isSymbolicLink()) {
|
|
528
|
-
// Already a symlink - no migration needed, no conflicts
|
|
529
|
-
return null;
|
|
530
|
-
}
|
|
531
|
-
else if (stat.isDirectory()) {
|
|
532
|
-
// Real directory exists - would need migration
|
|
533
|
-
// Detect conflicts between user's current config and version home
|
|
534
|
-
const conflicts = detectConflicts(configPath, versionConfigPath);
|
|
535
|
-
return {
|
|
536
|
-
agent,
|
|
537
|
-
version,
|
|
538
|
-
conflicts,
|
|
539
|
-
};
|
|
540
|
-
}
|
|
541
|
-
// Not a directory or symlink - unusual, no conflicts to report
|
|
542
|
-
return null;
|
|
543
|
-
}
|
|
544
|
-
catch (err) {
|
|
545
|
-
if (err.code === 'ENOENT') {
|
|
546
|
-
// Config path doesn't exist - no migration needed
|
|
547
|
-
return null;
|
|
548
|
-
}
|
|
549
|
-
return null;
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
/**
|
|
553
|
-
* Switch the agent's config symlink to point to a specific version.
|
|
554
|
-
* e.g., ~/.claude -> ~/.agents/versions/claude/2.0.65/home/.claude/
|
|
555
|
-
*
|
|
556
|
-
* If a real directory exists at the config path, it will be backed up
|
|
557
|
-
* to ~/.agents/backups/{agent}/{timestamp}/ and replaced with a symlink.
|
|
558
|
-
*
|
|
559
|
-
* @param agent - The agent ID
|
|
560
|
-
* @param version - The version to switch to
|
|
561
|
-
*
|
|
562
|
-
* Returns: { success: boolean, backupPath?: string, error?: string }
|
|
563
|
-
*/
|
|
564
|
-
export async function switchConfigSymlink(agent, version) {
|
|
565
|
-
const configPath = getAgentConfigPath(agent);
|
|
566
|
-
const versionConfigPath = getVersionConfigPath(agent, version);
|
|
567
|
-
// Ensure version config directory exists
|
|
568
|
-
if (!fs.existsSync(versionConfigPath)) {
|
|
569
|
-
fs.mkdirSync(versionConfigPath, { recursive: true });
|
|
570
|
-
}
|
|
571
|
-
try {
|
|
572
|
-
const stat = fs.lstatSync(configPath);
|
|
573
|
-
if (stat.isSymbolicLink()) {
|
|
574
|
-
// Already a symlink - check if it points to the correct target
|
|
575
|
-
const currentTarget = fs.readlinkSync(configPath);
|
|
576
|
-
const resolvedCurrent = path.resolve(path.dirname(configPath), currentTarget);
|
|
577
|
-
const resolvedTarget = path.resolve(versionConfigPath);
|
|
578
|
-
if (resolvedCurrent === resolvedTarget) {
|
|
579
|
-
// Already pointing to correct target, no-op
|
|
580
|
-
return { success: true };
|
|
581
|
-
}
|
|
582
|
-
// Different target - update it
|
|
583
|
-
fs.unlinkSync(configPath);
|
|
584
|
-
fs.symlinkSync(versionConfigPath, configPath);
|
|
585
|
-
return { success: true };
|
|
586
|
-
}
|
|
587
|
-
else if (stat.isDirectory()) {
|
|
588
|
-
// Real directory exists - backup and replace with symlink
|
|
589
|
-
const timestamp = Date.now();
|
|
590
|
-
// Move to backup location
|
|
591
|
-
const backupsDir = getBackupsDir();
|
|
592
|
-
const agentBackupDir = path.join(backupsDir, agent);
|
|
593
|
-
const finalBackupPath = path.join(agentBackupDir, String(timestamp));
|
|
594
|
-
fs.mkdirSync(agentBackupDir, { recursive: true });
|
|
595
|
-
fs.renameSync(configPath, finalBackupPath);
|
|
596
|
-
// Create symlink
|
|
597
|
-
fs.symlinkSync(versionConfigPath, configPath);
|
|
598
|
-
return { success: true, backupPath: finalBackupPath };
|
|
599
|
-
}
|
|
600
|
-
else {
|
|
601
|
-
return { success: false, error: `${configPath} exists but is not a directory or symlink` };
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
catch (err) {
|
|
605
|
-
if (err.code === 'ENOENT') {
|
|
606
|
-
// Config path doesn't exist - create symlink
|
|
607
|
-
fs.symlinkSync(versionConfigPath, configPath);
|
|
608
|
-
return { success: true };
|
|
609
|
-
}
|
|
610
|
-
return { success: false, error: err.message };
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
/**
|
|
614
|
-
* Switch home-level files (outside the config dir) to per-version symlinks.
|
|
615
|
-
* e.g., ~/.claude.json -> ~/.agents/versions/claude/2.0.65/home/.claude.json
|
|
616
|
-
*
|
|
617
|
-
* Uses atomic rename to avoid data loss if another session is running.
|
|
618
|
-
* On first migration (real file -> symlink), merges global auth into
|
|
619
|
-
* ALL installed versions so they inherit the current account.
|
|
620
|
-
*/
|
|
621
|
-
export function switchHomeFileSymlinks(agent, version) {
|
|
622
|
-
const agentConfig = AGENTS[agent];
|
|
623
|
-
const homeFiles = agentConfig.homeFiles;
|
|
624
|
-
if (!homeFiles || homeFiles.length === 0)
|
|
625
|
-
return { switched: [], errors: [] };
|
|
626
|
-
const home = process.env.AGENTS_REAL_HOME || os.homedir();
|
|
627
|
-
const versionsDir = getVersionsDir();
|
|
628
|
-
const switched = [];
|
|
629
|
-
const errors = [];
|
|
630
|
-
// For Claude, Claude's binary reads CLAUDE_CONFIG_DIR/.claude.json (INSIDE
|
|
631
|
-
// the per-version .claude dir) — not the home-level file this function
|
|
632
|
-
// manages. Reconcile all installed Claude versions so INSIDE is a symlink
|
|
633
|
-
// to OUTSIDE, making OUTSIDE the single source of truth.
|
|
634
|
-
if (agent === 'claude') {
|
|
635
|
-
const reconcile = ensureAllClaudeInsideSymlinks();
|
|
636
|
-
for (const e of reconcile.errors)
|
|
637
|
-
errors.push(e);
|
|
638
|
-
}
|
|
639
|
-
for (const fileName of homeFiles) {
|
|
640
|
-
const globalPath = path.join(home, fileName);
|
|
641
|
-
const versionFilePath = path.join(versionsDir, agent, version, 'home', fileName);
|
|
642
|
-
try {
|
|
643
|
-
// Ensure version home dir exists
|
|
644
|
-
const versionFileDir = path.dirname(versionFilePath);
|
|
645
|
-
if (!fs.existsSync(versionFileDir)) {
|
|
646
|
-
fs.mkdirSync(versionFileDir, { recursive: true });
|
|
647
|
-
}
|
|
648
|
-
let stat = null;
|
|
649
|
-
try {
|
|
650
|
-
stat = fs.lstatSync(globalPath);
|
|
651
|
-
}
|
|
652
|
-
catch {
|
|
653
|
-
// File doesn't exist at global path — just create symlink
|
|
654
|
-
if (!fs.existsSync(versionFilePath)) {
|
|
655
|
-
fs.writeFileSync(versionFilePath, '{}');
|
|
656
|
-
}
|
|
657
|
-
fs.symlinkSync(versionFilePath, globalPath);
|
|
658
|
-
switched.push(fileName);
|
|
659
|
-
continue;
|
|
660
|
-
}
|
|
661
|
-
if (stat.isSymbolicLink()) {
|
|
662
|
-
// Already a symlink — retarget atomically
|
|
663
|
-
const currentTarget = fs.readlinkSync(globalPath);
|
|
664
|
-
const resolvedCurrent = path.resolve(path.dirname(globalPath), currentTarget);
|
|
665
|
-
const resolvedTarget = path.resolve(versionFilePath);
|
|
666
|
-
if (resolvedCurrent === resolvedTarget) {
|
|
667
|
-
switched.push(fileName);
|
|
668
|
-
continue; // Already correct
|
|
669
|
-
}
|
|
670
|
-
// Atomic retarget: create temp symlink, rename over existing
|
|
671
|
-
if (!fs.existsSync(versionFilePath)) {
|
|
672
|
-
fs.writeFileSync(versionFilePath, '{}');
|
|
673
|
-
}
|
|
674
|
-
const tmpPath = `${globalPath}.agents-tmp-${process.pid}`;
|
|
675
|
-
fs.symlinkSync(versionFilePath, tmpPath);
|
|
676
|
-
fs.renameSync(tmpPath, globalPath);
|
|
677
|
-
switched.push(fileName);
|
|
678
|
-
}
|
|
679
|
-
else if (stat.isFile()) {
|
|
680
|
-
// Real file — first-time migration
|
|
681
|
-
// Read the global file content
|
|
682
|
-
const globalContent = JSON.parse(fs.readFileSync(globalPath, 'utf-8'));
|
|
683
|
-
// Merge auth into ALL installed version files for this agent
|
|
684
|
-
const agentVersionsDir = path.join(versionsDir, agent);
|
|
685
|
-
if (fs.existsSync(agentVersionsDir)) {
|
|
686
|
-
for (const ver of fs.readdirSync(agentVersionsDir)) {
|
|
687
|
-
const verFilePath = path.join(agentVersionsDir, ver, 'home', fileName);
|
|
688
|
-
const verFileDir = path.dirname(verFilePath);
|
|
689
|
-
if (!fs.existsSync(verFileDir)) {
|
|
690
|
-
fs.mkdirSync(verFileDir, { recursive: true });
|
|
691
|
-
}
|
|
692
|
-
if (fs.existsSync(verFilePath)) {
|
|
693
|
-
// Merge: version-specific fields + global auth fields
|
|
694
|
-
try {
|
|
695
|
-
const verContent = JSON.parse(fs.readFileSync(verFilePath, 'utf-8'));
|
|
696
|
-
const merged = { ...globalContent, ...verContent };
|
|
697
|
-
// Ensure auth from global always wins
|
|
698
|
-
if (globalContent.oauthAccount) {
|
|
699
|
-
merged.oauthAccount = globalContent.oauthAccount;
|
|
700
|
-
}
|
|
701
|
-
fs.writeFileSync(verFilePath, JSON.stringify(merged, null, 2));
|
|
702
|
-
}
|
|
703
|
-
catch {
|
|
704
|
-
// If version file is invalid JSON, overwrite with global
|
|
705
|
-
fs.writeFileSync(verFilePath, JSON.stringify(globalContent, null, 2));
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
else {
|
|
709
|
-
// No version file — copy global wholesale
|
|
710
|
-
fs.writeFileSync(verFilePath, JSON.stringify(globalContent, null, 2));
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
// Atomic swap: create temp symlink to target version, rename over real file
|
|
715
|
-
const tmpPath = `${globalPath}.agents-tmp-${process.pid}`;
|
|
716
|
-
fs.symlinkSync(versionFilePath, tmpPath);
|
|
717
|
-
fs.renameSync(tmpPath, globalPath);
|
|
718
|
-
switched.push(fileName);
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
catch (err) {
|
|
722
|
-
errors.push(`${fileName}: ${err.message}`);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
return { switched, errors };
|
|
726
|
-
}
|
|
727
|
-
/**
|
|
728
|
-
* Claude reads `.claude.json` at `$CLAUDE_CONFIG_DIR/.claude.json`. Our shim
|
|
729
|
-
* points CLAUDE_CONFIG_DIR at `<ver>/home/.claude`, so Claude's real config
|
|
730
|
-
* file lives at `<ver>/home/.claude/.claude.json` (INSIDE), while
|
|
731
|
-
* `switchHomeFileSymlinks` manages `<ver>/home/.claude.json` (OUTSIDE).
|
|
732
|
-
*
|
|
733
|
-
* To keep both views consistent we make INSIDE a symlink to OUTSIDE. Claude's
|
|
734
|
-
* atomic write (`Uf6`) resolves symlinks before the tmp+rename cycle, so the
|
|
735
|
-
* symlink survives across writes and OUTSIDE remains the single source of
|
|
736
|
-
* truth that agents-cli's home-file machinery already manages.
|
|
737
|
-
*
|
|
738
|
-
* This function idempotently reconciles one version:
|
|
739
|
-
* - INSIDE missing: create symlink -> `../.claude.json` (create OUTSIDE if needed).
|
|
740
|
-
* - INSIDE already symlink to OUTSIDE: no-op.
|
|
741
|
-
* - INSIDE is a real file: it's the authoritative auth state (Claude was
|
|
742
|
-
* writing to it). Move its content to OUTSIDE (merging with OUTSIDE,
|
|
743
|
-
* INSIDE wins for `oauthAccount`), then replace INSIDE with the symlink.
|
|
744
|
-
* - Symlink points elsewhere: replace it.
|
|
745
|
-
*/
|
|
746
|
-
export function ensureClaudeInsideSymlink(version) {
|
|
747
|
-
const versionsDir = getVersionsDir();
|
|
748
|
-
const versionHome = path.join(versionsDir, 'claude', version, 'home');
|
|
749
|
-
const outsidePath = path.join(versionHome, '.claude.json');
|
|
750
|
-
const insideDir = path.join(versionHome, '.claude');
|
|
751
|
-
const insidePath = path.join(insideDir, '.claude.json');
|
|
752
|
-
const linkTarget = '../.claude.json'; // relative so version dir can be moved
|
|
753
|
-
if (!fs.existsSync(insideDir)) {
|
|
754
|
-
fs.mkdirSync(insideDir, { recursive: true });
|
|
755
|
-
}
|
|
756
|
-
let insideStat = null;
|
|
757
|
-
try {
|
|
758
|
-
insideStat = fs.lstatSync(insidePath);
|
|
759
|
-
}
|
|
760
|
-
catch {
|
|
761
|
-
/* INSIDE does not exist */
|
|
762
|
-
}
|
|
763
|
-
if (insideStat?.isSymbolicLink()) {
|
|
764
|
-
const currentTarget = fs.readlinkSync(insidePath);
|
|
765
|
-
if (currentTarget === linkTarget)
|
|
766
|
-
return;
|
|
767
|
-
// Wrong target — replace.
|
|
768
|
-
if (!fs.existsSync(outsidePath))
|
|
769
|
-
fs.writeFileSync(outsidePath, '{}');
|
|
770
|
-
fs.unlinkSync(insidePath);
|
|
771
|
-
fs.symlinkSync(linkTarget, insidePath);
|
|
772
|
-
return;
|
|
773
|
-
}
|
|
774
|
-
if (insideStat?.isFile()) {
|
|
775
|
-
// INSIDE is the authoritative file — Claude has been reading/writing it.
|
|
776
|
-
// Merge INSIDE into OUTSIDE, with INSIDE winning on every field, then
|
|
777
|
-
// replace INSIDE with a symlink.
|
|
778
|
-
let insideContent = {};
|
|
779
|
-
try {
|
|
780
|
-
insideContent = JSON.parse(fs.readFileSync(insidePath, 'utf-8'));
|
|
781
|
-
}
|
|
782
|
-
catch {
|
|
783
|
-
/* INSIDE corrupt — treat as empty; OUTSIDE preserved as-is */
|
|
784
|
-
}
|
|
785
|
-
let outsideContent = {};
|
|
786
|
-
if (fs.existsSync(outsidePath)) {
|
|
787
|
-
try {
|
|
788
|
-
outsideContent = JSON.parse(fs.readFileSync(outsidePath, 'utf-8'));
|
|
789
|
-
}
|
|
790
|
-
catch {
|
|
791
|
-
/* OUTSIDE corrupt — drop it */
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
const merged = { ...outsideContent, ...insideContent };
|
|
795
|
-
fs.writeFileSync(outsidePath, JSON.stringify(merged, null, 2));
|
|
796
|
-
fs.unlinkSync(insidePath);
|
|
797
|
-
fs.symlinkSync(linkTarget, insidePath);
|
|
798
|
-
return;
|
|
799
|
-
}
|
|
800
|
-
// INSIDE missing — ensure OUTSIDE exists, then create symlink.
|
|
801
|
-
if (!fs.existsSync(outsidePath))
|
|
802
|
-
fs.writeFileSync(outsidePath, '{}');
|
|
803
|
-
fs.symlinkSync(linkTarget, insidePath);
|
|
804
|
-
}
|
|
805
|
-
/**
|
|
806
|
-
* Apply `ensureClaudeInsideSymlink` to every installed Claude version.
|
|
807
|
-
* Safe to call repeatedly; per-version calls are idempotent.
|
|
808
|
-
*/
|
|
809
|
-
export function ensureAllClaudeInsideSymlinks() {
|
|
810
|
-
const versionsDir = getVersionsDir();
|
|
811
|
-
const claudeVersionsDir = path.join(versionsDir, 'claude');
|
|
812
|
-
const migrated = [];
|
|
813
|
-
const errors = [];
|
|
814
|
-
if (!fs.existsSync(claudeVersionsDir))
|
|
815
|
-
return { migrated, errors };
|
|
816
|
-
for (const entry of fs.readdirSync(claudeVersionsDir, { withFileTypes: true })) {
|
|
817
|
-
if (!entry.isDirectory())
|
|
818
|
-
continue;
|
|
819
|
-
try {
|
|
820
|
-
ensureClaudeInsideSymlink(entry.name);
|
|
821
|
-
migrated.push(entry.name);
|
|
822
|
-
}
|
|
823
|
-
catch (err) {
|
|
824
|
-
errors.push(`${entry.name}: ${err.message}`);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
return { migrated, errors };
|
|
828
|
-
}
|
|
829
|
-
/**
|
|
830
|
-
* Get the current config symlink target version, if any.
|
|
831
|
-
*/
|
|
832
|
-
export function getConfigSymlinkVersion(agent) {
|
|
833
|
-
const configPath = getAgentConfigPath(agent);
|
|
834
|
-
try {
|
|
835
|
-
const stat = fs.lstatSync(configPath);
|
|
836
|
-
if (!stat.isSymbolicLink()) {
|
|
837
|
-
return null;
|
|
838
|
-
}
|
|
839
|
-
const target = fs.readlinkSync(configPath);
|
|
840
|
-
// Extract version from path like ~/.agents/versions/claude/2.0.65/home/.claude
|
|
841
|
-
const match = target.match(/versions\/[^/]+\/([^/]+)\/home/);
|
|
842
|
-
return match ? match[1] : null;
|
|
843
|
-
}
|
|
844
|
-
catch {
|
|
845
|
-
/* config path not accessible or not a symlink */
|
|
846
|
-
return null;
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
/**
|
|
850
|
-
* Copy directory contents with configurable conflict strategy.
|
|
851
|
-
* Skips when dest is a symlink (managed resources that shouldn't be overwritten).
|
|
852
|
-
*
|
|
853
|
-
* @param src - Source directory
|
|
854
|
-
* @param dest - Destination directory
|
|
855
|
-
* @param strategy - How to handle conflicts: 'keep-dest', 'overwrite', or 'ask-per-file'
|
|
856
|
-
* @param context - Agent/version context for prompts (only used when strategy is 'ask-per-file')
|
|
857
|
-
*/
|
|
858
|
-
async function copyDirContents(src, dest, strategy = 'keep-dest', context) {
|
|
859
|
-
// If dest is a symlink, skip - these are managed resources (skills, commands, etc.)
|
|
860
|
-
// that link to central ~/.agents/ and shouldn't be overwritten with local copies
|
|
861
|
-
try {
|
|
862
|
-
const destStat = fs.lstatSync(dest);
|
|
863
|
-
if (destStat.isSymbolicLink()) {
|
|
864
|
-
return; // Skip - don't copy into symlinked directories
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
catch {
|
|
868
|
-
// dest doesn't exist, that's fine
|
|
869
|
-
}
|
|
870
|
-
if (!fs.existsSync(dest)) {
|
|
871
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
872
|
-
}
|
|
873
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
874
|
-
for (const entry of entries) {
|
|
875
|
-
// Skip files/directories that should never be migrated
|
|
876
|
-
if (shouldIgnore(entry.name)) {
|
|
877
|
-
continue;
|
|
878
|
-
}
|
|
879
|
-
const srcPath = path.join(src, entry.name);
|
|
880
|
-
const destPath = path.join(dest, entry.name);
|
|
881
|
-
// Skip if dest entry is a symlink (managed resource)
|
|
882
|
-
try {
|
|
883
|
-
const entryDestStat = fs.lstatSync(destPath);
|
|
884
|
-
if (entryDestStat.isSymbolicLink()) {
|
|
885
|
-
continue; // Skip - managed resource
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
catch {
|
|
889
|
-
// dest entry doesn't exist, that's fine
|
|
890
|
-
}
|
|
891
|
-
if (entry.isDirectory()) {
|
|
892
|
-
await copyDirContents(srcPath, destPath, strategy, context);
|
|
893
|
-
}
|
|
894
|
-
else if (entry.isSymbolicLink()) {
|
|
895
|
-
const linkTarget = fs.readlinkSync(srcPath);
|
|
896
|
-
if (fs.existsSync(destPath)) {
|
|
897
|
-
fs.unlinkSync(destPath);
|
|
898
|
-
}
|
|
899
|
-
fs.symlinkSync(linkTarget, destPath);
|
|
900
|
-
}
|
|
901
|
-
else {
|
|
902
|
-
// File - check for conflict
|
|
903
|
-
if (fs.existsSync(destPath)) {
|
|
904
|
-
// Handle based on strategy
|
|
905
|
-
if (strategy === 'keep-dest') {
|
|
906
|
-
// Keep existing file, skip copying
|
|
907
|
-
continue;
|
|
908
|
-
}
|
|
909
|
-
else if (strategy === 'overwrite') {
|
|
910
|
-
// Back up and overwrite
|
|
911
|
-
fs.copyFileSync(destPath, `${destPath}.backup`);
|
|
912
|
-
}
|
|
913
|
-
else if (strategy === 'ask-per-file') {
|
|
914
|
-
// Back up dest file
|
|
915
|
-
fs.copyFileSync(destPath, `${destPath}.backup`);
|
|
916
|
-
// Ask user with context - use clear path-based terminology
|
|
917
|
-
const agentConfig = context ? AGENTS[context.agent] : null;
|
|
918
|
-
const versionLabel = agentConfig
|
|
919
|
-
? `${agentConfig.name}@${context.version}`
|
|
920
|
-
: 'version';
|
|
921
|
-
const useMyFile = await confirm({
|
|
922
|
-
message: `${entry.name}: Use your config file instead of ${versionLabel}?`,
|
|
923
|
-
default: false, // Default to keep version (safer)
|
|
924
|
-
});
|
|
925
|
-
if (!useMyFile) {
|
|
926
|
-
continue; // Keep dest (version file), skip copying src
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
fs.copyFileSync(srcPath, destPath);
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
/**
|
|
935
|
-
* Check if shim exists for an agent.
|
|
936
|
-
*/
|
|
937
|
-
export function shimExists(agent) {
|
|
938
|
-
const shimsDir = getShimsDir();
|
|
939
|
-
const agentConfig = AGENTS[agent];
|
|
940
|
-
const shimPath = path.join(shimsDir, agentConfig.cliCommand);
|
|
941
|
-
return fs.existsSync(shimPath);
|
|
942
|
-
}
|
|
943
|
-
/**
|
|
944
|
-
* Read the schema version embedded in an existing on-disk shim. Returns
|
|
945
|
-
* `null` if the shim doesn't exist or has no version marker (pre-v2 shim).
|
|
946
|
-
*/
|
|
947
|
-
export function readShimSchemaVersion(agent) {
|
|
948
|
-
if (!shimExists(agent))
|
|
949
|
-
return null;
|
|
950
|
-
try {
|
|
951
|
-
const content = fs.readFileSync(getShimPath(agent), 'utf8');
|
|
952
|
-
// Look at the first ~10 lines only — the marker lives in the header.
|
|
953
|
-
const header = content.split('\n', 10).join('\n');
|
|
954
|
-
const match = header.match(new RegExp(SHIM_VERSION_MARKER + '\\s*(\\d+)'));
|
|
955
|
-
if (!match)
|
|
956
|
-
return null;
|
|
957
|
-
return Number(match[1]);
|
|
958
|
-
}
|
|
959
|
-
catch {
|
|
960
|
-
return null;
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
/**
|
|
964
|
-
* True if the on-disk shim's schema version matches `SHIM_SCHEMA_VERSION`.
|
|
965
|
-
* False means either the shim is missing, is pre-v2 (no marker), or is an
|
|
966
|
-
* older version that needs regeneration.
|
|
967
|
-
*/
|
|
968
|
-
export function isShimCurrent(agent) {
|
|
969
|
-
const version = readShimSchemaVersion(agent);
|
|
970
|
-
return version === SHIM_SCHEMA_VERSION;
|
|
971
|
-
}
|
|
972
|
-
/**
|
|
973
|
-
* Regenerate the shim if it's missing or outdated. Returns a status describing
|
|
974
|
-
* what happened — callers can surface a one-line notice to the user ("Updated
|
|
975
|
-
* shim for codex") when appropriate.
|
|
976
|
-
*/
|
|
977
|
-
export function ensureShimCurrent(agent) {
|
|
978
|
-
if (!shimExists(agent)) {
|
|
979
|
-
createShim(agent);
|
|
980
|
-
return 'created';
|
|
981
|
-
}
|
|
982
|
-
if (!isShimCurrent(agent)) {
|
|
983
|
-
createShim(agent);
|
|
984
|
-
return 'updated';
|
|
985
|
-
}
|
|
986
|
-
return 'current';
|
|
987
|
-
}
|
|
988
|
-
/**
|
|
989
|
-
* Get the path to the shim for an agent.
|
|
990
|
-
*/
|
|
991
|
-
export function getShimPath(agent) {
|
|
992
|
-
const shimsDir = getShimsDir();
|
|
993
|
-
const agentConfig = AGENTS[agent];
|
|
994
|
-
return path.join(shimsDir, agentConfig.cliCommand);
|
|
995
|
-
}
|
|
996
|
-
/**
|
|
997
|
-
* Return the first executable path that would be launched for this agent when
|
|
998
|
-
* resolving against PATH, excluding the managed shim itself.
|
|
999
|
-
*/
|
|
1000
|
-
export function getPathShadowingExecutable(agent) {
|
|
1001
|
-
const pathDirs = (process.env.PATH || '').split(path.delimiter).filter(Boolean);
|
|
1002
|
-
const shimPath = path.resolve(getShimPath(agent));
|
|
1003
|
-
const cliCommand = AGENTS[agent].cliCommand;
|
|
1004
|
-
for (const dir of pathDirs) {
|
|
1005
|
-
const candidate = path.resolve(dir, cliCommand);
|
|
1006
|
-
if (!fs.existsSync(candidate)) {
|
|
1007
|
-
continue;
|
|
1008
|
-
}
|
|
1009
|
-
return candidate === shimPath ? null : candidate;
|
|
1010
|
-
}
|
|
1011
|
-
return null;
|
|
1012
|
-
}
|
|
1013
|
-
/**
|
|
1014
|
-
* Check if shims directory is in PATH.
|
|
1015
|
-
*/
|
|
1016
|
-
export function isShimsInPath() {
|
|
1017
|
-
const shimsDir = getShimsDir();
|
|
1018
|
-
const pathDirs = (process.env.PATH || '').split(path.delimiter);
|
|
1019
|
-
return pathDirs.some((dir) => path.resolve(dir) === path.resolve(shimsDir));
|
|
1020
|
-
}
|
|
1021
|
-
/**
|
|
1022
|
-
* Get the shell rc file path for the current shell.
|
|
1023
|
-
*/
|
|
1024
|
-
function getShellRcFile() {
|
|
1025
|
-
const shell = process.env.SHELL || '/bin/bash';
|
|
1026
|
-
const shellName = path.basename(shell);
|
|
1027
|
-
let rcFile;
|
|
1028
|
-
switch (shellName) {
|
|
1029
|
-
case 'zsh':
|
|
1030
|
-
rcFile = '.zshrc';
|
|
1031
|
-
break;
|
|
1032
|
-
case 'fish':
|
|
1033
|
-
rcFile = '.config/fish/config.fish';
|
|
1034
|
-
break;
|
|
1035
|
-
case 'bash':
|
|
1036
|
-
default:
|
|
1037
|
-
rcFile = '.bashrc';
|
|
1038
|
-
break;
|
|
1039
|
-
}
|
|
1040
|
-
return {
|
|
1041
|
-
rcFile,
|
|
1042
|
-
rcPath: path.join(os.homedir(), rcFile),
|
|
1043
|
-
shell: shellName,
|
|
1044
|
-
};
|
|
1045
|
-
}
|
|
1046
|
-
/**
|
|
1047
|
-
* Get shell configuration instructions for adding shims to PATH.
|
|
1048
|
-
*/
|
|
1049
|
-
export function getPathSetupInstructions() {
|
|
1050
|
-
const shimsDir = getShimsDir();
|
|
1051
|
-
const { rcFile, shell } = getShellRcFile();
|
|
1052
|
-
if (shell === 'fish') {
|
|
1053
|
-
return `Add to ~/.config/fish/config.fish:
|
|
1054
|
-
fish_add_path ${shimsDir}`;
|
|
1055
|
-
}
|
|
1056
|
-
return `Add to ~/${rcFile} (BEFORE any nvm/node setup):
|
|
1057
|
-
export PATH="${shimsDir}:$PATH"
|
|
1058
|
-
|
|
1059
|
-
IMPORTANT: Shims must come FIRST in PATH to override global installs.
|
|
1060
|
-
|
|
1061
|
-
Then restart your shell or run:
|
|
1062
|
-
source ~/${rcFile}`;
|
|
1063
|
-
}
|
|
1064
|
-
/**
|
|
1065
|
-
* Add shims directory to shell PATH configuration.
|
|
1066
|
-
* Returns true if added, false if already present or failed.
|
|
1067
|
-
*/
|
|
1068
|
-
export function addShimsToPath() {
|
|
1069
|
-
const shimsDir = getShimsDir();
|
|
1070
|
-
const { rcFile, rcPath, shell } = getShellRcFile();
|
|
1071
|
-
// Read current rc file content
|
|
1072
|
-
let content = '';
|
|
1073
|
-
try {
|
|
1074
|
-
if (fs.existsSync(rcPath)) {
|
|
1075
|
-
content = fs.readFileSync(rcPath, 'utf-8');
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
catch (err) {
|
|
1079
|
-
return { success: false, error: `Could not read ${rcFile}: ${err.message}` };
|
|
1080
|
-
}
|
|
1081
|
-
// Check if shims path already in file
|
|
1082
|
-
if (content.includes(shimsDir) || content.includes('$HOME/.agents/shims')) {
|
|
1083
|
-
return { success: true, alreadyPresent: true, rcFile };
|
|
1084
|
-
}
|
|
1085
|
-
// Generate the export line
|
|
1086
|
-
let exportLine;
|
|
1087
|
-
if (shell === 'fish') {
|
|
1088
|
-
exportLine = `\n# agents-cli: version-managed agent CLIs\nfish_add_path ${shimsDir}\n`;
|
|
1089
|
-
}
|
|
1090
|
-
else {
|
|
1091
|
-
exportLine = `\n# agents-cli: version-managed agent CLIs\nexport PATH="${shimsDir}:$PATH"\n`;
|
|
1092
|
-
}
|
|
1093
|
-
// Find insertion point - BEFORE nvm/node setup if possible
|
|
1094
|
-
// Look for common patterns that should come AFTER our shims
|
|
1095
|
-
const insertBeforePatterns = [
|
|
1096
|
-
/^export NVM_DIR=/m,
|
|
1097
|
-
/^source.*nvm/m,
|
|
1098
|
-
/^\[ -s.*nvm/m,
|
|
1099
|
-
/^eval.*fnm/m,
|
|
1100
|
-
/^export PATH.*node/m,
|
|
1101
|
-
/^export PATH.*npm/m,
|
|
1102
|
-
];
|
|
1103
|
-
let insertIndex = -1;
|
|
1104
|
-
for (const pattern of insertBeforePatterns) {
|
|
1105
|
-
const match = content.match(pattern);
|
|
1106
|
-
if (match && match.index !== undefined) {
|
|
1107
|
-
// Find start of this line
|
|
1108
|
-
let lineStart = match.index;
|
|
1109
|
-
while (lineStart > 0 && content[lineStart - 1] !== '\n') {
|
|
1110
|
-
lineStart--;
|
|
1111
|
-
}
|
|
1112
|
-
if (insertIndex === -1 || lineStart < insertIndex) {
|
|
1113
|
-
insertIndex = lineStart;
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
// Write the updated content
|
|
1118
|
-
try {
|
|
1119
|
-
// Ensure parent directories exist (especially for fish: ~/.config/fish/)
|
|
1120
|
-
const rcDir = path.dirname(rcPath);
|
|
1121
|
-
if (!fs.existsSync(rcDir)) {
|
|
1122
|
-
fs.mkdirSync(rcDir, { recursive: true });
|
|
1123
|
-
}
|
|
1124
|
-
let newContent;
|
|
1125
|
-
if (insertIndex >= 0) {
|
|
1126
|
-
// Insert before nvm/node setup (handles index 0 correctly)
|
|
1127
|
-
newContent = content.slice(0, insertIndex) + exportLine + content.slice(insertIndex);
|
|
1128
|
-
}
|
|
1129
|
-
else {
|
|
1130
|
-
// Append to end
|
|
1131
|
-
newContent = content + exportLine;
|
|
1132
|
-
}
|
|
1133
|
-
fs.writeFileSync(rcPath, newContent, 'utf-8');
|
|
1134
|
-
return { success: true, rcFile };
|
|
1135
|
-
}
|
|
1136
|
-
catch (err) {
|
|
1137
|
-
return { success: false, error: `Could not write ${rcFile}: ${err.message}` };
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
/**
|
|
1141
|
-
* Create shims for all installed agents.
|
|
1142
|
-
*/
|
|
1143
|
-
export function ensureAllShims() {
|
|
1144
|
-
const versionsDir = getVersionsDir();
|
|
1145
|
-
if (!fs.existsSync(versionsDir)) {
|
|
1146
|
-
return;
|
|
1147
|
-
}
|
|
1148
|
-
const entries = fs.readdirSync(versionsDir, { withFileTypes: true });
|
|
1149
|
-
for (const entry of entries) {
|
|
1150
|
-
if (entry.isDirectory() && AGENTS[entry.name]) {
|
|
1151
|
-
const agent = entry.name;
|
|
1152
|
-
const agentVersionsDir = path.join(versionsDir, agent);
|
|
1153
|
-
const versions = fs.readdirSync(agentVersionsDir, { withFileTypes: true })
|
|
1154
|
-
.filter((e) => e.isDirectory());
|
|
1155
|
-
if (versions.length > 0 && !shimExists(agent)) {
|
|
1156
|
-
createShim(agent);
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
/**
|
|
1162
|
-
* Compare resources between two versions.
|
|
1163
|
-
* Returns resources that exist in currentVersion but not in targetVersion.
|
|
1164
|
-
*/
|
|
1165
|
-
export function compareVersionResources(agent, currentVersion, targetVersion) {
|
|
1166
|
-
const agentConfig = AGENTS[agent];
|
|
1167
|
-
const currentPath = getVersionConfigPath(agent, currentVersion);
|
|
1168
|
-
const targetPath = getVersionConfigPath(agent, targetVersion);
|
|
1169
|
-
const diff = {
|
|
1170
|
-
commands: [],
|
|
1171
|
-
skills: [],
|
|
1172
|
-
hooks: [],
|
|
1173
|
-
memory: [],
|
|
1174
|
-
mcp: [],
|
|
1175
|
-
};
|
|
1176
|
-
// Helper to list directory contents (names only)
|
|
1177
|
-
const listDir = (dir) => {
|
|
1178
|
-
if (!fs.existsSync(dir))
|
|
1179
|
-
return [];
|
|
1180
|
-
try {
|
|
1181
|
-
return fs.readdirSync(dir).filter(f => !f.startsWith('.'));
|
|
1182
|
-
}
|
|
1183
|
-
catch {
|
|
1184
|
-
/* directory not readable */
|
|
1185
|
-
return [];
|
|
1186
|
-
}
|
|
1187
|
-
};
|
|
1188
|
-
// Helper to count lines in a file
|
|
1189
|
-
const countLines = (filePath) => {
|
|
1190
|
-
if (!fs.existsSync(filePath))
|
|
1191
|
-
return 0;
|
|
1192
|
-
try {
|
|
1193
|
-
return fs.readFileSync(filePath, 'utf-8').split('\n').length;
|
|
1194
|
-
}
|
|
1195
|
-
catch {
|
|
1196
|
-
/* file not readable */
|
|
1197
|
-
return 0;
|
|
1198
|
-
}
|
|
1199
|
-
};
|
|
1200
|
-
// Compare commands
|
|
1201
|
-
const currentCommands = listDir(path.join(currentPath, agentConfig.commandsSubdir));
|
|
1202
|
-
const targetCommands = new Set(listDir(path.join(targetPath, agentConfig.commandsSubdir)));
|
|
1203
|
-
diff.commands = currentCommands.filter(c => !targetCommands.has(c)).map(c => c.replace(/\.(md|toml)$/, ''));
|
|
1204
|
-
// Compare skills
|
|
1205
|
-
const currentSkills = listDir(path.join(currentPath, 'skills'));
|
|
1206
|
-
const targetSkills = new Set(listDir(path.join(targetPath, 'skills')));
|
|
1207
|
-
diff.skills = currentSkills.filter(s => !targetSkills.has(s));
|
|
1208
|
-
// Compare hooks
|
|
1209
|
-
const currentHooks = listDir(path.join(currentPath, 'hooks'));
|
|
1210
|
-
const targetHooks = new Set(listDir(path.join(targetPath, 'hooks')));
|
|
1211
|
-
diff.hooks = currentHooks.filter(h => !targetHooks.has(h));
|
|
1212
|
-
// Compare memory files (instructionsFile like CLAUDE.md)
|
|
1213
|
-
const memoryFile = agentConfig.instructionsFile;
|
|
1214
|
-
const currentMemoryPath = path.join(currentPath, memoryFile);
|
|
1215
|
-
const targetMemoryPath = path.join(targetPath, memoryFile);
|
|
1216
|
-
const currentLines = countLines(currentMemoryPath);
|
|
1217
|
-
const targetLines = countLines(targetMemoryPath);
|
|
1218
|
-
if (currentLines > 0 && currentLines !== targetLines) {
|
|
1219
|
-
diff.memory.push({ file: memoryFile, currentLines, targetLines });
|
|
1220
|
-
}
|
|
1221
|
-
// Compare MCP servers (from settings.json)
|
|
1222
|
-
const readMcpServers = (configPath) => {
|
|
1223
|
-
const settingsPath = path.join(configPath, 'settings.json');
|
|
1224
|
-
if (!fs.existsSync(settingsPath))
|
|
1225
|
-
return [];
|
|
1226
|
-
try {
|
|
1227
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
1228
|
-
return Object.keys(settings.mcpServers || {});
|
|
1229
|
-
}
|
|
1230
|
-
catch {
|
|
1231
|
-
/* settings.json corrupt or unreadable */
|
|
1232
|
-
return [];
|
|
1233
|
-
}
|
|
1234
|
-
};
|
|
1235
|
-
const currentMcp = readMcpServers(currentPath);
|
|
1236
|
-
const targetMcp = new Set(readMcpServers(targetPath));
|
|
1237
|
-
diff.mcp = currentMcp.filter(m => !targetMcp.has(m));
|
|
1238
|
-
return diff;
|
|
1239
|
-
}
|
|
1240
|
-
/**
|
|
1241
|
-
* Check if a ResourceDiff has any differences.
|
|
1242
|
-
*/
|
|
1243
|
-
export function hasResourceDiff(diff) {
|
|
1244
|
-
return (diff.commands.length > 0 ||
|
|
1245
|
-
diff.skills.length > 0 ||
|
|
1246
|
-
diff.hooks.length > 0 ||
|
|
1247
|
-
diff.memory.length > 0 ||
|
|
1248
|
-
diff.mcp.length > 0);
|
|
1249
|
-
}
|
|
1250
|
-
/**
|
|
1251
|
-
* Copy resources from one version to another.
|
|
1252
|
-
* Only copies resources listed in the diff (i.e., ones missing in target).
|
|
1253
|
-
*/
|
|
1254
|
-
export function copyResourcesToVersion(agent, fromVersion, toVersion, diff) {
|
|
1255
|
-
const agentConfig = AGENTS[agent];
|
|
1256
|
-
const fromPath = getVersionConfigPath(agent, fromVersion);
|
|
1257
|
-
const toPath = getVersionConfigPath(agent, toVersion);
|
|
1258
|
-
// Helper to copy a file or directory
|
|
1259
|
-
const copyItem = (srcDir, destDir, name) => {
|
|
1260
|
-
const srcPath = path.join(srcDir, name);
|
|
1261
|
-
const destPath = path.join(destDir, name);
|
|
1262
|
-
if (!fs.existsSync(srcPath))
|
|
1263
|
-
return;
|
|
1264
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
1265
|
-
const stat = fs.statSync(srcPath);
|
|
1266
|
-
if (stat.isDirectory()) {
|
|
1267
|
-
copyDirContents(srcPath, destPath);
|
|
1268
|
-
}
|
|
1269
|
-
else {
|
|
1270
|
-
fs.copyFileSync(srcPath, destPath);
|
|
1271
|
-
}
|
|
1272
|
-
};
|
|
1273
|
-
// Copy missing commands
|
|
1274
|
-
const commandsSubdir = agentConfig.commandsSubdir;
|
|
1275
|
-
const ext = agentConfig.format === 'toml' ? '.toml' : '.md';
|
|
1276
|
-
for (const cmd of diff.commands) {
|
|
1277
|
-
copyItem(path.join(fromPath, commandsSubdir), path.join(toPath, commandsSubdir), `${cmd}${ext}`);
|
|
1278
|
-
}
|
|
1279
|
-
// Copy missing skills
|
|
1280
|
-
for (const skill of diff.skills) {
|
|
1281
|
-
copyItem(path.join(fromPath, 'skills'), path.join(toPath, 'skills'), skill);
|
|
1282
|
-
}
|
|
1283
|
-
// Copy missing hooks
|
|
1284
|
-
for (const hook of diff.hooks) {
|
|
1285
|
-
copyItem(path.join(fromPath, 'hooks'), path.join(toPath, 'hooks'), hook);
|
|
1286
|
-
}
|
|
1287
|
-
// Copy memory file if different
|
|
1288
|
-
for (const mem of diff.memory) {
|
|
1289
|
-
const srcPath = path.join(fromPath, mem.file);
|
|
1290
|
-
const destPath = path.join(toPath, mem.file);
|
|
1291
|
-
if (fs.existsSync(srcPath)) {
|
|
1292
|
-
fs.copyFileSync(srcPath, destPath);
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
// Merge MCP servers into target settings.json
|
|
1296
|
-
if (diff.mcp.length > 0) {
|
|
1297
|
-
const fromSettingsPath = path.join(fromPath, 'settings.json');
|
|
1298
|
-
const toSettingsPath = path.join(toPath, 'settings.json');
|
|
1299
|
-
if (fs.existsSync(fromSettingsPath)) {
|
|
1300
|
-
try {
|
|
1301
|
-
const fromSettings = JSON.parse(fs.readFileSync(fromSettingsPath, 'utf-8'));
|
|
1302
|
-
let toSettings = {};
|
|
1303
|
-
if (fs.existsSync(toSettingsPath)) {
|
|
1304
|
-
toSettings = JSON.parse(fs.readFileSync(toSettingsPath, 'utf-8'));
|
|
1305
|
-
}
|
|
1306
|
-
if (!toSettings.mcpServers) {
|
|
1307
|
-
toSettings.mcpServers = {};
|
|
1308
|
-
}
|
|
1309
|
-
for (const serverName of diff.mcp) {
|
|
1310
|
-
if (fromSettings.mcpServers?.[serverName]) {
|
|
1311
|
-
toSettings.mcpServers[serverName] = fromSettings.mcpServers[serverName];
|
|
1312
|
-
}
|
|
1313
|
-
}
|
|
1314
|
-
fs.writeFileSync(toSettingsPath, JSON.stringify(toSettings, null, 2));
|
|
1315
|
-
}
|
|
1316
|
-
catch {
|
|
1317
|
-
/* settings.json parse error, skip MCP merge */
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
//# sourceMappingURL=shims.js.map
|