@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
package/dist/lib/shims.d.ts
CHANGED
|
@@ -62,8 +62,14 @@ export interface ConflictInfo {
|
|
|
62
62
|
* v15 — remove foreground resource sync / rules refresh from launch shims.
|
|
63
63
|
* Version homes are reconciled by agents-cli management commands; the
|
|
64
64
|
* shim hot path only resolves a version and execs the agent binary.
|
|
65
|
+
* v16 — re-introduce project-scoped compile to the shim hot path via
|
|
66
|
+
* `agents sync --launch`. This stays fast (filesystem-only): compiles
|
|
67
|
+
* project rules, mirrors workspace resources, and synthesizes the
|
|
68
|
+
* scoped plugin marketplaces (agents-cli/agents-system/extras-<alias>/
|
|
69
|
+
* agents-project). Version-home reconciliation stays out of the hot
|
|
70
|
+
* path — management commands still own that.
|
|
65
71
|
*/
|
|
66
|
-
export declare const SHIM_SCHEMA_VERSION =
|
|
72
|
+
export declare const SHIM_SCHEMA_VERSION = 16;
|
|
67
73
|
/**
|
|
68
74
|
* Generate the full bash shim script for the given agent. The returned string
|
|
69
75
|
* is written to ~/.agents/shims/{cliCommand} and made executable.
|
|
@@ -223,14 +229,9 @@ export declare function getPathShadowingExecutable(agent: AgentId): string | nul
|
|
|
223
229
|
export declare function removeLegacyUserShim(agent: AgentId, overrides?: {
|
|
224
230
|
homeDir?: string;
|
|
225
231
|
}): boolean;
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
* Shell aliases live in the user's session and aren't visible from a Node.js
|
|
230
|
-
* child process. We do a best-effort scan of common RC files for `alias
|
|
231
|
-
* <command>=` patterns. Returns false when detection is inconclusive.
|
|
232
|
-
*/
|
|
233
|
-
export declare function hasAliasShadowingShim(agent: AgentId): boolean;
|
|
232
|
+
export declare function hasAliasShadowingShim(agent: AgentId, overrides?: {
|
|
233
|
+
homeDir?: string;
|
|
234
|
+
}): boolean;
|
|
234
235
|
/**
|
|
235
236
|
* Check if shims directory is in PATH.
|
|
236
237
|
*/
|
package/dist/lib/shims.js
CHANGED
|
@@ -186,8 +186,14 @@ async function promptConflictStrategy(conflictInfos) {
|
|
|
186
186
|
* v15 — remove foreground resource sync / rules refresh from launch shims.
|
|
187
187
|
* Version homes are reconciled by agents-cli management commands; the
|
|
188
188
|
* shim hot path only resolves a version and execs the agent binary.
|
|
189
|
+
* v16 — re-introduce project-scoped compile to the shim hot path via
|
|
190
|
+
* `agents sync --launch`. This stays fast (filesystem-only): compiles
|
|
191
|
+
* project rules, mirrors workspace resources, and synthesizes the
|
|
192
|
+
* scoped plugin marketplaces (agents-cli/agents-system/extras-<alias>/
|
|
193
|
+
* agents-project). Version-home reconciliation stays out of the hot
|
|
194
|
+
* path — management commands still own that.
|
|
189
195
|
*/
|
|
190
|
-
export const SHIM_SCHEMA_VERSION =
|
|
196
|
+
export const SHIM_SCHEMA_VERSION = 16;
|
|
191
197
|
/** Internal marker string used to embed the schema version in shim scripts. */
|
|
192
198
|
const SHIM_VERSION_MARKER = 'agents-shim-version:';
|
|
193
199
|
function shellQuote(value) {
|
|
@@ -244,14 +250,19 @@ export COPILOT_HOME="$VERSION_DIR/home/${configDirName}"
|
|
|
244
250
|
# This gives agents-cli full versioned isolation + resource sync for grok.
|
|
245
251
|
export GROK_HOME="$VERSION_DIR/home/.grok"
|
|
246
252
|
`
|
|
247
|
-
: ''
|
|
253
|
+
: agent === 'kimi'
|
|
254
|
+
? `
|
|
255
|
+
# Kimi Code CLI honors KIMI_CODE_HOME to relocate ~/.kimi-code (config.toml,
|
|
256
|
+
# mcp.json, sessions, skills, hooks). Point it at the versioned home.
|
|
257
|
+
export KIMI_CODE_HOME="$VERSION_DIR/home/${configDirName}"
|
|
258
|
+
`
|
|
259
|
+
: '';
|
|
248
260
|
const launchArgs = agent === 'codex' ? ' -c check_for_update_on_startup=false' : '';
|
|
249
261
|
return `#!/bin/bash
|
|
250
262
|
# Auto-generated by agents-cli - do not edit
|
|
251
263
|
# Shim for ${agentConfig.name}
|
|
252
264
|
# ${SHIM_VERSION_MARKER} ${SHIM_SCHEMA_VERSION}
|
|
253
265
|
|
|
254
|
-
AGENTS_SYSTEM_DIR="$HOME/.agents-system"
|
|
255
266
|
AGENTS_USER_DIR="$HOME/.agents"
|
|
256
267
|
AGENTS_BIN=${agentsBin}
|
|
257
268
|
AGENT="${agent}"
|
|
@@ -262,10 +273,10 @@ if [ -z "$AGENTS_BIN" ] || [ ! -x "$AGENTS_BIN" ]; then
|
|
|
262
273
|
exit 127
|
|
263
274
|
fi
|
|
264
275
|
|
|
265
|
-
# Find project agents.yaml walking up from cwd (skip $HOME/.agents
|
|
276
|
+
# Find project agents.yaml walking up from cwd (skip $HOME/.agents/agents.yaml)
|
|
266
277
|
find_project_version() {
|
|
267
278
|
local dir="$PWD"
|
|
268
|
-
local user_agents_yaml="$
|
|
279
|
+
local user_agents_yaml="$AGENTS_USER_DIR/agents.yaml"
|
|
269
280
|
while [ "$dir" != "/" ]; do
|
|
270
281
|
local candidate="$dir/agents.yaml"
|
|
271
282
|
if [ -f "$candidate" ] && [ "$candidate" != "$user_agents_yaml" ]; then
|
|
@@ -384,6 +395,16 @@ if [ "$AGENT" = "grok" ]; then
|
|
|
384
395
|
# Last resort: whatever is on PATH (user may have installed grok globally)
|
|
385
396
|
BINARY=$(command -v grok 2>/dev/null || echo "")
|
|
386
397
|
fi
|
|
398
|
+
# Kimi special case: binary lives in ~/.kimi-code/bin/, not node_modules.
|
|
399
|
+
# We still use the agents-cli version dir purely for KIMI_CODE_HOME isolation.
|
|
400
|
+
elif [ "$AGENT" = "kimi" ]; then
|
|
401
|
+
KIMI_BINARY="$HOME/.kimi-code/bin/kimi"
|
|
402
|
+
if [ -x "$KIMI_BINARY" ]; then
|
|
403
|
+
BINARY="$KIMI_BINARY"
|
|
404
|
+
else
|
|
405
|
+
# Last resort: whatever is on PATH
|
|
406
|
+
BINARY=$(command -v kimi 2>/dev/null || echo "")
|
|
407
|
+
fi
|
|
387
408
|
else
|
|
388
409
|
BINARY="$VERSION_DIR/node_modules/.bin/$CLI_COMMAND"
|
|
389
410
|
fi
|
|
@@ -451,6 +472,10 @@ fi
|
|
|
451
472
|
|
|
452
473
|
${managedEnv}
|
|
453
474
|
|
|
475
|
+
# Project-scoped compile (rules, workspace resources, scoped plugin marketplaces).
|
|
476
|
+
# Filesystem-only — sub-50ms steady state. Never blocks launch on failure.
|
|
477
|
+
"$AGENTS_BIN" sync --agent "$AGENT" --agent-version "$VERSION" --launch --cwd "$PWD" --quiet 2>/dev/null || true
|
|
478
|
+
|
|
454
479
|
exec "$BINARY"${launchArgs} "$@"
|
|
455
480
|
`;
|
|
456
481
|
}
|
|
@@ -540,7 +565,13 @@ export CODEX_HOME="$HOME/.agents/.history/versions/${agent}/${version}/home/${co
|
|
|
540
565
|
# version MCP and session state are isolated.
|
|
541
566
|
export COPILOT_HOME="$HOME/.agents/.history/versions/${agent}/${version}/home/${configDirName}"
|
|
542
567
|
`
|
|
543
|
-
: ''
|
|
568
|
+
: agent === 'kimi'
|
|
569
|
+
? `
|
|
570
|
+
# Kimi Code CLI honors KIMI_CODE_HOME to relocate ~/.kimi-code (config.toml,
|
|
571
|
+
# mcp.json, sessions, skills, hooks). Point direct aliases at the versioned home.
|
|
572
|
+
export KIMI_CODE_HOME="$HOME/.agents/.history/versions/${agent}/${version}/home/${configDirName}"
|
|
573
|
+
`
|
|
574
|
+
: '';
|
|
544
575
|
const launchArgs = agent === 'codex' ? ' -c check_for_update_on_startup=false' : '';
|
|
545
576
|
return `#!/bin/bash
|
|
546
577
|
# Auto-generated by agents-cli - do not edit
|
|
@@ -754,7 +785,7 @@ export async function switchConfigSymlink(agent, version) {
|
|
|
754
785
|
// Different target - update it
|
|
755
786
|
fs.unlinkSync(configPath);
|
|
756
787
|
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
757
|
-
fs.symlinkSync(versionConfigPath, configPath);
|
|
788
|
+
fs.symlinkSync(versionConfigPath, configPath, process.platform === 'win32' ? 'junction' : undefined);
|
|
758
789
|
return { success: true };
|
|
759
790
|
}
|
|
760
791
|
else if (stat.isDirectory()) {
|
|
@@ -766,8 +797,25 @@ export async function switchConfigSymlink(agent, version) {
|
|
|
766
797
|
const finalBackupPath = path.join(agentBackupDir, String(timestamp));
|
|
767
798
|
fs.mkdirSync(agentBackupDir, { recursive: true });
|
|
768
799
|
fs.renameSync(configPath, finalBackupPath);
|
|
800
|
+
// Session JSONLs that lived under the old configPath have just moved to
|
|
801
|
+
// finalBackupPath on disk. Rewrite any DB rows pointing at the old prefix
|
|
802
|
+
// so querySessions stops returning phantom rows (issue #136). The
|
|
803
|
+
// discoverer at src/lib/session/discover.ts already scans backup dirs, so
|
|
804
|
+
// future indexer runs will find the new files — this just keeps the
|
|
805
|
+
// existing rows valid in the meantime.
|
|
806
|
+
//
|
|
807
|
+
// Dynamic import so loading shims.ts doesn't transitively open the
|
|
808
|
+
// sessions DB — many tests partially mock state.js and would break.
|
|
809
|
+
try {
|
|
810
|
+
const { updateSessionFilePaths } = await import('./session/db.js');
|
|
811
|
+
updateSessionFilePaths(configPath, finalBackupPath);
|
|
812
|
+
}
|
|
813
|
+
catch (err) {
|
|
814
|
+
console.error(`Warning: failed to update session file_paths after backing up ${configPath}: ` +
|
|
815
|
+
`${err.message}. Stale rows may appear in session listings until the next scan.`);
|
|
816
|
+
}
|
|
769
817
|
// Create symlink (parent already exists since the dir we just moved was here)
|
|
770
|
-
fs.symlinkSync(versionConfigPath, configPath);
|
|
818
|
+
fs.symlinkSync(versionConfigPath, configPath, process.platform === 'win32' ? 'junction' : undefined);
|
|
771
819
|
return { success: true, backupPath: finalBackupPath };
|
|
772
820
|
}
|
|
773
821
|
else {
|
|
@@ -780,7 +828,7 @@ export async function switchConfigSymlink(agent, version) {
|
|
|
780
828
|
// For nested layouts (e.g., ~/.gemini/antigravity-cli) the parent dir
|
|
781
829
|
// may also be missing if the parent agent (Gemini) is not installed.
|
|
782
830
|
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
783
|
-
fs.symlinkSync(versionConfigPath, configPath);
|
|
831
|
+
fs.symlinkSync(versionConfigPath, configPath, process.platform === 'win32' ? 'junction' : undefined);
|
|
784
832
|
return { success: true };
|
|
785
833
|
}
|
|
786
834
|
return { success: false, error: err.message };
|
|
@@ -1251,23 +1299,53 @@ export function removeLegacyUserShim(agent, overrides) {
|
|
|
1251
1299
|
* Shell aliases live in the user's session and aren't visible from a Node.js
|
|
1252
1300
|
* child process. We do a best-effort scan of common RC files for `alias
|
|
1253
1301
|
* <command>=` patterns. Returns false when detection is inconclusive.
|
|
1302
|
+
*
|
|
1303
|
+
* Tracks the LAST `alias` / `unalias` action for this command per rc file —
|
|
1304
|
+
* a trailing `unalias codex` cancels an earlier `alias codex=...`, and
|
|
1305
|
+
* `unalias` can name multiple commands on one line. Without this, an
|
|
1306
|
+
* `alias` line elsewhere in the file would surface as a false positive
|
|
1307
|
+
* (e.g. seen in zshrc setups that conditionally clear an alias later).
|
|
1254
1308
|
*/
|
|
1255
|
-
|
|
1309
|
+
function escapeRegex(value) {
|
|
1310
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
1311
|
+
}
|
|
1312
|
+
/** Walk rc lines in order; a later `unalias` clears an earlier `alias`. */
|
|
1313
|
+
function isAliasActiveInRcContent(content, cliCommand) {
|
|
1314
|
+
let active = false;
|
|
1315
|
+
const aliasPattern = new RegExp(`^\\s*alias\\s+${escapeRegex(cliCommand)}\\s*=`);
|
|
1316
|
+
for (const line of content.split('\n')) {
|
|
1317
|
+
const trimmed = line.trim();
|
|
1318
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
1319
|
+
continue;
|
|
1320
|
+
if (aliasPattern.test(line)) {
|
|
1321
|
+
active = true;
|
|
1322
|
+
continue;
|
|
1323
|
+
}
|
|
1324
|
+
const unaliasMatch = trimmed.match(/^unalias\s+(.+)$/);
|
|
1325
|
+
if (!unaliasMatch)
|
|
1326
|
+
continue;
|
|
1327
|
+
const tokens = unaliasMatch[1].split(/\s+/).filter((token) => !token.startsWith('-'));
|
|
1328
|
+
if (tokens.includes(cliCommand)) {
|
|
1329
|
+
active = false;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
return active;
|
|
1333
|
+
}
|
|
1334
|
+
export function hasAliasShadowingShim(agent, overrides) {
|
|
1256
1335
|
const cliCommand = AGENTS[agent].cliCommand;
|
|
1257
|
-
const
|
|
1336
|
+
const homeDir = overrides?.homeDir ?? os.homedir();
|
|
1258
1337
|
const rcFiles = [
|
|
1259
|
-
path.join(
|
|
1260
|
-
path.join(
|
|
1261
|
-
path.join(
|
|
1262
|
-
path.join(
|
|
1338
|
+
path.join(homeDir, '.zshrc'),
|
|
1339
|
+
path.join(homeDir, '.bashrc'),
|
|
1340
|
+
path.join(homeDir, '.bash_profile'),
|
|
1341
|
+
path.join(homeDir, '.profile'),
|
|
1263
1342
|
];
|
|
1264
|
-
const pattern = new RegExp(`^\\s*alias\\s+${cliCommand}\\s*=`, 'm');
|
|
1265
1343
|
for (const rcFile of rcFiles) {
|
|
1266
1344
|
try {
|
|
1267
1345
|
if (!fs.existsSync(rcFile))
|
|
1268
1346
|
continue;
|
|
1269
1347
|
const content = fs.readFileSync(rcFile, 'utf-8');
|
|
1270
|
-
if (
|
|
1348
|
+
if (isAliasActiveInRcContent(content, cliCommand))
|
|
1271
1349
|
return true;
|
|
1272
1350
|
}
|
|
1273
1351
|
catch {
|
|
@@ -1303,6 +1381,7 @@ function isShimPathCommandLine(line, shimsDir) {
|
|
|
1303
1381
|
const markerRegexes = exactMarkers.map((marker) => new RegExp(`${escapeRegex(marker)}(?=$|[:\\s])`));
|
|
1304
1382
|
const suffixRegexes = [
|
|
1305
1383
|
/\/\.agents-system\/shims(?=$|[:\s])/,
|
|
1384
|
+
/\/\.agents\/\.cache\/shims(?=$|[:\s])/,
|
|
1306
1385
|
/\/\.agents\/shims(?=$|[:\s])/,
|
|
1307
1386
|
];
|
|
1308
1387
|
const touchesShimPath = [...markerRegexes, ...suffixRegexes].some((pattern) => pattern.test(normalized));
|
|
@@ -1364,10 +1443,10 @@ export function getPathSetupInstructions() {
|
|
|
1364
1443
|
return `Add to ~/.config/fish/config.fish:
|
|
1365
1444
|
fish_add_path ${shimsDir}`;
|
|
1366
1445
|
}
|
|
1367
|
-
return `Add to ~/${rcFile} (
|
|
1446
|
+
return `Add to the end of ~/${rcFile} (after any nvm/node setup and agent installers):
|
|
1368
1447
|
export PATH="${shimsDir}:$PATH"
|
|
1369
1448
|
|
|
1370
|
-
IMPORTANT: Shims must
|
|
1449
|
+
IMPORTANT: Shims must be the last PATH prepend in your shell config to override global installs.
|
|
1371
1450
|
|
|
1372
1451
|
Then restart your shell or run:
|
|
1373
1452
|
source ~/${rcFile}`;
|
|
@@ -1398,25 +1477,6 @@ export function addShimsToPath(overrides) {
|
|
|
1398
1477
|
exportBlock = `# agents-cli: version-managed agent CLIs\nexport PATH="${shimsDir}:$PATH"\n`;
|
|
1399
1478
|
}
|
|
1400
1479
|
const contentWithoutShimLines = stripShimPathLines(content, shimsDir);
|
|
1401
|
-
// Find insertion point - AFTER node/nvm/fnm setup if present, otherwise append.
|
|
1402
|
-
const insertAfterPatterns = [
|
|
1403
|
-
/^export NVM_DIR=/m,
|
|
1404
|
-
/^source.*nvm/m,
|
|
1405
|
-
/^\[ -s.*nvm/m,
|
|
1406
|
-
/^eval.*fnm/m,
|
|
1407
|
-
/^export PATH.*node/m,
|
|
1408
|
-
/^export PATH.*npm/m,
|
|
1409
|
-
];
|
|
1410
|
-
let insertIndex = -1;
|
|
1411
|
-
const lines = contentWithoutShimLines.split('\n');
|
|
1412
|
-
let offset = 0;
|
|
1413
|
-
for (const line of lines) {
|
|
1414
|
-
const lineWithNewline = `${line}\n`;
|
|
1415
|
-
if (insertAfterPatterns.some((pattern) => pattern.test(line))) {
|
|
1416
|
-
insertIndex = offset + lineWithNewline.length;
|
|
1417
|
-
}
|
|
1418
|
-
offset += lineWithNewline.length;
|
|
1419
|
-
}
|
|
1420
1480
|
// Write the updated content
|
|
1421
1481
|
try {
|
|
1422
1482
|
// Ensure parent directories exist (especially for fish: ~/.config/fish/)
|
|
@@ -1424,18 +1484,9 @@ export function addShimsToPath(overrides) {
|
|
|
1424
1484
|
if (!fs.existsSync(rcDir)) {
|
|
1425
1485
|
fs.mkdirSync(rcDir, { recursive: true });
|
|
1426
1486
|
}
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
const before = contentWithoutShimLines.slice(0, insertIndex);
|
|
1431
|
-
const separator = before.length > 0 && !before.endsWith('\n\n') ? '\n' : '';
|
|
1432
|
-
newContent = before + separator + exportBlock + contentWithoutShimLines.slice(insertIndex);
|
|
1433
|
-
}
|
|
1434
|
-
else {
|
|
1435
|
-
// Append to end
|
|
1436
|
-
const separator = contentWithoutShimLines.length > 0 && !contentWithoutShimLines.endsWith('\n') ? '\n' : '';
|
|
1437
|
-
newContent = contentWithoutShimLines + separator + exportBlock;
|
|
1438
|
-
}
|
|
1487
|
+
// Append at EOF so later installer PATH prepends cannot shadow the shims.
|
|
1488
|
+
const separator = contentWithoutShimLines.length > 0 && !contentWithoutShimLines.endsWith('\n') ? '\n' : '';
|
|
1489
|
+
let newContent = contentWithoutShimLines + separator + exportBlock;
|
|
1439
1490
|
newContent = newContent.replace(/\n{2,}$/g, '\n');
|
|
1440
1491
|
if (newContent === content) {
|
|
1441
1492
|
return { success: true, alreadyPresent: true, rcFile };
|
package/dist/lib/skills.d.ts
CHANGED
|
@@ -73,7 +73,7 @@ export declare function skillExists(agentId: AgentId, skillName: string): boolea
|
|
|
73
73
|
*/
|
|
74
74
|
export declare function skillContentMatches(agentId: AgentId, skillName: string, sourcePath: string): boolean;
|
|
75
75
|
/**
|
|
76
|
-
* List skill names from user (~/.agents/skills/) and system (~/.agents
|
|
76
|
+
* List skill names from user (~/.agents/skills/) and system (~/.agents/.system/skills/) dirs.
|
|
77
77
|
* User dir takes priority; deduplication preserves first occurrence.
|
|
78
78
|
*/
|
|
79
79
|
export declare function listCentralSkills(): string[];
|
package/dist/lib/skills.js
CHANGED
|
@@ -10,7 +10,8 @@ import * as fs from 'fs';
|
|
|
10
10
|
import * as path from 'path';
|
|
11
11
|
import * as os from 'os';
|
|
12
12
|
import * as yaml from 'yaml';
|
|
13
|
-
import {
|
|
13
|
+
import { ensureSkillsDir, agentConfigDirName } from './agents.js';
|
|
14
|
+
import { capableAgents, isCapable } from './capabilities.js';
|
|
14
15
|
import { getUserSkillsDir, getSkillsDir as getSystemSkillsDir, getProjectAgentsDir, getEnabledExtraRepos, getTrashSkillsDir } from './state.js';
|
|
15
16
|
import { getEffectiveHome, getVersionHomePath, listInstalledVersions } from './versions.js';
|
|
16
17
|
import { emit } from './events.js';
|
|
@@ -27,7 +28,7 @@ export function ensureCentralSkillsDir() {
|
|
|
27
28
|
}
|
|
28
29
|
export function getAgentSkillsDir(agentId) {
|
|
29
30
|
const home = getEffectiveHome(agentId);
|
|
30
|
-
return path.join(home,
|
|
31
|
+
return path.join(home, agentConfigDirName(agentId), 'skills');
|
|
31
32
|
}
|
|
32
33
|
export function getProjectSkillsDir(agentId, cwd = process.cwd()) {
|
|
33
34
|
const dirs = [];
|
|
@@ -227,7 +228,7 @@ export function installSkill(sourcePath, skillName, agents, method = 'symlink')
|
|
|
227
228
|
}
|
|
228
229
|
// Symlink to each agent
|
|
229
230
|
for (const agentId of agents) {
|
|
230
|
-
if (!
|
|
231
|
+
if (!isCapable(agentId, 'skills')) {
|
|
231
232
|
continue;
|
|
232
233
|
}
|
|
233
234
|
ensureSkillsDir(agentId);
|
|
@@ -328,7 +329,7 @@ export function skillContentMatches(agentId, skillName, sourcePath) {
|
|
|
328
329
|
}
|
|
329
330
|
}
|
|
330
331
|
/**
|
|
331
|
-
* List skill names from user (~/.agents/skills/) and system (~/.agents
|
|
332
|
+
* List skill names from user (~/.agents/skills/) and system (~/.agents/.system/skills/) dirs.
|
|
332
333
|
* User dir takes priority; deduplication preserves first occurrence.
|
|
333
334
|
*/
|
|
334
335
|
export function listCentralSkills() {
|
|
@@ -388,7 +389,7 @@ export function listAllSkills() {
|
|
|
388
389
|
*/
|
|
389
390
|
export function getVersionSkillsDir(agent, version) {
|
|
390
391
|
const home = getVersionHomePath(agent, version);
|
|
391
|
-
return path.join(home,
|
|
392
|
+
return path.join(home, agentConfigDirName(agent), 'skills');
|
|
392
393
|
}
|
|
393
394
|
/**
|
|
394
395
|
* List skill names installed in a specific version home.
|
|
@@ -586,9 +587,9 @@ export function removeSkillFromVersion(agent, version, skillName) {
|
|
|
586
587
|
*/
|
|
587
588
|
export function iterSkillsCapableVersions(filter) {
|
|
588
589
|
const pairs = [];
|
|
589
|
-
const agents = filter?.agent ? [filter.agent] :
|
|
590
|
+
const agents = filter?.agent ? [filter.agent] : capableAgents('skills');
|
|
590
591
|
for (const agent of agents) {
|
|
591
|
-
if (!
|
|
592
|
+
if (!capableAgents('skills').includes(agent))
|
|
592
593
|
continue;
|
|
593
594
|
const versions = listInstalledVersions(agent);
|
|
594
595
|
for (const version of versions) {
|
|
@@ -606,7 +607,7 @@ export function uninstallSkill(skillName) {
|
|
|
606
607
|
return { success: false, error: `Skill '${skillName}' not found` };
|
|
607
608
|
}
|
|
608
609
|
// Remove from all agents
|
|
609
|
-
for (const agentId of
|
|
610
|
+
for (const agentId of capableAgents('skills')) {
|
|
610
611
|
const agentSkillPath = path.join(getAgentSkillsDir(agentId), skillName);
|
|
611
612
|
if (fs.existsSync(agentSkillPath)) {
|
|
612
613
|
try {
|
|
@@ -727,7 +728,7 @@ export function listInstalledSkillsWithScope(agentId, cwd = process.cwd(), optio
|
|
|
727
728
|
}
|
|
728
729
|
// User-scoped skills (version-aware when home is provided)
|
|
729
730
|
const userSkillsDir = options?.home
|
|
730
|
-
? path.join(options.home,
|
|
731
|
+
? path.join(options.home, agentConfigDirName(agentId), 'skills')
|
|
731
732
|
: getAgentSkillsDir(agentId);
|
|
732
733
|
if (fs.existsSync(userSkillsDir)) {
|
|
733
734
|
try {
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commands detector — mirrors versions.ts:343-357. Inspects the version home,
|
|
3
|
+
* returns command names. Honors the commands-as-skills marker for grok and
|
|
4
|
+
* Codex >= 0.117.0; falls back to scanning `{agentDir}/<commandsSubdir>/` for
|
|
5
|
+
* the native path.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import { AGENTS, agentConfigDirName } from '../../agents.js';
|
|
10
|
+
import { shouldInstallCommandAsSkill, listCommandSkillsInVersion } from '../../command-skills.js';
|
|
11
|
+
import { lazyAgentMap } from '../writers/lazy-map.js';
|
|
12
|
+
function buildCommandsDetector(agent) {
|
|
13
|
+
return {
|
|
14
|
+
kind: 'commands',
|
|
15
|
+
agent,
|
|
16
|
+
list({ version, versionHome }) {
|
|
17
|
+
const agentConfig = AGENTS[agent];
|
|
18
|
+
const agentDir = path.join(versionHome, agentConfigDirName(agent));
|
|
19
|
+
if (shouldInstallCommandAsSkill(agent, version)) {
|
|
20
|
+
return listCommandSkillsInVersion(agentDir);
|
|
21
|
+
}
|
|
22
|
+
const commandsDir = path.join(agentDir, agentConfig.commandsSubdir);
|
|
23
|
+
if (!fs.existsSync(commandsDir))
|
|
24
|
+
return [];
|
|
25
|
+
const ext = agentConfig.format === 'toml' ? '.toml' : '.md';
|
|
26
|
+
return fs.readdirSync(commandsDir)
|
|
27
|
+
.filter(f => f.endsWith(ext))
|
|
28
|
+
.map(f => f.replace(new RegExp(`\\${ext}$`), ''));
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// Detector registration mirrors writers/commands.ts — see that file for the
|
|
33
|
+
// openclaw vs grok asymmetry.
|
|
34
|
+
export const commandsDetectors = lazyAgentMap(() => {
|
|
35
|
+
const m = {};
|
|
36
|
+
for (const id of Object.keys(AGENTS)) {
|
|
37
|
+
const cfg = AGENTS[id];
|
|
38
|
+
if (cfg.capabilities.commands === false && (!cfg.commandsSubdir || cfg.commandsSubdir === '') && id !== 'grok')
|
|
39
|
+
continue;
|
|
40
|
+
const hasCommands = cfg.capabilities.commands !== false;
|
|
41
|
+
const hasSkills = cfg.capabilities.skills !== false;
|
|
42
|
+
if (hasCommands || hasSkills)
|
|
43
|
+
m[id] = buildCommandsDetector(id);
|
|
44
|
+
}
|
|
45
|
+
return m;
|
|
46
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks detector — names of hook scripts materialized in the version home
|
|
3
|
+
* whose contents match the central source. Mirrors versions.ts:391-421.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { agentConfigDirName } from '../../agents.js';
|
|
8
|
+
import { capableAgents } from '../../capabilities.js';
|
|
9
|
+
import { resolveHookSource } from '../writers/sources.js';
|
|
10
|
+
import { lazyAgentMap } from '../writers/lazy-map.js';
|
|
11
|
+
function buildHooksDetector(agent) {
|
|
12
|
+
return {
|
|
13
|
+
kind: 'hooks',
|
|
14
|
+
agent,
|
|
15
|
+
list({ versionHome }) {
|
|
16
|
+
const hooksDir = path.join(versionHome, agentConfigDirName(agent), 'hooks');
|
|
17
|
+
if (!fs.existsSync(hooksDir))
|
|
18
|
+
return [];
|
|
19
|
+
const installed = fs.readdirSync(hooksDir).filter(f => !f.startsWith('.'));
|
|
20
|
+
const synced = [];
|
|
21
|
+
for (const hook of installed) {
|
|
22
|
+
const src = resolveHookSource(hook);
|
|
23
|
+
if (!src) {
|
|
24
|
+
// True orphan — count as accounted for.
|
|
25
|
+
synced.push(hook);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
if (fs.readFileSync(src, 'utf-8') === fs.readFileSync(path.join(hooksDir, hook), 'utf-8')) {
|
|
30
|
+
synced.push(hook);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch { /* read failure → not synced */ }
|
|
34
|
+
}
|
|
35
|
+
return synced;
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export const hooksDetectors = lazyAgentMap(() => {
|
|
40
|
+
const m = {};
|
|
41
|
+
for (const agent of capableAgents('hooks'))
|
|
42
|
+
m[agent] = buildHooksDetector(agent);
|
|
43
|
+
return m;
|
|
44
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP detector — parses the agent's canonical MCP config in the version home
|
|
3
|
+
* and returns server names. Mirrors versions.ts:432-443.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import { capableAgents } from '../../capabilities.js';
|
|
7
|
+
import { getMcpConfigPathForHome, parseMcpConfig } from '../../agents.js';
|
|
8
|
+
import { lazyAgentMap } from '../writers/lazy-map.js';
|
|
9
|
+
function buildMcpDetector(agent) {
|
|
10
|
+
return {
|
|
11
|
+
kind: 'mcp',
|
|
12
|
+
agent,
|
|
13
|
+
list({ versionHome }) {
|
|
14
|
+
const p = getMcpConfigPathForHome(agent, versionHome);
|
|
15
|
+
if (!fs.existsSync(p))
|
|
16
|
+
return [];
|
|
17
|
+
try {
|
|
18
|
+
return Object.keys(parseMcpConfig(agent, p));
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export const mcpDetectors = lazyAgentMap(() => {
|
|
27
|
+
const m = {};
|
|
28
|
+
for (const agent of capableAgents('mcp'))
|
|
29
|
+
m[agent] = buildMcpDetector(agent);
|
|
30
|
+
return m;
|
|
31
|
+
});
|