@phnx-labs/agents-cli 1.20.4 → 1.20.6
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 +49 -18
- package/dist/commands/browser.js +31 -4
- package/dist/commands/cli.js +1 -1
- package/dist/commands/cloud.js +1 -1
- package/dist/commands/commands.js +2 -0
- package/dist/commands/computer.js +10 -2
- package/dist/commands/defaults.d.ts +7 -0
- package/dist/commands/defaults.js +89 -0
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/exec.js +73 -19
- 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 +4 -4
- package/dist/commands/secrets.js +46 -9
- package/dist/commands/sessions.js +1 -0
- package/dist/commands/setup.d.ts +3 -3
- package/dist/commands/setup.js +17 -17
- 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 +109 -11
- 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.d.ts +12 -1
- package/dist/commands/view.js +128 -40
- 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 +106 -41
- package/dist/lib/agents.d.ts +23 -10
- package/dist/lib/agents.js +88 -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/browser/chrome.d.ts +10 -0
- package/dist/lib/browser/chrome.js +84 -3
- 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 +59 -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 +233 -5
- package/dist/lib/models.js +62 -15
- package/dist/lib/permissions.d.ts +59 -2
- package/dist/lib/permissions.js +299 -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 +70 -0
- package/dist/lib/project-launch.js +404 -0
- package/dist/lib/pty-client.js +1 -1
- package/dist/lib/pty-server.d.ts +1 -1
- package/dist/lib/pty-server.js +8 -5
- 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.d.ts +2 -0
- package/dist/lib/resources.js +4 -3
- package/dist/lib/rotate.d.ts +1 -1
- package/dist/lib/rotate.js +7 -19
- 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/run-config.d.ts +9 -0
- package/dist/lib/run-config.js +35 -0
- package/dist/lib/run-defaults.d.ts +42 -0
- package/dist/lib/run-defaults.js +180 -0
- 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/install-helper.d.ts +11 -3
- package/dist/lib/secrets/install-helper.js +48 -6
- package/dist/lib/secrets/linux.d.ts +56 -9
- package/dist/lib/secrets/linux.js +327 -59
- 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 +18 -9
- package/dist/lib/shims.js +133 -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/api.d.ts +67 -0
- package/dist/lib/teams/api.js +78 -0
- 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 +73 -13
- 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 +138 -496
- package/dist/lib/workflows.d.ts +2 -4
- package/dist/lib/workflows.js +3 -4
- package/package.json +6 -3
- package/scripts/postinstall.js +16 -63
- package/dist/commands/status.d.ts +0 -9
- package/dist/commands/status.js +0 -25
package/dist/lib/auto-pull.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Background sync for tracked git repos:
|
|
3
|
-
* - System repo (~/.agents
|
|
3
|
+
* - System repo (~/.agents/.system/) is read-only locally — fast-forward auto-pull is safe.
|
|
4
4
|
* - User repo (~/.agents/) and enabled extras may have local commits, so we only
|
|
5
5
|
* `git fetch` and write a status marker. Next CLI invocation surfaces a one-line
|
|
6
6
|
* notice if upstream is ahead. Pulling is left to the user via `agents repo pull`.
|
package/dist/lib/auto-pull.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Background sync for tracked git repos:
|
|
3
|
-
* - System repo (~/.agents
|
|
3
|
+
* - System repo (~/.agents/.system/) is read-only locally — fast-forward auto-pull is safe.
|
|
4
4
|
* - User repo (~/.agents/) and enabled extras may have local commits, so we only
|
|
5
5
|
* `git fetch` and write a status marker. Next CLI invocation surfaces a one-line
|
|
6
6
|
* notice if upstream is ahead. Pulling is left to the user via `agents repo pull`.
|
package/dist/lib/beta.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Preview features live in the git-trackable user repo (~/.agents/agents.yaml)
|
|
5
5
|
* when present, and otherwise fall back to the local system state file
|
|
6
|
-
* (~/.agents
|
|
6
|
+
* (~/.agents/.system/agents.yaml). This keeps opt-ins portable for users with a
|
|
7
7
|
* personal agents repo without mixing them into unrelated version capability
|
|
8
8
|
* checks.
|
|
9
9
|
*/
|
package/dist/lib/beta.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Preview features live in the git-trackable user repo (~/.agents/agents.yaml)
|
|
5
5
|
* when present, and otherwise fall back to the local system state file
|
|
6
|
-
* (~/.agents
|
|
6
|
+
* (~/.agents/.system/agents.yaml). This keeps opt-ins portable for users with a
|
|
7
7
|
* personal agents repo without mixing them into unrelated version capability
|
|
8
8
|
* checks.
|
|
9
9
|
*/
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import type { ChromeOptions } from './types.js';
|
|
2
2
|
import type { BrowserType } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* True when `binaryPath` is a shebang script rather than a native browser
|
|
5
|
+
* executable. The Linux distro launchers (`/usr/bin/brave-browser`, …) are such
|
|
6
|
+
* scripts; `launchBrowser` can't drive one over `--remote-debugging-pipe` (see
|
|
7
|
+
* resolveBrowserBinary). `profiles doctor` uses this to flag a profile whose
|
|
8
|
+
* binary resolves to a wrapper we couldn't unwrap. Shebang scripts are a
|
|
9
|
+
* Linux/Unix concept — returns false on Windows/macOS app bundles.
|
|
10
|
+
*/
|
|
11
|
+
export declare function isLauncherScript(binaryPath: string): boolean;
|
|
12
|
+
export declare function resolveBrowserBinary(binaryPath: string): string;
|
|
3
13
|
export declare function findBrowserPath(browserType: BrowserType, customBinary?: string): string;
|
|
4
14
|
/**
|
|
5
15
|
* Walk the per-platform priority list and return the first browser that's
|
|
@@ -42,12 +42,90 @@ const BROWSER_PATHS = {
|
|
|
42
42
|
custom: [],
|
|
43
43
|
},
|
|
44
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* On Debian/Ubuntu the canonical launchers under `/usr/bin`
|
|
47
|
+
* (`brave-browser`, `google-chrome`, `chromium`) are not the browser ELF —
|
|
48
|
+
* they're `#!/bin/bash` wrapper scripts (the upstream Chromium wrapper) that,
|
|
49
|
+
* as their final step, run the real binary as a NON-exec child:
|
|
50
|
+
*
|
|
51
|
+
* exec < /dev/null
|
|
52
|
+
* exec > >(exec cat)
|
|
53
|
+
* exec 2> >(exec cat >&2)
|
|
54
|
+
* "$HERE/brave" "$@" || true
|
|
55
|
+
*
|
|
56
|
+
* That breaks `launchBrowser`'s `--remote-debugging-pipe` transport two ways:
|
|
57
|
+
* the std-fd sanitization (and the extra `cat` process-substitution children)
|
|
58
|
+
* disturbs the inherited CDP pipe on fd 3/4, and the pid we record is the
|
|
59
|
+
* wrapper's, not the browser's. The symptom is `read ECONNRESET` /
|
|
60
|
+
* `CDP connection closed` right after spawn (issue #229).
|
|
61
|
+
*
|
|
62
|
+
* Follow the wrapper to the ELF it execs. The wrapper sets
|
|
63
|
+
* `HERE="dirname(readlink -f "$0")"` and invokes `"$HERE/<name>"`, so we
|
|
64
|
+
* resolve the script path, scan for that invocation line, and join the two.
|
|
65
|
+
* Returns the original path untouched when it's already an ELF, when it's not
|
|
66
|
+
* a resolvable wrapper, or on any non-Linux platform.
|
|
67
|
+
*/
|
|
68
|
+
function readsAsShebangScript(binaryPath) {
|
|
69
|
+
let fd;
|
|
70
|
+
try {
|
|
71
|
+
fd = fs.openSync(binaryPath, 'r');
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const head = Buffer.alloc(2);
|
|
78
|
+
fs.readSync(fd, head, 0, 2, 0);
|
|
79
|
+
// ELF binaries start with 0x7f 'E'; shebang scripts with '#!'.
|
|
80
|
+
return head[0] === 0x23 && head[1] === 0x21;
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
fs.closeSync(fd);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* True when `binaryPath` is a shebang script rather than a native browser
|
|
88
|
+
* executable. The Linux distro launchers (`/usr/bin/brave-browser`, …) are such
|
|
89
|
+
* scripts; `launchBrowser` can't drive one over `--remote-debugging-pipe` (see
|
|
90
|
+
* resolveBrowserBinary). `profiles doctor` uses this to flag a profile whose
|
|
91
|
+
* binary resolves to a wrapper we couldn't unwrap. Shebang scripts are a
|
|
92
|
+
* Linux/Unix concept — returns false on Windows/macOS app bundles.
|
|
93
|
+
*/
|
|
94
|
+
export function isLauncherScript(binaryPath) {
|
|
95
|
+
if (os.platform() === 'win32')
|
|
96
|
+
return false;
|
|
97
|
+
return readsAsShebangScript(binaryPath);
|
|
98
|
+
}
|
|
99
|
+
export function resolveBrowserBinary(binaryPath) {
|
|
100
|
+
if (os.platform() !== 'linux')
|
|
101
|
+
return binaryPath;
|
|
102
|
+
// Only shebang scripts need unwrapping; a real ELF passes straight through.
|
|
103
|
+
if (!readsAsShebangScript(binaryPath))
|
|
104
|
+
return binaryPath;
|
|
105
|
+
let script;
|
|
106
|
+
let realScriptPath;
|
|
107
|
+
try {
|
|
108
|
+
realScriptPath = fs.realpathSync(binaryPath);
|
|
109
|
+
script = fs.readFileSync(realScriptPath, 'utf8');
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return binaryPath;
|
|
113
|
+
}
|
|
114
|
+
// Match the Chromium wrapper's launch line: `"$HERE/<name>" "$@"`, optionally
|
|
115
|
+
// prefixed with `exec -a "$0"`. The captured name is the real ELF, sitting in
|
|
116
|
+
// the same directory as the resolved wrapper.
|
|
117
|
+
const match = script.match(/"\$HERE\/([A-Za-z0-9._-]+)"\s+"\$@"/);
|
|
118
|
+
if (!match)
|
|
119
|
+
return binaryPath;
|
|
120
|
+
const realBinary = path.join(path.dirname(realScriptPath), match[1]);
|
|
121
|
+
return fs.existsSync(realBinary) ? realBinary : binaryPath;
|
|
122
|
+
}
|
|
45
123
|
export function findBrowserPath(browserType, customBinary) {
|
|
46
124
|
if (customBinary) {
|
|
47
125
|
if (!fs.existsSync(customBinary)) {
|
|
48
126
|
throw new Error(`Custom binary not found: ${customBinary}`);
|
|
49
127
|
}
|
|
50
|
-
return customBinary;
|
|
128
|
+
return resolveBrowserBinary(customBinary);
|
|
51
129
|
}
|
|
52
130
|
if (browserType === 'custom') {
|
|
53
131
|
throw new Error('browser: custom requires a binary path in the profile');
|
|
@@ -60,9 +138,12 @@ export function findBrowserPath(browserType, customBinary) {
|
|
|
60
138
|
const candidates = platformPaths[browserType] || [];
|
|
61
139
|
for (const p of candidates) {
|
|
62
140
|
if (fs.existsSync(p)) {
|
|
63
|
-
return p;
|
|
141
|
+
return resolveBrowserBinary(p);
|
|
64
142
|
}
|
|
65
143
|
}
|
|
144
|
+
if (browserType === 'comet' && platform !== 'darwin') {
|
|
145
|
+
throw new Error('Browser "comet" is macOS-only (Comet is a macOS Chromium fork). Use chrome, chromium, brave, or edge on this platform.');
|
|
146
|
+
}
|
|
66
147
|
throw new Error(`Browser "${browserType}" not found. Install it first.`);
|
|
67
148
|
}
|
|
68
149
|
// Per-platform Chromium-family priority list for "no --profile" auto-pick.
|
|
@@ -98,7 +179,7 @@ export function findFirstInstalledBrowser(platform = os.platform()) {
|
|
|
98
179
|
const candidates = platformPaths[browserType] || [];
|
|
99
180
|
for (const p of candidates) {
|
|
100
181
|
if (fs.existsSync(p)) {
|
|
101
|
-
return { browserType, binary: p };
|
|
182
|
+
return { browserType, binary: resolveBrowserBinary(p) };
|
|
102
183
|
}
|
|
103
184
|
}
|
|
104
185
|
}
|
package/dist/lib/capabilities.js
CHANGED
|
@@ -46,6 +46,8 @@ export function supports(agent, cap, version) {
|
|
|
46
46
|
return { ok: false, reason: 'unsupported' };
|
|
47
47
|
if (c === true)
|
|
48
48
|
return { ok: true };
|
|
49
|
+
if ('file' in c)
|
|
50
|
+
return { ok: true };
|
|
49
51
|
if (!version)
|
|
50
52
|
return { ok: true };
|
|
51
53
|
if (c.since && compareVersions(version, c.since) < 0) {
|
package/dist/lib/commands.d.ts
CHANGED
|
@@ -13,7 +13,28 @@ export type CommandScope = 'user' | 'project';
|
|
|
13
13
|
export interface CommandMetadata {
|
|
14
14
|
name: string;
|
|
15
15
|
description: string;
|
|
16
|
+
/** When set, sync only to these agents (aliases resolved at parse time). */
|
|
17
|
+
agents?: AgentId[];
|
|
18
|
+
/** Minimum agent CLI version (inclusive) for this command. */
|
|
19
|
+
since?: string;
|
|
20
|
+
/** Exclusive upper bound on agent CLI version for this command. */
|
|
21
|
+
until?: string;
|
|
16
22
|
}
|
|
23
|
+
export type CommandApplyFailReason = 'unsupported' | 'agent_excluded' | 'too_old' | 'too_new';
|
|
24
|
+
export type CommandApplyResult = {
|
|
25
|
+
ok: true;
|
|
26
|
+
} | {
|
|
27
|
+
ok: false;
|
|
28
|
+
reason: CommandApplyFailReason;
|
|
29
|
+
need?: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Whether a slash command should sync to the given agent@version. Checks
|
|
33
|
+
* frontmatter `agents` / `since` / `until` after the agent-level commands
|
|
34
|
+
* (or commands-as-skills) capability gate.
|
|
35
|
+
*/
|
|
36
|
+
export declare function commandAppliesTo(agent: AgentId, version: string, metadata: Pick<CommandMetadata, 'agents' | 'since' | 'until'> | null | undefined): CommandApplyResult;
|
|
37
|
+
export declare function explainCommandSkip(agent: AgentId, version: string, commandName: string, result: CommandApplyResult): string;
|
|
17
38
|
/** Result of validating command metadata. */
|
|
18
39
|
export interface ValidationResult {
|
|
19
40
|
valid: boolean;
|
|
@@ -35,6 +56,8 @@ export interface InstalledCommand {
|
|
|
35
56
|
path: string;
|
|
36
57
|
description?: string;
|
|
37
58
|
}
|
|
59
|
+
/** Parse command metadata (name, description, targeting) from YAML frontmatter or TOML headers. */
|
|
60
|
+
export declare function parseCommandMetadata(filePath: string): CommandMetadata | null;
|
|
38
61
|
/** Discover all command markdown files in a repository's commands/ directory. */
|
|
39
62
|
export declare function discoverCommands(repoPath: string): DiscoveredCommand[];
|
|
40
63
|
/** Find the source path for a command in a repository. */
|
|
@@ -59,6 +82,8 @@ export interface VersionCommandDiff {
|
|
|
59
82
|
toAdd: string[];
|
|
60
83
|
toUpdate: string[];
|
|
61
84
|
matched: string[];
|
|
85
|
+
/** Installed but excluded by frontmatter agents/since/until — safe to remove. */
|
|
86
|
+
toRemove: string[];
|
|
62
87
|
orphans: string[];
|
|
63
88
|
}
|
|
64
89
|
/**
|
|
@@ -72,6 +97,8 @@ export declare function diffVersionCommands(agent: AgentId, version: string): Ve
|
|
|
72
97
|
export declare function installCommandToVersion(agent: AgentId, version: string, commandName: string, method?: 'symlink' | 'copy'): {
|
|
73
98
|
success: boolean;
|
|
74
99
|
error?: string;
|
|
100
|
+
skipped?: boolean;
|
|
101
|
+
skipReason?: string;
|
|
75
102
|
};
|
|
76
103
|
/**
|
|
77
104
|
* Remove a single command from a specific version home.
|
|
@@ -112,7 +139,7 @@ export declare function installCommandCentrally(sourcePath: string, commandName:
|
|
|
112
139
|
warnings?: string[];
|
|
113
140
|
};
|
|
114
141
|
/**
|
|
115
|
-
* List commands from user (~/.agents/commands/) and system (~/.agents
|
|
142
|
+
* List commands from user (~/.agents/commands/) and system (~/.agents/.system/commands/) dirs.
|
|
116
143
|
* User dir takes priority; deduplication preserves first occurrence.
|
|
117
144
|
*/
|
|
118
145
|
export declare function listCentralCommands(): string[];
|
package/dist/lib/commands.js
CHANGED
|
@@ -9,13 +9,78 @@
|
|
|
9
9
|
import * as fs from 'fs';
|
|
10
10
|
import * as path from 'path';
|
|
11
11
|
import * as yaml from 'yaml';
|
|
12
|
-
import { AGENTS,
|
|
12
|
+
import { AGENTS, ensureCommandsDir, agentConfigDirName, resolveAgentName } from './agents.js';
|
|
13
|
+
import { capableAgents, isCapable, supports } from './capabilities.js';
|
|
13
14
|
import { markdownToToml } from './convert.js';
|
|
14
15
|
import { getCommandsDir, getUserCommandsDir, getEnabledExtraRepos, getProjectAgentsDir, getSkillsDir, getTrashCommandsDir } from './state.js';
|
|
15
|
-
import { getEffectiveHome, getVersionHomePath, listInstalledVersions } from './versions.js';
|
|
16
|
+
import { getEffectiveHome, getVersionHomePath, listInstalledVersions, resolveVersion } from './versions.js';
|
|
16
17
|
import { commandSkillMatches, installCommandSkillToVersion, listCommandSkillsInVersion, removeCommandSkillFromVersion, shouldInstallCommandAsSkill, } from './command-skills.js';
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
function compareVersions(a, b) {
|
|
19
|
+
const aParts = a.split('.').map((n) => parseInt(n, 10) || 0);
|
|
20
|
+
const bParts = b.split('.').map((n) => parseInt(n, 10) || 0);
|
|
21
|
+
for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
|
|
22
|
+
const aVal = aParts[i] || 0;
|
|
23
|
+
const bVal = bParts[i] || 0;
|
|
24
|
+
if (aVal !== bVal)
|
|
25
|
+
return aVal - bVal;
|
|
26
|
+
}
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
function parseAgentsField(raw) {
|
|
30
|
+
if (raw == null)
|
|
31
|
+
return undefined;
|
|
32
|
+
const tokens = Array.isArray(raw)
|
|
33
|
+
? raw
|
|
34
|
+
: typeof raw === 'string'
|
|
35
|
+
? raw.split(/[,\s]+/)
|
|
36
|
+
: [];
|
|
37
|
+
const out = [];
|
|
38
|
+
for (const token of tokens) {
|
|
39
|
+
const id = resolveAgentName(String(token).trim());
|
|
40
|
+
if (id && !out.includes(id))
|
|
41
|
+
out.push(id);
|
|
42
|
+
}
|
|
43
|
+
return out.length > 0 ? out : undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Whether a slash command should sync to the given agent@version. Checks
|
|
47
|
+
* frontmatter `agents` / `since` / `until` after the agent-level commands
|
|
48
|
+
* (or commands-as-skills) capability gate.
|
|
49
|
+
*/
|
|
50
|
+
export function commandAppliesTo(agent, version, metadata) {
|
|
51
|
+
if (!supports(agent, 'commands', version).ok && !shouldInstallCommandAsSkill(agent, version)) {
|
|
52
|
+
return { ok: false, reason: 'unsupported' };
|
|
53
|
+
}
|
|
54
|
+
if (metadata?.agents?.length && !metadata.agents.includes(agent)) {
|
|
55
|
+
return { ok: false, reason: 'agent_excluded' };
|
|
56
|
+
}
|
|
57
|
+
if (metadata?.since && compareVersions(version, metadata.since) < 0) {
|
|
58
|
+
return { ok: false, reason: 'too_old', need: `>= ${metadata.since}` };
|
|
59
|
+
}
|
|
60
|
+
if (metadata?.until && compareVersions(version, metadata.until) >= 0) {
|
|
61
|
+
return { ok: false, reason: 'too_new', need: `< ${metadata.until}` };
|
|
62
|
+
}
|
|
63
|
+
return { ok: true };
|
|
64
|
+
}
|
|
65
|
+
export function explainCommandSkip(agent, version, commandName, result) {
|
|
66
|
+
if (result.ok)
|
|
67
|
+
return '';
|
|
68
|
+
const tag = `${agent}@${version}`;
|
|
69
|
+
switch (result.reason) {
|
|
70
|
+
case 'unsupported':
|
|
71
|
+
return `${tag}: /${commandName} not supported for this agent version`;
|
|
72
|
+
case 'agent_excluded':
|
|
73
|
+
return `${tag}: /${commandName} excluded by command frontmatter agents list`;
|
|
74
|
+
case 'too_old':
|
|
75
|
+
return `${tag}: /${commandName} requires ${result.need}`;
|
|
76
|
+
case 'too_new':
|
|
77
|
+
return `${tag}: /${commandName} requires ${result.need}`;
|
|
78
|
+
default:
|
|
79
|
+
return `${tag}: /${commandName} skipped`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** Parse command metadata (name, description, targeting) from YAML frontmatter or TOML headers. */
|
|
83
|
+
export function parseCommandMetadata(filePath) {
|
|
19
84
|
if (!fs.existsSync(filePath)) {
|
|
20
85
|
return null;
|
|
21
86
|
}
|
|
@@ -31,6 +96,9 @@ function parseCommandMetadata(filePath) {
|
|
|
31
96
|
return {
|
|
32
97
|
name: parsed.name || '',
|
|
33
98
|
description: parsed.description || '',
|
|
99
|
+
agents: parseAgentsField(parsed.agents),
|
|
100
|
+
since: typeof parsed.since === 'string' ? parsed.since : undefined,
|
|
101
|
+
until: typeof parsed.until === 'string' ? parsed.until : undefined,
|
|
34
102
|
};
|
|
35
103
|
}
|
|
36
104
|
}
|
|
@@ -126,10 +194,22 @@ export function installCommand(sourcePath, agentId, commandName, method = 'symli
|
|
|
126
194
|
warnings: validation.warnings,
|
|
127
195
|
};
|
|
128
196
|
}
|
|
197
|
+
const pinnedVersion = resolveVersion(agentId, process.cwd());
|
|
198
|
+
if (pinnedVersion) {
|
|
199
|
+
const gate = commandAppliesTo(agentId, pinnedVersion, metadata);
|
|
200
|
+
if (!gate.ok) {
|
|
201
|
+
return {
|
|
202
|
+
path: '',
|
|
203
|
+
method: 'copy',
|
|
204
|
+
error: explainCommandSkip(agentId, pinnedVersion, commandName, gate),
|
|
205
|
+
warnings: validation.warnings,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
129
209
|
const agent = AGENTS[agentId];
|
|
130
210
|
ensureCommandsDir(agentId);
|
|
131
211
|
const home = getEffectiveHome(agentId);
|
|
132
|
-
const commandsDir = path.join(home,
|
|
212
|
+
const commandsDir = path.join(home, agentConfigDirName(agentId), agent.commandsSubdir);
|
|
133
213
|
fs.mkdirSync(commandsDir, { recursive: true });
|
|
134
214
|
const ext = agent.format === 'toml' ? '.toml' : '.md';
|
|
135
215
|
const targetPath = path.join(commandsDir, `${commandName}${ext}`);
|
|
@@ -157,14 +237,14 @@ export function installCommand(sourcePath, agentId, commandName, method = 'symli
|
|
|
157
237
|
*/
|
|
158
238
|
export function getVersionCommandsDir(agent, version) {
|
|
159
239
|
const home = getVersionHomePath(agent, version);
|
|
160
|
-
return path.join(home,
|
|
240
|
+
return path.join(home, agentConfigDirName(agent), AGENTS[agent].commandsSubdir);
|
|
161
241
|
}
|
|
162
242
|
/**
|
|
163
243
|
* List command names (without extension) installed in a specific version home.
|
|
164
244
|
*/
|
|
165
245
|
export function listCommandsInVersionHome(agent, version) {
|
|
166
246
|
const versionHome = getVersionHomePath(agent, version);
|
|
167
|
-
const agentDir = path.join(versionHome,
|
|
247
|
+
const agentDir = path.join(versionHome, agentConfigDirName(agent));
|
|
168
248
|
if (shouldInstallCommandAsSkill(agent, version)) {
|
|
169
249
|
return listCommandSkillsInVersion(agentDir);
|
|
170
250
|
}
|
|
@@ -186,7 +266,7 @@ function versionCommandMatches(agent, version, commandName) {
|
|
|
186
266
|
if (!fs.existsSync(sourcePath))
|
|
187
267
|
return false;
|
|
188
268
|
const versionHome = getVersionHomePath(agent, version);
|
|
189
|
-
const agentDir = path.join(versionHome,
|
|
269
|
+
const agentDir = path.join(versionHome, agentConfigDirName(agent));
|
|
190
270
|
if (shouldInstallCommandAsSkill(agent, version)) {
|
|
191
271
|
return commandSkillMatches(agentDir, commandName, sourcePath);
|
|
192
272
|
}
|
|
@@ -217,8 +297,13 @@ export function diffVersionCommands(agent, version) {
|
|
|
217
297
|
const toAdd = [];
|
|
218
298
|
const toUpdate = [];
|
|
219
299
|
const matched = [];
|
|
300
|
+
const toRemove = [];
|
|
220
301
|
const orphans = [];
|
|
221
302
|
for (const name of central) {
|
|
303
|
+
const sourcePath = path.join(getCommandsDir(), `${name}.md`);
|
|
304
|
+
const metadata = parseCommandMetadata(sourcePath);
|
|
305
|
+
if (!commandAppliesTo(agent, version, metadata).ok)
|
|
306
|
+
continue;
|
|
222
307
|
if (!installed.has(name)) {
|
|
223
308
|
toAdd.push(name);
|
|
224
309
|
}
|
|
@@ -230,10 +315,25 @@ export function diffVersionCommands(agent, version) {
|
|
|
230
315
|
}
|
|
231
316
|
}
|
|
232
317
|
for (const name of installed) {
|
|
233
|
-
if (!central.has(name))
|
|
318
|
+
if (!central.has(name)) {
|
|
234
319
|
orphans.push(name);
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
const sourcePath = path.join(getCommandsDir(), `${name}.md`);
|
|
323
|
+
const metadata = parseCommandMetadata(sourcePath);
|
|
324
|
+
if (!commandAppliesTo(agent, version, metadata).ok) {
|
|
325
|
+
toRemove.push(name);
|
|
326
|
+
}
|
|
235
327
|
}
|
|
236
|
-
return {
|
|
328
|
+
return {
|
|
329
|
+
agent,
|
|
330
|
+
version,
|
|
331
|
+
toAdd: toAdd.sort(),
|
|
332
|
+
toUpdate: toUpdate.sort(),
|
|
333
|
+
matched,
|
|
334
|
+
toRemove: toRemove.sort(),
|
|
335
|
+
orphans: orphans.sort(),
|
|
336
|
+
};
|
|
237
337
|
}
|
|
238
338
|
/**
|
|
239
339
|
* Install a single command from central into a specific version home.
|
|
@@ -244,8 +344,13 @@ export function installCommandToVersion(agent, version, commandName, method = 'c
|
|
|
244
344
|
if (!fs.existsSync(sourcePath)) {
|
|
245
345
|
return { success: false, error: `Command '${commandName}' not found in central` };
|
|
246
346
|
}
|
|
347
|
+
const metadata = parseCommandMetadata(sourcePath);
|
|
348
|
+
const gate = commandAppliesTo(agent, version, metadata);
|
|
349
|
+
if (!gate.ok) {
|
|
350
|
+
return { success: true, skipped: true, skipReason: explainCommandSkip(agent, version, commandName, gate) };
|
|
351
|
+
}
|
|
247
352
|
const versionHome = getVersionHomePath(agent, version);
|
|
248
|
-
const agentDir = path.join(versionHome,
|
|
353
|
+
const agentDir = path.join(versionHome, agentConfigDirName(agent));
|
|
249
354
|
if (shouldInstallCommandAsSkill(agent, version)) {
|
|
250
355
|
return installCommandSkillToVersion(agentDir, commandName, sourcePath, [
|
|
251
356
|
getSkillsDir(),
|
|
@@ -283,7 +388,7 @@ export function installCommandToVersion(agent, version, commandName, method = 'c
|
|
|
283
388
|
*/
|
|
284
389
|
export function removeCommandFromVersion(agent, version, commandName) {
|
|
285
390
|
const versionHome = getVersionHomePath(agent, version);
|
|
286
|
-
const agentDir = path.join(versionHome,
|
|
391
|
+
const agentDir = path.join(versionHome, agentConfigDirName(agent));
|
|
287
392
|
if (shouldInstallCommandAsSkill(agent, version)) {
|
|
288
393
|
return removeCommandSkillFromVersion(agentDir, commandName);
|
|
289
394
|
}
|
|
@@ -309,9 +414,9 @@ export function removeCommandFromVersion(agent, version, commandName) {
|
|
|
309
414
|
*/
|
|
310
415
|
export function iterCommandsCapableVersions(filter) {
|
|
311
416
|
const pairs = [];
|
|
312
|
-
const agents = filter?.agent ? [filter.agent] :
|
|
417
|
+
const agents = filter?.agent ? [filter.agent] : capableAgents('commands');
|
|
313
418
|
for (const agent of agents) {
|
|
314
|
-
if (!
|
|
419
|
+
if (!isCapable(agent, 'commands'))
|
|
315
420
|
continue;
|
|
316
421
|
const versions = listInstalledVersions(agent);
|
|
317
422
|
for (const version of versions) {
|
|
@@ -326,7 +431,7 @@ export function iterCommandsCapableVersions(filter) {
|
|
|
326
431
|
export function uninstallCommand(agentId, commandName) {
|
|
327
432
|
const agent = AGENTS[agentId];
|
|
328
433
|
const home = getEffectiveHome(agentId);
|
|
329
|
-
const commandsDir = path.join(home,
|
|
434
|
+
const commandsDir = path.join(home, agentConfigDirName(agentId), agent.commandsSubdir);
|
|
330
435
|
const ext = agent.format === 'toml' ? '.toml' : '.md';
|
|
331
436
|
const targetPath = path.join(commandsDir, `${commandName}${ext}`);
|
|
332
437
|
if (fs.existsSync(targetPath)) {
|
|
@@ -339,7 +444,7 @@ export function uninstallCommand(agentId, commandName) {
|
|
|
339
444
|
function listInstalledCommands(agentId) {
|
|
340
445
|
const agent = AGENTS[agentId];
|
|
341
446
|
const home = getEffectiveHome(agentId);
|
|
342
|
-
const commandsDir = path.join(home,
|
|
447
|
+
const commandsDir = path.join(home, agentConfigDirName(agentId), agent.commandsSubdir);
|
|
343
448
|
if (!fs.existsSync(commandsDir)) {
|
|
344
449
|
return [];
|
|
345
450
|
}
|
|
@@ -355,7 +460,7 @@ function listInstalledCommands(agentId) {
|
|
|
355
460
|
function commandExists(agentId, commandName) {
|
|
356
461
|
const agent = AGENTS[agentId];
|
|
357
462
|
const home = getEffectiveHome(agentId);
|
|
358
|
-
const commandsDir = path.join(home,
|
|
463
|
+
const commandsDir = path.join(home, agentConfigDirName(agentId), agent.commandsSubdir);
|
|
359
464
|
const ext = agent.format === 'toml' ? '.toml' : '.md';
|
|
360
465
|
const targetPath = path.join(commandsDir, `${commandName}${ext}`);
|
|
361
466
|
return fs.existsSync(targetPath);
|
|
@@ -373,7 +478,7 @@ function normalizeContent(content) {
|
|
|
373
478
|
function commandContentMatches(agentId, commandName, sourcePath) {
|
|
374
479
|
const agent = AGENTS[agentId];
|
|
375
480
|
const home = getEffectiveHome(agentId);
|
|
376
|
-
const commandsDir = path.join(home,
|
|
481
|
+
const commandsDir = path.join(home, agentConfigDirName(agentId), agent.commandsSubdir);
|
|
377
482
|
const ext = agent.format === 'toml' ? '.toml' : '.md';
|
|
378
483
|
const installedPath = path.join(commandsDir, `${commandName}${ext}`);
|
|
379
484
|
if (!fs.existsSync(installedPath) || !fs.existsSync(sourcePath)) {
|
|
@@ -455,7 +560,7 @@ export function listInstalledCommandsWithScope(agentId, cwd = process.cwd(), opt
|
|
|
455
560
|
}
|
|
456
561
|
// User-scoped commands (version-aware when home is provided)
|
|
457
562
|
const home = options?.home || getEffectiveHome(agentId);
|
|
458
|
-
const userCommandsDir = path.join(home,
|
|
563
|
+
const userCommandsDir = path.join(home, agentConfigDirName(agentId), agent.commandsSubdir);
|
|
459
564
|
const userExts = [ext];
|
|
460
565
|
const userCommands = listCommandsFromDir(userCommandsDir, userExts);
|
|
461
566
|
for (const name of userCommands) {
|
|
@@ -509,7 +614,7 @@ export function installCommandCentrally(sourcePath, commandName) {
|
|
|
509
614
|
}
|
|
510
615
|
}
|
|
511
616
|
/**
|
|
512
|
-
* List commands from user (~/.agents/commands/) and system (~/.agents
|
|
617
|
+
* List commands from user (~/.agents/commands/) and system (~/.agents/.system/commands/) dirs.
|
|
513
618
|
* User dir takes priority; deduplication preserves first occurrence.
|
|
514
619
|
*/
|
|
515
620
|
export function listCentralCommands() {
|
package/dist/lib/doctor-diff.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import * as fs from 'fs';
|
|
23
23
|
import * as path from 'path';
|
|
24
|
-
import { AGENTS } from './agents.js';
|
|
24
|
+
import { AGENTS, agentConfigDirName } from './agents.js';
|
|
25
25
|
import { getProjectAgentsDir, getUserAgentsDir, getSystemAgentsDir, getEnabledExtraRepos, getResolvedRulesDir, getUserRulesDir, getEffectivePromptcutsPath, } from './state.js';
|
|
26
26
|
import { getAvailableResources, getActuallySyncedResources, getVersionHomePath, } from './versions.js';
|
|
27
27
|
import { markdownToToml } from './convert.js';
|
|
@@ -352,7 +352,7 @@ function expectedRuleContent(agent, name, sourcePath) {
|
|
|
352
352
|
function diffRules(agent, version, cwd) {
|
|
353
353
|
const agentConfig = AGENTS[agent];
|
|
354
354
|
const versionHome = getVersionHomePath(agent, version);
|
|
355
|
-
const configDir = path.join(versionHome,
|
|
355
|
+
const configDir = path.join(versionHome, agentConfigDirName(agent));
|
|
356
356
|
const sourcesByName = listRulesNames(cwd);
|
|
357
357
|
// Files actually present in the version home.
|
|
358
358
|
const homeFiles = new Set();
|
package/dist/lib/exec.d.ts
CHANGED
|
@@ -23,6 +23,20 @@ export declare function normalizeMode(input: string | null | undefined): Mode;
|
|
|
23
23
|
* - `plan` on an agent without plan support throws the same way.
|
|
24
24
|
*/
|
|
25
25
|
export declare function resolveMode(agent: AgentId, requested: Mode): Mode;
|
|
26
|
+
/**
|
|
27
|
+
* The mode an agent should run in when the caller has no preference.
|
|
28
|
+
*
|
|
29
|
+
* Returns the first entry in the agent's `capabilities.modes` table — the
|
|
30
|
+
* declaration order is the source of truth for "the safest mode this agent
|
|
31
|
+
* supports." Agents that include `plan` list it first; agents like
|
|
32
|
+
* antigravity that have no read-only mode list `edit` first.
|
|
33
|
+
*
|
|
34
|
+
* Use this when the user did not pass `--mode` explicitly. When the user
|
|
35
|
+
* *did* pass `--mode plan` and the agent doesn't support it, call
|
|
36
|
+
* `resolveMode` instead so the user sees a loud error rather than a silent
|
|
37
|
+
* elevation from read-only to writable.
|
|
38
|
+
*/
|
|
39
|
+
export declare function defaultModeFor(agent: AgentId): Mode;
|
|
26
40
|
/** Reasoning effort levels passed to agents that support them. 'auto' defers to the agent's default. */
|
|
27
41
|
export type ExecEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'auto';
|
|
28
42
|
/** Options for spawning an agent process. Omitting `prompt` launches the CLI interactively. */
|