@phnx-labs/agents-cli 1.15.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -39
- package/README.md +6 -6
- package/dist/commands/alias.js +2 -2
- package/dist/commands/browser-picker.d.ts +21 -0
- package/dist/commands/browser-picker.js +114 -0
- package/dist/commands/browser.js +546 -75
- package/dist/commands/commands.js +72 -22
- package/dist/commands/daemon.js +2 -2
- package/dist/commands/fork.js +2 -2
- package/dist/commands/hooks.js +71 -26
- package/dist/commands/mcp.js +81 -39
- package/dist/commands/plugins.js +48 -15
- package/dist/commands/prune.js +23 -1
- package/dist/commands/pull.js +3 -3
- package/dist/commands/repo.js +1 -1
- package/dist/commands/routines.js +2 -2
- package/dist/commands/secrets.js +37 -1
- package/dist/commands/sessions.js +62 -19
- package/dist/commands/{init.d.ts → setup.d.ts} +7 -6
- package/dist/commands/{init.js → setup.js} +22 -21
- package/dist/commands/skills.js +60 -19
- package/dist/commands/subagents.js +41 -13
- package/dist/commands/utils.d.ts +16 -0
- package/dist/commands/utils.js +32 -0
- package/dist/commands/view.js +61 -16
- package/dist/index.d.ts +1 -1
- package/dist/index.js +17 -20
- package/dist/lib/agents.js +2 -2
- package/dist/lib/auto-pull-worker.js +2 -3
- package/dist/lib/auto-pull.js +2 -2
- package/dist/lib/browser/cdp.d.ts +7 -1
- package/dist/lib/browser/cdp.js +29 -1
- package/dist/lib/browser/chrome.js +5 -2
- package/dist/lib/browser/devices.d.ts +4 -0
- package/dist/lib/browser/devices.js +27 -0
- package/dist/lib/browser/drivers/local.js +9 -4
- package/dist/lib/browser/drivers/ssh.js +9 -2
- package/dist/lib/browser/ipc.js +144 -23
- package/dist/lib/browser/profiles.d.ts +5 -2
- package/dist/lib/browser/profiles.js +77 -37
- package/dist/lib/browser/service.d.ts +81 -13
- package/dist/lib/browser/service.js +738 -131
- package/dist/lib/browser/types.d.ts +81 -3
- package/dist/lib/browser/types.js +16 -0
- package/dist/lib/cloud/rush.js +2 -2
- package/dist/lib/cloud/store.js +2 -2
- package/dist/lib/commands.d.ts +1 -0
- package/dist/lib/commands.js +6 -2
- package/dist/lib/daemon.js +2 -3
- package/dist/lib/doctor-diff.js +4 -4
- package/dist/lib/events.js +2 -2
- package/dist/lib/hooks.d.ts +11 -7
- package/dist/lib/hooks.js +125 -49
- package/dist/lib/migrate.d.ts +1 -1
- package/dist/lib/migrate.js +1178 -21
- package/dist/lib/models.js +2 -2
- package/dist/lib/permissions.d.ts +8 -8
- package/dist/lib/permissions.js +8 -8
- package/dist/lib/plugins.d.ts +30 -1
- package/dist/lib/plugins.js +75 -3
- package/dist/lib/pty-server.js +9 -10
- package/dist/lib/resources/hooks.d.ts +5 -1
- package/dist/lib/resources/hooks.js +21 -4
- package/dist/lib/rotate.js +3 -4
- package/dist/lib/session/active.d.ts +3 -0
- package/dist/lib/session/active.js +92 -6
- package/dist/lib/session/cloud.js +2 -2
- package/dist/lib/session/db.js +8 -3
- package/dist/lib/session/discover.js +30 -15
- package/dist/lib/session/team-filter.js +2 -2
- package/dist/lib/shims.d.ts +2 -2
- package/dist/lib/shims.js +6 -6
- package/dist/lib/skills.js +6 -2
- package/dist/lib/state.d.ts +86 -14
- package/dist/lib/state.js +150 -23
- package/dist/lib/subagents.d.ts +28 -0
- package/dist/lib/subagents.js +98 -1
- package/dist/lib/sync-manifest.d.ts +1 -1
- package/dist/lib/sync-manifest.js +3 -3
- package/dist/lib/teams/persistence.js +15 -5
- package/dist/lib/teams/registry.js +2 -2
- package/dist/lib/types.d.ts +32 -3
- package/dist/lib/types.js +3 -3
- package/dist/lib/usage.js +2 -2
- package/dist/lib/versions.js +20 -21
- package/package.json +1 -1
- package/scripts/postinstall.js +1 -1
|
@@ -4,14 +4,14 @@ import * as fs from 'fs';
|
|
|
4
4
|
import * as os from 'os';
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import { checkbox } from '@inquirer/prompts';
|
|
7
|
-
import { ALL_AGENT_IDS, resolveAgentName, formatAgentError, agentLabel, } from '../lib/agents.js';
|
|
7
|
+
import { AGENTS, ALL_AGENT_IDS, resolveAgentName, formatAgentError, agentLabel, } from '../lib/agents.js';
|
|
8
8
|
import { cloneRepo } from '../lib/git.js';
|
|
9
|
-
import { discoverCommands, resolveCommandSource, installCommandCentrally,
|
|
9
|
+
import { discoverCommands, resolveCommandSource, installCommandCentrally, listCentralCommands, listInstalledCommandsWithScope, getCommandInfo, diffVersionCommands, iterCommandsCapableVersions, removeCommandFromVersion, } from '../lib/commands.js';
|
|
10
10
|
import { getCommandsDir } from '../lib/state.js';
|
|
11
11
|
import { showResourceList, buildTargetsSection, } from './resource-view.js';
|
|
12
|
-
import { getGlobalDefault, resolveVersionAlias, syncResourcesToVersion, promptAgentVersionSelection, resolveAgentVersionTargets, } from '../lib/versions.js';
|
|
12
|
+
import { getGlobalDefault, resolveVersionAlias, syncResourcesToVersion, promptAgentVersionSelection, getVersionHomePath, resolveAgentVersionTargets, } from '../lib/versions.js';
|
|
13
13
|
import { recordVersionResources } from '../lib/state.js';
|
|
14
|
-
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, } from './utils.js';
|
|
14
|
+
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, promptRemovalTargets, } from './utils.js';
|
|
15
15
|
/** Register the `agents commands` command tree (list, add, remove, sync, prune, view). */
|
|
16
16
|
export function registerCommandsCommands(program) {
|
|
17
17
|
const commandsCmd = program
|
|
@@ -271,15 +271,29 @@ Examples:
|
|
|
271
271
|
agents commands remove
|
|
272
272
|
`)
|
|
273
273
|
.action(async (name, options) => {
|
|
274
|
+
const cmdTargetMap = new Map();
|
|
275
|
+
for (const { agent, version } of iterCommandsCapableVersions()) {
|
|
276
|
+
const home = getVersionHomePath(agent, version);
|
|
277
|
+
const commands = listInstalledCommandsWithScope(agent, process.cwd(), { home });
|
|
278
|
+
for (const cmd of commands) {
|
|
279
|
+
if (cmd.scope !== 'user')
|
|
280
|
+
continue;
|
|
281
|
+
const existing = cmdTargetMap.get(cmd.name);
|
|
282
|
+
if (existing) {
|
|
283
|
+
existing.targets.push({ agent, version });
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
cmdTargetMap.set(cmd.name, { name: cmd.name, targets: [{ agent, version }] });
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
274
290
|
let commandsToRemove;
|
|
275
291
|
if (name) {
|
|
276
292
|
commandsToRemove = [name];
|
|
277
293
|
}
|
|
278
294
|
else {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if (centralCommands.length === 0) {
|
|
282
|
-
console.log(chalk.yellow('No commands installed.'));
|
|
295
|
+
if (cmdTargetMap.size === 0) {
|
|
296
|
+
console.log(chalk.yellow('No commands installed in any version.'));
|
|
283
297
|
return;
|
|
284
298
|
}
|
|
285
299
|
if (!isInteractiveTerminal()) {
|
|
@@ -288,12 +302,16 @@ Examples:
|
|
|
288
302
|
]);
|
|
289
303
|
}
|
|
290
304
|
try {
|
|
305
|
+
const choices = Array.from(cmdTargetMap.values()).map((cmd) => {
|
|
306
|
+
const agents = [...new Set(cmd.targets.map((t) => AGENTS[t.agent].name))];
|
|
307
|
+
return {
|
|
308
|
+
value: cmd.name,
|
|
309
|
+
name: `${cmd.name} (${agents.join(', ')})`,
|
|
310
|
+
};
|
|
311
|
+
});
|
|
291
312
|
const selected = await checkbox({
|
|
292
313
|
message: 'Select commands to remove',
|
|
293
|
-
choices
|
|
294
|
-
value: cmd,
|
|
295
|
-
name: cmd,
|
|
296
|
-
})),
|
|
314
|
+
choices,
|
|
297
315
|
});
|
|
298
316
|
if (selected.length === 0) {
|
|
299
317
|
console.log(chalk.gray('No commands selected.'));
|
|
@@ -309,20 +327,52 @@ Examples:
|
|
|
309
327
|
throw err;
|
|
310
328
|
}
|
|
311
329
|
}
|
|
312
|
-
|
|
313
|
-
? options.agents.split(',')
|
|
314
|
-
: ALL_AGENT_IDS;
|
|
330
|
+
let removed = 0;
|
|
315
331
|
for (const cmdName of commandsToRemove) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
332
|
+
const cmdInfo = cmdTargetMap.get(cmdName);
|
|
333
|
+
if (!cmdInfo || cmdInfo.targets.length === 0) {
|
|
334
|
+
console.log(chalk.yellow(` Command '${cmdName}' not found in any version.`));
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
// Filter by --agents if specified
|
|
338
|
+
let availableTargets = cmdInfo.targets;
|
|
339
|
+
if (options?.agents) {
|
|
340
|
+
const requestedAgents = new Set(options.agents.split(','));
|
|
341
|
+
availableTargets = availableTargets.filter((t) => requestedAgents.has(t.agent));
|
|
342
|
+
}
|
|
343
|
+
if (availableTargets.length === 0) {
|
|
344
|
+
console.log(chalk.yellow(` Command '${cmdName}' not found in specified agents.`));
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
const removalTargets = availableTargets.map((t) => ({
|
|
348
|
+
agent: t.agent,
|
|
349
|
+
version: t.version,
|
|
350
|
+
label: `${agentLabel(t.agent)}@${t.version}`,
|
|
351
|
+
}));
|
|
352
|
+
const selectedTargets = await promptRemovalTargets(cmdName, removalTargets, {
|
|
353
|
+
skipPrompt: !!options?.agents,
|
|
354
|
+
});
|
|
355
|
+
if (selectedTargets.length === 0) {
|
|
356
|
+
console.log(chalk.gray(` Skipped '${cmdName}'.`));
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
for (const target of selectedTargets) {
|
|
360
|
+
const result = removeCommandFromVersion(target.agent, target.version, cmdName);
|
|
361
|
+
if (result.success) {
|
|
362
|
+
console.log(` ${chalk.red('-')} ${target.label}: ${cmdName}`);
|
|
320
363
|
removed++;
|
|
321
364
|
}
|
|
365
|
+
else if (result.error) {
|
|
366
|
+
console.log(` ${chalk.yellow('!')} ${target.label}: ${result.error}`);
|
|
367
|
+
}
|
|
322
368
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
369
|
+
}
|
|
370
|
+
if (removed === 0) {
|
|
371
|
+
console.log(chalk.yellow('No commands removed.'));
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
console.log(chalk.green(`\nRemoved ${removed} command(s) from version homes.`));
|
|
375
|
+
console.log(chalk.gray('Central source unchanged. Commands will re-sync on next agent launch.'));
|
|
326
376
|
}
|
|
327
377
|
});
|
|
328
378
|
// `commands sync` is gone — sync runs automatically when the agent launches.
|
package/dist/commands/daemon.js
CHANGED
|
@@ -91,8 +91,8 @@ you never need to start it manually.
|
|
|
91
91
|
.action(async (options) => {
|
|
92
92
|
warnDeprecated('logs', 'agents routines scheduler-logs');
|
|
93
93
|
if (options.follow) {
|
|
94
|
-
const {
|
|
95
|
-
const logPath = path.join(
|
|
94
|
+
const { getDaemonDir } = await import('../lib/state.js');
|
|
95
|
+
const logPath = path.join(getDaemonDir(), 'logs.jsonl');
|
|
96
96
|
const child = spawn('tail', ['-f', logPath], { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
97
97
|
child.stdout.pipe(process.stdout);
|
|
98
98
|
child.stderr.pipe(process.stderr);
|
package/dist/commands/fork.js
CHANGED
|
@@ -15,14 +15,14 @@ import { isPromptCancelled } from './utils.js';
|
|
|
15
15
|
export function registerForkCommand(program) {
|
|
16
16
|
program
|
|
17
17
|
.command('fork')
|
|
18
|
-
.description('Copy the default config repo to your own GitHub so you can push changes. Runs once after
|
|
18
|
+
.description('Copy the default config repo to your own GitHub so you can push changes. Runs once after setup.')
|
|
19
19
|
.addHelpText('after', `
|
|
20
20
|
Examples:
|
|
21
21
|
# Fork the default repo to your GitHub account
|
|
22
22
|
agents fork
|
|
23
23
|
|
|
24
24
|
When to use:
|
|
25
|
-
- You
|
|
25
|
+
- You set up with 'agents setup' using the default config
|
|
26
26
|
- You've customized commands, skills, or settings
|
|
27
27
|
- You want to save your changes to your own GitHub repo
|
|
28
28
|
|
package/dist/commands/hooks.js
CHANGED
|
@@ -7,10 +7,10 @@ import { checkbox } from '@inquirer/prompts';
|
|
|
7
7
|
import { AGENTS, HOOKS_CAPABLE_AGENTS, resolveAgentName, formatAgentError, agentLabel, } from '../lib/agents.js';
|
|
8
8
|
import { supports } from '../lib/capabilities.js';
|
|
9
9
|
import { cloneRepo } from '../lib/git.js';
|
|
10
|
-
import { discoverHooksFromRepo, installHooksCentrally, listCentralHooks, listInstalledHooksWithScope,
|
|
10
|
+
import { discoverHooksFromRepo, installHooksCentrally, listCentralHooks, listInstalledHooksWithScope, getHookInfo, parseHookManifest, iterHooksCapableVersions, removeHookFromVersion, } from '../lib/hooks.js';
|
|
11
11
|
import { listInstalledVersions, getGlobalDefault, resolveVersionAlias, syncResourcesToVersion, promptAgentVersionSelection, getVersionHomePath, resolveAgentVersionTargets, } from '../lib/versions.js';
|
|
12
12
|
import { recordVersionResources } from '../lib/state.js';
|
|
13
|
-
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, } from './utils.js';
|
|
13
|
+
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, promptRemovalTargets, } from './utils.js';
|
|
14
14
|
/** Register the `agents hooks` command tree (list, add, remove, sync, prune, view). */
|
|
15
15
|
export function registerHooksCommands(program) {
|
|
16
16
|
const hooksCmd = program.command('hooks')
|
|
@@ -396,15 +396,29 @@ Examples:
|
|
|
396
396
|
agents hooks remove
|
|
397
397
|
`)
|
|
398
398
|
.action(async (name, options) => {
|
|
399
|
+
const hookTargetMap = new Map();
|
|
400
|
+
for (const { agent, version } of iterHooksCapableVersions()) {
|
|
401
|
+
const home = getVersionHomePath(agent, version);
|
|
402
|
+
const hooks = listInstalledHooksWithScope(agent, process.cwd(), { home });
|
|
403
|
+
for (const hook of hooks) {
|
|
404
|
+
if (hook.scope !== 'user')
|
|
405
|
+
continue;
|
|
406
|
+
const existing = hookTargetMap.get(hook.name);
|
|
407
|
+
if (existing) {
|
|
408
|
+
existing.targets.push({ agent, version });
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
hookTargetMap.set(hook.name, { name: hook.name, targets: [{ agent, version }] });
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
399
415
|
let hooksToRemove;
|
|
400
416
|
if (name) {
|
|
401
417
|
hooksToRemove = [name];
|
|
402
418
|
}
|
|
403
419
|
else {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
if (centralHooks.length === 0) {
|
|
407
|
-
console.log(chalk.yellow('No hooks installed.'));
|
|
420
|
+
if (hookTargetMap.size === 0) {
|
|
421
|
+
console.log(chalk.yellow('No hooks installed in any version.'));
|
|
408
422
|
return;
|
|
409
423
|
}
|
|
410
424
|
if (!isInteractiveTerminal()) {
|
|
@@ -413,12 +427,16 @@ Examples:
|
|
|
413
427
|
]);
|
|
414
428
|
}
|
|
415
429
|
try {
|
|
430
|
+
const choices = Array.from(hookTargetMap.values()).map((hook) => {
|
|
431
|
+
const agents = [...new Set(hook.targets.map((t) => AGENTS[t.agent].name))];
|
|
432
|
+
return {
|
|
433
|
+
value: hook.name,
|
|
434
|
+
name: `${hook.name} (${agents.join(', ')})`,
|
|
435
|
+
};
|
|
436
|
+
});
|
|
416
437
|
const selected = await checkbox({
|
|
417
438
|
message: 'Select hooks to remove',
|
|
418
|
-
choices
|
|
419
|
-
value: hook.name,
|
|
420
|
-
name: hook.name,
|
|
421
|
-
})),
|
|
439
|
+
choices,
|
|
422
440
|
});
|
|
423
441
|
if (selected.length === 0) {
|
|
424
442
|
console.log(chalk.gray('No hooks selected.'));
|
|
@@ -434,26 +452,53 @@ Examples:
|
|
|
434
452
|
throw err;
|
|
435
453
|
}
|
|
436
454
|
}
|
|
437
|
-
|
|
438
|
-
? options.agents.split(',')
|
|
439
|
-
: Array.from(HOOKS_CAPABLE_AGENTS);
|
|
455
|
+
let removed = 0;
|
|
440
456
|
for (const hookName of hooksToRemove) {
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
if (
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
457
|
+
const hookInfo = hookTargetMap.get(hookName);
|
|
458
|
+
if (!hookInfo || hookInfo.targets.length === 0) {
|
|
459
|
+
console.log(chalk.yellow(` Hook '${hookName}' not found in any version.`));
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
// Filter by --agents if specified
|
|
463
|
+
let availableTargets = hookInfo.targets;
|
|
464
|
+
if (options?.agents) {
|
|
465
|
+
const requestedAgents = new Set(options.agents.split(','));
|
|
466
|
+
availableTargets = availableTargets.filter((t) => requestedAgents.has(t.agent));
|
|
467
|
+
}
|
|
468
|
+
if (availableTargets.length === 0) {
|
|
469
|
+
console.log(chalk.yellow(` Hook '${hookName}' not found in specified agents.`));
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
const removalTargets = availableTargets.map((t) => ({
|
|
473
|
+
agent: t.agent,
|
|
474
|
+
version: t.version,
|
|
475
|
+
label: `${agentLabel(t.agent)}@${t.version}`,
|
|
476
|
+
}));
|
|
477
|
+
const selectedTargets = await promptRemovalTargets(hookName, removalTargets, {
|
|
478
|
+
skipPrompt: !!options?.agents,
|
|
479
|
+
});
|
|
480
|
+
if (selectedTargets.length === 0) {
|
|
481
|
+
console.log(chalk.gray(` Skipped '${hookName}'.`));
|
|
482
|
+
continue;
|
|
452
483
|
}
|
|
453
|
-
|
|
454
|
-
|
|
484
|
+
for (const target of selectedTargets) {
|
|
485
|
+
const result = removeHookFromVersion(target.agent, target.version, hookName);
|
|
486
|
+
if (result.success) {
|
|
487
|
+
console.log(` ${chalk.red('-')} ${target.label}: ${hookName}`);
|
|
488
|
+
removed++;
|
|
489
|
+
}
|
|
490
|
+
else if (result.error) {
|
|
491
|
+
console.log(` ${chalk.yellow('!')} ${target.label}: ${result.error}`);
|
|
492
|
+
}
|
|
455
493
|
}
|
|
456
494
|
}
|
|
495
|
+
if (removed === 0) {
|
|
496
|
+
console.log(chalk.yellow('No hooks removed.'));
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
console.log(chalk.green(`\nRemoved ${removed} hook(s) from version homes.`));
|
|
500
|
+
console.log(chalk.gray('Central source unchanged. Hooks will re-sync on next agent launch.'));
|
|
501
|
+
}
|
|
457
502
|
});
|
|
458
503
|
// `hooks sync` is gone — sync runs automatically when the agent launches.
|
|
459
504
|
hooksCmd
|
package/dist/commands/mcp.js
CHANGED
|
@@ -7,7 +7,7 @@ import { listMcpServerConfigs } from '../lib/mcp.js';
|
|
|
7
7
|
import { getMcpDir } from '../lib/state.js';
|
|
8
8
|
import { getEffectiveHome, getGlobalDefault, listInstalledVersions, getVersionHomePath, resolveInstalledAgentTargets, resolveConfiguredAgentTargets, resolveVersionAlias, } from '../lib/versions.js';
|
|
9
9
|
import { getUserAgentsDir } from '../lib/state.js';
|
|
10
|
-
import { isPromptCancelled, isInteractiveTerminal, requireInteractiveSelection } from './utils.js';
|
|
10
|
+
import { isPromptCancelled, isInteractiveTerminal, requireInteractiveSelection, promptRemovalTargets } from './utils.js';
|
|
11
11
|
import { showResourceList, buildTargetsSection, } from './resource-view.js';
|
|
12
12
|
/** Parse a comma-separated --agents string into validated agent IDs and optional version targets. */
|
|
13
13
|
function parseMcpAgentTargets(value) {
|
|
@@ -219,20 +219,33 @@ Examples:
|
|
|
219
219
|
.action(async (name, options) => {
|
|
220
220
|
const cwd = process.cwd();
|
|
221
221
|
const cliStates = await getAllCliStates();
|
|
222
|
+
const mcpTargetMap = new Map();
|
|
223
|
+
for (const agentId of MCP_CAPABLE_AGENTS) {
|
|
224
|
+
if (!cliStates[agentId]?.installed && listInstalledVersions(agentId).length === 0)
|
|
225
|
+
continue;
|
|
226
|
+
for (const version of listInstalledVersions(agentId)) {
|
|
227
|
+
const home = getVersionHomePath(agentId, version);
|
|
228
|
+
const configPath = getMcpConfigPathForHome(agentId, home);
|
|
229
|
+
const mcps = parseMcpConfig(agentId, configPath);
|
|
230
|
+
for (const mcpName of Object.keys(mcps)) {
|
|
231
|
+
const existing = mcpTargetMap.get(mcpName);
|
|
232
|
+
if (existing) {
|
|
233
|
+
existing.targets.push({ agentId, version, home });
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
mcpTargetMap.set(mcpName, { name: mcpName, targets: [{ agentId, version, home }] });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
222
241
|
let mcpsToRemove;
|
|
223
|
-
let targets;
|
|
224
242
|
if (name) {
|
|
225
243
|
mcpsToRemove = [name];
|
|
226
|
-
const installedAgents = MCP_CAPABLE_AGENTS.filter((agentId) => cliStates[agentId]?.installed || listInstalledVersions(agentId).length > 0);
|
|
227
|
-
targets = options?.agents
|
|
228
|
-
? resolveInstalledAgentTargets(options.agents, MCP_CAPABLE_AGENTS)
|
|
229
|
-
: resolveConfiguredAgentTargets(installedAgents, undefined, MCP_CAPABLE_AGENTS);
|
|
230
244
|
}
|
|
231
245
|
else {
|
|
232
|
-
// Interactive picker
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
console.log(chalk.yellow('No MCP-capable agents installed.'));
|
|
246
|
+
// Interactive picker for MCP selection
|
|
247
|
+
if (mcpTargetMap.size === 0) {
|
|
248
|
+
console.log(chalk.yellow('No MCP servers configured.'));
|
|
236
249
|
return;
|
|
237
250
|
}
|
|
238
251
|
if (!isInteractiveTerminal()) {
|
|
@@ -241,42 +254,22 @@ Examples:
|
|
|
241
254
|
'agents mcp remove my-server --agents codex,claude',
|
|
242
255
|
]);
|
|
243
256
|
}
|
|
244
|
-
// Gather all unique MCPs across agents (with agent info for display)
|
|
245
|
-
const mcpMap = new Map();
|
|
246
|
-
for (const agentId of installedAgents) {
|
|
247
|
-
const mcps = listInstalledMcpsWithScope(agentId, cwd, { home: getEffectiveHome(agentId) });
|
|
248
|
-
for (const mcp of mcps) {
|
|
249
|
-
const existing = mcpMap.get(mcp.name);
|
|
250
|
-
if (existing) {
|
|
251
|
-
existing.agents.push(AGENTS[agentId].name);
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
mcpMap.set(mcp.name, {
|
|
255
|
-
name: mcp.name,
|
|
256
|
-
agents: [AGENTS[agentId].name],
|
|
257
|
-
command: mcp.command,
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
if (mcpMap.size === 0) {
|
|
263
|
-
console.log(chalk.yellow('No MCP servers configured.'));
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
257
|
try {
|
|
267
258
|
const selected = await checkbox({
|
|
268
259
|
message: 'Select MCP servers to remove',
|
|
269
|
-
choices: Array.from(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
260
|
+
choices: Array.from(mcpTargetMap.values()).map((mcp) => {
|
|
261
|
+
const agents = [...new Set(mcp.targets.map((t) => AGENTS[t.agentId].name))];
|
|
262
|
+
return {
|
|
263
|
+
value: mcp.name,
|
|
264
|
+
name: `${mcp.name} (${agents.join(', ')})`,
|
|
265
|
+
};
|
|
266
|
+
}),
|
|
273
267
|
});
|
|
274
268
|
if (selected.length === 0) {
|
|
275
269
|
console.log(chalk.gray('No MCPs selected.'));
|
|
276
270
|
return;
|
|
277
271
|
}
|
|
278
272
|
mcpsToRemove = selected;
|
|
279
|
-
targets = resolveConfiguredAgentTargets(installedAgents, undefined, MCP_CAPABLE_AGENTS);
|
|
280
273
|
}
|
|
281
274
|
catch (err) {
|
|
282
275
|
if (isPromptCancelled(err)) {
|
|
@@ -286,10 +279,59 @@ Examples:
|
|
|
286
279
|
throw err;
|
|
287
280
|
}
|
|
288
281
|
}
|
|
289
|
-
// Execute removals
|
|
282
|
+
// Execute removals with target selection
|
|
290
283
|
let removed = 0;
|
|
291
284
|
for (const mcpName of mcpsToRemove) {
|
|
292
|
-
const
|
|
285
|
+
const mcpInfo = mcpTargetMap.get(mcpName);
|
|
286
|
+
if (!mcpInfo || mcpInfo.targets.length === 0) {
|
|
287
|
+
console.log(chalk.yellow(` MCP '${mcpName}' not found in any agent.`));
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
// If --agents was specified, filter targets
|
|
291
|
+
let availableTargets = mcpInfo.targets;
|
|
292
|
+
if (options?.agents) {
|
|
293
|
+
const requestedTargets = resolveInstalledAgentTargets(options.agents, MCP_CAPABLE_AGENTS);
|
|
294
|
+
const requested = new Set();
|
|
295
|
+
for (const aid of requestedTargets.directAgents) {
|
|
296
|
+
for (const ver of listInstalledVersions(aid)) {
|
|
297
|
+
requested.add(`${aid}@${ver}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
for (const [aid, versions] of requestedTargets.versionSelections) {
|
|
301
|
+
for (const ver of versions) {
|
|
302
|
+
requested.add(`${aid}@${ver}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
availableTargets = availableTargets.filter((t) => requested.has(`${t.agentId}@${t.version}`));
|
|
306
|
+
}
|
|
307
|
+
if (availableTargets.length === 0) {
|
|
308
|
+
console.log(chalk.yellow(` MCP '${mcpName}' not found in specified agents.`));
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
// Show target picker if multiple targets and no --agents flag
|
|
312
|
+
const removalTargets = availableTargets.map((t) => ({
|
|
313
|
+
agent: t.agentId,
|
|
314
|
+
version: t.version,
|
|
315
|
+
label: formatTargetLabel(t.agentId, t.version),
|
|
316
|
+
}));
|
|
317
|
+
const selectedTargets = await promptRemovalTargets(mcpName, removalTargets, {
|
|
318
|
+
skipPrompt: !!options?.agents,
|
|
319
|
+
});
|
|
320
|
+
if (selectedTargets.length === 0) {
|
|
321
|
+
console.log(chalk.gray(` Skipped '${mcpName}'.`));
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
// Build targets structure for unregister
|
|
325
|
+
const versionSelections = new Map();
|
|
326
|
+
for (const t of selectedTargets) {
|
|
327
|
+
const versions = versionSelections.get(t.agent) || [];
|
|
328
|
+
if (!versions.includes(t.version)) {
|
|
329
|
+
versions.push(t.version);
|
|
330
|
+
versionSelections.set(t.agent, versions);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
const targetsToRemove = { directAgents: [], versionSelections };
|
|
334
|
+
const results = await unregisterMcpFromTargets(targetsToRemove, mcpName);
|
|
293
335
|
for (const result of results) {
|
|
294
336
|
if (result.success) {
|
|
295
337
|
console.log(` ${chalk.red('-')} ${formatTargetLabel(result.agentId, result.version)}: ${mcpName}`);
|
package/dist/commands/plugins.js
CHANGED
|
@@ -12,7 +12,7 @@ import { PLUGINS_CAPABLE_AGENTS, agentLabel } from '../lib/agents.js';
|
|
|
12
12
|
import { discoverPlugins, getPlugin, pluginSupportsAgent, removePluginFromVersion } from '../lib/plugins.js';
|
|
13
13
|
import { listInstalledVersions, syncResourcesToVersion, getGlobalDefault, getVersionHomePath, } from '../lib/versions.js';
|
|
14
14
|
import { isPluginSynced } from '../lib/plugins.js';
|
|
15
|
-
import { isPromptCancelled, isInteractiveTerminal, requireDestructiveArg, requireInteractiveSelection, } from './utils.js';
|
|
15
|
+
import { isPromptCancelled, isInteractiveTerminal, requireDestructiveArg, requireInteractiveSelection, promptRemovalTargets, } from './utils.js';
|
|
16
16
|
import { itemPicker } from '../lib/picker.js';
|
|
17
17
|
import { showResourceList, buildTargetsSection, } from './resource-view.js';
|
|
18
18
|
import { getPluginsDir } from '../lib/state.js';
|
|
@@ -255,7 +255,7 @@ Examples:
|
|
|
255
255
|
# Unsync but keep source directory
|
|
256
256
|
agents plugins remove rush-toolkit --keep-source
|
|
257
257
|
`)
|
|
258
|
-
.action((nameArg, options) => {
|
|
258
|
+
.action(async (nameArg, options) => {
|
|
259
259
|
if (!nameArg) {
|
|
260
260
|
requireDestructiveArg({
|
|
261
261
|
argName: 'name',
|
|
@@ -275,31 +275,64 @@ Examples:
|
|
|
275
275
|
console.log(chalk.red(`Plugin '${name}' not found`));
|
|
276
276
|
process.exit(1);
|
|
277
277
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
let totalPerms = 0;
|
|
281
|
-
let versionsTouched = 0;
|
|
278
|
+
// Build list of targets that have this plugin synced
|
|
279
|
+
const availableTargets = [];
|
|
282
280
|
for (const agentId of PLUGINS_CAPABLE_AGENTS) {
|
|
281
|
+
if (plugin && !pluginSupportsAgent(plugin, agentId))
|
|
282
|
+
continue;
|
|
283
283
|
const versions = listInstalledVersions(agentId);
|
|
284
284
|
for (const version of versions) {
|
|
285
285
|
const versionHome = getVersionHomePath(agentId, version);
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
versionsTouched += 1;
|
|
289
|
-
totalSkills += r.skills.length;
|
|
290
|
-
totalHooks += r.hooks.length;
|
|
291
|
-
totalPerms += r.permissions;
|
|
292
|
-
console.log(chalk.gray(` ${agentLabel(agentId)}@${version}: ${r.skills.length} skill(s), ${r.hooks.length} hook(s), ${r.permissions} perm(s)`));
|
|
286
|
+
if (plugin && isPluginSynced(plugin, agentId, versionHome)) {
|
|
287
|
+
availableTargets.push({ agent: agentId, version });
|
|
293
288
|
}
|
|
294
289
|
}
|
|
295
290
|
}
|
|
296
|
-
|
|
297
|
-
|
|
291
|
+
if (availableTargets.length === 0) {
|
|
292
|
+
console.log(chalk.yellow(`Plugin '${name}' not synced to any version.`));
|
|
293
|
+
if (!options.keepSource && fs.existsSync(pluginRoot)) {
|
|
294
|
+
fs.rmSync(pluginRoot, { recursive: true, force: true });
|
|
295
|
+
console.log(chalk.green(`Deleted ${formatPath(pluginRoot)}`));
|
|
296
|
+
}
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
// Show multi-select picker for targets
|
|
300
|
+
const removalTargets = availableTargets.map((t) => ({
|
|
301
|
+
agent: t.agent,
|
|
302
|
+
version: t.version,
|
|
303
|
+
label: `${agentLabel(t.agent)}@${t.version}`,
|
|
304
|
+
}));
|
|
305
|
+
const selectedTargets = await promptRemovalTargets(name, removalTargets);
|
|
306
|
+
if (selectedTargets.length === 0) {
|
|
307
|
+
console.log(chalk.gray('Cancelled.'));
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
let totalSkills = 0;
|
|
311
|
+
let totalHooks = 0;
|
|
312
|
+
let totalPerms = 0;
|
|
313
|
+
let versionsTouched = 0;
|
|
314
|
+
for (const target of selectedTargets) {
|
|
315
|
+
const versionHome = getVersionHomePath(target.agent, target.version);
|
|
316
|
+
const r = removePluginFromVersion(name, resolvedRoot, target.agent, versionHome);
|
|
317
|
+
if (r.skills.length > 0 || r.hooks.length > 0 || r.permissions > 0) {
|
|
318
|
+
versionsTouched += 1;
|
|
319
|
+
totalSkills += r.skills.length;
|
|
320
|
+
totalHooks += r.hooks.length;
|
|
321
|
+
totalPerms += r.permissions;
|
|
322
|
+
console.log(` ${chalk.red('-')} ${target.label}: ${r.skills.length} skill(s), ${r.hooks.length} hook(s), ${r.permissions} perm(s)`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
console.log(chalk.green(`\nUnsynced ${name} from ${versionsTouched} version(s) — ${totalSkills} skills, ${totalHooks} hooks, ${totalPerms} permissions`));
|
|
326
|
+
// Only delete source if ALL targets were selected
|
|
327
|
+
if (!options.keepSource && selectedTargets.length === availableTargets.length) {
|
|
298
328
|
if (fs.existsSync(pluginRoot)) {
|
|
299
329
|
fs.rmSync(pluginRoot, { recursive: true, force: true });
|
|
300
330
|
console.log(chalk.green(`Deleted ${formatPath(pluginRoot)}`));
|
|
301
331
|
}
|
|
302
332
|
}
|
|
333
|
+
else if (!options.keepSource && selectedTargets.length < availableTargets.length) {
|
|
334
|
+
console.log(chalk.gray(`Source kept — plugin still synced to other versions.`));
|
|
335
|
+
}
|
|
303
336
|
else {
|
|
304
337
|
console.log(chalk.gray(`Kept source at ${formatPath(pluginRoot)}`));
|
|
305
338
|
}
|
package/dist/commands/prune.js
CHANGED
|
@@ -27,6 +27,8 @@ import { confirm } from '@inquirer/prompts';
|
|
|
27
27
|
import { diffVersionCommands, iterCommandsCapableVersions, removeCommandFromVersion, } from '../lib/commands.js';
|
|
28
28
|
import { diffVersionSkills, iterSkillsCapableVersions, removeSkillFromVersion, } from '../lib/skills.js';
|
|
29
29
|
import { diffVersionHooks, iterHooksCapableVersions, removeHookFromVersion, } from '../lib/hooks.js';
|
|
30
|
+
import { diffVersionPlugins, iterPluginsCapableVersions, removePluginSkillFromVersion, } from '../lib/plugins.js';
|
|
31
|
+
import { diffVersionSubagents, iterSubagentsCapableVersions, removeSubagentFromVersion, } from '../lib/subagents.js';
|
|
30
32
|
import { getGlobalDefault } from '../lib/versions.js';
|
|
31
33
|
import { resolveAgentName, formatAgentError } from '../lib/agents.js';
|
|
32
34
|
import { pruneDuplicates } from './view.js';
|
|
@@ -34,7 +36,7 @@ import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
|
|
|
34
36
|
import { getTrashDir } from '../lib/state.js';
|
|
35
37
|
import { countSessionsOlderThan, deleteSessionsOlderThan } from '../lib/session/db.js';
|
|
36
38
|
import { previewRunsPrune, pruneRuns, countAllRuns } from '../lib/routines.js';
|
|
37
|
-
const RESOURCE_TYPES = ['commands', 'skills', 'hooks'];
|
|
39
|
+
const RESOURCE_TYPES = ['commands', 'skills', 'hooks', 'plugins', 'subagents'];
|
|
38
40
|
const STATE_TYPES = ['trash', 'sessions', 'runs'];
|
|
39
41
|
const ALL_TYPES = [...RESOURCE_TYPES, 'versions', ...STATE_TYPES];
|
|
40
42
|
function scopePairs(pairs, all) {
|
|
@@ -68,6 +70,22 @@ function collectOrphans(types, all) {
|
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
72
|
}
|
|
73
|
+
if (types.includes('plugins')) {
|
|
74
|
+
for (const { agent, version } of scopePairs(iterPluginsCapableVersions(), all)) {
|
|
75
|
+
const diff = diffVersionPlugins(agent, version);
|
|
76
|
+
if (diff.orphans.length > 0) {
|
|
77
|
+
groups.push({ type: 'plugins', agent, version, orphans: diff.orphans });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (types.includes('subagents')) {
|
|
82
|
+
for (const { agent, version } of scopePairs(iterSubagentsCapableVersions(), all)) {
|
|
83
|
+
const diff = diffVersionSubagents(agent, version);
|
|
84
|
+
if (diff.orphans.length > 0) {
|
|
85
|
+
groups.push({ type: 'subagents', agent, version, orphans: diff.orphans });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
71
89
|
return groups;
|
|
72
90
|
}
|
|
73
91
|
function removeOne(group, name) {
|
|
@@ -78,6 +96,10 @@ function removeOne(group, name) {
|
|
|
78
96
|
return removeSkillFromVersion(group.agent, group.version, name);
|
|
79
97
|
case 'hooks':
|
|
80
98
|
return removeHookFromVersion(group.agent, group.version, name);
|
|
99
|
+
case 'plugins':
|
|
100
|
+
return removePluginSkillFromVersion(group.agent, group.version, name);
|
|
101
|
+
case 'subagents':
|
|
102
|
+
return removeSubagentFromVersion(group.agent, group.version, name);
|
|
81
103
|
}
|
|
82
104
|
}
|
|
83
105
|
function parseTarget(arg) {
|
package/dist/commands/pull.js
CHANGED
|
@@ -80,12 +80,12 @@ Skip CLI installs with --skip-clis when you only want config updates, not versio
|
|
|
80
80
|
// auto-syncs the system repo in the background and surfaces upstream
|
|
81
81
|
// changes for user/extra repos as one-line notices. Repo lifecycle is
|
|
82
82
|
// managed under `agents repo`. We keep this command functional today
|
|
83
|
-
// because `agents
|
|
84
|
-
//
|
|
83
|
+
// because `agents setup` still invokes it for first-time setup; once
|
|
84
|
+
// setup is refactored to call the bootstrap helpers directly, this
|
|
85
85
|
// command will hard-error like `agents memory` does.
|
|
86
86
|
if (!options.yes && process.argv[2] === 'pull') {
|
|
87
87
|
process.stderr.write('agents-cli: "agents pull" is deprecated.\n' +
|
|
88
|
-
' First-time setup: agents
|
|
88
|
+
' First-time setup: agents setup\n' +
|
|
89
89
|
' Force a sync now: agents repo pull\n' +
|
|
90
90
|
' Push your repo: agents repo push\n\n');
|
|
91
91
|
}
|
package/dist/commands/repo.js
CHANGED
|
@@ -257,7 +257,7 @@ Examples:
|
|
|
257
257
|
const systemStatus = !systemOnDisk
|
|
258
258
|
? chalk.red('missing')
|
|
259
259
|
: !systemIsGit
|
|
260
|
-
? chalk.yellow('not a git repo — run: agents
|
|
260
|
+
? chalk.yellow('not a git repo — run: agents setup')
|
|
261
261
|
: chalk.green('cloned');
|
|
262
262
|
const systemCommitLabel = systemCommit ? chalk.gray(`(${systemCommit})`) : '';
|
|
263
263
|
console.log(chalk.bold('System (~/.agents-system/)'));
|