@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/permissions.js
DELETED
|
@@ -1,1071 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Permission management for AI coding agents.
|
|
3
|
-
*
|
|
4
|
-
* Provides a canonical permission format (PermissionSet with allow/deny rules)
|
|
5
|
-
* and converters to/from each agent's native format (Claude settings.json,
|
|
6
|
-
* OpenCode opencode.jsonc, Codex config.toml + .rules). Handles discovery,
|
|
7
|
-
* installation, removal, and merging of permission groups stored in
|
|
8
|
-
* ~/.agents/permissions/groups/.
|
|
9
|
-
*/
|
|
10
|
-
import * as fs from 'fs';
|
|
11
|
-
import * as path from 'path';
|
|
12
|
-
import * as os from 'os';
|
|
13
|
-
import * as yaml from 'yaml';
|
|
14
|
-
import * as TOML from 'smol-toml';
|
|
15
|
-
import { getPermissionsDir, ensureAgentsDir } from './state.js';
|
|
16
|
-
const HOME = os.homedir();
|
|
17
|
-
/** Agents that support the permissions subsystem. */
|
|
18
|
-
export const PERMISSIONS_CAPABLE_AGENTS = ['claude', 'codex', 'opencode'];
|
|
19
|
-
/** Filename used for Codex Starlark deny-rules generated from permission groups. */
|
|
20
|
-
export const CODEX_RULES_FILENAME = 'agents-deny.rules';
|
|
21
|
-
/**
|
|
22
|
-
* Convert canonical deny rules to Codex Starlark .rules format.
|
|
23
|
-
* E.g. "Bash(git reset:*)" -> prefix_rule(pattern=["git", "reset"], decision="forbidden")
|
|
24
|
-
*/
|
|
25
|
-
export function convertDenyToCodexRules(deny) {
|
|
26
|
-
const rules = [];
|
|
27
|
-
for (const perm of deny) {
|
|
28
|
-
const parsed = parseCanonicalPattern(perm);
|
|
29
|
-
if (!parsed || parsed.tool !== 'bash')
|
|
30
|
-
continue;
|
|
31
|
-
// Pattern format: "command arg1 arg2:*" or "command:*"
|
|
32
|
-
const command = parsed.pattern.replace(/:?\*$/, '').trim();
|
|
33
|
-
if (!command)
|
|
34
|
-
continue;
|
|
35
|
-
const parts = command.split(/\s+/);
|
|
36
|
-
const patternStr = parts.map(p => `"${p}"`).join(', ');
|
|
37
|
-
rules.push(`prefix_rule(\n pattern = [${patternStr}],\n decision = "forbidden",\n)`);
|
|
38
|
-
}
|
|
39
|
-
if (rules.length === 0)
|
|
40
|
-
return null;
|
|
41
|
-
return `# Auto-generated by agents-cli from deny permission groups.\n# Do not edit manually — re-run "agents use" to regenerate.\n\n${rules.join('\n\n')}\n`;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Ensure central permissions directory exists.
|
|
45
|
-
*/
|
|
46
|
-
export function ensurePermissionsDir() {
|
|
47
|
-
const dir = getPermissionsDir();
|
|
48
|
-
if (!fs.existsSync(dir)) {
|
|
49
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Parse a permission set from a YAML file.
|
|
54
|
-
*/
|
|
55
|
-
export function parsePermissionSet(filePath) {
|
|
56
|
-
if (!fs.existsSync(filePath)) {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
try {
|
|
60
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
61
|
-
const parsed = yaml.parse(content);
|
|
62
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
return {
|
|
66
|
-
name: parsed.name || path.basename(filePath, path.extname(filePath)),
|
|
67
|
-
description: parsed.description,
|
|
68
|
-
allow: Array.isArray(parsed.allow) ? parsed.allow : [],
|
|
69
|
-
deny: Array.isArray(parsed.deny) ? parsed.deny : [],
|
|
70
|
-
additionalDirectories: Array.isArray(parsed.additionalDirectories) ? parsed.additionalDirectories : undefined,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Discover permission sets from a repository.
|
|
79
|
-
*/
|
|
80
|
-
export function discoverPermissionsFromRepo(repoPath) {
|
|
81
|
-
const results = [];
|
|
82
|
-
// Look for permissions in common locations
|
|
83
|
-
const searchPaths = [
|
|
84
|
-
path.join(repoPath, 'permissions'),
|
|
85
|
-
path.join(repoPath, 'agent-permissions'),
|
|
86
|
-
repoPath,
|
|
87
|
-
];
|
|
88
|
-
for (const searchPath of searchPaths) {
|
|
89
|
-
if (!fs.existsSync(searchPath))
|
|
90
|
-
continue;
|
|
91
|
-
try {
|
|
92
|
-
const entries = fs.readdirSync(searchPath, { withFileTypes: true });
|
|
93
|
-
for (const entry of entries) {
|
|
94
|
-
if (!entry.isFile())
|
|
95
|
-
continue;
|
|
96
|
-
if (!entry.name.endsWith('.yml') && !entry.name.endsWith('.yaml'))
|
|
97
|
-
continue;
|
|
98
|
-
const filePath = path.join(searchPath, entry.name);
|
|
99
|
-
const set = parsePermissionSet(filePath);
|
|
100
|
-
if (set) {
|
|
101
|
-
results.push({
|
|
102
|
-
name: set.name,
|
|
103
|
-
path: filePath,
|
|
104
|
-
set,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
catch {
|
|
110
|
-
// Skip inaccessible directories
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return results;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Discover permission groups from ~/.agents/permissions/groups/.
|
|
117
|
-
* Returns groups with their rule counts.
|
|
118
|
-
*/
|
|
119
|
-
export function discoverPermissionGroups() {
|
|
120
|
-
const groupsDir = path.join(getPermissionsDir(), 'groups');
|
|
121
|
-
if (!fs.existsSync(groupsDir)) {
|
|
122
|
-
return [];
|
|
123
|
-
}
|
|
124
|
-
const groups = [];
|
|
125
|
-
try {
|
|
126
|
-
const entries = fs.readdirSync(groupsDir, { withFileTypes: true });
|
|
127
|
-
for (const entry of entries) {
|
|
128
|
-
if (!entry.isFile())
|
|
129
|
-
continue;
|
|
130
|
-
if (!entry.name.endsWith('.yml') && !entry.name.endsWith('.yaml'))
|
|
131
|
-
continue;
|
|
132
|
-
const filePath = path.join(groupsDir, entry.name);
|
|
133
|
-
const name = entry.name.replace(/\.(yaml|yml)$/, '');
|
|
134
|
-
// Count rules in this group
|
|
135
|
-
let ruleCount = 0;
|
|
136
|
-
try {
|
|
137
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
138
|
-
// Count lines that look like permission entries (start with - " after optional whitespace)
|
|
139
|
-
const matches = content.match(/^\s*-\s*"/gm);
|
|
140
|
-
ruleCount = matches ? matches.length : 0;
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
// Skip files we can't read
|
|
144
|
-
}
|
|
145
|
-
groups.push({ name, ruleCount, path: filePath });
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
catch {
|
|
149
|
-
// Skip inaccessible directory
|
|
150
|
-
}
|
|
151
|
-
// Sort by name (which sorts by numeric prefix)
|
|
152
|
-
return groups.sort((a, b) => a.name.localeCompare(b.name));
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Get total rule count across all permission groups.
|
|
156
|
-
*/
|
|
157
|
-
export function getTotalPermissionRuleCount() {
|
|
158
|
-
const groups = discoverPermissionGroups();
|
|
159
|
-
return groups.reduce((sum, g) => sum + g.ruleCount, 0);
|
|
160
|
-
}
|
|
161
|
-
/** Env var that selects which set recipe to apply at sync time. */
|
|
162
|
-
export const PERMISSION_SET_ENV_VAR = 'AGENTS_PERMISSION_SET';
|
|
163
|
-
/**
|
|
164
|
-
* Read a permission set recipe by name from ~/.agents/permissions/sets/.
|
|
165
|
-
* Returns null if the recipe file is missing or malformed.
|
|
166
|
-
*/
|
|
167
|
-
export function readPermissionSetRecipe(name) {
|
|
168
|
-
const setsDir = path.join(getPermissionsDir(), 'sets');
|
|
169
|
-
for (const ext of ['.yaml', '.yml']) {
|
|
170
|
-
const filePath = path.join(setsDir, name + ext);
|
|
171
|
-
if (!fs.existsSync(filePath))
|
|
172
|
-
continue;
|
|
173
|
-
try {
|
|
174
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
175
|
-
const parsed = yaml.parse(content);
|
|
176
|
-
if (!parsed || typeof parsed !== 'object')
|
|
177
|
-
return null;
|
|
178
|
-
if (!Array.isArray(parsed.includes))
|
|
179
|
-
return null;
|
|
180
|
-
return {
|
|
181
|
-
name: parsed.name || name,
|
|
182
|
-
description: parsed.description,
|
|
183
|
-
includes: parsed.includes.filter((v) => typeof v === 'string'),
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
catch {
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Return the active permission set name from AGENTS_PERMISSION_SET env var,
|
|
194
|
-
* or null if unset. Caller decides the default behavior when null.
|
|
195
|
-
*/
|
|
196
|
-
export function getActivePermissionSetName() {
|
|
197
|
-
const v = process.env[PERMISSION_SET_ENV_VAR];
|
|
198
|
-
return v && v.trim() ? v.trim() : null;
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Build a PermissionSet from selected groups.
|
|
202
|
-
* Concatenates allow/deny rules from each group.
|
|
203
|
-
*
|
|
204
|
-
* Uses line-by-line regex extraction instead of YAML parsing because
|
|
205
|
-
* permission files often contain unescaped nested quotes that break YAML.
|
|
206
|
-
*/
|
|
207
|
-
export function buildPermissionsFromGroups(groupNames) {
|
|
208
|
-
const groupsDir = path.join(getPermissionsDir(), 'groups');
|
|
209
|
-
const allAllow = [];
|
|
210
|
-
const allDeny = [];
|
|
211
|
-
for (const groupName of groupNames) {
|
|
212
|
-
// Try both .yaml and .yml extensions
|
|
213
|
-
let filePath = path.join(groupsDir, `${groupName}.yaml`);
|
|
214
|
-
if (!fs.existsSync(filePath)) {
|
|
215
|
-
filePath = path.join(groupsDir, `${groupName}.yml`);
|
|
216
|
-
}
|
|
217
|
-
if (!fs.existsSync(filePath)) {
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
try {
|
|
221
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
222
|
-
// Extract rules using line-by-line regex (more robust than YAML parsing)
|
|
223
|
-
// Matches lines like: - "Bash(git *)" or - "WebFetch(domain:example.com)"
|
|
224
|
-
// Handles nested quotes that break YAML parsers
|
|
225
|
-
const lines = content.split('\n');
|
|
226
|
-
for (const line of lines) {
|
|
227
|
-
// Match: optional whitespace, dash, whitespace, quote, content, quote
|
|
228
|
-
// Use greedy match to capture everything between first and last quote
|
|
229
|
-
const match = line.match(/^\s*-\s*"(.+)"$/);
|
|
230
|
-
if (match) {
|
|
231
|
-
const rule = match[1];
|
|
232
|
-
// 99-deny group rules go to deny, others to allow
|
|
233
|
-
if (groupName === '99-deny' || groupName.includes('-deny')) {
|
|
234
|
-
allDeny.push(rule);
|
|
235
|
-
}
|
|
236
|
-
else {
|
|
237
|
-
allAllow.push(rule);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
catch {
|
|
243
|
-
// Skip files we can't read
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
return {
|
|
247
|
-
name: 'built',
|
|
248
|
-
description: `Built from groups: ${groupNames.join(', ')}`,
|
|
249
|
-
allow: allAllow,
|
|
250
|
-
deny: allDeny.length > 0 ? allDeny : undefined,
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* List installed permission sets from central storage.
|
|
255
|
-
*/
|
|
256
|
-
export function listInstalledPermissions() {
|
|
257
|
-
ensureAgentsDir();
|
|
258
|
-
const dir = getPermissionsDir();
|
|
259
|
-
if (!fs.existsSync(dir)) {
|
|
260
|
-
return [];
|
|
261
|
-
}
|
|
262
|
-
const results = [];
|
|
263
|
-
try {
|
|
264
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
265
|
-
for (const entry of entries) {
|
|
266
|
-
if (!entry.isFile())
|
|
267
|
-
continue;
|
|
268
|
-
if (!entry.name.endsWith('.yml') && !entry.name.endsWith('.yaml'))
|
|
269
|
-
continue;
|
|
270
|
-
const filePath = path.join(dir, entry.name);
|
|
271
|
-
const set = parsePermissionSet(filePath);
|
|
272
|
-
if (set) {
|
|
273
|
-
results.push({
|
|
274
|
-
name: set.name,
|
|
275
|
-
path: filePath,
|
|
276
|
-
set,
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
catch {
|
|
282
|
-
// Ignore errors
|
|
283
|
-
}
|
|
284
|
-
return results;
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Get a specific permission set by name.
|
|
288
|
-
*/
|
|
289
|
-
export function getPermissionSet(name) {
|
|
290
|
-
const dir = getPermissionsDir();
|
|
291
|
-
for (const ext of ['.yml', '.yaml']) {
|
|
292
|
-
const filePath = path.join(dir, name + ext);
|
|
293
|
-
if (fs.existsSync(filePath)) {
|
|
294
|
-
const set = parsePermissionSet(filePath);
|
|
295
|
-
if (set) {
|
|
296
|
-
return { name: set.name, path: filePath, set };
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
return null;
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Install a permission set to central storage.
|
|
304
|
-
*/
|
|
305
|
-
export function installPermissionSet(sourcePath, name) {
|
|
306
|
-
ensurePermissionsDir();
|
|
307
|
-
const set = parsePermissionSet(sourcePath);
|
|
308
|
-
if (!set) {
|
|
309
|
-
return { success: false, error: 'Invalid permission file' };
|
|
310
|
-
}
|
|
311
|
-
const targetPath = path.join(getPermissionsDir(), name + '.yml');
|
|
312
|
-
try {
|
|
313
|
-
fs.copyFileSync(sourcePath, targetPath);
|
|
314
|
-
return { success: true };
|
|
315
|
-
}
|
|
316
|
-
catch (err) {
|
|
317
|
-
return { success: false, error: err.message };
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Remove a permission set from central storage.
|
|
322
|
-
*/
|
|
323
|
-
export function removePermissionSet(name) {
|
|
324
|
-
const dir = getPermissionsDir();
|
|
325
|
-
for (const ext of ['.yml', '.yaml']) {
|
|
326
|
-
const filePath = path.join(dir, name + ext);
|
|
327
|
-
if (fs.existsSync(filePath)) {
|
|
328
|
-
try {
|
|
329
|
-
fs.unlinkSync(filePath);
|
|
330
|
-
return { success: true };
|
|
331
|
-
}
|
|
332
|
-
catch (err) {
|
|
333
|
-
return { success: false, error: err.message };
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
return { success: false, error: `Permission set '${name}' not found` };
|
|
338
|
-
}
|
|
339
|
-
// ============================================================================
|
|
340
|
-
// Agent-specific converters
|
|
341
|
-
// ============================================================================
|
|
342
|
-
/**
|
|
343
|
-
* Convert canonical permission set to Claude format.
|
|
344
|
-
* Claude uses: { permissions: { allow: ["Bash(*)", "Read(**)"], deny: [] } }
|
|
345
|
-
*/
|
|
346
|
-
export function convertToClaudeFormat(set) {
|
|
347
|
-
const permissions = {
|
|
348
|
-
allow: [...set.allow],
|
|
349
|
-
deny: set.deny ? [...set.deny] : [],
|
|
350
|
-
};
|
|
351
|
-
if (set.additionalDirectories?.length) {
|
|
352
|
-
permissions.additionalDirectories = [...set.additionalDirectories];
|
|
353
|
-
}
|
|
354
|
-
return { permissions };
|
|
355
|
-
}
|
|
356
|
-
/**
|
|
357
|
-
* Parse canonical permission pattern to extract tool and pattern.
|
|
358
|
-
* "Bash(git *)" -> { tool: "bash", pattern: "git *" }
|
|
359
|
-
* "Read(**)" -> { tool: "read", pattern: "**" }
|
|
360
|
-
*/
|
|
361
|
-
function parseCanonicalPattern(permission) {
|
|
362
|
-
const match = permission.match(/^(\w+)\((.+)\)$/);
|
|
363
|
-
if (!match)
|
|
364
|
-
return null;
|
|
365
|
-
return { tool: match[1].toLowerCase(), pattern: match[2] };
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* Convert canonical permission set to OpenCode format.
|
|
369
|
-
* OpenCode uses: { permission: { bash: { "git *": "allow", "rm *": "deny" } } }
|
|
370
|
-
*/
|
|
371
|
-
export function convertToOpenCodeFormat(set) {
|
|
372
|
-
const bashPermissions = {};
|
|
373
|
-
// Process allow list
|
|
374
|
-
for (const perm of set.allow) {
|
|
375
|
-
const parsed = parseCanonicalPattern(perm);
|
|
376
|
-
if (parsed && parsed.tool === 'bash') {
|
|
377
|
-
bashPermissions[parsed.pattern] = 'allow';
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
// Process deny list
|
|
381
|
-
if (set.deny) {
|
|
382
|
-
for (const perm of set.deny) {
|
|
383
|
-
const parsed = parseCanonicalPattern(perm);
|
|
384
|
-
if (parsed && parsed.tool === 'bash') {
|
|
385
|
-
bashPermissions[parsed.pattern] = 'deny';
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
return {
|
|
390
|
-
permission: {
|
|
391
|
-
bash: bashPermissions,
|
|
392
|
-
},
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
/**
|
|
396
|
-
* Convert canonical permission set to Codex format.
|
|
397
|
-
* Codex uses coarse-grained modes, so we infer the best fit.
|
|
398
|
-
*/
|
|
399
|
-
export function convertToCodexFormat(set, cwd) {
|
|
400
|
-
const result = {};
|
|
401
|
-
// Check for broad bash permissions -> suggest full-auto
|
|
402
|
-
const hasBroadBash = set.allow.some((p) => {
|
|
403
|
-
const parsed = parseCanonicalPattern(p);
|
|
404
|
-
return parsed && parsed.tool === 'bash' && (parsed.pattern === '*' || parsed.pattern === '**');
|
|
405
|
-
});
|
|
406
|
-
if (hasBroadBash) {
|
|
407
|
-
result.approval_policy = 'never';
|
|
408
|
-
result.sandbox_mode = 'workspace-write';
|
|
409
|
-
}
|
|
410
|
-
else if (set.allow.length > 0) {
|
|
411
|
-
result.approval_policy = 'on-request';
|
|
412
|
-
result.sandbox_mode = 'workspace-write';
|
|
413
|
-
}
|
|
414
|
-
// Check for network/web permissions
|
|
415
|
-
const hasNetwork = set.allow.some((p) => {
|
|
416
|
-
const parsed = parseCanonicalPattern(p);
|
|
417
|
-
return parsed && (parsed.tool === 'websearch' || parsed.tool === 'webfetch');
|
|
418
|
-
});
|
|
419
|
-
if (hasNetwork) {
|
|
420
|
-
result.sandbox_workspace_write = {
|
|
421
|
-
network_access: true,
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
return result;
|
|
425
|
-
}
|
|
426
|
-
// ============================================================================
|
|
427
|
-
// Read agent permissions from native configs
|
|
428
|
-
// ============================================================================
|
|
429
|
-
/**
|
|
430
|
-
* Strip JSON comments for JSONC parsing.
|
|
431
|
-
*/
|
|
432
|
-
function stripJsonComments(content) {
|
|
433
|
-
let result = '';
|
|
434
|
-
let inString = false;
|
|
435
|
-
let escape = false;
|
|
436
|
-
let i = 0;
|
|
437
|
-
while (i < content.length) {
|
|
438
|
-
const char = content[i];
|
|
439
|
-
const next = content[i + 1];
|
|
440
|
-
if (escape) {
|
|
441
|
-
result += char;
|
|
442
|
-
escape = false;
|
|
443
|
-
i++;
|
|
444
|
-
continue;
|
|
445
|
-
}
|
|
446
|
-
if (char === '\\' && inString) {
|
|
447
|
-
result += char;
|
|
448
|
-
escape = true;
|
|
449
|
-
i++;
|
|
450
|
-
continue;
|
|
451
|
-
}
|
|
452
|
-
if (char === '"') {
|
|
453
|
-
inString = !inString;
|
|
454
|
-
result += char;
|
|
455
|
-
i++;
|
|
456
|
-
continue;
|
|
457
|
-
}
|
|
458
|
-
if (!inString) {
|
|
459
|
-
if (char === '/' && next === '/') {
|
|
460
|
-
while (i < content.length && content[i] !== '\n') {
|
|
461
|
-
i++;
|
|
462
|
-
}
|
|
463
|
-
continue;
|
|
464
|
-
}
|
|
465
|
-
if (char === '/' && next === '*') {
|
|
466
|
-
i += 2;
|
|
467
|
-
while (i < content.length && !(content[i] === '*' && content[i + 1] === '/')) {
|
|
468
|
-
i++;
|
|
469
|
-
}
|
|
470
|
-
i += 2;
|
|
471
|
-
continue;
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
result += char;
|
|
475
|
-
i++;
|
|
476
|
-
}
|
|
477
|
-
return result;
|
|
478
|
-
}
|
|
479
|
-
/**
|
|
480
|
-
* Read Claude's current permissions from settings.json.
|
|
481
|
-
*/
|
|
482
|
-
export function readClaudePermissions(scope = 'user', cwd, options) {
|
|
483
|
-
const home = options?.home || HOME;
|
|
484
|
-
const configPath = scope === 'user'
|
|
485
|
-
? path.join(home, '.claude', 'settings.json')
|
|
486
|
-
: path.join(cwd || process.cwd(), '.claude', 'settings.json');
|
|
487
|
-
if (!fs.existsSync(configPath)) {
|
|
488
|
-
return null;
|
|
489
|
-
}
|
|
490
|
-
try {
|
|
491
|
-
const content = fs.readFileSync(configPath, 'utf-8');
|
|
492
|
-
const config = JSON.parse(content);
|
|
493
|
-
if (config.permissions) {
|
|
494
|
-
return {
|
|
495
|
-
permissions: {
|
|
496
|
-
allow: config.permissions.allow || [],
|
|
497
|
-
deny: config.permissions.deny || [],
|
|
498
|
-
},
|
|
499
|
-
};
|
|
500
|
-
}
|
|
501
|
-
return null;
|
|
502
|
-
}
|
|
503
|
-
catch {
|
|
504
|
-
return null;
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
/**
|
|
508
|
-
* Read OpenCode's current permissions from opencode.jsonc.
|
|
509
|
-
*/
|
|
510
|
-
export function readOpenCodePermissions(scope = 'user', cwd, options) {
|
|
511
|
-
const home = options?.home || HOME;
|
|
512
|
-
const configPath = scope === 'user'
|
|
513
|
-
? path.join(home, '.opencode', 'opencode.jsonc')
|
|
514
|
-
: path.join(cwd || process.cwd(), '.opencode', 'opencode.jsonc');
|
|
515
|
-
if (!fs.existsSync(configPath)) {
|
|
516
|
-
return null;
|
|
517
|
-
}
|
|
518
|
-
try {
|
|
519
|
-
const content = stripJsonComments(fs.readFileSync(configPath, 'utf-8'));
|
|
520
|
-
const config = JSON.parse(content);
|
|
521
|
-
if (config.permission) {
|
|
522
|
-
return {
|
|
523
|
-
permission: {
|
|
524
|
-
bash: config.permission.bash || {},
|
|
525
|
-
},
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
return null;
|
|
529
|
-
}
|
|
530
|
-
catch {
|
|
531
|
-
return null;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* Read Codex's current permissions from config.toml.
|
|
536
|
-
*/
|
|
537
|
-
export function readCodexPermissions(scope = 'user', cwd, options) {
|
|
538
|
-
const home = options?.home || HOME;
|
|
539
|
-
const configPath = scope === 'user'
|
|
540
|
-
? path.join(home, '.codex', 'config.toml')
|
|
541
|
-
: path.join(cwd || process.cwd(), '.codex', 'config.toml');
|
|
542
|
-
if (!fs.existsSync(configPath)) {
|
|
543
|
-
return null;
|
|
544
|
-
}
|
|
545
|
-
try {
|
|
546
|
-
const content = fs.readFileSync(configPath, 'utf-8');
|
|
547
|
-
const config = TOML.parse(content);
|
|
548
|
-
const result = {};
|
|
549
|
-
if (config.approval_policy) {
|
|
550
|
-
result.approval_policy = config.approval_policy;
|
|
551
|
-
}
|
|
552
|
-
if (config.sandbox_mode) {
|
|
553
|
-
result.sandbox_mode = config.sandbox_mode;
|
|
554
|
-
}
|
|
555
|
-
if (config.sandbox_workspace_write) {
|
|
556
|
-
const sw = config.sandbox_workspace_write;
|
|
557
|
-
result.sandbox_workspace_write = {
|
|
558
|
-
network_access: sw.network_access,
|
|
559
|
-
writable_roots: sw.writable_roots,
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
return result;
|
|
563
|
-
}
|
|
564
|
-
catch {
|
|
565
|
-
return null;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Read agent permissions based on agent ID.
|
|
570
|
-
*/
|
|
571
|
-
export function readAgentPermissions(agentId, scope = 'user', cwd, options) {
|
|
572
|
-
switch (agentId) {
|
|
573
|
-
case 'claude':
|
|
574
|
-
return readClaudePermissions(scope, cwd, options);
|
|
575
|
-
case 'opencode':
|
|
576
|
-
return readOpenCodePermissions(scope, cwd, options);
|
|
577
|
-
case 'codex':
|
|
578
|
-
return readCodexPermissions(scope, cwd, options);
|
|
579
|
-
default:
|
|
580
|
-
return null;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
// ============================================================================
|
|
584
|
-
// Apply permissions to agents
|
|
585
|
-
// ============================================================================
|
|
586
|
-
/**
|
|
587
|
-
* Apply a permission set to Claude's settings.json.
|
|
588
|
-
*/
|
|
589
|
-
export function applyClaudePermissions(set, scope = 'user', cwd, merge = true) {
|
|
590
|
-
const configDir = scope === 'user'
|
|
591
|
-
? path.join(HOME, '.claude')
|
|
592
|
-
: path.join(cwd || process.cwd(), '.claude');
|
|
593
|
-
const configPath = path.join(configDir, 'settings.json');
|
|
594
|
-
try {
|
|
595
|
-
// Ensure directory exists
|
|
596
|
-
if (!fs.existsSync(configDir)) {
|
|
597
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
598
|
-
}
|
|
599
|
-
// Read existing config
|
|
600
|
-
let config = {};
|
|
601
|
-
if (fs.existsSync(configPath)) {
|
|
602
|
-
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
603
|
-
}
|
|
604
|
-
const newPermissions = convertToClaudeFormat(set);
|
|
605
|
-
if (merge && config.permissions) {
|
|
606
|
-
const existing = config.permissions;
|
|
607
|
-
const mergedAllow = new Set([...(existing.allow || []), ...newPermissions.permissions.allow]);
|
|
608
|
-
const mergedDeny = new Set([...(existing.deny || []), ...newPermissions.permissions.deny]);
|
|
609
|
-
config.permissions = {
|
|
610
|
-
allow: [...mergedAllow],
|
|
611
|
-
deny: [...mergedDeny],
|
|
612
|
-
};
|
|
613
|
-
}
|
|
614
|
-
else {
|
|
615
|
-
config.permissions = newPermissions.permissions;
|
|
616
|
-
}
|
|
617
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
618
|
-
return { success: true };
|
|
619
|
-
}
|
|
620
|
-
catch (err) {
|
|
621
|
-
return { success: false, error: err.message };
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
/**
|
|
625
|
-
* Apply a permission set to OpenCode's opencode.jsonc.
|
|
626
|
-
*/
|
|
627
|
-
export function applyOpenCodePermissions(set, scope = 'user', cwd, merge = true) {
|
|
628
|
-
const configDir = scope === 'user'
|
|
629
|
-
? path.join(HOME, '.opencode')
|
|
630
|
-
: path.join(cwd || process.cwd(), '.opencode');
|
|
631
|
-
const configPath = path.join(configDir, 'opencode.jsonc');
|
|
632
|
-
try {
|
|
633
|
-
// Ensure directory exists
|
|
634
|
-
if (!fs.existsSync(configDir)) {
|
|
635
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
636
|
-
}
|
|
637
|
-
// Read existing config
|
|
638
|
-
let config = {};
|
|
639
|
-
if (fs.existsSync(configPath)) {
|
|
640
|
-
const content = stripJsonComments(fs.readFileSync(configPath, 'utf-8'));
|
|
641
|
-
config = JSON.parse(content);
|
|
642
|
-
}
|
|
643
|
-
const newPermissions = convertToOpenCodeFormat(set);
|
|
644
|
-
if (merge && config.permission) {
|
|
645
|
-
const existing = config.permission;
|
|
646
|
-
config.permission = {
|
|
647
|
-
...existing,
|
|
648
|
-
bash: {
|
|
649
|
-
...(existing.bash || {}),
|
|
650
|
-
...newPermissions.permission.bash,
|
|
651
|
-
},
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
else {
|
|
655
|
-
config.permission = newPermissions.permission;
|
|
656
|
-
}
|
|
657
|
-
// Write without comments (they'll be lost)
|
|
658
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
659
|
-
return { success: true };
|
|
660
|
-
}
|
|
661
|
-
catch (err) {
|
|
662
|
-
return { success: false, error: err.message };
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
/**
|
|
666
|
-
* Apply a permission set to Codex's config.toml.
|
|
667
|
-
*/
|
|
668
|
-
export function applyCodexPermissions(set, scope = 'user', cwd, merge = true) {
|
|
669
|
-
const configDir = scope === 'user'
|
|
670
|
-
? path.join(HOME, '.codex')
|
|
671
|
-
: path.join(cwd || process.cwd(), '.codex');
|
|
672
|
-
const configPath = path.join(configDir, 'config.toml');
|
|
673
|
-
try {
|
|
674
|
-
// Ensure directory exists
|
|
675
|
-
if (!fs.existsSync(configDir)) {
|
|
676
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
677
|
-
}
|
|
678
|
-
// Read existing config
|
|
679
|
-
let config = {};
|
|
680
|
-
if (fs.existsSync(configPath)) {
|
|
681
|
-
const content = fs.readFileSync(configPath, 'utf-8');
|
|
682
|
-
config = TOML.parse(content);
|
|
683
|
-
}
|
|
684
|
-
const newPermissions = convertToCodexFormat(set, cwd);
|
|
685
|
-
// Merge or replace
|
|
686
|
-
if (newPermissions.approval_policy) {
|
|
687
|
-
config.approval_policy = newPermissions.approval_policy;
|
|
688
|
-
}
|
|
689
|
-
if (newPermissions.sandbox_mode) {
|
|
690
|
-
config.sandbox_mode = newPermissions.sandbox_mode;
|
|
691
|
-
}
|
|
692
|
-
if (newPermissions.sandbox_workspace_write) {
|
|
693
|
-
const existing = config.sandbox_workspace_write;
|
|
694
|
-
config.sandbox_workspace_write = merge
|
|
695
|
-
? { ...existing, ...newPermissions.sandbox_workspace_write }
|
|
696
|
-
: newPermissions.sandbox_workspace_write;
|
|
697
|
-
}
|
|
698
|
-
fs.writeFileSync(configPath, TOML.stringify(config), 'utf-8');
|
|
699
|
-
// Write .rules file for deny permissions
|
|
700
|
-
if (set.deny && set.deny.length > 0) {
|
|
701
|
-
const rulesContent = convertDenyToCodexRules(set.deny);
|
|
702
|
-
if (rulesContent) {
|
|
703
|
-
const rulesDir = path.join(configDir, 'rules');
|
|
704
|
-
fs.mkdirSync(rulesDir, { recursive: true });
|
|
705
|
-
fs.writeFileSync(path.join(rulesDir, CODEX_RULES_FILENAME), rulesContent, 'utf-8');
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
return { success: true };
|
|
709
|
-
}
|
|
710
|
-
catch (err) {
|
|
711
|
-
return { success: false, error: err.message };
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
/**
|
|
715
|
-
* Apply a permission set to an agent (global config).
|
|
716
|
-
*/
|
|
717
|
-
export function applyPermissionsToAgent(agentId, set, scope = 'user', cwd, merge = true) {
|
|
718
|
-
switch (agentId) {
|
|
719
|
-
case 'claude':
|
|
720
|
-
return applyClaudePermissions(set, scope, cwd, merge);
|
|
721
|
-
case 'opencode':
|
|
722
|
-
return applyOpenCodePermissions(set, scope, cwd, merge);
|
|
723
|
-
case 'codex':
|
|
724
|
-
return applyCodexPermissions(set, scope, cwd, merge);
|
|
725
|
-
default:
|
|
726
|
-
return { success: false, error: `Agent '${agentId}' does not support permissions` };
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
/**
|
|
730
|
-
* Apply a permission set to a specific version's home directory.
|
|
731
|
-
* This writes to {versionHome}/.{agent}/settings.json (or equivalent).
|
|
732
|
-
*/
|
|
733
|
-
export function applyPermissionsToVersion(agentId, set, versionHome, merge = true) {
|
|
734
|
-
const configDir = path.join(versionHome, `.${agentId}`);
|
|
735
|
-
try {
|
|
736
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
737
|
-
if (agentId === 'claude') {
|
|
738
|
-
const configPath = path.join(configDir, 'settings.json');
|
|
739
|
-
let config = {};
|
|
740
|
-
if (fs.existsSync(configPath)) {
|
|
741
|
-
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
742
|
-
}
|
|
743
|
-
const newPermissions = convertToClaudeFormat(set);
|
|
744
|
-
if (merge && config.permissions) {
|
|
745
|
-
const existing = config.permissions;
|
|
746
|
-
const mergedAllow = new Set([...(existing.allow || []), ...newPermissions.permissions.allow]);
|
|
747
|
-
const mergedDeny = new Set([...(existing.deny || []), ...newPermissions.permissions.deny]);
|
|
748
|
-
const mergedDirs = new Set([...(existing.additionalDirectories || []), ...(newPermissions.permissions.additionalDirectories || [])]);
|
|
749
|
-
const perms = {
|
|
750
|
-
allow: [...mergedAllow],
|
|
751
|
-
deny: [...mergedDeny],
|
|
752
|
-
};
|
|
753
|
-
if (mergedDirs.size > 0) {
|
|
754
|
-
perms.additionalDirectories = [...mergedDirs];
|
|
755
|
-
}
|
|
756
|
-
config.permissions = perms;
|
|
757
|
-
}
|
|
758
|
-
else {
|
|
759
|
-
config.permissions = newPermissions.permissions;
|
|
760
|
-
}
|
|
761
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
762
|
-
return { success: true };
|
|
763
|
-
}
|
|
764
|
-
if (agentId === 'opencode') {
|
|
765
|
-
const configPath = path.join(configDir, 'opencode.jsonc');
|
|
766
|
-
let config = {};
|
|
767
|
-
if (fs.existsSync(configPath)) {
|
|
768
|
-
const content = stripJsonComments(fs.readFileSync(configPath, 'utf-8'));
|
|
769
|
-
config = JSON.parse(content);
|
|
770
|
-
}
|
|
771
|
-
const newPermissions = convertToOpenCodeFormat(set);
|
|
772
|
-
if (merge && config.permission) {
|
|
773
|
-
const existing = config.permission;
|
|
774
|
-
config.permission = {
|
|
775
|
-
...existing,
|
|
776
|
-
bash: {
|
|
777
|
-
...(existing.bash || {}),
|
|
778
|
-
...newPermissions.permission.bash,
|
|
779
|
-
},
|
|
780
|
-
};
|
|
781
|
-
}
|
|
782
|
-
else {
|
|
783
|
-
config.permission = newPermissions.permission;
|
|
784
|
-
}
|
|
785
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
786
|
-
return { success: true };
|
|
787
|
-
}
|
|
788
|
-
if (agentId === 'codex') {
|
|
789
|
-
const configPath = path.join(configDir, 'config.toml');
|
|
790
|
-
let config = {};
|
|
791
|
-
if (fs.existsSync(configPath)) {
|
|
792
|
-
const content = fs.readFileSync(configPath, 'utf-8');
|
|
793
|
-
config = TOML.parse(content);
|
|
794
|
-
}
|
|
795
|
-
const newPermissions = convertToCodexFormat(set);
|
|
796
|
-
if (newPermissions.approval_policy) {
|
|
797
|
-
config.approval_policy = newPermissions.approval_policy;
|
|
798
|
-
}
|
|
799
|
-
if (newPermissions.sandbox_mode) {
|
|
800
|
-
config.sandbox_mode = newPermissions.sandbox_mode;
|
|
801
|
-
}
|
|
802
|
-
if (newPermissions.sandbox_workspace_write) {
|
|
803
|
-
const existing = config.sandbox_workspace_write;
|
|
804
|
-
config.sandbox_workspace_write = merge
|
|
805
|
-
? { ...existing, ...newPermissions.sandbox_workspace_write }
|
|
806
|
-
: newPermissions.sandbox_workspace_write;
|
|
807
|
-
}
|
|
808
|
-
fs.writeFileSync(configPath, TOML.stringify(config), 'utf-8');
|
|
809
|
-
// Write .rules file for deny permissions
|
|
810
|
-
if (set.deny && set.deny.length > 0) {
|
|
811
|
-
const rulesContent = convertDenyToCodexRules(set.deny);
|
|
812
|
-
if (rulesContent) {
|
|
813
|
-
const rulesDir = path.join(configDir, 'rules');
|
|
814
|
-
fs.mkdirSync(rulesDir, { recursive: true });
|
|
815
|
-
fs.writeFileSync(path.join(rulesDir, CODEX_RULES_FILENAME), rulesContent, 'utf-8');
|
|
816
|
-
}
|
|
817
|
-
}
|
|
818
|
-
return { success: true };
|
|
819
|
-
}
|
|
820
|
-
return { success: false, error: `Agent '${agentId}' does not support permissions` };
|
|
821
|
-
}
|
|
822
|
-
catch (err) {
|
|
823
|
-
return { success: false, error: err.message };
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
// ============================================================================
|
|
827
|
-
// Export canonical format from agent
|
|
828
|
-
// ============================================================================
|
|
829
|
-
/**
|
|
830
|
-
* Convert Claude permissions back to canonical format.
|
|
831
|
-
*/
|
|
832
|
-
export function claudeToCanonical(perms) {
|
|
833
|
-
const result = {
|
|
834
|
-
name: 'exported',
|
|
835
|
-
allow: perms.permissions.allow,
|
|
836
|
-
deny: perms.permissions.deny.length > 0 ? perms.permissions.deny : undefined,
|
|
837
|
-
};
|
|
838
|
-
if (perms.permissions.additionalDirectories?.length) {
|
|
839
|
-
result.additionalDirectories = perms.permissions.additionalDirectories;
|
|
840
|
-
}
|
|
841
|
-
return result;
|
|
842
|
-
}
|
|
843
|
-
/**
|
|
844
|
-
* Convert OpenCode permissions back to canonical format.
|
|
845
|
-
*/
|
|
846
|
-
export function openCodeToCanonical(perms) {
|
|
847
|
-
const allow = [];
|
|
848
|
-
const deny = [];
|
|
849
|
-
for (const [pattern, action] of Object.entries(perms.permission.bash)) {
|
|
850
|
-
if (action === 'allow') {
|
|
851
|
-
allow.push(`Bash(${pattern})`);
|
|
852
|
-
}
|
|
853
|
-
else if (action === 'deny') {
|
|
854
|
-
deny.push(`Bash(${pattern})`);
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
return {
|
|
858
|
-
name: 'exported',
|
|
859
|
-
allow,
|
|
860
|
-
deny: deny.length > 0 ? deny : undefined,
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
/**
|
|
864
|
-
* Convert Codex permissions back to canonical format (approximation).
|
|
865
|
-
*/
|
|
866
|
-
export function codexToCanonical(perms) {
|
|
867
|
-
const allow = [];
|
|
868
|
-
if (perms.approval_policy === 'never' || perms.sandbox_mode === 'danger-full-access') {
|
|
869
|
-
allow.push('Bash(*)');
|
|
870
|
-
allow.push('Read(**)');
|
|
871
|
-
allow.push('Write(**)');
|
|
872
|
-
allow.push('Edit(**)');
|
|
873
|
-
}
|
|
874
|
-
else if (perms.sandbox_mode === 'workspace-write') {
|
|
875
|
-
allow.push('Bash(*)');
|
|
876
|
-
allow.push('Read(**)');
|
|
877
|
-
}
|
|
878
|
-
if (perms.sandbox_workspace_write?.network_access) {
|
|
879
|
-
allow.push('WebSearch(*)');
|
|
880
|
-
allow.push('WebFetch(*)');
|
|
881
|
-
}
|
|
882
|
-
return {
|
|
883
|
-
name: 'exported',
|
|
884
|
-
allow,
|
|
885
|
-
};
|
|
886
|
-
}
|
|
887
|
-
/**
|
|
888
|
-
* Export agent's current permissions to canonical format.
|
|
889
|
-
*/
|
|
890
|
-
export function exportAgentPermissions(agentId, scope = 'user', cwd) {
|
|
891
|
-
const perms = readAgentPermissions(agentId, scope, cwd);
|
|
892
|
-
if (!perms)
|
|
893
|
-
return null;
|
|
894
|
-
switch (agentId) {
|
|
895
|
-
case 'claude':
|
|
896
|
-
return claudeToCanonical(perms);
|
|
897
|
-
case 'opencode':
|
|
898
|
-
return openCodeToCanonical(perms);
|
|
899
|
-
case 'codex':
|
|
900
|
-
return codexToCanonical(perms);
|
|
901
|
-
default:
|
|
902
|
-
return null;
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
/**
|
|
906
|
-
* Export permissions from a specific config file path to canonical format.
|
|
907
|
-
* Auto-detects agent type from file path/name.
|
|
908
|
-
*/
|
|
909
|
-
export function exportPermissionsFromPath(filePath) {
|
|
910
|
-
if (!fs.existsSync(filePath)) {
|
|
911
|
-
return null;
|
|
912
|
-
}
|
|
913
|
-
const content = fs.readFileSync(filePath, 'utf-8');
|
|
914
|
-
const fileName = path.basename(filePath);
|
|
915
|
-
const parentDir = path.basename(path.dirname(filePath));
|
|
916
|
-
// Detect agent type from path
|
|
917
|
-
let agentId = null;
|
|
918
|
-
if (fileName === 'settings.json' && parentDir === '.claude') {
|
|
919
|
-
agentId = 'claude';
|
|
920
|
-
}
|
|
921
|
-
else if (fileName === 'opencode.jsonc' || parentDir === '.opencode') {
|
|
922
|
-
agentId = 'opencode';
|
|
923
|
-
}
|
|
924
|
-
else if (fileName === 'config.toml' && parentDir === '.codex') {
|
|
925
|
-
agentId = 'codex';
|
|
926
|
-
}
|
|
927
|
-
else if (filePath.includes('.claude')) {
|
|
928
|
-
agentId = 'claude';
|
|
929
|
-
}
|
|
930
|
-
else if (filePath.includes('.opencode')) {
|
|
931
|
-
agentId = 'opencode';
|
|
932
|
-
}
|
|
933
|
-
else if (filePath.includes('.codex')) {
|
|
934
|
-
agentId = 'codex';
|
|
935
|
-
}
|
|
936
|
-
if (!agentId) {
|
|
937
|
-
return null;
|
|
938
|
-
}
|
|
939
|
-
try {
|
|
940
|
-
switch (agentId) {
|
|
941
|
-
case 'claude': {
|
|
942
|
-
const config = JSON.parse(content);
|
|
943
|
-
if (config.permissions) {
|
|
944
|
-
return claudeToCanonical({
|
|
945
|
-
permissions: {
|
|
946
|
-
allow: config.permissions.allow || [],
|
|
947
|
-
deny: config.permissions.deny || [],
|
|
948
|
-
},
|
|
949
|
-
});
|
|
950
|
-
}
|
|
951
|
-
return null;
|
|
952
|
-
}
|
|
953
|
-
case 'opencode': {
|
|
954
|
-
// Strip JSONC comments
|
|
955
|
-
const jsonContent = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
|
|
956
|
-
const config = JSON.parse(jsonContent);
|
|
957
|
-
if (config.permission) {
|
|
958
|
-
return openCodeToCanonical({
|
|
959
|
-
permission: {
|
|
960
|
-
bash: config.permission.bash || {},
|
|
961
|
-
},
|
|
962
|
-
});
|
|
963
|
-
}
|
|
964
|
-
return null;
|
|
965
|
-
}
|
|
966
|
-
case 'codex': {
|
|
967
|
-
const config = TOML.parse(content);
|
|
968
|
-
const perms = {};
|
|
969
|
-
if (config.approval_policy) {
|
|
970
|
-
perms.approval_policy = config.approval_policy;
|
|
971
|
-
}
|
|
972
|
-
if (config.sandbox_mode) {
|
|
973
|
-
perms.sandbox_mode = config.sandbox_mode;
|
|
974
|
-
}
|
|
975
|
-
if (config.sandbox_workspace_write) {
|
|
976
|
-
const sw = config.sandbox_workspace_write;
|
|
977
|
-
perms.sandbox_workspace_write = {
|
|
978
|
-
network_access: sw.network_access,
|
|
979
|
-
writable_roots: sw.writable_roots,
|
|
980
|
-
};
|
|
981
|
-
}
|
|
982
|
-
return codexToCanonical(perms);
|
|
983
|
-
}
|
|
984
|
-
default:
|
|
985
|
-
return null;
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
catch {
|
|
989
|
-
return null;
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
/**
|
|
993
|
-
* Save a permission set to central storage.
|
|
994
|
-
*/
|
|
995
|
-
export function savePermissionSet(set) {
|
|
996
|
-
ensurePermissionsDir();
|
|
997
|
-
const filePath = path.join(getPermissionsDir(), set.name + '.yml');
|
|
998
|
-
try {
|
|
999
|
-
const content = yaml.stringify({
|
|
1000
|
-
name: set.name,
|
|
1001
|
-
description: set.description,
|
|
1002
|
-
allow: set.allow,
|
|
1003
|
-
deny: set.deny,
|
|
1004
|
-
});
|
|
1005
|
-
fs.writeFileSync(filePath, content, 'utf-8');
|
|
1006
|
-
return { success: true };
|
|
1007
|
-
}
|
|
1008
|
-
catch (err) {
|
|
1009
|
-
return { success: false, error: err.message };
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
/** Name used for the default permission set in central storage. */
|
|
1013
|
-
const DEFAULT_PERMISSION_SET_NAME = 'default';
|
|
1014
|
-
/**
|
|
1015
|
-
* Get the default permission set from central storage.
|
|
1016
|
-
*/
|
|
1017
|
-
export function getDefaultPermissionSet() {
|
|
1018
|
-
const existing = getPermissionSet(DEFAULT_PERMISSION_SET_NAME);
|
|
1019
|
-
if (existing) {
|
|
1020
|
-
return existing.set;
|
|
1021
|
-
}
|
|
1022
|
-
return {
|
|
1023
|
-
name: DEFAULT_PERMISSION_SET_NAME,
|
|
1024
|
-
description: 'Default permission set',
|
|
1025
|
-
allow: [],
|
|
1026
|
-
deny: [],
|
|
1027
|
-
};
|
|
1028
|
-
}
|
|
1029
|
-
/**
|
|
1030
|
-
* Compute diff between existing and new permissions.
|
|
1031
|
-
* Returns { added, existing, removed } for both allow and deny rules.
|
|
1032
|
-
*/
|
|
1033
|
-
export function computePermissionsDiff(existing, incoming) {
|
|
1034
|
-
const existingAllowSet = new Set(existing.allow);
|
|
1035
|
-
const existingDenySet = new Set(existing.deny || []);
|
|
1036
|
-
const allowAdded = incoming.allow.filter((r) => !existingAllowSet.has(r));
|
|
1037
|
-
const allowExisting = incoming.allow.filter((r) => existingAllowSet.has(r));
|
|
1038
|
-
const incomingDeny = incoming.deny || [];
|
|
1039
|
-
const denyAdded = incomingDeny.filter((r) => !existingDenySet.has(r));
|
|
1040
|
-
const denyExisting = incomingDeny.filter((r) => existingDenySet.has(r));
|
|
1041
|
-
return {
|
|
1042
|
-
allow: { added: allowAdded, existing: allowExisting },
|
|
1043
|
-
deny: { added: denyAdded, existing: denyExisting },
|
|
1044
|
-
};
|
|
1045
|
-
}
|
|
1046
|
-
/**
|
|
1047
|
-
* Merge incoming permissions into existing, deduplicating.
|
|
1048
|
-
*/
|
|
1049
|
-
export function mergePermissionSets(existing, incoming) {
|
|
1050
|
-
const allowSet = new Set([...existing.allow, ...incoming.allow]);
|
|
1051
|
-
const denySet = new Set([...(existing.deny || []), ...(incoming.deny || [])]);
|
|
1052
|
-
const dirsSet = new Set([...(existing.additionalDirectories || []), ...(incoming.additionalDirectories || [])]);
|
|
1053
|
-
const result = {
|
|
1054
|
-
name: existing.name,
|
|
1055
|
-
description: existing.description,
|
|
1056
|
-
allow: Array.from(allowSet).sort(),
|
|
1057
|
-
deny: Array.from(denySet).sort(),
|
|
1058
|
-
};
|
|
1059
|
-
if (dirsSet.size > 0) {
|
|
1060
|
-
result.additionalDirectories = Array.from(dirsSet).sort();
|
|
1061
|
-
}
|
|
1062
|
-
return result;
|
|
1063
|
-
}
|
|
1064
|
-
/**
|
|
1065
|
-
* Save the default permission set.
|
|
1066
|
-
*/
|
|
1067
|
-
export function saveDefaultPermissionSet(set) {
|
|
1068
|
-
set.name = DEFAULT_PERMISSION_SET_NAME;
|
|
1069
|
-
return savePermissionSet(set);
|
|
1070
|
-
}
|
|
1071
|
-
//# sourceMappingURL=permissions.js.map
|