@phnx-labs/agents-cli 1.19.2 → 1.20.3
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 +140 -0
- package/README.md +72 -12
- package/dist/browser.js +0 -0
- package/dist/commands/browser.js +88 -16
- package/dist/commands/cli.d.ts +14 -0
- package/dist/commands/cli.js +244 -0
- package/dist/commands/cloud.js +1 -1
- package/dist/commands/commands.js +27 -10
- package/dist/commands/computer.js +18 -1
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/exec.js +38 -18
- package/dist/commands/factory.d.ts +3 -14
- package/dist/commands/factory.js +3 -3
- package/dist/commands/feedback.d.ts +7 -0
- package/dist/commands/feedback.js +89 -0
- package/dist/commands/helper.d.ts +12 -0
- package/dist/commands/helper.js +87 -0
- package/dist/commands/hooks.js +89 -10
- package/dist/commands/mcp.js +166 -10
- package/dist/commands/packages.js +196 -27
- package/dist/commands/permissions.js +21 -6
- package/dist/commands/plugins.js +11 -4
- package/dist/commands/profiles.d.ts +8 -0
- package/dist/commands/profiles.js +118 -5
- package/dist/commands/prune.js +39 -160
- package/dist/commands/pull.js +58 -5
- package/dist/commands/routines.js +107 -14
- package/dist/commands/rules.js +8 -4
- package/dist/commands/secrets-migrate.d.ts +24 -0
- package/dist/commands/secrets-migrate.js +198 -0
- package/dist/commands/secrets-sync.d.ts +11 -0
- package/dist/commands/secrets-sync.js +155 -0
- package/dist/commands/secrets.js +79 -46
- package/dist/commands/sessions.d.ts +28 -0
- package/dist/commands/sessions.js +98 -33
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +37 -28
- package/dist/commands/skills.js +25 -8
- package/dist/commands/subagents.js +69 -49
- package/dist/commands/teams.js +61 -10
- package/dist/commands/utils.d.ts +33 -0
- package/dist/commands/utils.js +139 -0
- package/dist/commands/versions.d.ts +4 -3
- package/dist/commands/versions.js +134 -130
- package/dist/commands/view.d.ts +6 -0
- package/dist/commands/view.js +175 -19
- package/dist/commands/workflows.js +29 -6
- package/dist/computer.js +0 -0
- package/dist/index.js +38 -6
- package/dist/lib/acp/client.js +6 -1
- package/dist/lib/acp/harnesses.js +8 -0
- package/dist/lib/agents.d.ts +4 -0
- package/dist/lib/agents.js +125 -34
- package/dist/lib/auto-pull-worker.js +18 -1
- package/dist/lib/browser/cdp.d.ts +8 -1
- package/dist/lib/browser/cdp.js +40 -3
- package/dist/lib/browser/chrome.d.ts +13 -0
- package/dist/lib/browser/chrome.js +46 -3
- package/dist/lib/browser/domain-skills.d.ts +51 -0
- package/dist/lib/browser/domain-skills.js +157 -0
- package/dist/lib/browser/drivers/local.js +45 -4
- package/dist/lib/browser/drivers/ssh.js +2 -2
- package/dist/lib/browser/ipc.d.ts +8 -1
- package/dist/lib/browser/ipc.js +37 -28
- package/dist/lib/browser/profiles.d.ts +16 -3
- package/dist/lib/browser/profiles.js +44 -4
- package/dist/lib/browser/service.d.ts +3 -0
- package/dist/lib/browser/service.js +40 -5
- package/dist/lib/browser/types.d.ts +11 -4
- package/dist/lib/cli-resources.d.ts +137 -0
- package/dist/lib/cli-resources.js +477 -0
- package/dist/lib/cloud/factory.d.ts +1 -1
- package/dist/lib/cloud/factory.js +1 -1
- package/dist/lib/cloud/rush.js +5 -5
- package/dist/lib/command-skills.js +0 -2
- package/dist/lib/computer-rpc.d.ts +3 -0
- package/dist/lib/computer-rpc.js +53 -0
- package/dist/lib/daemon.js +20 -0
- package/dist/lib/events.d.ts +16 -2
- package/dist/lib/events.js +33 -2
- package/dist/lib/exec.d.ts +42 -13
- package/dist/lib/exec.js +127 -33
- package/dist/lib/help.js +11 -5
- package/dist/lib/hooks/cache.d.ts +38 -0
- package/dist/lib/hooks/cache.js +242 -0
- package/dist/lib/hooks/profile.d.ts +33 -0
- package/dist/lib/hooks/profile.js +129 -0
- package/dist/lib/hooks.d.ts +0 -10
- package/dist/lib/hooks.js +246 -11
- package/dist/lib/mcp.d.ts +15 -0
- package/dist/lib/mcp.js +46 -0
- package/dist/lib/migrate.js +1 -1
- package/dist/lib/overdue.d.ts +26 -0
- package/dist/lib/overdue.js +101 -0
- package/dist/lib/permissions.d.ts +13 -0
- package/dist/lib/permissions.js +55 -1
- package/dist/lib/plugin-marketplace.js +1 -1
- package/dist/lib/plugins.js +15 -1
- package/dist/lib/profiles-presets.d.ts +26 -0
- package/dist/lib/profiles-presets.js +216 -0
- package/dist/lib/profiles.d.ts +34 -0
- package/dist/lib/profiles.js +112 -1
- package/dist/lib/resources/mcp.js +37 -0
- package/dist/lib/resources.d.ts +1 -1
- package/dist/lib/rotate.js +10 -4
- package/dist/lib/routines-format.d.ts +47 -0
- package/dist/lib/routines-format.js +194 -0
- package/dist/lib/routines.d.ts +8 -2
- package/dist/lib/routines.js +34 -14
- package/dist/lib/runner.js +83 -15
- package/dist/lib/scheduler.js +8 -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 +1 -9
- package/dist/lib/secrets/bundles.d.ts +34 -17
- package/dist/lib/secrets/bundles.js +210 -36
- package/dist/lib/secrets/index.d.ts +49 -30
- package/dist/lib/secrets/index.js +126 -115
- package/dist/lib/secrets/install-helper.d.ts +45 -0
- package/dist/lib/secrets/install-helper.js +165 -0
- package/dist/lib/secrets/linux.js +4 -4
- package/dist/lib/secrets/sync.d.ts +56 -0
- package/dist/lib/secrets/sync.js +180 -0
- package/dist/lib/session/active.d.ts +8 -0
- package/dist/lib/session/active.js +3 -2
- package/dist/lib/session/db.d.ts +0 -4
- package/dist/lib/session/db.js +0 -26
- package/dist/lib/session/parse.d.ts +1 -0
- package/dist/lib/session/parse.js +44 -0
- package/dist/lib/session/render.js +4 -4
- package/dist/lib/session/types.d.ts +2 -2
- package/dist/lib/session/types.js +1 -1
- package/dist/lib/shims.d.ts +5 -2
- package/dist/lib/shims.js +70 -38
- package/dist/lib/state.d.ts +14 -2
- package/dist/lib/state.js +51 -20
- package/dist/lib/teams/agents.d.ts +5 -4
- package/dist/lib/teams/agents.js +48 -22
- package/dist/lib/teams/api.d.ts +2 -1
- package/dist/lib/teams/api.js +4 -3
- package/dist/lib/teams/parsers.d.ts +1 -1
- package/dist/lib/teams/parsers.js +153 -3
- package/dist/lib/teams/summarizer.js +18 -2
- package/dist/lib/teams/worktree.js +14 -3
- package/dist/lib/types.d.ts +63 -4
- package/dist/lib/types.js +8 -3
- package/dist/lib/usage.d.ts +27 -2
- package/dist/lib/usage.js +100 -17
- package/dist/lib/versions.d.ts +45 -3
- package/dist/lib/versions.js +455 -60
- package/package.json +15 -14
- package/scripts/install-helper.js +97 -0
- package/scripts/postinstall.js +16 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
- package/npm-shrinkwrap.json +0 -3162
|
@@ -14,10 +14,13 @@ import { cloneRepo } from '../lib/git.js';
|
|
|
14
14
|
import { discoverCommands, resolveCommandSource, installCommand, installCommandCentrally, } from '../lib/commands.js';
|
|
15
15
|
import { discoverSkillsFromRepo, installSkill, installSkillCentrally, } from '../lib/skills.js';
|
|
16
16
|
import { discoverHooksFromRepo, installHooks, installHooksCentrally, } from '../lib/hooks.js';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { discoverWorkflowsFromRepo, installWorkflowCentrally, } from '../lib/workflows.js';
|
|
18
|
+
import { discoverSubagentsFromRepo, installSubagentCentrally, } from '../lib/subagents.js';
|
|
19
|
+
import { discoverPermissionsFromRepo, installPermissionSet, } from '../lib/permissions.js';
|
|
20
|
+
import { listInstalledVersions, resolveConfiguredAgentTargets, syncResourcesToVersion, } from '../lib/versions.js';
|
|
21
|
+
import { isInteractiveTerminal, isPromptCancelled, parseCommaSeparatedList, requireDestructiveArg, requireInteractiveSelection, resolveInstalledAgentTargetsAutoInstalling, } from './utils.js';
|
|
19
22
|
import { itemPicker } from '../lib/picker.js';
|
|
20
|
-
import { registerMcpCommandToTargets } from '../lib/mcp.js';
|
|
23
|
+
import { registerMcpCommandToTargets, discoverMcpConfigsFromRepo, installMcpConfigCentrally, } from '../lib/mcp.js';
|
|
21
24
|
export function buildMcpPackageCommand(pkg) {
|
|
22
25
|
const packageName = pkg.name || pkg.registry_name;
|
|
23
26
|
if (pkg.runtime === 'node') {
|
|
@@ -326,6 +329,9 @@ When to use:
|
|
|
326
329
|
.command('install <identifier>')
|
|
327
330
|
.description('Install a package by registry name (mcp:notion), GitHub URL (gh:user/repo), or skill identifier')
|
|
328
331
|
.option('-a, --agents <list>', 'Targets: claude, codex@0.116.0, or gemini@default')
|
|
332
|
+
.option('--types <list>', 'When source is a repo: comma-separated resource types to install (skills,workflows,commands,hooks,permissions,subagents,mcp)')
|
|
333
|
+
.option('--names <list>', 'When source is a repo: comma-separated resource names within the selected types')
|
|
334
|
+
.option('-y, --yes', 'Auto-install any missing agent versions without prompting')
|
|
329
335
|
.addHelpText('after', `
|
|
330
336
|
Install resolves the package type (MCP server, skill, command, hook) and installs to the specified agents. Packages can come from registries (mcp:, skill:), GitHub (gh:user/repo), or direct URLs.
|
|
331
337
|
|
|
@@ -339,6 +345,12 @@ Examples:
|
|
|
339
345
|
# Install using GitHub shorthand
|
|
340
346
|
agents install gh:user/repo --agents claude@2.1.112
|
|
341
347
|
|
|
348
|
+
# Install only specific resource types from a multi-resource repo
|
|
349
|
+
agents install gh:phnx-labs/.agents-system --types skills,workflows --agents claude@all
|
|
350
|
+
|
|
351
|
+
# Install specific resources by name
|
|
352
|
+
agents install gh:phnx-labs/.agents-system --types skills --names animator,composer --agents claude@all
|
|
353
|
+
|
|
342
354
|
# Install to all installed agents (uses defaults or prompts)
|
|
343
355
|
agents install mcp:postgres
|
|
344
356
|
|
|
@@ -399,9 +411,18 @@ When to use:
|
|
|
399
411
|
}
|
|
400
412
|
const cliStates = await getAllCliStates();
|
|
401
413
|
const installedAgents = MCP_CAPABLE_AGENTS.filter((id) => cliStates[id]?.installed || listInstalledVersions(id).length > 0);
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
414
|
+
let targets;
|
|
415
|
+
if (options.agents) {
|
|
416
|
+
const resolved = await resolveInstalledAgentTargetsAutoInstalling(options.agents, MCP_CAPABLE_AGENTS, { yes: options.yes });
|
|
417
|
+
if (!resolved) {
|
|
418
|
+
console.log(chalk.gray('Cancelled.'));
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
targets = resolved;
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
targets = resolveConfiguredAgentTargets(installedAgents, undefined, MCP_CAPABLE_AGENTS);
|
|
425
|
+
}
|
|
405
426
|
if (targets.selectedAgents.length === 0) {
|
|
406
427
|
console.log(chalk.yellow('\nNo MCP-capable agents installed.'));
|
|
407
428
|
process.exit(1);
|
|
@@ -420,38 +441,95 @@ When to use:
|
|
|
420
441
|
console.log(chalk.green('\nMCP server installed.'));
|
|
421
442
|
}
|
|
422
443
|
else if (resolved.type === 'git' || resolved.type === 'skill') {
|
|
423
|
-
// Install from git source
|
|
444
|
+
// Install from git source: sniff every resource type the repo
|
|
445
|
+
// contains. Optional --types narrows which kinds get installed;
|
|
446
|
+
// --names narrows which specific resources within those kinds.
|
|
424
447
|
console.log(chalk.bold(`\nInstalling from ${resolved.source}`));
|
|
425
448
|
const { localPath } = await cloneRepo(resolved.source);
|
|
426
|
-
|
|
427
|
-
const
|
|
428
|
-
const
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
449
|
+
const requestedTypes = new Set(parseCommaSeparatedList(options.types));
|
|
450
|
+
const includeType = (type) => requestedTypes.size === 0 || requestedTypes.has(type);
|
|
451
|
+
const requestedNames = new Set(parseCommaSeparatedList(options.names));
|
|
452
|
+
const nameFilter = (items) => {
|
|
453
|
+
if (requestedNames.size === 0)
|
|
454
|
+
return items;
|
|
455
|
+
return items.filter((item) => requestedNames.has(item.name));
|
|
456
|
+
};
|
|
457
|
+
// Discover everything; filter to requested types up front so the
|
|
458
|
+
// summary table reflects what will actually be installed.
|
|
459
|
+
let commands = includeType('commands') ? discoverCommands(localPath) : [];
|
|
460
|
+
let skills = includeType('skills') ? discoverSkillsFromRepo(localPath) : [];
|
|
461
|
+
let hooks = includeType('hooks') ? discoverHooksFromRepo(localPath) : [];
|
|
462
|
+
let workflows = includeType('workflows') ? discoverWorkflowsFromRepo(localPath) : [];
|
|
463
|
+
let subagents = includeType('subagents') ? discoverSubagentsFromRepo(localPath) : [];
|
|
464
|
+
let permissions = includeType('permissions') ? discoverPermissionsFromRepo(localPath) : [];
|
|
465
|
+
let mcpServers = includeType('mcp') ? discoverMcpConfigsFromRepo(localPath) : [];
|
|
466
|
+
// --names filter applies across every discovered type. If the user
|
|
467
|
+
// typed a name that matched nothing, fail loud so they can fix the
|
|
468
|
+
// typo rather than silently install zero items.
|
|
469
|
+
if (requestedNames.size > 0) {
|
|
470
|
+
const allNames = new Set([
|
|
471
|
+
...commands.map((c) => c.name),
|
|
472
|
+
...skills.map((s) => s.name),
|
|
473
|
+
...hooks,
|
|
474
|
+
...workflows.map((w) => w.name),
|
|
475
|
+
...subagents.map((s) => s.name),
|
|
476
|
+
...permissions.map((p) => p.name),
|
|
477
|
+
...mcpServers.map((s) => s.name),
|
|
478
|
+
]);
|
|
479
|
+
const missing = [...requestedNames].filter((n) => !allNames.has(n));
|
|
480
|
+
if (missing.length > 0) {
|
|
481
|
+
console.log(chalk.red(`\nResource(s) not found in repo: ${missing.join(', ')}`));
|
|
482
|
+
console.log(chalk.gray(`Available: ${[...allNames].sort().join(', ')}`));
|
|
483
|
+
process.exit(1);
|
|
484
|
+
}
|
|
485
|
+
commands = nameFilter(commands);
|
|
486
|
+
skills = nameFilter(skills);
|
|
487
|
+
hooks = hooks.filter((h) => requestedNames.has(h));
|
|
488
|
+
workflows = nameFilter(workflows);
|
|
489
|
+
subagents = nameFilter(subagents);
|
|
490
|
+
permissions = nameFilter(permissions);
|
|
491
|
+
mcpServers = nameFilter(mcpServers);
|
|
492
|
+
}
|
|
493
|
+
const summary = [
|
|
494
|
+
{ kind: 'commands', count: commands.length },
|
|
495
|
+
{ kind: 'skills', count: skills.length },
|
|
496
|
+
{ kind: 'hooks', count: hooks.length },
|
|
497
|
+
{ kind: 'workflows', count: workflows.length },
|
|
498
|
+
{ kind: 'subagents', count: subagents.length },
|
|
499
|
+
{ kind: 'permissions', count: permissions.length },
|
|
500
|
+
{ kind: 'mcp', count: mcpServers.length },
|
|
501
|
+
].filter((s) => s.count > 0);
|
|
502
|
+
if (summary.length === 0) {
|
|
434
503
|
console.log(chalk.yellow('No installable content found in repository.'));
|
|
504
|
+
if (requestedTypes.size > 0 || requestedNames.size > 0) {
|
|
505
|
+
console.log(chalk.gray('Try removing --types/--names to see everything the repo offers.'));
|
|
506
|
+
}
|
|
435
507
|
process.exit(1);
|
|
436
508
|
}
|
|
437
509
|
console.log(chalk.bold('\nFound:'));
|
|
438
|
-
|
|
439
|
-
console.log(` ${
|
|
440
|
-
|
|
441
|
-
console.log(` ${skills.length} skills`);
|
|
442
|
-
if (hasHooks)
|
|
443
|
-
console.log(` ${hooks.length} hooks`);
|
|
510
|
+
for (const { kind, count } of summary) {
|
|
511
|
+
console.log(` ${count} ${kind}`);
|
|
512
|
+
}
|
|
444
513
|
const gitCliStates = await getAllCliStates();
|
|
445
514
|
const installedAgents = ALL_AGENT_IDS.filter((id) => gitCliStates[id]?.installed || listInstalledVersions(id).length > 0);
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
515
|
+
let targets;
|
|
516
|
+
if (options.agents) {
|
|
517
|
+
const resolved = await resolveInstalledAgentTargetsAutoInstalling(options.agents, ALL_AGENT_IDS, { yes: options.yes });
|
|
518
|
+
if (!resolved) {
|
|
519
|
+
console.log(chalk.gray('Cancelled.'));
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
targets = resolved;
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
targets = resolveConfiguredAgentTargets(installedAgents, undefined, ALL_AGENT_IDS);
|
|
526
|
+
}
|
|
449
527
|
if (targets.selectedAgents.length === 0) {
|
|
450
528
|
console.log(chalk.yellow('\nNo agents selected.'));
|
|
451
529
|
return;
|
|
452
530
|
}
|
|
453
531
|
// Install commands
|
|
454
|
-
if (
|
|
532
|
+
if (commands.length > 0) {
|
|
455
533
|
console.log(chalk.bold('\nInstalling commands...'));
|
|
456
534
|
let directInstalled = 0;
|
|
457
535
|
let syncedVersions = 0;
|
|
@@ -495,7 +573,7 @@ When to use:
|
|
|
495
573
|
}
|
|
496
574
|
}
|
|
497
575
|
// Install skills
|
|
498
|
-
if (
|
|
576
|
+
if (skills.length > 0) {
|
|
499
577
|
console.log(chalk.bold('\nInstalling skills...'));
|
|
500
578
|
const directAgents = targets.directAgents.filter((agentId) => AGENTS[agentId].capabilities.skills && gitCliStates[agentId]?.installed);
|
|
501
579
|
let syncedVersions = 0;
|
|
@@ -522,7 +600,7 @@ When to use:
|
|
|
522
600
|
console.log(` Synced skills to ${syncedVersions} managed version(s)`);
|
|
523
601
|
}
|
|
524
602
|
// Install hooks
|
|
525
|
-
if (
|
|
603
|
+
if (hooks.length > 0) {
|
|
526
604
|
console.log(chalk.bold('\nInstalling hooks...'));
|
|
527
605
|
let syncedVersions = 0;
|
|
528
606
|
const directHookAgents = targets.directAgents.filter((id) => AGENTS[id].supportsHooks && gitCliStates[id]?.installed);
|
|
@@ -543,6 +621,97 @@ When to use:
|
|
|
543
621
|
}
|
|
544
622
|
console.log(` Synced hooks to ${syncedVersions} managed version(s)`);
|
|
545
623
|
}
|
|
624
|
+
// Install workflows
|
|
625
|
+
if (workflows.length > 0) {
|
|
626
|
+
console.log(chalk.bold('\nInstalling workflows...'));
|
|
627
|
+
let installed = 0;
|
|
628
|
+
for (const w of workflows) {
|
|
629
|
+
const result = installWorkflowCentrally(w.path, w.name);
|
|
630
|
+
if (result.success) {
|
|
631
|
+
installed++;
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
console.log(` ${chalk.red('x')} ${w.name}: ${result.error}`);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
const workflowNames = workflows.map((w) => w.name);
|
|
638
|
+
let syncedVersions = 0;
|
|
639
|
+
for (const [agentId, versions] of targets.versionSelections) {
|
|
640
|
+
for (const version of versions) {
|
|
641
|
+
const result = syncResourcesToVersion(agentId, version, { workflows: workflowNames });
|
|
642
|
+
if (result.workflows.length > 0)
|
|
643
|
+
syncedVersions++;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
console.log(` Installed ${installed} workflow(s) to ~/.agents/workflows/`);
|
|
647
|
+
console.log(` Synced workflows to ${syncedVersions} managed version(s)`);
|
|
648
|
+
}
|
|
649
|
+
// Install subagents
|
|
650
|
+
if (subagents.length > 0) {
|
|
651
|
+
console.log(chalk.bold('\nInstalling subagents...'));
|
|
652
|
+
let installed = 0;
|
|
653
|
+
for (const s of subagents) {
|
|
654
|
+
const result = installSubagentCentrally(s.path, s.name);
|
|
655
|
+
if (result.success) {
|
|
656
|
+
installed++;
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
console.log(` ${chalk.red('x')} ${s.name}: ${result.error}`);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
const subagentNames = subagents.map((s) => s.name);
|
|
663
|
+
let syncedVersions = 0;
|
|
664
|
+
for (const [agentId, versions] of targets.versionSelections) {
|
|
665
|
+
for (const version of versions) {
|
|
666
|
+
const result = syncResourcesToVersion(agentId, version, { subagents: subagentNames });
|
|
667
|
+
if (result.subagents.length > 0)
|
|
668
|
+
syncedVersions++;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
console.log(` Installed ${installed} subagent(s) to ~/.agents/subagents/`);
|
|
672
|
+
console.log(` Synced subagents to ${syncedVersions} managed version(s)`);
|
|
673
|
+
}
|
|
674
|
+
// Install permissions
|
|
675
|
+
if (permissions.length > 0) {
|
|
676
|
+
console.log(chalk.bold('\nInstalling permission sets...'));
|
|
677
|
+
let installed = 0;
|
|
678
|
+
for (const p of permissions) {
|
|
679
|
+
const result = installPermissionSet(p.path, p.name);
|
|
680
|
+
if (result.success) {
|
|
681
|
+
installed++;
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
console.log(` ${chalk.red('x')} ${p.name}: ${result.error}`);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
console.log(` Installed ${installed} permission set(s) to ~/.agents/permissions/`);
|
|
688
|
+
console.log(chalk.gray(' Apply with: agents permissions apply <name> --agents <selector>'));
|
|
689
|
+
}
|
|
690
|
+
// Install MCP server configs
|
|
691
|
+
if (mcpServers.length > 0) {
|
|
692
|
+
console.log(chalk.bold('\nInstalling MCP server configs...'));
|
|
693
|
+
let installed = 0;
|
|
694
|
+
for (const s of mcpServers) {
|
|
695
|
+
const result = installMcpConfigCentrally(s.path);
|
|
696
|
+
if (result.success) {
|
|
697
|
+
installed++;
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
console.log(` ${chalk.red('x')} ${s.name}: ${result.error}`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
const mcpNames = mcpServers.map((s) => s.name);
|
|
704
|
+
let syncedVersions = 0;
|
|
705
|
+
for (const [agentId, versions] of targets.versionSelections) {
|
|
706
|
+
for (const version of versions) {
|
|
707
|
+
const result = syncResourcesToVersion(agentId, version, { mcp: mcpNames });
|
|
708
|
+
if (result.mcp.length > 0)
|
|
709
|
+
syncedVersions++;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
console.log(` Installed ${installed} MCP config(s) to ~/.agents/mcp/`);
|
|
713
|
+
console.log(` Synced MCP configs to ${syncedVersions} managed version(s)`);
|
|
714
|
+
}
|
|
546
715
|
console.log(chalk.green('\nPackage installed.'));
|
|
547
716
|
}
|
|
548
717
|
}
|
|
@@ -7,9 +7,9 @@ import { confirm, checkbox } from '@inquirer/prompts';
|
|
|
7
7
|
import { AGENTS, resolveAgentName, formatAgentError, agentLabel, } from '../lib/agents.js';
|
|
8
8
|
import { cloneRepo } from '../lib/git.js';
|
|
9
9
|
import { PERMISSIONS_CAPABLE_AGENTS, listInstalledPermissions, discoverPermissionsFromRepo, installPermissionSet, removePermissionSet, applyPermissionsToVersion, readAgentPermissions, exportPermissionsFromPath, getDefaultPermissionSet, computePermissionsDiff, mergePermissionSets, saveDefaultPermissionSet, containsBroadGrants, } from '../lib/permissions.js';
|
|
10
|
-
import { listInstalledVersions, getGlobalDefault, getVersionHomePath, promptAgentVersionSelection,
|
|
10
|
+
import { listInstalledVersions, getGlobalDefault, getVersionHomePath, promptAgentVersionSelection, resolveVersionAlias, } from '../lib/versions.js';
|
|
11
11
|
import { recordVersionResources } from '../lib/state.js';
|
|
12
|
-
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, } from './utils.js';
|
|
12
|
+
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, resolveAgentTargetsAutoInstalling, } from './utils.js';
|
|
13
13
|
export function shouldRefuseBroadPermissions(permissions, allowBroadPermissions) {
|
|
14
14
|
return !allowBroadPermissions && permissions.some((perm) => containsBroadGrants(perm.set) !== null);
|
|
15
15
|
}
|
|
@@ -279,9 +279,14 @@ Examples:
|
|
|
279
279
|
let selectedAgents;
|
|
280
280
|
let versionSelections;
|
|
281
281
|
if (options.agents) {
|
|
282
|
-
const result =
|
|
282
|
+
const result = await resolveAgentTargetsAutoInstalling(options.agents, PERMISSIONS_CAPABLE_AGENTS, {
|
|
283
|
+
yes: options.yes,
|
|
283
284
|
allVersions: options.all,
|
|
284
285
|
});
|
|
286
|
+
if (!result) {
|
|
287
|
+
console.log(chalk.gray('Cancelled.'));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
285
290
|
selectedAgents = result.selectedAgents;
|
|
286
291
|
versionSelections = result.versionSelections;
|
|
287
292
|
}
|
|
@@ -296,7 +301,7 @@ Examples:
|
|
|
296
301
|
}
|
|
297
302
|
}
|
|
298
303
|
else {
|
|
299
|
-
const result = await promptAgentVersionSelection(PERMISSIONS_CAPABLE_AGENTS, { skipPrompts });
|
|
304
|
+
const result = await promptAgentVersionSelection(PERMISSIONS_CAPABLE_AGENTS, { skipPrompts: options.yes });
|
|
300
305
|
selectedAgents = result.selectedAgents;
|
|
301
306
|
versionSelections = result.versionSelections;
|
|
302
307
|
}
|
|
@@ -412,9 +417,14 @@ Examples:
|
|
|
412
417
|
let selectedAgents;
|
|
413
418
|
let versionSelections;
|
|
414
419
|
if (options.agents) {
|
|
415
|
-
const result =
|
|
420
|
+
const result = await resolveAgentTargetsAutoInstalling(options.agents, PERMISSIONS_CAPABLE_AGENTS, {
|
|
421
|
+
yes: options.yes,
|
|
416
422
|
allVersions: options.all,
|
|
417
423
|
});
|
|
424
|
+
if (!result) {
|
|
425
|
+
console.log(chalk.gray('Cancelled.'));
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
418
428
|
selectedAgents = result.selectedAgents;
|
|
419
429
|
versionSelections = result.versionSelections;
|
|
420
430
|
}
|
|
@@ -537,9 +547,14 @@ Examples:
|
|
|
537
547
|
let selectedAgents;
|
|
538
548
|
let versionSelections;
|
|
539
549
|
if (options.agents) {
|
|
540
|
-
const result =
|
|
550
|
+
const result = await resolveAgentTargetsAutoInstalling(options.agents, PERMISSIONS_CAPABLE_AGENTS, {
|
|
551
|
+
yes: options.yes,
|
|
541
552
|
allVersions: options.all,
|
|
542
553
|
});
|
|
554
|
+
if (!result) {
|
|
555
|
+
console.log(chalk.gray('Cancelled.'));
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
543
558
|
selectedAgents = result.selectedAgents;
|
|
544
559
|
versionSelections = result.versionSelections;
|
|
545
560
|
}
|
package/dist/commands/plugins.js
CHANGED
|
@@ -237,6 +237,7 @@ Examples:
|
|
|
237
237
|
pluginsCmd
|
|
238
238
|
.command('sync <name> [agent]')
|
|
239
239
|
.description('Apply a plugin to the default version of an agent (or all supported agents if none specified)')
|
|
240
|
+
.option('--allow-exec-surfaces', 'Enable the plugin even when it ships hooks/, .mcp.json, bin/, scripts/, settings.json, or permissions/')
|
|
240
241
|
.addHelpText('after', `
|
|
241
242
|
Examples:
|
|
242
243
|
# Sync a plugin to a specific agent (default version)
|
|
@@ -244,8 +245,11 @@ Examples:
|
|
|
244
245
|
|
|
245
246
|
# Sync to all supported agents
|
|
246
247
|
agents plugins sync rush-toolkit
|
|
248
|
+
|
|
249
|
+
# Re-affirm consent for a hooks-bearing plugin
|
|
250
|
+
agents plugins sync hivemind claude --allow-exec-surfaces
|
|
247
251
|
`)
|
|
248
|
-
.action(async (name, agentArg) => {
|
|
252
|
+
.action(async (name, agentArg, options) => {
|
|
249
253
|
const plugin = getPlugin(name);
|
|
250
254
|
if (!plugin) {
|
|
251
255
|
console.log(chalk.red(`Plugin '${name}' not found`));
|
|
@@ -268,6 +272,7 @@ Examples:
|
|
|
268
272
|
else {
|
|
269
273
|
targetAgents = PLUGINS_CAPABLE_AGENTS.filter(a => pluginSupportsAgent(plugin, a));
|
|
270
274
|
}
|
|
275
|
+
const allowExec = options.allowExecSurfaces === true;
|
|
271
276
|
for (const agentId of targetAgents) {
|
|
272
277
|
const versions = listInstalledVersions(agentId);
|
|
273
278
|
if (versions.length === 0)
|
|
@@ -275,9 +280,11 @@ Examples:
|
|
|
275
280
|
const defaultVer = getGlobalDefault(agentId);
|
|
276
281
|
const targetVersions = defaultVer ? [defaultVer] : [versions[versions.length - 1]];
|
|
277
282
|
for (const version of targetVersions) {
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
283
|
+
const didSync = allowExec
|
|
284
|
+
? syncPluginToVersion(plugin, agentId, getVersionHomePath(agentId, version), { allowExecSurfaces: true, version }).success
|
|
285
|
+
: syncResourcesToVersion(agentId, version, { plugins: [name] }).plugins.length > 0;
|
|
286
|
+
if (didSync) {
|
|
287
|
+
console.log(chalk.green(`Synced ${name} to ${agentLabel(agentId)}@${version}${allowExec ? ' (exec surfaces enabled)' : ''}`));
|
|
281
288
|
}
|
|
282
289
|
else {
|
|
283
290
|
console.log(chalk.gray(`${name} already synced to ${agentLabel(agentId)}@${version}`));
|
|
@@ -7,5 +7,13 @@
|
|
|
7
7
|
* through a standard agent CLI with no local proxy.
|
|
8
8
|
*/
|
|
9
9
|
import type { Command } from 'commander';
|
|
10
|
+
import { type Profile } from '../lib/profiles.js';
|
|
11
|
+
import { type Preset } from '../lib/profiles-presets.js';
|
|
12
|
+
/**
|
|
13
|
+
* Pure helper: builds a Profile from collected wizard inputs. Extracted so the
|
|
14
|
+
* shape of preset->profile mapping for the `create` wizard is unit-testable
|
|
15
|
+
* without mocking @inquirer/prompts.
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildProfileFromCollection(name: string, preset: Preset, collected: Record<string, string>, version?: string): Profile;
|
|
10
18
|
/** Register the `agents profiles` command tree. */
|
|
11
19
|
export declare function registerProfilesCommands(program: Command): void;
|
|
@@ -8,10 +8,30 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import chalk from 'chalk';
|
|
10
10
|
import * as fs from 'fs';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { spawn } from 'child_process';
|
|
12
|
+
import { listProfiles, readProfile, writeProfile, deleteProfile, profileExists, profileFromPreset, validateProfileName, getPresetForProfile, } from '../lib/profiles.js';
|
|
13
|
+
import { getPreset, listPresets, expandPreset } from '../lib/profiles-presets.js';
|
|
13
14
|
import { hasKeychainToken, keychainItemName, setKeychainToken, deleteKeychainToken, } from '../lib/secrets/profiles.js';
|
|
14
15
|
import { isInteractiveTerminal } from './utils.js';
|
|
16
|
+
/**
|
|
17
|
+
* Pure helper: builds a Profile from collected wizard inputs. Extracted so the
|
|
18
|
+
* shape of preset->profile mapping for the `create` wizard is unit-testable
|
|
19
|
+
* without mocking @inquirer/prompts.
|
|
20
|
+
*/
|
|
21
|
+
export function buildProfileFromCollection(name, preset, collected, version) {
|
|
22
|
+
return {
|
|
23
|
+
name,
|
|
24
|
+
host: { agent: preset.host, version },
|
|
25
|
+
env: { ...preset.env, ...collected },
|
|
26
|
+
auth: {
|
|
27
|
+
envVar: preset.authEnvVar,
|
|
28
|
+
keychainItem: keychainItemName(preset.provider),
|
|
29
|
+
},
|
|
30
|
+
description: preset.description,
|
|
31
|
+
preset: preset.name,
|
|
32
|
+
provider: preset.provider,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
15
35
|
/** Prompt the user for a secret value with masked input. Requires an interactive TTY. */
|
|
16
36
|
async function promptForSecret(message) {
|
|
17
37
|
if (!isInteractiveTerminal()) {
|
|
@@ -86,7 +106,8 @@ Built-in presets (via OpenRouter, one shared key):
|
|
|
86
106
|
Run 'agents profiles presets' for the full list with pricing and context sizes.
|
|
87
107
|
|
|
88
108
|
Typical flow:
|
|
89
|
-
agents profiles
|
|
109
|
+
agents profiles create # interactive wizard for any provider
|
|
110
|
+
agents profiles add kimi # one-line preset (existing)
|
|
90
111
|
agents run kimi "refactor this" # Claude Code UI, Kimi model responses
|
|
91
112
|
agents profiles add deepseek # reuses OpenRouter key, no re-prompt
|
|
92
113
|
|
|
@@ -116,7 +137,7 @@ Examples:
|
|
|
116
137
|
|
|
117
138
|
# Add MiniMax for SWE-bench style fixes; reuses the same OpenRouter key
|
|
118
139
|
agents profiles add minimax
|
|
119
|
-
agents run minimax "investigate
|
|
140
|
+
agents run minimax "investigate PROJ-456 and patch the off-by-one in pagination"
|
|
120
141
|
|
|
121
142
|
# Add DeepSeek for cheap, fast non-reasoning work
|
|
122
143
|
agents profiles add deepseek
|
|
@@ -202,6 +223,96 @@ Examples:
|
|
|
202
223
|
process.exit(1);
|
|
203
224
|
}
|
|
204
225
|
});
|
|
226
|
+
cmd
|
|
227
|
+
.command('create')
|
|
228
|
+
.description('Interactive profile creation wizard (any provider, with prompts for endpoints + keys).')
|
|
229
|
+
.option('--name <name>', 'Profile name (skips the name prompt)')
|
|
230
|
+
.option('--provider <provider>', 'Provider preset name (skips the provider prompt)')
|
|
231
|
+
.option('--no-smoke-test', 'Skip the post-create smoke test prompt')
|
|
232
|
+
.action(async (opts) => {
|
|
233
|
+
if (!isInteractiveTerminal()) {
|
|
234
|
+
console.error(chalk.red('agents profiles create requires an interactive terminal. Use `agents profiles add <preset>` for scriptable creation.'));
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
const { input, select, confirm } = await import('@inquirer/prompts');
|
|
238
|
+
const name = opts.name
|
|
239
|
+
? opts.name
|
|
240
|
+
: await input({
|
|
241
|
+
message: 'Profile name',
|
|
242
|
+
validate: (v) => /^[a-z0-9][a-z0-9-_]{0,48}$/i.test(v) || 'lowercase alphanumeric + -_ only, max 48 chars',
|
|
243
|
+
});
|
|
244
|
+
validateProfileName(name);
|
|
245
|
+
if (profileExists(name)) {
|
|
246
|
+
const overwrite = await confirm({
|
|
247
|
+
message: `Profile '${name}' already exists. Overwrite?`,
|
|
248
|
+
default: false,
|
|
249
|
+
});
|
|
250
|
+
if (!overwrite) {
|
|
251
|
+
console.log(chalk.gray('Cancelled.'));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const presets = listPresets();
|
|
256
|
+
const providerName = opts.provider
|
|
257
|
+
? opts.provider
|
|
258
|
+
: await select({
|
|
259
|
+
message: 'Provider',
|
|
260
|
+
choices: presets.map((p) => ({
|
|
261
|
+
name: `${p.name.padEnd(18)} ${chalk.gray(p.description.slice(0, 70))}`,
|
|
262
|
+
value: p.name,
|
|
263
|
+
})),
|
|
264
|
+
});
|
|
265
|
+
const preset = getPreset(providerName);
|
|
266
|
+
if (!preset) {
|
|
267
|
+
console.error(chalk.red(`Unknown provider '${providerName}'. Run 'agents profiles presets' for the list.`));
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
const expanded = expandPreset(preset);
|
|
271
|
+
const collected = {};
|
|
272
|
+
for (const v of expanded.prompts) {
|
|
273
|
+
if (v.secret) {
|
|
274
|
+
collected[v.envVar] = await promptForSecret(v.prompt);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const value = await input({
|
|
278
|
+
message: v.hint ? `${v.prompt} ${chalk.gray('(' + v.hint + ')')}` : v.prompt,
|
|
279
|
+
default: v.default,
|
|
280
|
+
validate: v.pattern
|
|
281
|
+
? (val) => new RegExp(v.pattern).test(val) || `must match ${v.pattern}`
|
|
282
|
+
: undefined,
|
|
283
|
+
});
|
|
284
|
+
collected[v.envVar] = value;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (!preset.authOptional) {
|
|
288
|
+
await ensureProviderToken(preset.provider, preset.signupUrl);
|
|
289
|
+
}
|
|
290
|
+
const profile = buildProfileFromCollection(name, preset, collected);
|
|
291
|
+
writeProfile(profile);
|
|
292
|
+
console.log(chalk.green(`Profile '${name}' created.`));
|
|
293
|
+
if (preset.docPath) {
|
|
294
|
+
console.log(chalk.gray(`See docs/profiles/${preset.docPath}.md for provider-specific caveats.`));
|
|
295
|
+
}
|
|
296
|
+
if (opts.smokeTest !== false) {
|
|
297
|
+
const run = await confirm({ message: 'Run smoke test now?', default: true });
|
|
298
|
+
if (run) {
|
|
299
|
+
console.log(chalk.gray(`Spawning: agents run ${name} "say alive in one word" (60s timeout)`));
|
|
300
|
+
const child = spawn(process.argv[0], [
|
|
301
|
+
process.argv[1],
|
|
302
|
+
'run',
|
|
303
|
+
name,
|
|
304
|
+
'say alive in one word',
|
|
305
|
+
'--headless',
|
|
306
|
+
'--timeout',
|
|
307
|
+
'60s',
|
|
308
|
+
], { stdio: 'inherit' });
|
|
309
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
console.log(chalk.gray(`Try later: agents run ${name} "hello"`));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
});
|
|
205
316
|
cmd
|
|
206
317
|
.command('add <name>')
|
|
207
318
|
.description('Add a profile. If <name> matches a built-in preset, the preset is applied. Prompts for API key (once per provider).')
|
|
@@ -223,7 +334,9 @@ Examples:
|
|
|
223
334
|
console.error(chalk.gray('Or pass --preset <name> to pick explicitly.'));
|
|
224
335
|
process.exit(1);
|
|
225
336
|
}
|
|
226
|
-
|
|
337
|
+
if (!preset.authOptional) {
|
|
338
|
+
await ensureProviderToken(preset.provider, preset.signupUrl, opts.keyStdin);
|
|
339
|
+
}
|
|
227
340
|
const profile = profileFromPreset(name, preset, opts.version);
|
|
228
341
|
writeProfile(profile);
|
|
229
342
|
console.log(chalk.green(`Profile '${name}' added.`));
|