@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
package/dist/commands/skills.js
CHANGED
|
@@ -7,9 +7,9 @@ import { select, checkbox } from '@inquirer/prompts';
|
|
|
7
7
|
import { AGENTS, SKILLS_CAPABLE_AGENTS, resolveAgentName, formatAgentError, agentLabel, } from '../lib/agents.js';
|
|
8
8
|
import { cloneRepo } from '../lib/git.js';
|
|
9
9
|
import { discoverSkillsFromRepo, installSkillCentrally, listInstalledSkills, listInstalledSkillsWithScope, getSkillInfo, getSkillRules, getSkillsDir, countSkillFiles, tryParseSkillMetadata, diffVersionSkills, iterSkillsCapableVersions, removeSkillFromVersion, } from '../lib/skills.js';
|
|
10
|
-
import { getGlobalDefault, resolveVersionAlias, syncResourcesToVersion, promptAgentVersionSelection, getVersionHomePath,
|
|
10
|
+
import { getGlobalDefault, resolveVersionAlias, syncResourcesToVersion, promptAgentVersionSelection, getVersionHomePath, } from '../lib/versions.js';
|
|
11
11
|
import { recordVersionResources } from '../lib/state.js';
|
|
12
|
-
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, promptRemovalTargets, } from './utils.js';
|
|
12
|
+
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, resolveAgentTargetsAutoInstalling, promptRemovalTargets, } from './utils.js';
|
|
13
13
|
import { showResourceList, buildTargetsSection, } from './resource-view.js';
|
|
14
14
|
/** Register the `agents skills` command tree (list, add, remove, sync, prune, view). */
|
|
15
15
|
export function registerSkillsCommands(program) {
|
|
@@ -202,11 +202,24 @@ Examples:
|
|
|
202
202
|
spinner.succeed('Using local path');
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
|
-
console.log(chalk.bold(`\nFound ${discoveredSkills.length} skill(s):`));
|
|
206
205
|
if (discoveredSkills.length === 0) {
|
|
207
206
|
console.log(chalk.yellow('No skills found (looking for SKILL.md files)'));
|
|
208
207
|
return;
|
|
209
208
|
}
|
|
209
|
+
// Filter by --names if provided. Mirrors the no-source path's behavior
|
|
210
|
+
// so users can pluck specific skills from a multi-skill repo.
|
|
211
|
+
const requestedNames = parseCommaSeparatedList(options.names);
|
|
212
|
+
if (requestedNames.length > 0) {
|
|
213
|
+
const discoveredNames = new Set(discoveredSkills.map((s) => s.name));
|
|
214
|
+
const missing = requestedNames.filter((n) => !discoveredNames.has(n));
|
|
215
|
+
if (missing.length > 0) {
|
|
216
|
+
console.log(chalk.red(`\nSkill(s) not found in source: ${missing.join(', ')}`));
|
|
217
|
+
console.log(chalk.gray(`Available: ${[...discoveredNames].join(', ')}`));
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
discoveredSkills = discoveredSkills.filter((s) => requestedNames.includes(s.name));
|
|
221
|
+
}
|
|
222
|
+
console.log(chalk.bold(`\nFound ${discoveredSkills.length} skill(s):`));
|
|
210
223
|
for (const skill of discoveredSkills) {
|
|
211
224
|
const nameColor = skill.parseError ? chalk.yellow : chalk.cyan;
|
|
212
225
|
console.log(`\n ${nameColor(skill.name)}: ${skill.metadata.description || 'no description'}`);
|
|
@@ -238,13 +251,17 @@ Examples:
|
|
|
238
251
|
let selectedAgents;
|
|
239
252
|
let versionSelections;
|
|
240
253
|
if (options.agents) {
|
|
241
|
-
const result =
|
|
254
|
+
const result = await resolveAgentTargetsAutoInstalling(options.agents, SKILLS_CAPABLE_AGENTS, { yes: options.yes });
|
|
255
|
+
if (!result) {
|
|
256
|
+
console.log(chalk.gray('Cancelled.'));
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
242
259
|
selectedAgents = result.selectedAgents;
|
|
243
260
|
versionSelections = result.versionSelections;
|
|
244
261
|
}
|
|
245
262
|
else {
|
|
246
263
|
const result = await promptAgentVersionSelection(SKILLS_CAPABLE_AGENTS, {
|
|
247
|
-
skipPrompts: options.yes
|
|
264
|
+
skipPrompts: options.yes,
|
|
248
265
|
});
|
|
249
266
|
selectedAgents = result.selectedAgents;
|
|
250
267
|
versionSelections = result.versionSelections;
|
|
@@ -394,17 +411,17 @@ Examples:
|
|
|
394
411
|
.action(() => {
|
|
395
412
|
console.error(chalk.red('"agents skills sync" is gone.'));
|
|
396
413
|
console.error(chalk.gray('Sync runs automatically when you launch the agent.'));
|
|
397
|
-
console.error(chalk.gray('To remove orphans, use: agents prune skills'));
|
|
414
|
+
console.error(chalk.gray('To remove orphans, use: agents prune cleanup skills'));
|
|
398
415
|
process.exit(1);
|
|
399
416
|
});
|
|
400
|
-
// `skills prune` moved to the top-level `agents prune` command.
|
|
417
|
+
// `skills prune` moved to the top-level `agents prune cleanup` command.
|
|
401
418
|
skillsCmd
|
|
402
419
|
.command('prune', { hidden: true })
|
|
403
420
|
.allowUnknownOption()
|
|
404
421
|
.allowExcessArguments()
|
|
405
422
|
.action(() => {
|
|
406
423
|
console.error(chalk.red('"agents skills prune" moved.'));
|
|
407
|
-
console.error(chalk.gray('Use: agents prune skills (or `agents prune` for everything)'));
|
|
424
|
+
console.error(chalk.gray('Use: agents prune cleanup skills (or `agents prune cleanup` for everything)'));
|
|
408
425
|
process.exit(1);
|
|
409
426
|
});
|
|
410
427
|
skillsCmd
|
|
@@ -9,13 +9,12 @@ import chalk from 'chalk';
|
|
|
9
9
|
import ora from 'ora';
|
|
10
10
|
import * as fs from 'fs';
|
|
11
11
|
import * as path from 'path';
|
|
12
|
-
import {
|
|
13
|
-
import { AGENTS, agentLabel } from '../lib/agents.js';
|
|
12
|
+
import { agentLabel } from '../lib/agents.js';
|
|
14
13
|
import { cloneRepo } from '../lib/git.js';
|
|
15
14
|
import { discoverSubagentsFromRepo, installSubagentCentrally, listInstalledSubagents, getInstalledSubagent, listSubagentsForAgent, SUBAGENT_CAPABLE_AGENTS, iterSubagentsCapableVersions, removeSubagentFromVersion, } from '../lib/subagents.js';
|
|
16
|
-
import { listInstalledVersions, syncResourcesToVersion, getGlobalDefault, getVersionHomePath, } from '../lib/versions.js';
|
|
17
|
-
import { getSubagentsDir } from '../lib/state.js';
|
|
18
|
-
import {
|
|
15
|
+
import { listInstalledVersions, syncResourcesToVersion, getGlobalDefault, getVersionHomePath, promptAgentVersionSelection, } from '../lib/versions.js';
|
|
16
|
+
import { getSubagentsDir, recordVersionResources } from '../lib/state.js';
|
|
17
|
+
import { requireDestructiveArg, promptRemovalTargets, parseCommaSeparatedList, resolveAgentTargetsAutoInstalling, } from './utils.js';
|
|
19
18
|
import { showResourceList, buildTargetsSection, } from './resource-view.js';
|
|
20
19
|
/** Replace the home directory prefix with ~ for display. */
|
|
21
20
|
function formatPath(p) {
|
|
@@ -102,13 +101,20 @@ Examples:
|
|
|
102
101
|
subagentsCmd
|
|
103
102
|
.command('add <source>')
|
|
104
103
|
.description('Install subagents from a source (GitHub, local path) and sync to agent versions')
|
|
105
|
-
.option('-a, --agents <
|
|
104
|
+
.option('-a, --agents <list>', 'Targets: claude, openclaw, claude@2.1.141, claude@all, all')
|
|
105
|
+
.option('--names <list>', 'Subagent names from the source (comma-separated)')
|
|
106
106
|
.option('-y, --yes', 'Skip all prompts and confirmations')
|
|
107
107
|
.addHelpText('after', `
|
|
108
108
|
Examples:
|
|
109
109
|
# Install from GitHub
|
|
110
110
|
agents subagents add gh:team/subagents --agents claude,openclaw
|
|
111
111
|
|
|
112
|
+
# Pluck specific subagents from a multi-subagent repo
|
|
113
|
+
agents subagents add gh:team/subagents --names code-reviewer,planner
|
|
114
|
+
|
|
115
|
+
# Install across every installed Claude version
|
|
116
|
+
agents subagents add gh:team/subagents --agents claude@all
|
|
117
|
+
|
|
112
118
|
# Install from local directory (must contain subagents/*/AGENT.md)
|
|
113
119
|
agents subagents add ~/my-subagent --agents claude
|
|
114
120
|
|
|
@@ -117,9 +123,13 @@ Examples:
|
|
|
117
123
|
`)
|
|
118
124
|
.action(async (source, options) => {
|
|
119
125
|
const spinner = ora({ text: 'Fetching source...', isSilent: !process.stdout.isTTY }).start();
|
|
120
|
-
// Clone or use local source
|
|
126
|
+
// Clone or use local source. Accept any git-like scheme to match the
|
|
127
|
+
// other <resource> add commands (skills, workflows, commands, hooks).
|
|
121
128
|
let sourcePath;
|
|
122
|
-
|
|
129
|
+
const isGitRepo = source.startsWith('gh:') || source.startsWith('git:') ||
|
|
130
|
+
source.startsWith('ssh:') || source.startsWith('https://') ||
|
|
131
|
+
source.startsWith('http://');
|
|
132
|
+
if (isGitRepo) {
|
|
123
133
|
try {
|
|
124
134
|
const cloneResult = await cloneRepo(source);
|
|
125
135
|
sourcePath = cloneResult.localPath;
|
|
@@ -138,12 +148,24 @@ Examples:
|
|
|
138
148
|
}
|
|
139
149
|
// Discover subagents
|
|
140
150
|
spinner.text = 'Discovering subagents...';
|
|
141
|
-
|
|
151
|
+
let discovered = discoverSubagentsFromRepo(sourcePath);
|
|
142
152
|
if (discovered.length === 0) {
|
|
143
153
|
spinner.fail('No subagents found in source');
|
|
144
154
|
console.log(chalk.gray(`Expected: subagents/*/AGENT.md`));
|
|
145
155
|
process.exit(1);
|
|
146
156
|
}
|
|
157
|
+
// --names filter: pluck specific subagents from a multi-subagent source.
|
|
158
|
+
const requestedNames = parseCommaSeparatedList(options.names);
|
|
159
|
+
if (requestedNames.length > 0) {
|
|
160
|
+
const discoveredNames = new Set(discovered.map((s) => s.name));
|
|
161
|
+
const missing = requestedNames.filter((n) => !discoveredNames.has(n));
|
|
162
|
+
if (missing.length > 0) {
|
|
163
|
+
spinner.fail(`Subagent(s) not found in source: ${missing.join(', ')}`);
|
|
164
|
+
console.log(chalk.gray(`Available: ${[...discoveredNames].join(', ')}`));
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
discovered = discovered.filter((s) => requestedNames.includes(s.name));
|
|
168
|
+
}
|
|
147
169
|
spinner.succeed(`Found ${discovered.length} subagent(s)`);
|
|
148
170
|
// Show what we found
|
|
149
171
|
console.log();
|
|
@@ -151,42 +173,29 @@ Examples:
|
|
|
151
173
|
console.log(` ${chalk.cyan(sub.name)}: ${chalk.gray(sub.frontmatter.description)}`);
|
|
152
174
|
}
|
|
153
175
|
console.log();
|
|
154
|
-
// Determine target
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
else {
|
|
168
|
-
if (!isInteractiveTerminal()) {
|
|
169
|
-
requireInteractiveSelection('Selecting target agents for subagents', [
|
|
170
|
-
'agents subagents add <source> --agents claude openclaw',
|
|
171
|
-
'agents subagents add <source> --yes',
|
|
172
|
-
]);
|
|
173
|
-
}
|
|
174
|
-
try {
|
|
175
|
-
targetAgents = await checkbox({
|
|
176
|
-
message: 'Install to which agents?',
|
|
177
|
-
choices: installedAgents.map(id => ({
|
|
178
|
-
name: AGENTS[id].name,
|
|
179
|
-
value: id,
|
|
180
|
-
checked: true,
|
|
181
|
-
})),
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
catch (err) {
|
|
185
|
-
if (isPromptCancelled(err))
|
|
186
|
-
return;
|
|
187
|
-
throw err;
|
|
188
|
-
}
|
|
176
|
+
// Determine target agent versions, using the same path skills/workflows use.
|
|
177
|
+
// Back-compat: commander's old `--agents <agents...>` shape arrives as an array;
|
|
178
|
+
// join it with commas so resolveAgentVersionTargets can parse it.
|
|
179
|
+
const agentsArg = Array.isArray(options.agents)
|
|
180
|
+
? options.agents.join(',')
|
|
181
|
+
: options.agents;
|
|
182
|
+
let selectedAgents;
|
|
183
|
+
let versionSelections;
|
|
184
|
+
if (agentsArg) {
|
|
185
|
+
const result = await resolveAgentTargetsAutoInstalling(agentsArg, SUBAGENT_CAPABLE_AGENTS, { yes: options.yes });
|
|
186
|
+
if (!result) {
|
|
187
|
+
console.log(chalk.gray('Cancelled.'));
|
|
188
|
+
return;
|
|
189
189
|
}
|
|
190
|
+
selectedAgents = result.selectedAgents;
|
|
191
|
+
versionSelections = result.versionSelections;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
const result = await promptAgentVersionSelection(SUBAGENT_CAPABLE_AGENTS, {
|
|
195
|
+
skipPrompts: options.yes,
|
|
196
|
+
});
|
|
197
|
+
selectedAgents = result.selectedAgents;
|
|
198
|
+
versionSelections = result.versionSelections;
|
|
190
199
|
}
|
|
191
200
|
// Install centrally
|
|
192
201
|
const installSpinner = ora({ text: 'Installing subagents...', isSilent: !process.stdout.isTTY }).start();
|
|
@@ -198,16 +207,27 @@ Examples:
|
|
|
198
207
|
}
|
|
199
208
|
}
|
|
200
209
|
installSpinner.succeed(`Installed ${discovered.length} subagent(s) to ${formatPath(getSubagentsDir())}`);
|
|
201
|
-
// Sync to
|
|
202
|
-
if (
|
|
210
|
+
// Sync to selected versions
|
|
211
|
+
if (versionSelections.size > 0) {
|
|
203
212
|
const syncSpinner = ora({ text: 'Syncing to agents...', isSilent: !process.stdout.isTTY }).start();
|
|
204
|
-
|
|
205
|
-
|
|
213
|
+
const subagentNames = discovered.map((s) => s.name);
|
|
214
|
+
let synced = 0;
|
|
215
|
+
for (const [agentId, versions] of versionSelections) {
|
|
206
216
|
for (const version of versions) {
|
|
207
217
|
syncResourcesToVersion(agentId, version);
|
|
218
|
+
recordVersionResources(agentId, version, 'subagents', subagentNames);
|
|
219
|
+
synced++;
|
|
208
220
|
}
|
|
209
221
|
}
|
|
210
|
-
|
|
222
|
+
if (synced > 0) {
|
|
223
|
+
syncSpinner.succeed(`Synced to ${synced} agent version(s) across ${selectedAgents.map((id) => agentLabel(id)).join(', ')}`);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
syncSpinner.info('No version-managed agents to sync');
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
console.log(chalk.gray('Stored centrally; no agent versions selected for sync.'));
|
|
211
231
|
}
|
|
212
232
|
console.log();
|
|
213
233
|
});
|
package/dist/commands/teams.js
CHANGED
|
@@ -14,6 +14,7 @@ import { buildPreview as buildSessionPreview } from './sessions-picker.js';
|
|
|
14
14
|
import { parseExecEnv } from '../lib/exec.js';
|
|
15
15
|
import { teamPicker, printTeamTable } from './teams-picker.js';
|
|
16
16
|
import { itemPicker } from '../lib/picker.js';
|
|
17
|
+
import { profileExists, readProfile } from '../lib/profiles.js';
|
|
17
18
|
import { isPromptCancelled, isInteractiveTerminal, requireDestructiveArg, requireInteractiveSelection, } from './utils.js';
|
|
18
19
|
const AGENT_NAMES = {
|
|
19
20
|
claude: 'Claude',
|
|
@@ -21,9 +22,12 @@ const AGENT_NAMES = {
|
|
|
21
22
|
gemini: 'Gemini',
|
|
22
23
|
cursor: 'Cursor',
|
|
23
24
|
opencode: 'OpenCode',
|
|
25
|
+
grok: 'Grok',
|
|
26
|
+
antigravity: 'Antigravity',
|
|
24
27
|
};
|
|
25
28
|
const VALID_AGENTS = Object.keys(AGENT_NAMES);
|
|
26
|
-
|
|
29
|
+
// 'full' kept as historical alias for 'skip'; normalized to 'skip' downstream.
|
|
30
|
+
const VALID_MODES = ['plan', 'edit', 'auto', 'skip', 'full'];
|
|
27
31
|
const VALID_EFFORTS = ['low', 'medium', 'high', 'xhigh', 'max', 'auto'];
|
|
28
32
|
const VALID_CLOUD_PROVIDERS = ['rush', 'codex', 'factory'];
|
|
29
33
|
// Auto-enable JSON mode when piped / not a TTY so AI agent consumers get
|
|
@@ -85,14 +89,48 @@ function fullName(type, version) {
|
|
|
85
89
|
const name = AGENT_NAMES[type];
|
|
86
90
|
return version ? `${name} ${version}` : name;
|
|
87
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Resolve a teammate spec to its execution target.
|
|
94
|
+
*
|
|
95
|
+
* Accepts:
|
|
96
|
+
* - `claude` — default version of an installed agent
|
|
97
|
+
* - `claude@2.1.112` — pinned version of an installed agent
|
|
98
|
+
* - `<profile-name>` — runs through `agents run <profile>`, with the
|
|
99
|
+
* profile's host agent used as the underlying
|
|
100
|
+
* AgentType for event parsing and CLI checks.
|
|
101
|
+
*
|
|
102
|
+
* `agent` is always the underlying harness so event parsers, CLI-availability
|
|
103
|
+
* checks, and version pins keep working. `profileName` is set only when the
|
|
104
|
+
* spec resolved through a profile.
|
|
105
|
+
*/
|
|
88
106
|
function parseTeammate(spec) {
|
|
89
107
|
const [name, version] = spec.split('@');
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
108
|
+
if (VALID_AGENTS.includes(name)) {
|
|
109
|
+
const agent = name;
|
|
110
|
+
return {
|
|
111
|
+
agent,
|
|
112
|
+
version: resolveVersionAlias(agent, version) ?? null,
|
|
113
|
+
profileName: null,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// Not a built-in agent id — try resolving as a profile name. A profile
|
|
117
|
+
// pinning a version is allowed; `profile@<override>` is not (would conflict
|
|
118
|
+
// with the profile's own host.version).
|
|
119
|
+
if (!version && profileExists(name)) {
|
|
120
|
+
try {
|
|
121
|
+
const profile = readProfile(name);
|
|
122
|
+
return {
|
|
123
|
+
agent: profile.host.agent,
|
|
124
|
+
version: profile.host.version ?? null,
|
|
125
|
+
profileName: profile.name,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
die(`Profile '${name}' is malformed: ${err.message}`);
|
|
130
|
+
}
|
|
93
131
|
}
|
|
94
|
-
|
|
95
|
-
|
|
132
|
+
die(`Unknown teammate '${spec}'. Available agents: ${VALID_AGENTS.join(', ')}.\n` +
|
|
133
|
+
` Use 'claude', 'claude@2.1.112', or the name of a profile from 'agents view'.`);
|
|
96
134
|
}
|
|
97
135
|
function shortId(id) {
|
|
98
136
|
return id.slice(0, 8);
|
|
@@ -545,6 +583,8 @@ export function registerTeamsCommands(program) {
|
|
|
545
583
|
Teammate syntax:
|
|
546
584
|
'claude' the default Claude version on this machine
|
|
547
585
|
'claude@2.1.112' a specific installed version (see 'agents view')
|
|
586
|
+
'<profile>' a profile from 'agents view' — runs through 'agents
|
|
587
|
+
run <profile>' with the profile's host harness
|
|
548
588
|
|
|
549
589
|
Short aliases:
|
|
550
590
|
teams c = create teams a = add teams s = status
|
|
@@ -709,7 +749,7 @@ export function registerTeamsCommands(program) {
|
|
|
709
749
|
.alias('a')
|
|
710
750
|
.description("Add a teammate to work on a task. Runs in background; returns immediately. Use 'status' to check in.")
|
|
711
751
|
.option('-n, --name <name>', 'Friendly name for this teammate (e.g. alice). Required if using --after. Unique within team.')
|
|
712
|
-
.option('-m, --mode <mode>', `Permissions: plan (read-only) | edit (can write files) |
|
|
752
|
+
.option('-m, --mode <mode>', `Permissions: plan (read-only) | edit (can write files) | auto (smart classifier auto-approves safe ops) | skip (bypass all permission prompts). 'full' accepted as alias for skip.`, 'edit')
|
|
713
753
|
.option('-e, --effort <effort>', `Reasoning intensity: ${VALID_EFFORTS.join('|')}`, 'medium')
|
|
714
754
|
.option('--model <model>', 'Override the effort tier and use this specific model (e.g. claude-opus-4-6)')
|
|
715
755
|
.option('--env <key=value>', 'Set an environment variable for this teammate (repeatable for multiple vars)', (val, prev) => [...prev, val], [])
|
|
@@ -745,7 +785,7 @@ export function registerTeamsCommands(program) {
|
|
|
745
785
|
die(`--cloud rush requires --repo <owner/repo>`);
|
|
746
786
|
}
|
|
747
787
|
}
|
|
748
|
-
const { agent, version } = parseTeammate(teammate);
|
|
788
|
+
const { agent, version, profileName } = parseTeammate(teammate);
|
|
749
789
|
if (version && !isVersionInstalled(agent, version)) {
|
|
750
790
|
die(`${AGENT_NAMES[agent]} ${version} isn't installed.\n` +
|
|
751
791
|
` Install it: agents add ${agent}@${version}\n` +
|
|
@@ -756,6 +796,11 @@ export function registerTeamsCommands(program) {
|
|
|
756
796
|
die(`Invalid teammate name '${opts.name}'. Use letters, numbers, '-', or '_'.`);
|
|
757
797
|
}
|
|
758
798
|
}
|
|
799
|
+
if (opts.worktree !== undefined) {
|
|
800
|
+
if (!opts.worktree || !/^[A-Za-z0-9_-]+$/.test(opts.worktree)) {
|
|
801
|
+
die(`Invalid worktree name '${opts.worktree}'. Use letters, numbers, '-', or '_'.`);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
759
804
|
const after = opts.after
|
|
760
805
|
? opts.after.split(',').map((s) => s.trim()).filter(Boolean)
|
|
761
806
|
: [];
|
|
@@ -865,12 +910,12 @@ export function registerTeamsCommands(program) {
|
|
|
865
910
|
}
|
|
866
911
|
}
|
|
867
912
|
try {
|
|
868
|
-
const result = await handleSpawn(mgr, team, agent, effectiveTask, cwd, opts.mode, opts.effort, null, cwd, version, opts.name ?? null, after, opts.model ?? null, envOverrides ?? null, taskType, cloudProviderId, cloudSessionId, opts.repo ?? null, opts.branch ?? null, worktreeName, worktreePath);
|
|
913
|
+
const result = await handleSpawn(mgr, team, agent, effectiveTask, cwd, opts.mode, opts.effort, null, cwd, version, opts.name ?? null, after, opts.model ?? null, envOverrides ?? null, taskType, cloudProviderId, cloudSessionId, opts.repo ?? null, opts.branch ?? null, worktreeName, worktreePath, profileName);
|
|
869
914
|
if (isJsonMode(opts)) {
|
|
870
915
|
console.log(JSON.stringify(result, null, 2));
|
|
871
916
|
return;
|
|
872
917
|
}
|
|
873
|
-
const who = fullName(agent, version);
|
|
918
|
+
const who = profileName ? `${profileName} (via ${fullName(agent, version)})` : fullName(agent, version);
|
|
874
919
|
const staged = result.status === 'pending';
|
|
875
920
|
const verb = staged ? 'Staged' : 'Welcomed';
|
|
876
921
|
const greeting = result.name
|
|
@@ -899,6 +944,12 @@ export function registerTeamsCommands(program) {
|
|
|
899
944
|
console.log();
|
|
900
945
|
if (staged) {
|
|
901
946
|
console.log(chalk.gray(`Start the ready teammates: agents teams start ${team}`));
|
|
947
|
+
if (after.length > 0) {
|
|
948
|
+
process.stderr.write(chalk.yellow(`\nWarning: this teammate has --after dependencies and will NEVER start on its own.\n` +
|
|
949
|
+
` A supervisor watch process is required to launch it when its deps complete.\n` +
|
|
950
|
+
` Run this in another terminal:\n` +
|
|
951
|
+
` agents teams start ${team} --watch\n`));
|
|
952
|
+
}
|
|
902
953
|
}
|
|
903
954
|
else {
|
|
904
955
|
console.log(chalk.gray(`Check in later: agents teams status ${team}`));
|
package/dist/commands/utils.d.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Small helpers used across multiple commands: prompt cancellation detection,
|
|
5
5
|
* table formatting, spinner management, and platform-specific workarounds.
|
|
6
6
|
*/
|
|
7
|
+
import type { AgentId } from '../lib/types.js';
|
|
8
|
+
import { type InstalledAgentTargetResult, type VersionSelectionResult } from '../lib/versions.js';
|
|
7
9
|
/**
|
|
8
10
|
* Check if an error is from user cancelling a prompt (Ctrl+C)
|
|
9
11
|
*/
|
|
@@ -58,3 +60,34 @@ export declare function promptRemovalTargets(resourceName: string, targets: Remo
|
|
|
58
60
|
* Format a path for display, using ~ for home directory
|
|
59
61
|
*/
|
|
60
62
|
export declare function formatPath(fullPath: string, cwd?: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Make sure every specific `agent@x.y.z` the user typed is installed before
|
|
65
|
+
* the caller resolves targets. Returns true if the caller should continue,
|
|
66
|
+
* false if the user declined the prompt. Exported so non-standard caller
|
|
67
|
+
* shapes (e.g. mcp.ts's manifest-shaped parser) can run the pre-flight
|
|
68
|
+
* without going through resolveAgentVersionTargets first.
|
|
69
|
+
*/
|
|
70
|
+
export declare function ensureAgentVersionsInstalled(value: string, availableAgents: readonly AgentId[], options?: {
|
|
71
|
+
yes?: boolean;
|
|
72
|
+
}): Promise<boolean>;
|
|
73
|
+
/**
|
|
74
|
+
* Resolve a `--agents` selector and, if any requested `agent@version` isn't
|
|
75
|
+
* installed yet, prompt to install it (or auto-install with --yes) before
|
|
76
|
+
* delegating to resolveAgentVersionTargets. Returns null when the user
|
|
77
|
+
* declines the install prompt — callers should treat that as a clean cancel.
|
|
78
|
+
*/
|
|
79
|
+
export declare function resolveAgentTargetsAutoInstalling(value: string, availableAgents: readonly AgentId[], options?: {
|
|
80
|
+
yes?: boolean;
|
|
81
|
+
allVersions?: boolean;
|
|
82
|
+
}): Promise<VersionSelectionResult | null>;
|
|
83
|
+
/**
|
|
84
|
+
* Same as resolveAgentTargetsAutoInstalling but returns the broader
|
|
85
|
+
* InstalledAgentTargetResult that includes `directAgents` (for paths like
|
|
86
|
+
* `agents install` and `mcp register` that fall through to unmanaged homes
|
|
87
|
+
* when no managed version is installed).
|
|
88
|
+
*/
|
|
89
|
+
export declare function resolveInstalledAgentTargetsAutoInstalling(value: string, availableAgents: readonly AgentId[], options?: {
|
|
90
|
+
yes?: boolean;
|
|
91
|
+
allVersions?: boolean;
|
|
92
|
+
}): Promise<InstalledAgentTargetResult | null>;
|
|
93
|
+
export { VersionNotInstalledError } from '../lib/versions.js';
|
package/dist/commands/utils.js
CHANGED
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
import * as os from 'os';
|
|
8
8
|
import { spawnSync } from 'child_process';
|
|
9
9
|
import chalk from 'chalk';
|
|
10
|
+
import ora from 'ora';
|
|
11
|
+
import { confirm } from '@inquirer/prompts';
|
|
12
|
+
import { agentLabel, resolveAgentName } from '../lib/agents.js';
|
|
13
|
+
import { installVersion, listInstalledVersions, resolveAgentVersionTargets, resolveInstalledAgentTargets, } from '../lib/versions.js';
|
|
10
14
|
/**
|
|
11
15
|
* Check if an error is from user cancelling a prompt (Ctrl+C)
|
|
12
16
|
*/
|
|
@@ -135,3 +139,138 @@ export function formatPath(fullPath, cwd) {
|
|
|
135
139
|
}
|
|
136
140
|
return fullPath;
|
|
137
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Parse a --agents selector and collect every (agentId, specificVersion) pair
|
|
144
|
+
* the user requested where the version is a concrete x.y.z (not `default`,
|
|
145
|
+
* not `all`, not `latest`) and is NOT currently installed.
|
|
146
|
+
*
|
|
147
|
+
* This is the lookahead the auto-install wrappers use to decide whether to
|
|
148
|
+
* prompt + install before delegating to resolveAgentVersionTargets.
|
|
149
|
+
*/
|
|
150
|
+
function collectMissingVersions(value, availableAgents) {
|
|
151
|
+
const missing = [];
|
|
152
|
+
const seen = new Set();
|
|
153
|
+
for (const raw of value.split(',').map((s) => s.trim()).filter(Boolean)) {
|
|
154
|
+
// Literal `all` / `all@all` expand to per-agent — never missing.
|
|
155
|
+
if (raw === 'all' || raw === 'all@all')
|
|
156
|
+
continue;
|
|
157
|
+
const atIndex = raw.indexOf('@');
|
|
158
|
+
if (atIndex === -1)
|
|
159
|
+
continue; // bare agent → resolves to default; never missing in this sense
|
|
160
|
+
const agentToken = raw.slice(0, atIndex).trim();
|
|
161
|
+
const versionToken = raw.slice(atIndex + 1).trim();
|
|
162
|
+
// Non-specific selectors handled by the underlying resolver.
|
|
163
|
+
if (!versionToken || versionToken === 'default' || versionToken === 'all')
|
|
164
|
+
continue;
|
|
165
|
+
const agentId = resolveAgentName(agentToken);
|
|
166
|
+
if (!agentId || !availableAgents.includes(agentId))
|
|
167
|
+
continue;
|
|
168
|
+
const installed = listInstalledVersions(agentId);
|
|
169
|
+
if (installed.includes(versionToken))
|
|
170
|
+
continue;
|
|
171
|
+
const key = `${agentId}@${versionToken}`;
|
|
172
|
+
if (seen.has(key))
|
|
173
|
+
continue;
|
|
174
|
+
seen.add(key);
|
|
175
|
+
missing.push({ agentId, version: versionToken });
|
|
176
|
+
}
|
|
177
|
+
return missing;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Sequentially install every requested missing version with a per-version
|
|
181
|
+
* spinner. Aborts via process.exit(1) on the first failure — the user
|
|
182
|
+
* already approved the install so a partial-install outcome is worse than
|
|
183
|
+
* a hard stop.
|
|
184
|
+
*/
|
|
185
|
+
async function installMissingVersions(missing) {
|
|
186
|
+
for (const { agentId, version } of missing) {
|
|
187
|
+
const label = `${agentLabel(agentId)}@${version}`;
|
|
188
|
+
const spinner = ora(`Installing ${label}...`).start();
|
|
189
|
+
try {
|
|
190
|
+
const result = await installVersion(agentId, version, (msg) => {
|
|
191
|
+
spinner.text = msg;
|
|
192
|
+
});
|
|
193
|
+
if (!result.success) {
|
|
194
|
+
spinner.fail(`Failed to install ${label}: ${result.error ?? 'unknown error'}`);
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
spinner.succeed(`Installed ${label}`);
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
spinner.fail(`Failed to install ${label}: ${err.message}`);
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Make sure every specific `agent@x.y.z` the user typed is installed before
|
|
207
|
+
* the caller resolves targets. Returns true if the caller should continue,
|
|
208
|
+
* false if the user declined the prompt. Exported so non-standard caller
|
|
209
|
+
* shapes (e.g. mcp.ts's manifest-shaped parser) can run the pre-flight
|
|
210
|
+
* without going through resolveAgentVersionTargets first.
|
|
211
|
+
*/
|
|
212
|
+
export async function ensureAgentVersionsInstalled(value, availableAgents, options = {}) {
|
|
213
|
+
const missing = collectMissingVersions(value, availableAgents);
|
|
214
|
+
if (missing.length === 0)
|
|
215
|
+
return true;
|
|
216
|
+
const summary = missing.map((m) => `${agentLabel(m.agentId)}@${m.version}`).join(', ');
|
|
217
|
+
if (!options.yes) {
|
|
218
|
+
if (!isInteractiveTerminal()) {
|
|
219
|
+
console.error(chalk.red(`Missing agent version(s): ${summary}`));
|
|
220
|
+
console.error(chalk.gray('In a scripted shell, opt in to auto-install:'));
|
|
221
|
+
console.error(chalk.cyan(` rerun with --yes`));
|
|
222
|
+
console.error(chalk.gray('Or pre-install:'));
|
|
223
|
+
for (const m of missing) {
|
|
224
|
+
console.error(chalk.cyan(` agents add ${m.agentId}@${m.version}`));
|
|
225
|
+
}
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
console.log(chalk.yellow(`\nThe following agent version(s) are not installed:`));
|
|
229
|
+
for (const m of missing) {
|
|
230
|
+
console.log(` ${chalk.cyan(`${agentLabel(m.agentId)}@${m.version}`)}`);
|
|
231
|
+
}
|
|
232
|
+
let proceed;
|
|
233
|
+
try {
|
|
234
|
+
proceed = await confirm({
|
|
235
|
+
message: `Install ${missing.length} missing version${missing.length === 1 ? '' : 's'}?`,
|
|
236
|
+
default: true,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
if (isPromptCancelled(err))
|
|
241
|
+
return false;
|
|
242
|
+
throw err;
|
|
243
|
+
}
|
|
244
|
+
if (!proceed)
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
await installMissingVersions(missing);
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Resolve a `--agents` selector and, if any requested `agent@version` isn't
|
|
252
|
+
* installed yet, prompt to install it (or auto-install with --yes) before
|
|
253
|
+
* delegating to resolveAgentVersionTargets. Returns null when the user
|
|
254
|
+
* declines the install prompt — callers should treat that as a clean cancel.
|
|
255
|
+
*/
|
|
256
|
+
export async function resolveAgentTargetsAutoInstalling(value, availableAgents, options = {}) {
|
|
257
|
+
const ok = await ensureAgentVersionsInstalled(value, availableAgents, options);
|
|
258
|
+
if (!ok)
|
|
259
|
+
return null;
|
|
260
|
+
return resolveAgentVersionTargets(value, availableAgents, { allVersions: options.allVersions });
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Same as resolveAgentTargetsAutoInstalling but returns the broader
|
|
264
|
+
* InstalledAgentTargetResult that includes `directAgents` (for paths like
|
|
265
|
+
* `agents install` and `mcp register` that fall through to unmanaged homes
|
|
266
|
+
* when no managed version is installed).
|
|
267
|
+
*/
|
|
268
|
+
export async function resolveInstalledAgentTargetsAutoInstalling(value, availableAgents, options = {}) {
|
|
269
|
+
const ok = await ensureAgentVersionsInstalled(value, availableAgents, options);
|
|
270
|
+
if (!ok)
|
|
271
|
+
return null;
|
|
272
|
+
return resolveInstalledAgentTargets(value, availableAgents, { allVersions: options.allVersions });
|
|
273
|
+
}
|
|
274
|
+
// Re-export so callers can `catch (err) { if (err instanceof VersionNotInstalledError) … }`
|
|
275
|
+
// without reaching into ../lib/versions directly.
|
|
276
|
+
export { VersionNotInstalledError } from '../lib/versions.js';
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Version management commands for installing, switching, and removing agent CLIs.
|
|
3
3
|
*
|
|
4
|
-
* Implements `agents add`, `agents
|
|
5
|
-
* `agents list`. Handles npm-based installation,
|
|
4
|
+
* Implements `agents add`, `agents prune`, `agents remove` (alias),
|
|
5
|
+
* `agents use`, and the deprecated `agents list`. Handles npm-based installation,
|
|
6
|
+
* shim creation, config symlink
|
|
6
7
|
* switching, resource sync prompts, and project-level version pinning.
|
|
7
8
|
*/
|
|
8
9
|
import type { Command } from 'commander';
|
|
9
|
-
/** Register `agents add`, `agents remove`, `agents use`, and `agents list` (deprecated). */
|
|
10
|
+
/** Register `agents add`, `agents prune`, `agents remove`, `agents use`, and `agents list` (deprecated). */
|
|
10
11
|
export declare function registerVersionsCommands(program: Command): void;
|