@phnx-labs/agents-cli 1.14.7 → 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 +74 -7
- package/dist/commands/alias.js +2 -2
- package/dist/commands/beta.js +6 -1
- 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/exec.js +9 -2
- package/dist/commands/fork.js +2 -2
- package/dist/commands/hooks.js +71 -26
- package/dist/commands/mcp.js +85 -43
- package/dist/commands/plugins.js +48 -15
- package/dist/commands/prune.d.ts +0 -20
- package/dist/commands/prune.js +291 -16
- 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} +32 -21
- package/dist/commands/skills.js +60 -19
- package/dist/commands/subagents.js +41 -13
- package/dist/commands/teams.js +2 -3
- package/dist/commands/usage.js +6 -0
- package/dist/commands/utils.d.ts +16 -0
- package/dist/commands/utils.js +32 -0
- package/dist/commands/versions.js +8 -6
- 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 +6 -3
- 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.d.ts +1 -0
- package/dist/lib/browser/drivers/ssh.js +32 -4
- package/dist/lib/browser/ipc.js +145 -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 +84 -13
- package/dist/lib/browser/service.js +806 -122
- 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 +6 -7
- package/dist/lib/doctor-diff.js +4 -4
- package/dist/lib/events.d.ts +94 -1
- package/dist/lib/events.js +264 -6
- package/dist/lib/exec.js +16 -10
- 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 +14 -11
- package/dist/lib/permissions.js +46 -42
- 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/routines.d.ts +15 -0
- package/dist/lib/routines.js +68 -0
- package/dist/lib/runner.js +9 -5
- package/dist/lib/secrets/index.d.ts +14 -11
- package/dist/lib/secrets/index.js +49 -21
- package/dist/lib/secrets/linux.d.ts +27 -0
- package/dist/lib/secrets/linux.js +161 -0
- 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.d.ts +4 -0
- package/dist/lib/session/db.js +34 -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.d.ts +1 -1
- package/dist/lib/usage.js +15 -48
- package/dist/lib/versions.js +31 -21
- package/package.json +1 -1
- package/scripts/postinstall.js +37 -9
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* First-run
|
|
2
|
+
* First-run setup command.
|
|
3
3
|
*
|
|
4
|
-
* Registers the `agents
|
|
4
|
+
* Registers the `agents setup` command which clones the system repo into
|
|
5
5
|
* ~/.agents-system/ and installs agent CLIs with resource syncing.
|
|
6
6
|
*/
|
|
7
7
|
import chalk from 'chalk';
|
|
@@ -52,13 +52,13 @@ async function importAgent(agentId, version) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
/** First-run setup. Clones ~/.agents-system/ from the system repo if needed. */
|
|
55
|
-
export async function
|
|
55
|
+
export async function runSetup(program, options = {}) {
|
|
56
56
|
const agentsDir = getAgentsDir();
|
|
57
57
|
const alreadyConfigured = isGitRepo(agentsDir);
|
|
58
58
|
if (alreadyConfigured && !options.force) {
|
|
59
59
|
console.log(chalk.gray('~/.agents-system/ is already set up.'));
|
|
60
60
|
console.log(chalk.gray('\nTo sync updates: agents repo pull system'));
|
|
61
|
-
console.log(chalk.gray('To re-
|
|
61
|
+
console.log(chalk.gray('To re-run setup: agents setup --force'));
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
64
|
// Detect existing installations BEFORE cloning (they won't exist after if we import)
|
|
@@ -76,16 +76,26 @@ export async function runInit(program, options = {}) {
|
|
|
76
76
|
const result = await pullRepo(agentsDir);
|
|
77
77
|
if (!result.success) {
|
|
78
78
|
spinner.fail(`Pull failed: ${result.error}`);
|
|
79
|
-
console.log(chalk.gray('Fix the issue and re-run: agents
|
|
79
|
+
console.log(chalk.gray('Fix the issue and re-run: agents setup --force'));
|
|
80
80
|
process.exit(1);
|
|
81
81
|
}
|
|
82
82
|
spinner.succeed(`Updated to ${result.commit}`);
|
|
83
83
|
}
|
|
84
84
|
else {
|
|
85
|
+
// Check git is available
|
|
86
|
+
try {
|
|
87
|
+
const { execSync } = await import('child_process');
|
|
88
|
+
execSync('which git', { stdio: 'ignore' });
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
spinner.fail('git is not installed');
|
|
92
|
+
console.log(chalk.gray('Install git first: https://git-scm.com/downloads'));
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
85
95
|
const result = await cloneIntoExisting(DEFAULT_SYSTEM_REPO, agentsDir);
|
|
86
96
|
if (!result.success) {
|
|
87
97
|
spinner.fail(`Clone failed: ${result.error}`);
|
|
88
|
-
console.log(chalk.gray('Fix the issue and re-run: agents
|
|
98
|
+
console.log(chalk.gray('Fix the issue and re-run: agents setup --force'));
|
|
89
99
|
process.exit(1);
|
|
90
100
|
}
|
|
91
101
|
spinner.succeed(`Cloned ${systemRepoSlug(DEFAULT_SYSTEM_REPO)} (${result.commit})`);
|
|
@@ -146,6 +156,8 @@ export async function runInit(program, options = {}) {
|
|
|
146
156
|
}
|
|
147
157
|
}
|
|
148
158
|
}
|
|
159
|
+
if (options.suppressFooter)
|
|
160
|
+
return;
|
|
149
161
|
console.log(chalk.bold('\nSetup complete. Try:'));
|
|
150
162
|
console.log(chalk.cyan(' agents view ') + chalk.gray(' # see what\'s installed'));
|
|
151
163
|
console.log(chalk.cyan(' agents run <agent> "hello" ') + chalk.gray(' # run an agent'));
|
|
@@ -155,7 +167,7 @@ export async function runInit(program, options = {}) {
|
|
|
155
167
|
/**
|
|
156
168
|
* Ensure the system repo exists before running a command that needs it.
|
|
157
169
|
* If ~/.agents-system/ is not a git repo AND we're in an interactive TTY,
|
|
158
|
-
* prompt the user to run
|
|
170
|
+
* prompt the user to run setup now. In non-interactive mode, print a clear
|
|
159
171
|
* error and exit.
|
|
160
172
|
*/
|
|
161
173
|
export async function ensureInitialized(program) {
|
|
@@ -163,34 +175,33 @@ export async function ensureInitialized(program) {
|
|
|
163
175
|
if (isGitRepo(agentsDir))
|
|
164
176
|
return;
|
|
165
177
|
if (!isInteractiveTerminal()) {
|
|
166
|
-
console.error(chalk.red('agents-cli is not
|
|
178
|
+
console.error(chalk.red('agents-cli is not set up. Run: agents setup'));
|
|
167
179
|
process.exit(1);
|
|
168
180
|
}
|
|
169
181
|
console.log(chalk.yellow('\nagents-cli has not been set up yet.'));
|
|
170
182
|
const proceed = await confirm({
|
|
171
|
-
message: 'Run `agents
|
|
183
|
+
message: 'Run `agents setup` now?',
|
|
172
184
|
default: true,
|
|
173
185
|
}).catch(() => false);
|
|
174
186
|
if (!proceed) {
|
|
175
|
-
console.log(chalk.gray('Skipped. Run `agents
|
|
187
|
+
console.log(chalk.gray('Skipped. Run `agents setup` when ready.'));
|
|
176
188
|
process.exit(0);
|
|
177
189
|
}
|
|
178
|
-
await
|
|
179
|
-
process.exit(0);
|
|
190
|
+
await runSetup(program, { suppressFooter: true });
|
|
180
191
|
}
|
|
181
|
-
/** Register the `agents
|
|
182
|
-
export function
|
|
192
|
+
/** Register the `agents setup` command. */
|
|
193
|
+
export function registerSetupCommand(program) {
|
|
183
194
|
program
|
|
184
|
-
.command('
|
|
195
|
+
.command('setup')
|
|
185
196
|
.description('Set up agents-cli for the first time. Clones a config repo and installs agent CLIs.')
|
|
186
|
-
.option('-f, --force', '
|
|
197
|
+
.option('-f, --force', 'Re-run setup even if ~/.agents-system/ already exists (use with caution)')
|
|
187
198
|
.addHelpText('after', `
|
|
188
199
|
Examples:
|
|
189
200
|
# First-time setup (clones the system repo into ~/.agents-system/)
|
|
190
|
-
agents
|
|
201
|
+
agents setup
|
|
191
202
|
|
|
192
|
-
# Re-
|
|
193
|
-
agents
|
|
203
|
+
# Re-run setup after corruption
|
|
204
|
+
agents setup --force
|
|
194
205
|
|
|
195
206
|
When to use:
|
|
196
207
|
- First time running agents-cli: this is your starting point
|
|
@@ -203,12 +214,12 @@ What it does:
|
|
|
203
214
|
3. Syncs commands, skills, hooks, and MCP servers to each version
|
|
204
215
|
|
|
205
216
|
Non-interactive alternative:
|
|
206
|
-
Skip '
|
|
217
|
+
Skip 'setup' and run:
|
|
207
218
|
agents pull
|
|
208
219
|
`)
|
|
209
220
|
.action(async (options) => {
|
|
210
221
|
try {
|
|
211
|
-
await
|
|
222
|
+
await runSetup(program, options);
|
|
212
223
|
}
|
|
213
224
|
catch (err) {
|
|
214
225
|
if (isPromptCancelled(err)) {
|
package/dist/commands/skills.js
CHANGED
|
@@ -4,12 +4,12 @@ import * as fs from 'fs';
|
|
|
4
4
|
import * as os from 'os';
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import { select, checkbox } from '@inquirer/prompts';
|
|
7
|
-
import { SKILLS_CAPABLE_AGENTS, resolveAgentName, formatAgentError, agentLabel, } from '../lib/agents.js';
|
|
7
|
+
import { AGENTS, SKILLS_CAPABLE_AGENTS, resolveAgentName, formatAgentError, agentLabel, } from '../lib/agents.js';
|
|
8
8
|
import { cloneRepo } from '../lib/git.js';
|
|
9
|
-
import { discoverSkillsFromRepo, installSkillCentrally,
|
|
10
|
-
import { getGlobalDefault, resolveVersionAlias, syncResourcesToVersion, promptAgentVersionSelection, resolveAgentVersionTargets, } from '../lib/versions.js';
|
|
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, resolveAgentVersionTargets, } 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, 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) {
|
|
@@ -294,15 +294,29 @@ Examples:
|
|
|
294
294
|
agents skills remove
|
|
295
295
|
`)
|
|
296
296
|
.action(async (name) => {
|
|
297
|
+
const skillTargetMap = new Map();
|
|
298
|
+
for (const { agent, version } of iterSkillsCapableVersions()) {
|
|
299
|
+
const home = getVersionHomePath(agent, version);
|
|
300
|
+
const skills = listInstalledSkillsWithScope(agent, process.cwd(), { home });
|
|
301
|
+
for (const skill of skills) {
|
|
302
|
+
if (skill.scope !== 'user')
|
|
303
|
+
continue;
|
|
304
|
+
const existing = skillTargetMap.get(skill.name);
|
|
305
|
+
if (existing) {
|
|
306
|
+
existing.targets.push({ agent, version });
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
skillTargetMap.set(skill.name, { name: skill.name, targets: [{ agent, version }] });
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
297
313
|
let skillsToRemove;
|
|
298
314
|
if (name) {
|
|
299
315
|
skillsToRemove = [name];
|
|
300
316
|
}
|
|
301
317
|
else {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (installedSkills.size === 0) {
|
|
305
|
-
console.log(chalk.yellow('No skills installed.'));
|
|
318
|
+
if (skillTargetMap.size === 0) {
|
|
319
|
+
console.log(chalk.yellow('No skills installed in any version.'));
|
|
306
320
|
return;
|
|
307
321
|
}
|
|
308
322
|
if (!isInteractiveTerminal()) {
|
|
@@ -311,12 +325,13 @@ Examples:
|
|
|
311
325
|
]);
|
|
312
326
|
}
|
|
313
327
|
try {
|
|
314
|
-
const choices = Array.from(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
:
|
|
319
|
-
|
|
328
|
+
const choices = Array.from(skillTargetMap.values()).map((skill) => {
|
|
329
|
+
const agents = [...new Set(skill.targets.map((t) => AGENTS[t.agent].name))];
|
|
330
|
+
return {
|
|
331
|
+
value: skill.name,
|
|
332
|
+
name: `${skill.name} (${agents.join(', ')})`,
|
|
333
|
+
};
|
|
334
|
+
});
|
|
320
335
|
const selected = await checkbox({
|
|
321
336
|
message: 'Select skills to remove',
|
|
322
337
|
choices,
|
|
@@ -335,14 +350,40 @@ Examples:
|
|
|
335
350
|
throw err;
|
|
336
351
|
}
|
|
337
352
|
}
|
|
353
|
+
let removed = 0;
|
|
338
354
|
for (const skillName of skillsToRemove) {
|
|
339
|
-
const
|
|
340
|
-
if (
|
|
341
|
-
console.log(chalk.
|
|
355
|
+
const skillInfo = skillTargetMap.get(skillName);
|
|
356
|
+
if (!skillInfo || skillInfo.targets.length === 0) {
|
|
357
|
+
console.log(chalk.yellow(` Skill '${skillName}' not found in any version.`));
|
|
358
|
+
continue;
|
|
342
359
|
}
|
|
343
|
-
|
|
344
|
-
|
|
360
|
+
const removalTargets = skillInfo.targets.map((t) => ({
|
|
361
|
+
agent: t.agent,
|
|
362
|
+
version: t.version,
|
|
363
|
+
label: `${agentLabel(t.agent)}@${t.version}`,
|
|
364
|
+
}));
|
|
365
|
+
const selectedTargets = await promptRemovalTargets(skillName, removalTargets);
|
|
366
|
+
if (selectedTargets.length === 0) {
|
|
367
|
+
console.log(chalk.gray(` Skipped '${skillName}'.`));
|
|
368
|
+
continue;
|
|
345
369
|
}
|
|
370
|
+
for (const target of selectedTargets) {
|
|
371
|
+
const result = removeSkillFromVersion(target.agent, target.version, skillName);
|
|
372
|
+
if (result.success) {
|
|
373
|
+
console.log(` ${chalk.red('-')} ${target.label}: ${skillName}`);
|
|
374
|
+
removed++;
|
|
375
|
+
}
|
|
376
|
+
else if (result.error) {
|
|
377
|
+
console.log(` ${chalk.yellow('!')} ${target.label}: ${result.error}`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (removed === 0) {
|
|
382
|
+
console.log(chalk.yellow('No skills removed.'));
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
console.log(chalk.green(`\nRemoved ${removed} skill(s) from version homes.`));
|
|
386
|
+
console.log(chalk.gray('Central source unchanged. Skills will re-sync on next agent launch.'));
|
|
346
387
|
}
|
|
347
388
|
});
|
|
348
389
|
// `skills sync` is gone — sync runs automatically when the agent launches.
|
|
@@ -12,10 +12,10 @@ import * as path from 'path';
|
|
|
12
12
|
import { checkbox } from '@inquirer/prompts';
|
|
13
13
|
import { AGENTS, agentLabel } from '../lib/agents.js';
|
|
14
14
|
import { cloneRepo } from '../lib/git.js';
|
|
15
|
-
import { discoverSubagentsFromRepo, installSubagentCentrally,
|
|
15
|
+
import { discoverSubagentsFromRepo, installSubagentCentrally, listInstalledSubagents, getInstalledSubagent, listSubagentsForAgent, SUBAGENT_CAPABLE_AGENTS, iterSubagentsCapableVersions, removeSubagentFromVersion, } from '../lib/subagents.js';
|
|
16
16
|
import { listInstalledVersions, syncResourcesToVersion, getGlobalDefault, getVersionHomePath, } from '../lib/versions.js';
|
|
17
17
|
import { getSubagentsDir } from '../lib/state.js';
|
|
18
|
-
import { isInteractiveTerminal, isPromptCancelled, requireInteractiveSelection, requireDestructiveArg, } from './utils.js';
|
|
18
|
+
import { isInteractiveTerminal, isPromptCancelled, requireInteractiveSelection, requireDestructiveArg, promptRemovalTargets, } from './utils.js';
|
|
19
19
|
import { showResourceList, buildTargetsSection, } from './resource-view.js';
|
|
20
20
|
/** Replace the home directory prefix with ~ for display. */
|
|
21
21
|
function formatPath(p) {
|
|
@@ -240,20 +240,48 @@ Examples:
|
|
|
240
240
|
console.log(chalk.red(`Subagent '${name}' not found`));
|
|
241
241
|
process.exit(1);
|
|
242
242
|
}
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
243
|
+
// Build list of targets that have this subagent synced
|
|
244
|
+
const availableTargets = [];
|
|
245
|
+
for (const { agent, version } of iterSubagentsCapableVersions()) {
|
|
246
|
+
const home = getVersionHomePath(agent, version);
|
|
247
|
+
const installed = listSubagentsForAgent(agent, home).some((s) => s.name === name);
|
|
248
|
+
if (installed) {
|
|
249
|
+
availableTargets.push({ agent, version });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (availableTargets.length === 0) {
|
|
253
|
+
console.log(chalk.yellow(`Subagent '${name}' not synced to any version.`));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
// Show multi-select picker for targets
|
|
257
|
+
const removalTargets = availableTargets.map((t) => ({
|
|
258
|
+
agent: t.agent,
|
|
259
|
+
version: t.version,
|
|
260
|
+
label: `${agentLabel(t.agent)}@${t.version}`,
|
|
261
|
+
}));
|
|
262
|
+
const selectedTargets = await promptRemovalTargets(name, removalTargets);
|
|
263
|
+
if (selectedTargets.length === 0) {
|
|
264
|
+
console.log(chalk.gray('Cancelled.'));
|
|
265
|
+
return;
|
|
248
266
|
}
|
|
249
|
-
|
|
250
|
-
for (const
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
267
|
+
let removed = 0;
|
|
268
|
+
for (const target of selectedTargets) {
|
|
269
|
+
const result = removeSubagentFromVersion(target.agent, target.version, name);
|
|
270
|
+
if (result.success) {
|
|
271
|
+
console.log(` ${chalk.red('-')} ${target.label}: ${name}`);
|
|
272
|
+
removed++;
|
|
273
|
+
}
|
|
274
|
+
else if (result.error) {
|
|
275
|
+
console.log(` ${chalk.yellow('!')} ${target.label}: ${result.error}`);
|
|
254
276
|
}
|
|
255
277
|
}
|
|
256
|
-
|
|
278
|
+
if (removed === 0) {
|
|
279
|
+
console.log(chalk.yellow('No subagents removed.'));
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
console.log(chalk.green(`\nRemoved ${removed} subagent(s) from version homes.`));
|
|
283
|
+
console.log(chalk.gray('Central source unchanged. Subagents will re-sync on next agent launch.'));
|
|
284
|
+
}
|
|
257
285
|
});
|
|
258
286
|
}
|
|
259
287
|
/** Every (agent, version) that supports subagents and is installed. */
|
package/dist/commands/teams.js
CHANGED
|
@@ -922,13 +922,12 @@ Name teammates with --name alice to refer to them as 'alice' instead of a UUID.
|
|
|
922
922
|
.command('status [team]')
|
|
923
923
|
.aliases(['s', 'st', 'check'])
|
|
924
924
|
.description("Check in on a team: who's working, what files they touched, recent commands, last output. Pass --since for efficient delta polling.")
|
|
925
|
-
.option('-f, --filter <state>', 'Show only teammates in this state:
|
|
925
|
+
.option('-f, --filter <state>', 'Show only teammates in this state: running, completed, failed, stopped, or all (default: all)', 'all')
|
|
926
926
|
.option('-s, --since <iso>', 'Cursor from a previous status call; only show updates after this timestamp (enables efficient polling)')
|
|
927
927
|
.option('--agent-id <id>', 'Show only this one teammate (by UUID or UUID prefix)')
|
|
928
928
|
.option('--json', 'Output machine-readable JSON')
|
|
929
929
|
.action(async (team, opts) => {
|
|
930
|
-
|
|
931
|
-
const filter = opts.filter === 'working' ? 'running' : opts.filter;
|
|
930
|
+
const filter = opts.filter;
|
|
932
931
|
const mgr = mkManager();
|
|
933
932
|
// No team given → drop into the picker (TTY) or fail clearly (script).
|
|
934
933
|
if (!team) {
|
package/dist/commands/usage.js
CHANGED
|
@@ -8,6 +8,12 @@ export function registerUsageCommand(program) {
|
|
|
8
8
|
program
|
|
9
9
|
.command('usage [agent]')
|
|
10
10
|
.description('Show rate-limit / quota usage per agent')
|
|
11
|
+
.addHelpText('after', `
|
|
12
|
+
Examples:
|
|
13
|
+
agents usage Show usage for all installed agents
|
|
14
|
+
agents usage claude Show usage for Claude only
|
|
15
|
+
agents usage codex Show usage for Codex only
|
|
16
|
+
`)
|
|
11
17
|
.action(async (agentFilter) => {
|
|
12
18
|
const filter = agentFilter;
|
|
13
19
|
const targets = filter
|
package/dist/commands/utils.d.ts
CHANGED
|
@@ -38,6 +38,22 @@ export declare function printWithPager(output: string, lineCount: number): void;
|
|
|
38
38
|
* Parse a comma-separated CLI list, trimming whitespace and dropping empties.
|
|
39
39
|
*/
|
|
40
40
|
export declare function parseCommaSeparatedList(value: string | undefined): string[];
|
|
41
|
+
/**
|
|
42
|
+
* A target for resource removal: agent + version.
|
|
43
|
+
*/
|
|
44
|
+
export interface RemovalTarget {
|
|
45
|
+
agent: string;
|
|
46
|
+
version: string;
|
|
47
|
+
label: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Prompt user to select which agent/version targets to remove a resource from.
|
|
51
|
+
* If only one target, returns it without prompting. If multiple, shows checkbox.
|
|
52
|
+
* Returns empty array if user cancels or selects nothing.
|
|
53
|
+
*/
|
|
54
|
+
export declare function promptRemovalTargets(resourceName: string, targets: RemovalTarget[], options?: {
|
|
55
|
+
skipPrompt?: boolean;
|
|
56
|
+
}): Promise<RemovalTarget[]>;
|
|
41
57
|
/**
|
|
42
58
|
* Format a path for display, using ~ for home directory
|
|
43
59
|
*/
|
package/dist/commands/utils.js
CHANGED
|
@@ -89,6 +89,38 @@ export function parseCommaSeparatedList(value) {
|
|
|
89
89
|
.map((item) => item.trim())
|
|
90
90
|
.filter(Boolean);
|
|
91
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Prompt user to select which agent/version targets to remove a resource from.
|
|
94
|
+
* If only one target, returns it without prompting. If multiple, shows checkbox.
|
|
95
|
+
* Returns empty array if user cancels or selects nothing.
|
|
96
|
+
*/
|
|
97
|
+
export async function promptRemovalTargets(resourceName, targets, options) {
|
|
98
|
+
if (targets.length === 0)
|
|
99
|
+
return [];
|
|
100
|
+
if (targets.length === 1 || options?.skipPrompt)
|
|
101
|
+
return targets;
|
|
102
|
+
if (!isInteractiveTerminal()) {
|
|
103
|
+
return targets;
|
|
104
|
+
}
|
|
105
|
+
const { checkbox } = await import('@inquirer/prompts');
|
|
106
|
+
try {
|
|
107
|
+
const selected = await checkbox({
|
|
108
|
+
message: `Select targets to remove '${resourceName}' from`,
|
|
109
|
+
choices: targets.map((t) => ({
|
|
110
|
+
value: t,
|
|
111
|
+
name: t.label,
|
|
112
|
+
checked: true,
|
|
113
|
+
})),
|
|
114
|
+
});
|
|
115
|
+
return selected;
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
if (isPromptCancelled(err)) {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
92
124
|
/**
|
|
93
125
|
* Format a path for display, using ~ for home directory
|
|
94
126
|
*/
|
|
@@ -104,7 +104,7 @@ When to use:
|
|
|
104
104
|
- Multi-account: install different versions for different accounts (each version has its own auth)
|
|
105
105
|
- Project-specific: lock a version for a repo with --project
|
|
106
106
|
|
|
107
|
-
Note: The first version you install
|
|
107
|
+
Note: The first version you install becomes the default automatically.
|
|
108
108
|
`)
|
|
109
109
|
.action(async (specs, options) => {
|
|
110
110
|
const isProject = options.project;
|
|
@@ -220,10 +220,14 @@ Note: The first version you install is NOT set as default automatically. Run 'ag
|
|
|
220
220
|
console.log(chalk.green(` Synced: ${synced.join(', ')}`));
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
|
-
//
|
|
223
|
+
// Set as default: auto-set if no default exists, otherwise prompt
|
|
224
224
|
const currentDefault = getGlobalDefault(agent);
|
|
225
225
|
if (currentDefault !== installedVersion) {
|
|
226
|
-
if (
|
|
226
|
+
if (!currentDefault) {
|
|
227
|
+
// First install for this agent - auto-set without prompting
|
|
228
|
+
await setDefaultVersion(agent, installedVersion);
|
|
229
|
+
}
|
|
230
|
+
else if (skipPrompts) {
|
|
227
231
|
await setDefaultVersion(agent, installedVersion);
|
|
228
232
|
}
|
|
229
233
|
else {
|
|
@@ -238,9 +242,7 @@ Note: The first version you install is NOT set as default automatically. Run 'ag
|
|
|
238
242
|
info,
|
|
239
243
|
});
|
|
240
244
|
const accountHint = formatAccountHint(info, usage.snapshot);
|
|
241
|
-
const message = currentDefault
|
|
242
|
-
? `Switch default from ${agentLabel(agentConfig.id)}@${currentDefault} to ${agentLabel(agentConfig.id)}@${installedVersion}${accountHint}?`
|
|
243
|
-
: `Set ${agentLabel(agentConfig.id)}@${installedVersion}${accountHint} as default?`;
|
|
245
|
+
const message = `Switch default from ${agentLabel(agentConfig.id)}@${currentDefault} to ${agentLabel(agentConfig.id)}@${installedVersion}${accountHint}?`;
|
|
244
246
|
const setAsDefault = await confirm({
|
|
245
247
|
message,
|
|
246
248
|
default: true,
|
package/dist/commands/view.js
CHANGED
|
@@ -2,16 +2,16 @@ import chalk from 'chalk';
|
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
4
|
import * as path from 'path';
|
|
5
|
-
import * as yaml from 'yaml';
|
|
6
5
|
import { AGENTS, ALL_AGENT_IDS, getAllCliStates, getAccountInfo, resolveAgentName, formatAgentError, agentLabel, colorAgent, } from '../lib/agents.js';
|
|
7
6
|
import { formatUsageSection, formatUsageSummary, getUsageInfoForIdentity, getUsageInfoByIdentity, getUsageLookupKey, } from '../lib/usage.js';
|
|
8
7
|
import { readManifest } from '../lib/manifest.js';
|
|
9
8
|
import { listInstalledVersions, listInstalledVersionDirs, getGlobalDefault, getVersionHomePath, getVersionDir, resolveVersionAlias, getAvailableResources, getActuallySyncedResources, getNewResources, hasNewResources, promptNewResourceSelection, syncResourcesToVersion, removeVersion, } from '../lib/versions.js';
|
|
10
9
|
import { getShimsDir, isShimsInPath, ensureVersionedAliasCurrent, removeShim, } from '../lib/shims.js';
|
|
11
10
|
import { getAgentResources } from '../lib/resources.js';
|
|
12
|
-
import { getAgentsDir, getUserAgentsDir,
|
|
11
|
+
import { getAgentsDir, getUserAgentsDir, getEffectivePromptcutsPath, readMergedPromptcuts } from '../lib/state.js';
|
|
13
12
|
import { isGitRepo, getGitSyncStatus } from '../lib/git.js';
|
|
14
13
|
import { getCentralRulesFileName } from '../lib/rules/rules.js';
|
|
14
|
+
import { composeRulesFromState } from '../lib/rules/compose.js';
|
|
15
15
|
import { getConfiguredRunStrategy } from '../lib/rotate.js';
|
|
16
16
|
import { confirm } from '@inquirer/prompts';
|
|
17
17
|
import { formatPath, isInteractiveTerminal, isPromptCancelled } from './utils.js';
|
|
@@ -512,25 +512,19 @@ async function showAgentResources(agentId, requestedVersion) {
|
|
|
512
512
|
console.log(` ${display.padEnd(38)} ${pathStr}${syncStr}`);
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
|
-
// Render
|
|
516
|
-
//
|
|
515
|
+
// Render promptcuts (cross-agent, not per-version). Shortcuts are layered
|
|
516
|
+
// across system + user files with user precedence; the displayed file path
|
|
517
|
+
// is whichever is "live" — user if it exists, else system.
|
|
517
518
|
function renderPromptcuts() {
|
|
518
519
|
console.log(chalk.bold(`\nPromptcuts\n`));
|
|
519
|
-
const
|
|
520
|
-
|
|
520
|
+
const merged = readMergedPromptcuts();
|
|
521
|
+
const count = Object.keys(merged).length;
|
|
522
|
+
if (count === 0) {
|
|
521
523
|
console.log(` ${chalk.gray('none')}`);
|
|
522
524
|
return;
|
|
523
525
|
}
|
|
524
|
-
let count = 0;
|
|
525
|
-
try {
|
|
526
|
-
const parsed = yaml.parse(fs.readFileSync(promptcutsPath, 'utf-8'));
|
|
527
|
-
count = parsed?.shortcuts ? Object.keys(parsed.shortcuts).length : 0;
|
|
528
|
-
}
|
|
529
|
-
catch {
|
|
530
|
-
count = 0;
|
|
531
|
-
}
|
|
532
526
|
const label = `${count} shortcut${count === 1 ? '' : 's'}`;
|
|
533
|
-
console.log(` ${chalk.green(label).padEnd(24)} ${chalk.gray(formatPath(
|
|
527
|
+
console.log(` ${chalk.green(label).padEnd(24)} ${chalk.gray(formatPath(getEffectivePromptcutsPath(), cwd))}`);
|
|
534
528
|
}
|
|
535
529
|
// 1. Agent CLI info
|
|
536
530
|
console.log(chalk.bold('Agent CLIs\n'));
|
|
@@ -565,7 +559,58 @@ async function showAgentResources(agentId, requestedVersion) {
|
|
|
565
559
|
}
|
|
566
560
|
}
|
|
567
561
|
renderSection('MCP Servers', agentData.mcp);
|
|
568
|
-
|
|
562
|
+
// Rules section with subrules breakdown
|
|
563
|
+
function renderRulesSection() {
|
|
564
|
+
console.log(chalk.bold('\nRules\n'));
|
|
565
|
+
const items = agentData.memory;
|
|
566
|
+
if (items.length === 0) {
|
|
567
|
+
console.log(` ${chalk.gray('none')}`);
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
const versionStr = agentData.version ? ` (${agentData.version})` : '';
|
|
571
|
+
console.log(` ${chalk.bold(agentData.agentName)}${chalk.gray(versionStr)}:`);
|
|
572
|
+
// Get composed subrules for the user scope
|
|
573
|
+
let composedSubrules = [];
|
|
574
|
+
try {
|
|
575
|
+
const composed = composeRulesFromState({ cwd });
|
|
576
|
+
composedSubrules = composed.subrules;
|
|
577
|
+
}
|
|
578
|
+
catch {
|
|
579
|
+
// No preset configured or rules.yaml missing — show rules without subrule breakdown
|
|
580
|
+
}
|
|
581
|
+
for (const r of items) {
|
|
582
|
+
let nameColor = chalk.cyan;
|
|
583
|
+
if (r.syncState === 'synced')
|
|
584
|
+
nameColor = chalk.green;
|
|
585
|
+
else if (r.syncState === 'new')
|
|
586
|
+
nameColor = chalk.blue;
|
|
587
|
+
else if (r.syncState === 'modified')
|
|
588
|
+
nameColor = chalk.yellow;
|
|
589
|
+
else if (r.syncState === 'deleted')
|
|
590
|
+
nameColor = chalk.red;
|
|
591
|
+
let display = nameColor(r.name);
|
|
592
|
+
if (r.ruleCount !== undefined)
|
|
593
|
+
display += chalk.gray(` (${r.ruleCount} rules)`);
|
|
594
|
+
const sourceTag = r.scope === 'project' ? chalk.blue('[project]')
|
|
595
|
+
: r.scope === 'user' ? chalk.cyan('[user]')
|
|
596
|
+
: chalk.gray('[system]');
|
|
597
|
+
display += ` ${sourceTag}`;
|
|
598
|
+
const pathStr = r.path ? chalk.gray(formatPath(r.path, cwd)) : '';
|
|
599
|
+
const syncStr = r.syncState ? chalk.gray(` [${r.syncState}]`) : '';
|
|
600
|
+
console.log(` ${display.padEnd(38)} ${pathStr}${syncStr}`);
|
|
601
|
+
// Show subrules for user-scope rules (the compiled CLAUDE.md)
|
|
602
|
+
if (r.scope === 'user' && composedSubrules.length > 0) {
|
|
603
|
+
for (const sub of composedSubrules) {
|
|
604
|
+
const scopeLabel = sub.layerScope === 'project' ? chalk.blue('[project]')
|
|
605
|
+
: sub.layerScope === 'user' ? chalk.cyan('[user]')
|
|
606
|
+
: sub.layerScope === 'extra' ? chalk.magenta(`[${sub.layerAlias || 'extra'}]`)
|
|
607
|
+
: chalk.gray('[system]');
|
|
608
|
+
console.log(` ${chalk.gray('-')} ${sub.name} ${scopeLabel}`);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
renderRulesSection();
|
|
569
614
|
renderSection('Hooks', agentData.hooks);
|
|
570
615
|
renderPromptcuts();
|
|
571
616
|
// Show legend at the end if git repo exists
|
package/dist/index.d.ts
CHANGED