@phnx-labs/agents-cli 1.20.4 → 1.20.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +48 -17
- package/dist/commands/cli.js +1 -1
- package/dist/commands/cloud.js +1 -1
- package/dist/commands/commands.js +2 -0
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/exec.js +52 -16
- package/dist/commands/hooks.js +6 -6
- package/dist/commands/inspect.d.ts +26 -0
- package/dist/commands/inspect.js +590 -0
- package/dist/commands/mcp.js +17 -16
- package/dist/commands/models.js +1 -1
- package/dist/commands/packages.js +6 -4
- package/dist/commands/permissions.js +13 -12
- package/dist/commands/plugins.d.ts +13 -0
- package/dist/commands/plugins.js +100 -11
- package/dist/commands/prune.js +3 -2
- package/dist/commands/pull.d.ts +12 -5
- package/dist/commands/pull.js +26 -422
- package/dist/commands/push.d.ts +14 -0
- package/dist/commands/push.js +30 -0
- package/dist/commands/repo.d.ts +1 -1
- package/dist/commands/repo.js +155 -112
- package/dist/commands/resource-view.d.ts +2 -0
- package/dist/commands/resource-view.js +12 -3
- package/dist/commands/routines.js +32 -7
- package/dist/commands/rules.js +1 -1
- package/dist/commands/sessions.js +1 -0
- package/dist/commands/setup.d.ts +3 -3
- package/dist/commands/setup.js +15 -15
- package/dist/commands/skills.js +6 -5
- package/dist/commands/subagents.js +5 -4
- package/dist/commands/sync.d.ts +18 -5
- package/dist/commands/sync.js +251 -65
- package/dist/commands/teams.js +1 -0
- package/dist/commands/tmux.d.ts +25 -0
- package/dist/commands/tmux.js +415 -0
- package/dist/commands/trash.d.ts +2 -2
- package/dist/commands/trash.js +1 -1
- package/dist/commands/versions.js +2 -2
- package/dist/commands/view.js +9 -4
- package/dist/commands/workflows.js +4 -3
- package/dist/commands/worktree.d.ts +4 -5
- package/dist/commands/worktree.js +4 -4
- package/dist/index.js +68 -20
- package/dist/lib/agents.d.ts +19 -10
- package/dist/lib/agents.js +79 -25
- package/dist/lib/auto-pull-worker.d.ts +1 -1
- package/dist/lib/auto-pull-worker.js +2 -2
- package/dist/lib/auto-pull.d.ts +1 -1
- package/dist/lib/auto-pull.js +1 -1
- package/dist/lib/beta.d.ts +1 -1
- package/dist/lib/beta.js +1 -1
- package/dist/lib/capabilities.js +2 -0
- package/dist/lib/commands.d.ts +28 -1
- package/dist/lib/commands.js +125 -20
- package/dist/lib/doctor-diff.js +2 -2
- package/dist/lib/exec.d.ts +14 -0
- package/dist/lib/exec.js +39 -5
- package/dist/lib/fuzzy.d.ts +12 -2
- package/dist/lib/fuzzy.js +29 -4
- package/dist/lib/git.js +8 -1
- package/dist/lib/hooks.d.ts +2 -2
- package/dist/lib/hooks.js +97 -10
- package/dist/lib/mcp.js +32 -2
- package/dist/lib/migrate.d.ts +51 -0
- package/dist/lib/migrate.js +227 -1
- package/dist/lib/models.js +62 -15
- package/dist/lib/permissions.d.ts +36 -2
- package/dist/lib/permissions.js +217 -7
- package/dist/lib/plugin-marketplace.d.ts +98 -40
- package/dist/lib/plugin-marketplace.js +196 -93
- package/dist/lib/plugins.d.ts +21 -4
- package/dist/lib/plugins.js +130 -49
- package/dist/lib/profiles-presets.js +12 -12
- package/dist/lib/project-launch.d.ts +65 -0
- package/dist/lib/project-launch.js +367 -0
- package/dist/lib/pty-client.js +1 -1
- package/dist/lib/pty-server.d.ts +1 -1
- package/dist/lib/pty-server.js +1 -1
- package/dist/lib/refresh.d.ts +26 -0
- package/dist/lib/refresh.js +315 -0
- package/dist/lib/resource-patterns.d.ts +1 -1
- package/dist/lib/resource-patterns.js +1 -1
- package/dist/lib/resources/commands.js +2 -2
- package/dist/lib/resources/hooks.d.ts +1 -1
- package/dist/lib/resources/hooks.js +1 -1
- package/dist/lib/resources/mcp.d.ts +1 -1
- package/dist/lib/resources/mcp.js +5 -6
- package/dist/lib/resources/permissions.js +5 -2
- package/dist/lib/resources/rules.js +3 -2
- package/dist/lib/resources/skills.js +3 -2
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.js +2 -2
- package/dist/lib/rotate.d.ts +1 -1
- package/dist/lib/rotate.js +1 -1
- package/dist/lib/routines.d.ts +16 -4
- package/dist/lib/routines.js +67 -17
- package/dist/lib/rules/compile.js +22 -10
- package/dist/lib/rules/rules.js +3 -3
- package/dist/lib/runner.js +16 -3
- package/dist/lib/scheduler.js +15 -1
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +9 -1
- package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
- package/dist/lib/secrets/linux.d.ts +44 -9
- package/dist/lib/secrets/linux.js +302 -48
- package/dist/lib/session/db.js +15 -2
- package/dist/lib/session/discover.js +118 -3
- package/dist/lib/session/parse.js +3 -0
- package/dist/lib/session/types.d.ts +1 -1
- package/dist/lib/session/types.js +1 -1
- package/dist/lib/shims.d.ts +10 -9
- package/dist/lib/shims.js +101 -50
- package/dist/lib/skills.d.ts +1 -1
- package/dist/lib/skills.js +10 -9
- package/dist/lib/staleness/detectors/commands.d.ts +3 -0
- package/dist/lib/staleness/detectors/commands.js +46 -0
- package/dist/lib/staleness/detectors/hooks.d.ts +3 -0
- package/dist/lib/staleness/detectors/hooks.js +44 -0
- package/dist/lib/staleness/detectors/mcp.d.ts +3 -0
- package/dist/lib/staleness/detectors/mcp.js +31 -0
- package/dist/lib/staleness/detectors/permissions.d.ts +3 -0
- package/dist/lib/staleness/detectors/permissions.js +201 -0
- package/dist/lib/staleness/detectors/plugins.d.ts +8 -0
- package/dist/lib/staleness/detectors/plugins.js +23 -0
- package/dist/lib/staleness/detectors/rules.d.ts +3 -0
- package/dist/lib/staleness/detectors/rules.js +34 -0
- package/dist/lib/staleness/detectors/skills.d.ts +3 -0
- package/dist/lib/staleness/detectors/skills.js +71 -0
- package/dist/lib/staleness/detectors/subagents.d.ts +3 -0
- package/dist/lib/staleness/detectors/subagents.js +50 -0
- package/dist/lib/staleness/detectors/types.d.ts +22 -0
- package/dist/lib/staleness/detectors/types.js +1 -0
- package/dist/lib/staleness/detectors/workflows.d.ts +3 -0
- package/dist/lib/staleness/detectors/workflows.js +28 -0
- package/dist/lib/staleness/registry.d.ts +26 -0
- package/dist/lib/staleness/registry.js +123 -0
- package/dist/lib/staleness/writers/commands.d.ts +3 -0
- package/dist/lib/staleness/writers/commands.js +111 -0
- package/dist/lib/staleness/writers/hooks.d.ts +3 -0
- package/dist/lib/staleness/writers/hooks.js +47 -0
- package/dist/lib/staleness/writers/kinds.d.ts +10 -0
- package/dist/lib/staleness/writers/kinds.js +15 -0
- package/dist/lib/staleness/writers/lazy-map.d.ts +13 -0
- package/dist/lib/staleness/writers/lazy-map.js +19 -0
- package/dist/lib/staleness/writers/mcp.d.ts +10 -0
- package/dist/lib/staleness/writers/mcp.js +19 -0
- package/dist/lib/staleness/writers/permissions.d.ts +13 -0
- package/dist/lib/staleness/writers/permissions.js +26 -0
- package/dist/lib/staleness/writers/plugins.d.ts +7 -0
- package/dist/lib/staleness/writers/plugins.js +31 -0
- package/dist/lib/staleness/writers/rules.d.ts +7 -0
- package/dist/lib/staleness/writers/rules.js +55 -0
- package/dist/lib/staleness/writers/skills.d.ts +3 -0
- package/dist/lib/staleness/writers/skills.js +81 -0
- package/dist/lib/staleness/writers/sources.d.ts +16 -0
- package/dist/lib/staleness/writers/sources.js +72 -0
- package/dist/lib/staleness/writers/subagents.d.ts +3 -0
- package/dist/lib/staleness/writers/subagents.js +53 -0
- package/dist/lib/staleness/writers/types.d.ts +36 -0
- package/dist/lib/staleness/writers/types.js +1 -0
- package/dist/lib/staleness/writers/workflows.d.ts +7 -0
- package/dist/lib/staleness/writers/workflows.js +31 -0
- package/dist/lib/state.d.ts +34 -11
- package/dist/lib/state.js +58 -13
- package/dist/lib/subagents.d.ts +0 -2
- package/dist/lib/subagents.js +6 -6
- package/dist/lib/teams/agents.js +1 -1
- package/dist/lib/teams/parsers.d.ts +1 -1
- package/dist/lib/tmux/binary.d.ts +67 -0
- package/dist/lib/tmux/binary.js +141 -0
- package/dist/lib/tmux/index.d.ts +8 -0
- package/dist/lib/tmux/index.js +8 -0
- package/dist/lib/tmux/paths.d.ts +17 -0
- package/dist/lib/tmux/paths.js +30 -0
- package/dist/lib/tmux/session.d.ts +122 -0
- package/dist/lib/tmux/session.js +305 -0
- package/dist/lib/types.d.ts +58 -7
- package/dist/lib/types.js +1 -1
- package/dist/lib/usage.js +1 -1
- package/dist/lib/versions.d.ts +4 -4
- package/dist/lib/versions.js +135 -493
- package/dist/lib/workflows.d.ts +2 -4
- package/dist/lib/workflows.js +3 -4
- package/package.json +2 -2
- package/scripts/postinstall.js +16 -63
- package/dist/commands/status.d.ts +0 -9
- package/dist/commands/status.js +0 -25
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { AgentId, PermissionSet, InstalledPermission, ClaudePermissions, OpenCodePermissions, CodexPermissions } from './types.js';
|
|
2
|
-
/** Agents that support the permissions subsystem. */
|
|
3
|
-
export declare const PERMISSIONS_CAPABLE_AGENTS: AgentId[];
|
|
4
2
|
/** Filename used for Codex Starlark deny-rules generated from permission groups. */
|
|
5
3
|
export declare const CODEX_RULES_FILENAME = "agents-deny.rules";
|
|
6
4
|
export type ParsedRules = PermissionSet;
|
|
@@ -110,6 +108,42 @@ export declare function convertToGeminiFormat(set: PermissionSet): {
|
|
|
110
108
|
allowed: string[];
|
|
111
109
|
};
|
|
112
110
|
};
|
|
111
|
+
/**
|
|
112
|
+
* Convert canonical permission set to Antigravity format.
|
|
113
|
+
* Antigravity reads ~/.gemini/antigravity-cli/settings.json with
|
|
114
|
+
* { permissions: { allow: [...], deny: [...] } }
|
|
115
|
+
* where each entry is action-namespaced: command(...), read_file(...),
|
|
116
|
+
* write_file(...), read_url(...), mcp(...).
|
|
117
|
+
* Bash maps to `command`, Read to `read_file`, Write to `write_file`,
|
|
118
|
+
* WebFetch to `read_url`. Other canonical tools are skipped.
|
|
119
|
+
* Note: Antigravity matches `command(npm install)` as an exact string,
|
|
120
|
+
* not a prefix — `Bash(npm:*)` becomes `command(npm *)` which is a glob
|
|
121
|
+
* but Antigravity upstream has a known exact-match bug for some forms.
|
|
122
|
+
*/
|
|
123
|
+
export declare function convertToAntigravityFormat(set: PermissionSet): {
|
|
124
|
+
permissions: {
|
|
125
|
+
allow: string[];
|
|
126
|
+
deny?: string[];
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Convert canonical permission set to Grok format.
|
|
131
|
+
* Grok reads ~/.grok/config.toml with
|
|
132
|
+
* [permission]
|
|
133
|
+
* rules = [ { action = "allow", tool = "bash", pattern = "git *" }, ... ]
|
|
134
|
+
* Tool names are lowercase: bash, read, edit, grep, mcptool, webfetch.
|
|
135
|
+
* Canonical Write maps to Grok's `edit` tool.
|
|
136
|
+
*/
|
|
137
|
+
export declare function convertToGrokFormat(set: PermissionSet): {
|
|
138
|
+
permission: {
|
|
139
|
+
rules: GrokRule[];
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
export type GrokRule = {
|
|
143
|
+
action: 'allow' | 'deny';
|
|
144
|
+
tool: string;
|
|
145
|
+
pattern?: string;
|
|
146
|
+
};
|
|
113
147
|
/**
|
|
114
148
|
* Convert canonical permission set to OpenCode format.
|
|
115
149
|
* OpenCode uses: { permission: { bash: { "git *": "allow", "rm *": "deny" } } }
|
package/dist/lib/permissions.js
CHANGED
|
@@ -14,14 +14,15 @@ import * as yaml from 'yaml';
|
|
|
14
14
|
import * as TOML from 'smol-toml';
|
|
15
15
|
import { getPermissionsDir, getUserPermissionsDir, ensureAgentsDir } from './state.js';
|
|
16
16
|
import { safeJoin } from './paths.js';
|
|
17
|
+
import { agentConfigDirName } from './agents.js';
|
|
17
18
|
import { updateGeminiSettings } from './gemini-settings.js';
|
|
18
19
|
const HOME = os.homedir();
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// ~/.grok/config.toml
|
|
24
|
-
|
|
20
|
+
// PERMISSIONS_CAPABLE_AGENTS removed — use `capableAgents('allowlist')`
|
|
21
|
+
// from lib/capabilities.ts. The capability matrix on AgentConfig is the
|
|
22
|
+
// single source of truth. (Per-agent native format details:
|
|
23
|
+
// antigravity → ~/.gemini/antigravity-cli/settings.json `permissions.{allow,deny}`
|
|
24
|
+
// grok → ~/.grok/config.toml `[permission].rules`
|
|
25
|
+
// the writer in `applyPermissionsToVersion` handles the format dispatch.)
|
|
25
26
|
/** Filename used for Codex Starlark deny-rules generated from permission groups. */
|
|
26
27
|
export const CODEX_RULES_FILENAME = 'agents-deny.rules';
|
|
27
28
|
export function containsBroadGrants(rules) {
|
|
@@ -446,6 +447,116 @@ export function convertToGeminiFormat(set) {
|
|
|
446
447
|
}
|
|
447
448
|
return { tools: { allowed: Array.from(allowed) } };
|
|
448
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* Strip Claude's `:*` subcommand-wildcard suffix and return a space-glob form.
|
|
452
|
+
* "mq:*" -> "mq *", "git status" -> "git status", "*" -> "*".
|
|
453
|
+
* Used by serializers whose native pattern grammar uses ` *` instead of `:*`.
|
|
454
|
+
*/
|
|
455
|
+
function normalizeBashPattern(pattern) {
|
|
456
|
+
if (pattern === '*' || pattern === '**')
|
|
457
|
+
return '*';
|
|
458
|
+
if (pattern.endsWith(':*'))
|
|
459
|
+
return pattern.slice(0, -2) + ' *';
|
|
460
|
+
return pattern;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Convert canonical permission set to Antigravity format.
|
|
464
|
+
* Antigravity reads ~/.gemini/antigravity-cli/settings.json with
|
|
465
|
+
* { permissions: { allow: [...], deny: [...] } }
|
|
466
|
+
* where each entry is action-namespaced: command(...), read_file(...),
|
|
467
|
+
* write_file(...), read_url(...), mcp(...).
|
|
468
|
+
* Bash maps to `command`, Read to `read_file`, Write to `write_file`,
|
|
469
|
+
* WebFetch to `read_url`. Other canonical tools are skipped.
|
|
470
|
+
* Note: Antigravity matches `command(npm install)` as an exact string,
|
|
471
|
+
* not a prefix — `Bash(npm:*)` becomes `command(npm *)` which is a glob
|
|
472
|
+
* but Antigravity upstream has a known exact-match bug for some forms.
|
|
473
|
+
*/
|
|
474
|
+
export function convertToAntigravityFormat(set) {
|
|
475
|
+
const allow = serializeAntigravityEntries(set.allow);
|
|
476
|
+
const deny = set.deny ? serializeAntigravityEntries(set.deny) : [];
|
|
477
|
+
return {
|
|
478
|
+
permissions: {
|
|
479
|
+
allow,
|
|
480
|
+
...(deny.length ? { deny } : {}),
|
|
481
|
+
},
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
function serializeAntigravityEntries(perms) {
|
|
485
|
+
const out = new Set();
|
|
486
|
+
for (const perm of perms) {
|
|
487
|
+
if (BLANKET_BASH_FORMS.has(perm)) {
|
|
488
|
+
out.add('command(*)');
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const parsed = parseCanonicalPattern(perm);
|
|
492
|
+
if (!parsed)
|
|
493
|
+
continue;
|
|
494
|
+
const action = ANTIGRAVITY_ACTION_BY_TOOL[parsed.tool];
|
|
495
|
+
if (!action)
|
|
496
|
+
continue;
|
|
497
|
+
if (parsed.tool === 'bash') {
|
|
498
|
+
out.add(`${action}(${normalizeBashPattern(parsed.pattern)})`);
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
const p = parsed.pattern === '**' ? '*' : parsed.pattern;
|
|
502
|
+
out.add(`${action}(${p})`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return Array.from(out);
|
|
506
|
+
}
|
|
507
|
+
const ANTIGRAVITY_ACTION_BY_TOOL = {
|
|
508
|
+
bash: 'command',
|
|
509
|
+
read: 'read_file',
|
|
510
|
+
write: 'write_file',
|
|
511
|
+
webfetch: 'read_url',
|
|
512
|
+
};
|
|
513
|
+
/**
|
|
514
|
+
* Convert canonical permission set to Grok format.
|
|
515
|
+
* Grok reads ~/.grok/config.toml with
|
|
516
|
+
* [permission]
|
|
517
|
+
* rules = [ { action = "allow", tool = "bash", pattern = "git *" }, ... ]
|
|
518
|
+
* Tool names are lowercase: bash, read, edit, grep, mcptool, webfetch.
|
|
519
|
+
* Canonical Write maps to Grok's `edit` tool.
|
|
520
|
+
*/
|
|
521
|
+
export function convertToGrokFormat(set) {
|
|
522
|
+
const rules = [];
|
|
523
|
+
for (const perm of set.allow) {
|
|
524
|
+
const rule = canonicalToGrokRule(perm, 'allow');
|
|
525
|
+
if (rule)
|
|
526
|
+
rules.push(rule);
|
|
527
|
+
}
|
|
528
|
+
if (set.deny) {
|
|
529
|
+
for (const perm of set.deny) {
|
|
530
|
+
const rule = canonicalToGrokRule(perm, 'deny');
|
|
531
|
+
if (rule)
|
|
532
|
+
rules.push(rule);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return { permission: { rules } };
|
|
536
|
+
}
|
|
537
|
+
const GROK_TOOL_BY_CANONICAL = {
|
|
538
|
+
bash: 'bash',
|
|
539
|
+
read: 'read',
|
|
540
|
+
write: 'edit',
|
|
541
|
+
grep: 'grep',
|
|
542
|
+
webfetch: 'webfetch',
|
|
543
|
+
};
|
|
544
|
+
function canonicalToGrokRule(perm, action) {
|
|
545
|
+
if (BLANKET_BASH_FORMS.has(perm)) {
|
|
546
|
+
return { action, tool: 'bash', pattern: '*' };
|
|
547
|
+
}
|
|
548
|
+
const parsed = parseCanonicalPattern(perm);
|
|
549
|
+
if (!parsed)
|
|
550
|
+
return null;
|
|
551
|
+
const tool = GROK_TOOL_BY_CANONICAL[parsed.tool];
|
|
552
|
+
if (!tool)
|
|
553
|
+
return null;
|
|
554
|
+
const pattern = parsed.tool === 'bash' ? normalizeBashPattern(parsed.pattern) : parsed.pattern;
|
|
555
|
+
if (pattern === '' || pattern === undefined) {
|
|
556
|
+
return { action, tool };
|
|
557
|
+
}
|
|
558
|
+
return { action, tool, pattern };
|
|
559
|
+
}
|
|
449
560
|
/**
|
|
450
561
|
* Convert canonical permission set to OpenCode format.
|
|
451
562
|
* OpenCode uses: { permission: { bash: { "git *": "allow", "rm *": "deny" } } }
|
|
@@ -825,7 +936,7 @@ function applyPermissionsToAgent(agentId, set, scope = 'user', cwd, merge = true
|
|
|
825
936
|
* This writes to {versionHome}/.{agent}/settings.json (or equivalent).
|
|
826
937
|
*/
|
|
827
938
|
export function applyPermissionsToVersion(agentId, set, versionHome, merge = true) {
|
|
828
|
-
const configDir = path.join(versionHome,
|
|
939
|
+
const configDir = path.join(versionHome, agentConfigDirName(agentId));
|
|
829
940
|
try {
|
|
830
941
|
fs.mkdirSync(configDir, { recursive: true });
|
|
831
942
|
if (agentId === 'claude') {
|
|
@@ -931,6 +1042,105 @@ export function applyPermissionsToVersion(agentId, set, versionHome, merge = tru
|
|
|
931
1042
|
});
|
|
932
1043
|
return { success: true };
|
|
933
1044
|
}
|
|
1045
|
+
if (agentId === 'antigravity') {
|
|
1046
|
+
const antigravityPerms = convertToAntigravityFormat(set);
|
|
1047
|
+
const settingsPath = path.join(versionHome, '.gemini', 'antigravity-cli', 'settings.json');
|
|
1048
|
+
updateGeminiSettings(settingsPath, (settings) => {
|
|
1049
|
+
const perms = (typeof settings.permissions === 'object' && settings.permissions !== null && !Array.isArray(settings.permissions))
|
|
1050
|
+
? settings.permissions
|
|
1051
|
+
: {};
|
|
1052
|
+
if (merge) {
|
|
1053
|
+
const existingAllow = Array.isArray(perms.allow) ? perms.allow : [];
|
|
1054
|
+
const existingDeny = Array.isArray(perms.deny) ? perms.deny : [];
|
|
1055
|
+
perms.allow = Array.from(new Set([...existingAllow, ...antigravityPerms.permissions.allow]));
|
|
1056
|
+
const mergedDeny = Array.from(new Set([...existingDeny, ...(antigravityPerms.permissions.deny ?? [])]));
|
|
1057
|
+
if (mergedDeny.length)
|
|
1058
|
+
perms.deny = mergedDeny;
|
|
1059
|
+
else
|
|
1060
|
+
delete perms.deny;
|
|
1061
|
+
}
|
|
1062
|
+
else {
|
|
1063
|
+
perms.allow = antigravityPerms.permissions.allow;
|
|
1064
|
+
if (antigravityPerms.permissions.deny?.length)
|
|
1065
|
+
perms.deny = antigravityPerms.permissions.deny;
|
|
1066
|
+
else
|
|
1067
|
+
delete perms.deny;
|
|
1068
|
+
}
|
|
1069
|
+
settings.permissions = perms;
|
|
1070
|
+
});
|
|
1071
|
+
return { success: true };
|
|
1072
|
+
}
|
|
1073
|
+
if (agentId === 'grok') {
|
|
1074
|
+
const grokPerms = convertToGrokFormat(set);
|
|
1075
|
+
const configPath = path.join(versionHome, '.grok', 'config.toml');
|
|
1076
|
+
let config = {};
|
|
1077
|
+
if (fs.existsSync(configPath)) {
|
|
1078
|
+
config = TOML.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
1079
|
+
}
|
|
1080
|
+
const existingPermission = (typeof config.permission === 'object' && config.permission !== null && !Array.isArray(config.permission))
|
|
1081
|
+
? config.permission
|
|
1082
|
+
: {};
|
|
1083
|
+
if (merge) {
|
|
1084
|
+
const existingRules = Array.isArray(existingPermission.rules) ? existingPermission.rules : [];
|
|
1085
|
+
const seen = new Set();
|
|
1086
|
+
const dedup = [];
|
|
1087
|
+
for (const r of [...existingRules, ...grokPerms.permission.rules]) {
|
|
1088
|
+
const key = `${r.action}|${r.tool}|${r.pattern ?? ''}`;
|
|
1089
|
+
if (seen.has(key))
|
|
1090
|
+
continue;
|
|
1091
|
+
seen.add(key);
|
|
1092
|
+
dedup.push(r);
|
|
1093
|
+
}
|
|
1094
|
+
existingPermission.rules = dedup;
|
|
1095
|
+
}
|
|
1096
|
+
else {
|
|
1097
|
+
existingPermission.rules = grokPerms.permission.rules;
|
|
1098
|
+
}
|
|
1099
|
+
config.permission = existingPermission;
|
|
1100
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
1101
|
+
fs.writeFileSync(configPath, TOML.stringify(config), 'utf-8');
|
|
1102
|
+
return { success: true };
|
|
1103
|
+
}
|
|
1104
|
+
if (agentId === 'kimi') {
|
|
1105
|
+
const configPath = path.join(versionHome, '.kimi-code', 'config.toml');
|
|
1106
|
+
let config = {};
|
|
1107
|
+
if (fs.existsSync(configPath)) {
|
|
1108
|
+
config = TOML.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
1109
|
+
}
|
|
1110
|
+
const newRules = [];
|
|
1111
|
+
for (const allow of set.allow) {
|
|
1112
|
+
newRules.push({ decision: 'allow', pattern: allow });
|
|
1113
|
+
}
|
|
1114
|
+
for (const deny of set.deny || []) {
|
|
1115
|
+
newRules.push({ decision: 'deny', pattern: deny });
|
|
1116
|
+
}
|
|
1117
|
+
if (merge) {
|
|
1118
|
+
const existingPermission = (typeof config.permission === 'object' && config.permission !== null && !Array.isArray(config.permission))
|
|
1119
|
+
? config.permission
|
|
1120
|
+
: {};
|
|
1121
|
+
const existingRules = Array.isArray(existingPermission.rules)
|
|
1122
|
+
? existingPermission.rules
|
|
1123
|
+
: [];
|
|
1124
|
+
const seen = new Set();
|
|
1125
|
+
const dedup = [];
|
|
1126
|
+
for (const r of [...existingRules, ...newRules]) {
|
|
1127
|
+
if (!r.decision || !r.pattern)
|
|
1128
|
+
continue;
|
|
1129
|
+
const key = `${r.decision}|${r.pattern}`;
|
|
1130
|
+
if (seen.has(key))
|
|
1131
|
+
continue;
|
|
1132
|
+
seen.add(key);
|
|
1133
|
+
dedup.push({ decision: r.decision, pattern: r.pattern });
|
|
1134
|
+
}
|
|
1135
|
+
config.permission = { rules: dedup };
|
|
1136
|
+
}
|
|
1137
|
+
else {
|
|
1138
|
+
config.permission = { rules: newRules };
|
|
1139
|
+
}
|
|
1140
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
1141
|
+
fs.writeFileSync(configPath, TOML.stringify(config), 'utf-8');
|
|
1142
|
+
return { success: true };
|
|
1143
|
+
}
|
|
934
1144
|
return { success: false, error: `Agent '${agentId}' does not support permissions` };
|
|
935
1145
|
}
|
|
936
1146
|
catch (err) {
|
|
@@ -1,23 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Native plugin
|
|
2
|
+
* Native plugin marketplaces for Claude / OpenClaw — one per DotAgents repo.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Every DotAgents repo that holds plugins synthesizes its OWN synthetic local
|
|
5
|
+
* marketplace under each version's plugin directory, named after the repo:
|
|
6
6
|
*
|
|
7
7
|
* <versionHome>/.{claude,openclaw}/plugins/
|
|
8
|
-
* known_marketplaces.json
|
|
9
|
-
* marketplaces/agents-cli/
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* known_marketplaces.json # registers each repo's marketplace
|
|
9
|
+
* marketplaces/agents-cli/ # ~/.agents/plugins/* (user repo)
|
|
10
|
+
* marketplaces/agents-<alias>/ # ~/.agents-<alias>/plugins/* (extra repo)
|
|
11
|
+
* marketplaces/agents-project/ # <cwd>/.agents/plugins/* (project repo)
|
|
12
|
+
* .claude-plugin/marketplace.json # synthesized catalog
|
|
13
|
+
* plugins/<plugin>/ # copied plugin source
|
|
12
14
|
*
|
|
13
|
-
* Plus the version's settings.json gets
|
|
15
|
+
* Plus the version's settings.json gets
|
|
16
|
+
* `enabledPlugins["<plugin>@<marketplace>"] = true`.
|
|
14
17
|
*
|
|
15
|
-
* This produces native `/plugin:skill` slash namespacing, visibility in
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
+
* This produces native `/plugin:skill` slash namespacing, visibility in
|
|
19
|
+
* `/plugins`, `/plugin enable|disable` support, AND honest attribution (the
|
|
20
|
+
* user can see which repo each plugin came from) — matching the Claude Code
|
|
21
|
+
* spec at https://code.claude.com/docs/en/plugins and /plugin-marketplaces.
|
|
22
|
+
*
|
|
23
|
+
* The naming policy lives in one place — marketplaceNameFor(). Source-side
|
|
24
|
+
* discovery (discoverMarketplaces) and per-version synthesis (syncMarketplaceManifest
|
|
25
|
+
* / registerMarketplace / syncAllMarketplaces) all key off a MarketplaceSpec so
|
|
26
|
+
* the catalog name and on-disk layout are derived, never hard-coded per call.
|
|
27
|
+
*/
|
|
28
|
+
import type { AgentId, DiscoveredPlugin, MarketplaceSpec, DiscoveredMarketplace } from './types.js';
|
|
29
|
+
/**
|
|
30
|
+
* Canonical name for the user-repo marketplace (~/.agents/plugins/). Kept as an
|
|
31
|
+
* exported constant for callers that operate on the user repo directly and for
|
|
32
|
+
* the `marketplaces/agents-cli/` on-disk path that existing installs already have.
|
|
18
33
|
*/
|
|
19
|
-
import type { AgentId, DiscoveredPlugin } from './types.js';
|
|
20
34
|
export declare const MARKETPLACE_NAME = "agents-cli";
|
|
35
|
+
export declare const SYSTEM_MARKETPLACE_NAME = "agents-system";
|
|
36
|
+
/** Marketplace name for <cwd>/.agents/plugins/*. */
|
|
37
|
+
export declare const PROJECT_MARKETPLACE_NAME = "agents-project";
|
|
21
38
|
interface MarketplacePluginEntry {
|
|
22
39
|
name: string;
|
|
23
40
|
source: string;
|
|
@@ -28,7 +45,7 @@ interface MarketplacePluginEntry {
|
|
|
28
45
|
email?: string;
|
|
29
46
|
};
|
|
30
47
|
}
|
|
31
|
-
interface MarketplaceManifest {
|
|
48
|
+
export interface MarketplaceManifest {
|
|
32
49
|
$schema?: string;
|
|
33
50
|
name: string;
|
|
34
51
|
description?: string;
|
|
@@ -38,13 +55,37 @@ interface MarketplaceManifest {
|
|
|
38
55
|
};
|
|
39
56
|
plugins: MarketplacePluginEntry[];
|
|
40
57
|
}
|
|
41
|
-
|
|
42
|
-
export
|
|
43
|
-
|
|
58
|
+
/** Result of synthesizing + registering one marketplace via syncAllMarketplaces. */
|
|
59
|
+
export interface SyncAllResult {
|
|
60
|
+
spec: MarketplaceSpec;
|
|
61
|
+
name: string;
|
|
62
|
+
plugins: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Map a MarketplaceSpec to its catalog name. This is the ONLY place that
|
|
66
|
+
* encodes the repo → name policy; every other function derives the name here.
|
|
67
|
+
*/
|
|
68
|
+
export declare function marketplaceNameFor(spec: MarketplaceSpec): string;
|
|
69
|
+
/**
|
|
70
|
+
* Discover every DotAgents repo that contributes plugins, in precedence order
|
|
71
|
+
* (user, then each enabled extra repo, then the project repo when cwd has one).
|
|
72
|
+
* No agent / version is involved — this walks source-side plugin roots only.
|
|
73
|
+
*
|
|
74
|
+
* A repo is included when its plugins/ directory exists on disk. The user repo
|
|
75
|
+
* is always probed; extras come from getEnabledExtraRepos() (already filtered to
|
|
76
|
+
* enabled + on-disk repos); the project repo is included only when
|
|
77
|
+
* <cwd>/.agents/plugins/ exists.
|
|
78
|
+
*/
|
|
79
|
+
export declare function discoverMarketplaces(opts?: {
|
|
80
|
+
cwd?: string;
|
|
81
|
+
}): DiscoveredMarketplace[];
|
|
82
|
+
export declare function marketplaceRoot(specOrName: MarketplaceSpec | string, agent: AgentId, versionHome: string): string;
|
|
83
|
+
export declare function marketplaceManifestPath(specOrName: MarketplaceSpec | string, agent: AgentId, versionHome: string): string;
|
|
84
|
+
export declare function pluginInstallDir(plugin: DiscoveredPlugin, specOrName: MarketplaceSpec | string, agent: AgentId, versionHome: string): string;
|
|
44
85
|
export declare function knownMarketplacesPath(agent: AgentId, versionHome: string): string;
|
|
45
86
|
/**
|
|
46
|
-
* Copy plugin source into marketplace install dir.
|
|
47
|
-
* Source of truth remains
|
|
87
|
+
* Copy plugin source into the marketplace install dir for the given spec.
|
|
88
|
+
* Source of truth remains the plugin's source dir — this is a per-version snapshot.
|
|
48
89
|
*
|
|
49
90
|
* Symlinks pointing OUTSIDE the plugin source root are dropped. They show up
|
|
50
91
|
* when plugin authors (legitimately) link prompt-side references to sibling
|
|
@@ -56,50 +97,67 @@ export declare function knownMarketplacesPath(agent: AgentId, versionHome: strin
|
|
|
56
97
|
*
|
|
57
98
|
* Internal symlinks (target stays inside the plugin root) are preserved.
|
|
58
99
|
*/
|
|
59
|
-
export declare function copyPluginToMarketplace(plugin: DiscoveredPlugin, agent: AgentId, versionHome: string): string;
|
|
100
|
+
export declare function copyPluginToMarketplace(plugin: DiscoveredPlugin, spec: MarketplaceSpec | string, agent: AgentId, versionHome: string): string;
|
|
60
101
|
/**
|
|
61
|
-
* Re-synthesize <marketplace>/.claude-plugin/marketplace.json from the
|
|
62
|
-
*
|
|
63
|
-
* so the manifest stays in lockstep with on-disk contents.
|
|
102
|
+
* Re-synthesize <marketplace>/.claude-plugin/marketplace.json from the plugins
|
|
103
|
+
* already installed under <marketplace>/plugins/. Always run after add or remove
|
|
104
|
+
* so the manifest stays in lockstep with on-disk contents. Returns the manifest
|
|
105
|
+
* it wrote, or null when the marketplace has no plugins dir yet.
|
|
64
106
|
*/
|
|
65
|
-
export declare function syncMarketplaceManifest(agent: AgentId, versionHome: string): MarketplaceManifest | null;
|
|
107
|
+
export declare function syncMarketplaceManifest(spec: MarketplaceSpec, agent: AgentId, versionHome: string): MarketplaceManifest | null;
|
|
66
108
|
/**
|
|
67
|
-
* Register
|
|
68
|
-
*
|
|
109
|
+
* Register a marketplace in known_marketplaces.json so Claude Code discovers
|
|
110
|
+
* it on startup. Idempotent: re-running just refreshes lastUpdated. Other
|
|
111
|
+
* marketplaces' entries are preserved untouched.
|
|
69
112
|
*/
|
|
70
|
-
export declare function registerMarketplace(agent: AgentId, versionHome: string): void;
|
|
113
|
+
export declare function registerMarketplace(spec: MarketplaceSpec, agent: AgentId, versionHome: string): void;
|
|
71
114
|
/**
|
|
72
|
-
* Drop
|
|
73
|
-
*
|
|
115
|
+
* Drop a marketplace entry from known_marketplaces.json. Called when the last
|
|
116
|
+
* plugin under it is removed. Removes only its own entry; deletes the file only
|
|
117
|
+
* when no entries remain.
|
|
118
|
+
*/
|
|
119
|
+
export declare function unregisterMarketplace(specOrName: MarketplaceSpec | string, agent: AgentId, versionHome: string): void;
|
|
120
|
+
/**
|
|
121
|
+
* Discover every source-side marketplace, then for each one re-synthesize its
|
|
122
|
+
* catalog from the plugins already copied under the version home and register
|
|
123
|
+
* it in known_marketplaces.json. Returns one result per marketplace that has at
|
|
124
|
+
* least one plugin installed.
|
|
125
|
+
*
|
|
126
|
+
* Copying plugin source into a marketplace is the caller's responsibility
|
|
127
|
+
* (copyPluginToMarketplace / syncPluginToVersion) — this reconciles catalogs +
|
|
128
|
+
* registrations across all repos once the copies are in place. Marketplaces
|
|
129
|
+
* whose version-home plugins dir is empty or absent are skipped, so we never
|
|
130
|
+
* register a known_marketplace pointing at a directory with no catalog.
|
|
74
131
|
*/
|
|
75
|
-
export declare function
|
|
132
|
+
export declare function syncAllMarketplaces(agent: AgentId, versionHome: string, opts?: {
|
|
133
|
+
cwd?: string;
|
|
134
|
+
}): SyncAllResult[];
|
|
76
135
|
/**
|
|
77
136
|
* Mark a plugin as enabled in <versionHome>/.{agent}/settings.json under
|
|
78
|
-
* enabledPlugins["<plugin
|
|
79
|
-
* preserving every other key.
|
|
137
|
+
* enabledPlugins["<plugin>@<marketplace>"]: true. Reads, mutates, writes —
|
|
138
|
+
* preserving every other key. Trust/exec-surface gating is the caller's
|
|
139
|
+
* responsibility (plugins.ts owns plugin capability inspection).
|
|
80
140
|
*/
|
|
81
|
-
export declare function
|
|
82
|
-
allowExecSurfaces?: boolean;
|
|
83
|
-
}): void;
|
|
141
|
+
export declare function addPluginToSettings(pluginName: string, marketplaceName: string, agent: AgentId, versionHome: string): void;
|
|
84
142
|
/**
|
|
85
|
-
* Remove the enabledPlugins key for this plugin. Inverse of
|
|
143
|
+
* Remove the enabledPlugins key for this plugin. Inverse of addPluginToSettings.
|
|
86
144
|
*/
|
|
87
|
-
export declare function
|
|
145
|
+
export declare function removePluginFromSettings(pluginName: string, marketplaceName: string, agent: AgentId, versionHome: string): void;
|
|
88
146
|
/**
|
|
89
147
|
* Remove a plugin's installed marketplace directory. Returns true if the dir
|
|
90
148
|
* existed and was removed.
|
|
91
149
|
*/
|
|
92
|
-
export declare function removePluginFromMarketplace(pluginName: string, agent: AgentId, versionHome: string): boolean;
|
|
150
|
+
export declare function removePluginFromMarketplace(pluginName: string, specOrName: MarketplaceSpec | string, agent: AgentId, versionHome: string): boolean;
|
|
93
151
|
/**
|
|
94
152
|
* Return true if the marketplace has no plugins left under it.
|
|
95
153
|
*/
|
|
96
|
-
export declare function marketplaceIsEmpty(agent: AgentId, versionHome: string): boolean;
|
|
154
|
+
export declare function marketplaceIsEmpty(specOrName: MarketplaceSpec | string, agent: AgentId, versionHome: string): boolean;
|
|
97
155
|
/**
|
|
98
156
|
* Drop the entire marketplace directory. Called after the last plugin removal.
|
|
99
157
|
*/
|
|
100
|
-
export declare function removeEmptyMarketplaceDir(agent: AgentId, versionHome: string): void;
|
|
158
|
+
export declare function removeEmptyMarketplaceDir(specOrName: MarketplaceSpec | string, agent: AgentId, versionHome: string): void;
|
|
101
159
|
/**
|
|
102
160
|
* Detect whether a plugin is installed via the native marketplace path.
|
|
103
161
|
*/
|
|
104
|
-
export declare function isInstalledInMarketplace(pluginName: string, agent: AgentId, versionHome: string): boolean;
|
|
162
|
+
export declare function isInstalledInMarketplace(pluginName: string, specOrName: MarketplaceSpec | string, agent: AgentId, versionHome: string): boolean;
|
|
105
163
|
export {};
|