@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
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { confirm } from '@inquirer/prompts';
|
|
5
|
+
import { listCliManifests, listCliStatus, resolveCliManifest, installCli, describeMethod, describeCheck, selectInstallMethod, isCliInstalled, } from '../lib/cli-resources.js';
|
|
6
|
+
import { getUserAgentsDir } from '../lib/state.js';
|
|
7
|
+
import { isPromptCancelled } from './utils.js';
|
|
8
|
+
function userCliDir() {
|
|
9
|
+
return path.join(getUserAgentsDir(), 'cli');
|
|
10
|
+
}
|
|
11
|
+
/** Render the status table — one row per declared CLI. */
|
|
12
|
+
function printStatus(rows) {
|
|
13
|
+
if (rows.length === 0) {
|
|
14
|
+
console.log(chalk.gray('No CLIs declared.'));
|
|
15
|
+
console.log(chalk.gray(`Create one with: agents cli add <name>`));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const nameWidth = Math.max(4, ...rows.map((r) => r.manifest.name.length));
|
|
19
|
+
for (const row of rows) {
|
|
20
|
+
const status = row.installed
|
|
21
|
+
? chalk.green('installed')
|
|
22
|
+
: chalk.yellow('missing');
|
|
23
|
+
const name = row.manifest.name.padEnd(nameWidth);
|
|
24
|
+
const source = chalk.gray(`[${row.manifest.source}]`);
|
|
25
|
+
const desc = row.manifest.description ? ' ' + chalk.gray(row.manifest.description) : '';
|
|
26
|
+
console.log(` ${name} ${status} ${source}${desc}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function registerCliCommands(program) {
|
|
30
|
+
const cliCmd = program
|
|
31
|
+
.command('cli')
|
|
32
|
+
.description('Declare and install host CLI binaries (gh, higgsfield, glab, ...)')
|
|
33
|
+
.addHelpText('after', `
|
|
34
|
+
CLI manifests live in <repo>/cli/<name>.yaml and declare how to install a
|
|
35
|
+
binary on the host. On a fresh machine, 'agents cli install' runs the first
|
|
36
|
+
compatible method (npm > brew > script > binary) for every declared entry.
|
|
37
|
+
|
|
38
|
+
Examples:
|
|
39
|
+
# See which declared CLIs are installed on this host
|
|
40
|
+
agents cli list
|
|
41
|
+
|
|
42
|
+
# Install everything that's missing
|
|
43
|
+
agents cli install
|
|
44
|
+
|
|
45
|
+
# Install one
|
|
46
|
+
agents cli install higgsfield
|
|
47
|
+
|
|
48
|
+
# Show the manifest detail
|
|
49
|
+
agents cli view higgsfield
|
|
50
|
+
|
|
51
|
+
# Exit 0 if all declared CLIs are installed (use in CI / setup scripts)
|
|
52
|
+
agents cli check
|
|
53
|
+
|
|
54
|
+
When to use:
|
|
55
|
+
- After 'agents pull' on a new machine, to materialize host binaries
|
|
56
|
+
- In a team setup: commit cli/ entries so teammates get the same toolchain
|
|
57
|
+
`);
|
|
58
|
+
cliCmd
|
|
59
|
+
.command('list')
|
|
60
|
+
.description('Show all declared CLIs and whether each is installed on this host')
|
|
61
|
+
.action(() => {
|
|
62
|
+
const { statuses, errors } = listCliStatus(process.cwd());
|
|
63
|
+
printStatus(statuses);
|
|
64
|
+
for (const err of errors) {
|
|
65
|
+
console.log(chalk.red(` parse error: ${err.file}: ${err.reason}`));
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
cliCmd
|
|
69
|
+
.command('check')
|
|
70
|
+
.description('Exit 0 if every declared CLI is installed, 1 otherwise')
|
|
71
|
+
.action(() => {
|
|
72
|
+
const { statuses, errors } = listCliStatus(process.cwd());
|
|
73
|
+
const missing = statuses.filter((s) => !s.installed);
|
|
74
|
+
if (errors.length > 0) {
|
|
75
|
+
for (const err of errors) {
|
|
76
|
+
console.error(chalk.red(`parse error: ${err.file}: ${err.reason}`));
|
|
77
|
+
}
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
if (missing.length === 0) {
|
|
81
|
+
console.log(chalk.green(`All ${statuses.length} declared CLI(s) installed.`));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
console.log(chalk.yellow(`Missing: ${missing.map((s) => s.manifest.name).join(', ')}`));
|
|
85
|
+
process.exit(1);
|
|
86
|
+
});
|
|
87
|
+
cliCmd
|
|
88
|
+
.command('install [name]')
|
|
89
|
+
.description('Install one (by name) or all missing declared CLIs')
|
|
90
|
+
.option('-y, --yes', 'skip the confirmation prompt')
|
|
91
|
+
.option('--dry-run', 'print install commands without executing them')
|
|
92
|
+
.option('--force', 'reinstall even when the check command currently passes')
|
|
93
|
+
.action(async (nameArg, opts) => {
|
|
94
|
+
let targets;
|
|
95
|
+
if (nameArg) {
|
|
96
|
+
const manifest = resolveCliManifest(nameArg, process.cwd());
|
|
97
|
+
if (!manifest) {
|
|
98
|
+
console.error(chalk.red(`No CLI manifest named "${nameArg}".`));
|
|
99
|
+
console.error(chalk.gray(`Looked in: ${userCliDir()}`));
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
targets = [manifest];
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const { manifests, errors } = listCliManifests(process.cwd());
|
|
106
|
+
for (const err of errors) {
|
|
107
|
+
console.error(chalk.red(`parse error: ${err.file}: ${err.reason}`));
|
|
108
|
+
}
|
|
109
|
+
if (manifests.length === 0) {
|
|
110
|
+
console.log(chalk.gray('No CLIs declared. Nothing to install.'));
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
targets = manifests;
|
|
114
|
+
}
|
|
115
|
+
// Filter out already-installed unless --force
|
|
116
|
+
const work = targets.filter((m) => opts.force || !isCliInstalled(m));
|
|
117
|
+
if (work.length === 0) {
|
|
118
|
+
console.log(chalk.green(`All ${targets.length} declared CLI(s) already installed.`));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// Preview + confirm
|
|
122
|
+
console.log(chalk.bold('\nWill install:'));
|
|
123
|
+
for (const m of work) {
|
|
124
|
+
const method = selectInstallMethod(m);
|
|
125
|
+
const action = method ? describeMethod(method) : chalk.red('no compatible install method');
|
|
126
|
+
console.log(` ${chalk.cyan(m.name.padEnd(20))} ${chalk.gray(action)}`);
|
|
127
|
+
}
|
|
128
|
+
console.log('');
|
|
129
|
+
if (!opts.yes && !opts.dryRun) {
|
|
130
|
+
try {
|
|
131
|
+
const proceed = await confirm({ message: 'Proceed?', default: true });
|
|
132
|
+
if (!proceed) {
|
|
133
|
+
console.log(chalk.gray('Cancelled.'));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
if (isPromptCancelled(err)) {
|
|
139
|
+
console.log(chalk.gray('Cancelled.'));
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
throw err;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Execute
|
|
146
|
+
let failures = 0;
|
|
147
|
+
for (const m of work) {
|
|
148
|
+
console.log(chalk.bold(`\n→ ${m.name}`));
|
|
149
|
+
const result = installCli(m, { dryRun: opts.dryRun });
|
|
150
|
+
if (result.output)
|
|
151
|
+
console.log(chalk.gray(result.output));
|
|
152
|
+
if (result.error) {
|
|
153
|
+
console.log(chalk.red(` ${result.error}`));
|
|
154
|
+
failures++;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (opts.dryRun)
|
|
158
|
+
continue;
|
|
159
|
+
if (result.installed) {
|
|
160
|
+
console.log(chalk.green(` installed (${describeMethod(result.method)})`));
|
|
161
|
+
if (m.postInstall) {
|
|
162
|
+
console.log(chalk.gray(m.postInstall.trim().split('\n').map((l) => ' ' + l).join('\n')));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
console.log(chalk.yellow(` install command ran but \`${describeCheck(m.check)}\` still fails — check the output above`));
|
|
167
|
+
failures++;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (failures > 0)
|
|
171
|
+
process.exit(1);
|
|
172
|
+
});
|
|
173
|
+
cliCmd
|
|
174
|
+
.command('view <name>')
|
|
175
|
+
.description('Show the parsed manifest detail')
|
|
176
|
+
.action((name) => {
|
|
177
|
+
const manifest = resolveCliManifest(name, process.cwd());
|
|
178
|
+
if (!manifest) {
|
|
179
|
+
console.error(chalk.red(`No CLI manifest named "${name}".`));
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
console.log(chalk.bold.cyan(manifest.name));
|
|
183
|
+
if (manifest.description)
|
|
184
|
+
console.log(' ' + chalk.gray(manifest.description));
|
|
185
|
+
if (manifest.homepage)
|
|
186
|
+
console.log(' ' + chalk.gray(manifest.homepage));
|
|
187
|
+
console.log(' ' + chalk.gray(`source: ${manifest.source}`));
|
|
188
|
+
console.log(' ' + chalk.gray(`file: ${manifest.path}`));
|
|
189
|
+
console.log('');
|
|
190
|
+
console.log(chalk.bold(' check'));
|
|
191
|
+
console.log(' ' + describeCheck(manifest.check));
|
|
192
|
+
console.log('');
|
|
193
|
+
console.log(chalk.bold(' install methods'));
|
|
194
|
+
for (const method of manifest.install) {
|
|
195
|
+
console.log(' ' + describeMethod(method));
|
|
196
|
+
}
|
|
197
|
+
if (manifest.postInstall) {
|
|
198
|
+
console.log('');
|
|
199
|
+
console.log(chalk.bold(' post_install'));
|
|
200
|
+
for (const line of manifest.postInstall.trim().split('\n')) {
|
|
201
|
+
console.log(' ' + line);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
console.log('');
|
|
205
|
+
console.log(` status: ${isCliInstalled(manifest) ? chalk.green('installed') : chalk.yellow('missing')}`);
|
|
206
|
+
});
|
|
207
|
+
cliCmd
|
|
208
|
+
.command('add <name>')
|
|
209
|
+
.description('Scaffold a new manifest at ~/.agents/cli/<name>.yaml')
|
|
210
|
+
.option('--npm <pkg>', 'declare an npm install method')
|
|
211
|
+
.option('--brew <formula>', 'declare a brew install method')
|
|
212
|
+
.option('--script <url>', 'declare a curl|sh install method')
|
|
213
|
+
.option('--description <text>', 'one-line description')
|
|
214
|
+
.option('--homepage <url>', 'project homepage')
|
|
215
|
+
.action((name, opts) => {
|
|
216
|
+
const dir = userCliDir();
|
|
217
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
218
|
+
const target = path.join(dir, `${name}.yaml`);
|
|
219
|
+
if (fs.existsSync(target)) {
|
|
220
|
+
console.error(chalk.red(`Already exists: ${target}`));
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
const methods = [];
|
|
224
|
+
if (opts.npm)
|
|
225
|
+
methods.push(` - npm: "${opts.npm}"`);
|
|
226
|
+
if (opts.brew)
|
|
227
|
+
methods.push(` - brew: ${opts.brew}`);
|
|
228
|
+
if (opts.script)
|
|
229
|
+
methods.push(` - script: ${opts.script}`);
|
|
230
|
+
if (methods.length === 0) {
|
|
231
|
+
methods.push(` - npm: "${name}"`);
|
|
232
|
+
}
|
|
233
|
+
const lines = [
|
|
234
|
+
`name: ${name}`,
|
|
235
|
+
...(opts.description ? [`description: ${opts.description}`] : []),
|
|
236
|
+
...(opts.homepage ? [`homepage: ${opts.homepage}`] : []),
|
|
237
|
+
`check: ${name} --version`,
|
|
238
|
+
`install:`,
|
|
239
|
+
...methods,
|
|
240
|
+
];
|
|
241
|
+
fs.writeFileSync(target, lines.join('\n') + '\n');
|
|
242
|
+
console.log(chalk.green(`Created ${target}`));
|
|
243
|
+
});
|
|
244
|
+
}
|
package/dist/commands/cloud.js
CHANGED
|
@@ -68,7 +68,7 @@ Examples:
|
|
|
68
68
|
agents cloud run "add pytest fixtures for the new billing module" --provider codex --env env_a1b2c3 --agent codex --timeout 30m
|
|
69
69
|
|
|
70
70
|
# Factory pod targeting a specific computer (Droid)
|
|
71
|
-
agents cloud run "QA the new onboarding flow end-to-end" --provider factory --computer
|
|
71
|
+
agents cloud run "QA the new onboarding flow end-to-end" --provider factory --computer linux-vm-1 --agent droid
|
|
72
72
|
|
|
73
73
|
# See every cloud task you've dispatched (most recent first)
|
|
74
74
|
agents cloud list
|
|
@@ -9,9 +9,9 @@ import { cloneRepo } from '../lib/git.js';
|
|
|
9
9
|
import { discoverCommands, resolveCommandSource, installCommandCentrally, listCentralCommands, listInstalledCommandsWithScope, getCommandInfo, diffVersionCommands, iterCommandsCapableVersions, removeCommandFromVersion, } from '../lib/commands.js';
|
|
10
10
|
import { getCommandsDir } from '../lib/state.js';
|
|
11
11
|
import { showResourceList, buildTargetsSection, } from './resource-view.js';
|
|
12
|
-
import { getGlobalDefault, resolveVersionAlias, syncResourcesToVersion, promptAgentVersionSelection, getVersionHomePath,
|
|
12
|
+
import { listInstalledVersions, getGlobalDefault, resolveVersionAlias, syncResourcesToVersion, promptAgentVersionSelection, getVersionHomePath, resolveInstalledAgentTargets, } from '../lib/versions.js';
|
|
13
13
|
import { recordVersionResources } from '../lib/state.js';
|
|
14
|
-
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, promptRemovalTargets, } from './utils.js';
|
|
14
|
+
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, promptRemovalTargets, resolveAgentTargetsAutoInstalling, } from './utils.js';
|
|
15
15
|
/** Register the `agents commands` command tree (list, add, remove, sync, prune, view). */
|
|
16
16
|
export function registerCommandsCommands(program) {
|
|
17
17
|
const commandsCmd = program
|
|
@@ -214,13 +214,17 @@ Examples:
|
|
|
214
214
|
let selectedAgents;
|
|
215
215
|
let versionSelections;
|
|
216
216
|
if (options.agents) {
|
|
217
|
-
const result =
|
|
217
|
+
const result = await resolveAgentTargetsAutoInstalling(options.agents, ALL_AGENT_IDS, { yes: options.yes });
|
|
218
|
+
if (!result) {
|
|
219
|
+
console.log(chalk.gray('Cancelled.'));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
218
222
|
selectedAgents = result.selectedAgents;
|
|
219
223
|
versionSelections = result.versionSelections;
|
|
220
224
|
}
|
|
221
225
|
else {
|
|
222
226
|
const result = await promptAgentVersionSelection(ALL_AGENT_IDS, {
|
|
223
|
-
skipPrompts: options.yes
|
|
227
|
+
skipPrompts: options.yes,
|
|
224
228
|
});
|
|
225
229
|
selectedAgents = result.selectedAgents;
|
|
226
230
|
versionSelections = result.versionSelections;
|
|
@@ -334,11 +338,24 @@ Examples:
|
|
|
334
338
|
console.log(chalk.yellow(` Command '${cmdName}' not found in any version.`));
|
|
335
339
|
continue;
|
|
336
340
|
}
|
|
337
|
-
// Filter by --agents if specified
|
|
341
|
+
// Filter by --agents if specified. Routes through resolveInstalledAgentTargets
|
|
342
|
+
// so the same selector syntax used everywhere else (agent, agent@default,
|
|
343
|
+
// agent@x.y.z, agent@all, literal all) works here too.
|
|
338
344
|
let availableTargets = cmdInfo.targets;
|
|
339
345
|
if (options?.agents) {
|
|
340
|
-
const
|
|
341
|
-
|
|
346
|
+
const requestedTargets = resolveInstalledAgentTargets(options.agents, ALL_AGENT_IDS);
|
|
347
|
+
const requested = new Set();
|
|
348
|
+
for (const aid of requestedTargets.directAgents) {
|
|
349
|
+
for (const ver of listInstalledVersions(aid)) {
|
|
350
|
+
requested.add(`${aid}@${ver}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
for (const [aid, versions] of requestedTargets.versionSelections) {
|
|
354
|
+
for (const ver of versions) {
|
|
355
|
+
requested.add(`${aid}@${ver}`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
availableTargets = availableTargets.filter((t) => requested.has(`${t.agent}@${t.version}`));
|
|
342
359
|
}
|
|
343
360
|
if (availableTargets.length === 0) {
|
|
344
361
|
console.log(chalk.yellow(` Command '${cmdName}' not found in specified agents.`));
|
|
@@ -383,17 +400,17 @@ Examples:
|
|
|
383
400
|
.action(() => {
|
|
384
401
|
console.error(chalk.red('"agents commands sync" is gone.'));
|
|
385
402
|
console.error(chalk.gray('Sync runs automatically when you launch the agent.'));
|
|
386
|
-
console.error(chalk.gray('To remove orphans, use: agents prune commands'));
|
|
403
|
+
console.error(chalk.gray('To remove orphans, use: agents prune cleanup commands'));
|
|
387
404
|
process.exit(1);
|
|
388
405
|
});
|
|
389
|
-
// `commands prune` moved to the top-level `agents prune` command.
|
|
406
|
+
// `commands prune` moved to the top-level `agents prune cleanup` command.
|
|
390
407
|
commandsCmd
|
|
391
408
|
.command('prune', { hidden: true })
|
|
392
409
|
.allowUnknownOption()
|
|
393
410
|
.allowExcessArguments()
|
|
394
411
|
.action(() => {
|
|
395
412
|
console.error(chalk.red('"agents commands prune" moved.'));
|
|
396
|
-
console.error(chalk.gray('Use: agents prune commands (or `agents prune` for everything)'));
|
|
413
|
+
console.error(chalk.gray('Use: agents prune cleanup commands (or `agents prune cleanup` for everything)'));
|
|
397
414
|
process.exit(1);
|
|
398
415
|
});
|
|
399
416
|
commandsCmd
|
|
@@ -3,7 +3,7 @@ import * as fs from 'fs';
|
|
|
3
3
|
import * as os from 'os';
|
|
4
4
|
import * as path from 'path';
|
|
5
5
|
import { registerCommandGroups } from '../lib/help.js';
|
|
6
|
-
import { openComputerClient, resolveHelperApp, resolveHelperExec, resolveSocketPath, resolveLogPath, resolvePolicyPath, describeTransport, loadComputerAllowList, writeComputerPolicy, } from '../lib/computer-rpc.js';
|
|
6
|
+
import { openComputerClient, resolveHelperApp, resolveHelperExec, resolveSocketPath, resolveLogPath, resolvePolicyPath, resolvePeersPath, describeTransport, loadComputerAllowList, loadDefaultPeers, writeComputerPolicy, writeComputerPeers, } from '../lib/computer-rpc.js';
|
|
7
7
|
// Help groups — mirror `agents browser` so the mental model carries over.
|
|
8
8
|
const COMPUTER_HELP_GROUPS = [
|
|
9
9
|
{ title: 'Installation', names: ['install-helper'] },
|
|
@@ -46,6 +46,8 @@ function registerStatusCommand(program) {
|
|
|
46
46
|
const previewParts = allowed.slice(0, 5);
|
|
47
47
|
const previewSuffix = allowed.length > 5 ? ` (+${allowed.length - 5} more)` : '';
|
|
48
48
|
console.log(`policy: ${allowed.length} app${allowed.length === 1 ? '' : 's'} allowed${allowed.length > 0 ? `: ${previewParts.join(', ')}${previewSuffix}` : ''}`);
|
|
49
|
+
const callers = loadDefaultPeers();
|
|
50
|
+
console.log(`peers: ${callers.length} caller${callers.length === 1 ? '' : 's'} (peer-auth on socket)`);
|
|
49
51
|
if (!installed) {
|
|
50
52
|
console.log('');
|
|
51
53
|
console.log('Run: agents computer install-helper');
|
|
@@ -284,6 +286,15 @@ function registerStartCommand(program) {
|
|
|
284
286
|
console.log(` add to ~/.agents/permissions/groups/<name>.yaml under allow:`);
|
|
285
287
|
console.log(` - "Computer(com.apple.finder)"`);
|
|
286
288
|
}
|
|
289
|
+
// Peer-auth allow list — which caller executables may connect to
|
|
290
|
+
// the socket. Default: this CLI's Node binary, plus Rush.app if
|
|
291
|
+
// installed. A `nc -U socket` from a malicious npm postinstall has
|
|
292
|
+
// a different exec path and gets refused at accept().
|
|
293
|
+
const callers = loadDefaultPeers();
|
|
294
|
+
writeComputerPeers(callers);
|
|
295
|
+
console.log(`peers: ${callers.length} caller${callers.length === 1 ? '' : 's'} allowed (${resolvePeersPath()})`);
|
|
296
|
+
for (const p of callers)
|
|
297
|
+
console.log(` ${p}`);
|
|
287
298
|
// Bootout first to clear any prior registration. Best-effort.
|
|
288
299
|
try {
|
|
289
300
|
execFileSync('/bin/launchctl', ['bootout', domain, plistPath], { stdio: 'pipe' });
|
|
@@ -356,6 +367,12 @@ function registerReloadCommand(program) {
|
|
|
356
367
|
const allowed = loadComputerAllowList();
|
|
357
368
|
writeComputerPolicy(allowed);
|
|
358
369
|
console.log(`policy: ${allowed.length} app${allowed.length === 1 ? '' : 's'} allowed (${resolvePolicyPath()})`);
|
|
370
|
+
// Rewrite peers list too — an upgrade of the npm-global CLI moves
|
|
371
|
+
// its node path; without this the reloaded daemon would reject the
|
|
372
|
+
// very binary that just signaled it.
|
|
373
|
+
const callers = loadDefaultPeers();
|
|
374
|
+
writeComputerPeers(callers);
|
|
375
|
+
console.log(`peers: ${callers.length} caller${callers.length === 1 ? '' : 's'} allowed (${resolvePeersPath()})`);
|
|
359
376
|
// Resolve the daemon's pid via `launchctl list <label>`. The plist
|
|
360
377
|
// output includes a "PID" key when the service is running.
|
|
361
378
|
const uid = process.getuid?.();
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* unified diff body for each divergent file. Mirrors the resolution that
|
|
16
16
|
* the shim drives at runtime: project > user > system > extras.
|
|
17
17
|
*
|
|
18
|
-
* Read-only: doctor never mutates state. Run `agents prune` to act on orphan
|
|
18
|
+
* Read-only: doctor never mutates state. Run `agents prune cleanup` to act on orphan
|
|
19
19
|
* readouts, or just launch the agent to apply pending sync.
|
|
20
20
|
*/
|
|
21
21
|
import type { Command } from 'commander';
|
package/dist/commands/doctor.js
CHANGED
|
@@ -114,7 +114,7 @@ function renderOverviewText(clis, syncRows, orphanRows) {
|
|
|
114
114
|
const label = `${AGENT_NAMES[row.agent] || row.agent}@${row.version}`;
|
|
115
115
|
console.log(` ${chalk.yellow('warn ')} ${label} ${chalk.gray(parts.join(', '))}`);
|
|
116
116
|
}
|
|
117
|
-
console.log(chalk.gray(' Run `agents prune` to remove.'));
|
|
117
|
+
console.log(chalk.gray(' Run `agents prune cleanup` to remove.'));
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
function parseTargetArg(arg) {
|
|
@@ -310,7 +310,7 @@ function renderTargetText(report, options) {
|
|
|
310
310
|
}
|
|
311
311
|
else {
|
|
312
312
|
console.log(` Verdict: ${verdictParts.join(', ')}.`);
|
|
313
|
-
console.log(chalk.gray(` Run \`agents sync --agent ${report.agent} --agent-version ${report.version}\` to reconcile, or \`agents prune\` to drop extras.`));
|
|
313
|
+
console.log(chalk.gray(` Run \`agents sync --agent ${report.agent} --agent-version ${report.version}\` to reconcile, or \`agents prune cleanup\` to drop extras.`));
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
316
|
// ─── command registration ────────────────────────────────────────────────────
|
package/dist/commands/exec.js
CHANGED
|
@@ -6,20 +6,13 @@
|
|
|
6
6
|
* injection, and multi-agent fallback chains for rate-limit resilience.
|
|
7
7
|
*/
|
|
8
8
|
import chalk from 'chalk';
|
|
9
|
-
import { buildExecCommand, parseExecEnv, execAgent, runWithFallback, AGENT_COMMANDS, } from '../lib/exec.js';
|
|
10
|
-
import { profileExists, resolveProfileForRun } from '../lib/profiles.js';
|
|
11
9
|
import { setHelpSections } from '../lib/help.js';
|
|
12
|
-
import {
|
|
13
|
-
import { getConfiguredRunStrategy, normalizeRunStrategy, resolveRunVersion, RUN_STRATEGIES, } from '../lib/rotate.js';
|
|
14
|
-
import { getGlobalDefault, getVersionHomePath, resolveVersionAlias } from '../lib/versions.js';
|
|
15
|
-
import { buildDiscoveredPlugin, loadPluginManifest, syncPluginToVersion } from '../lib/plugins.js';
|
|
16
|
-
import { parseWorkflowFrontmatter, resolveWorkflowRef } from '../lib/workflows.js';
|
|
10
|
+
import { AGENTS } from '../lib/agents.js';
|
|
17
11
|
import * as fs from 'fs';
|
|
18
12
|
import * as path from 'path';
|
|
19
|
-
const VALID_AGENTS = Object.keys(AGENT_COMMANDS);
|
|
20
13
|
/** Type guard that narrows a string to a known AgentId. */
|
|
21
14
|
function isValidAgent(agent) {
|
|
22
|
-
return
|
|
15
|
+
return agent in AGENTS;
|
|
23
16
|
}
|
|
24
17
|
/** Build a one-line banner describing which version the strategy picked. */
|
|
25
18
|
function formatRotationBanner(result, verb = 'balanced') {
|
|
@@ -33,7 +26,7 @@ export function registerRunCommand(program) {
|
|
|
33
26
|
const runCmd = program
|
|
34
27
|
.command('run <agent> [prompt]')
|
|
35
28
|
.description('Execute an agent. Pass a prompt for headless runs; omit it to launch the agent interactively.')
|
|
36
|
-
.option('-m, --mode <mode>', 'How much the agent can do: plan (read-only), edit (can write files),
|
|
29
|
+
.option('-m, --mode <mode>', 'How much the agent can do: plan (read-only), edit (can write files), auto (smart classifier auto-approves safe ops, prompts for risky), skip (bypass all permission prompts). \'full\' accepted as alias for skip.', 'plan')
|
|
37
30
|
.option('-e, --effort <effort>', 'Reasoning effort: low | medium | high | xhigh | max | auto (claude and codex only)', 'auto')
|
|
38
31
|
.option('--model <model>', 'Override the model directly (e.g., claude-opus-4-6)')
|
|
39
32
|
.option('--env <key=value>', 'Pass environment variable to the agent (repeatable, e.g., --env DEBUG=1 --env API_KEY=xyz)', (val, prev) => [...prev, val], [])
|
|
@@ -73,8 +66,12 @@ export function registerRunCommand(program) {
|
|
|
73
66
|
agents run claude "deploy the worker" --secrets prod --mode edit
|
|
74
67
|
`,
|
|
75
68
|
notes: `
|
|
76
|
-
Modes:
|
|
77
|
-
plan read-only
|
|
69
|
+
Modes (not every agent supports every mode — check agents.yaml capabilities):
|
|
70
|
+
plan read-only investigation; no writes, no shell side-effects
|
|
71
|
+
edit may edit files; prompts for shell / risky operations
|
|
72
|
+
auto smart classifier auto-approves safe ops, prompts for risky (claude, copilot)
|
|
73
|
+
skip bypass every permission prompt (dangerously-skip-permissions)
|
|
74
|
+
Legacy 'full' is silently rewritten to 'skip'.
|
|
78
75
|
|
|
79
76
|
Run strategy (set via --strategy or run.<agent>.strategy in agents.yaml):
|
|
80
77
|
pinned use the workspace/global pinned version (default)
|
|
@@ -88,6 +85,17 @@ export function registerRunCommand(program) {
|
|
|
88
85
|
`,
|
|
89
86
|
});
|
|
90
87
|
runCmd.action(async (agentSpec, prompt, options) => {
|
|
88
|
+
const [{ buildExecCommand, parseExecEnv, execAgent, runWithFallback, normalizeMode, resolveMode }, { ALL_AGENT_IDS }, { profileExists, resolveProfileForRun }, { readAndResolveBundleEnv, describeBundle }, { getConfiguredRunStrategy, normalizeRunStrategy, resolveRunVersion, RUN_STRATEGIES }, { getGlobalDefault, getVersionHomePath, resolveVersionAlias }, { buildDiscoveredPlugin, loadPluginManifest, syncPluginToVersion }, { parseWorkflowFrontmatter, resolveWorkflowRef },] = await Promise.all([
|
|
89
|
+
import('../lib/exec.js'),
|
|
90
|
+
import('../lib/agents.js'),
|
|
91
|
+
import('../lib/profiles.js'),
|
|
92
|
+
import('../lib/secrets/bundles.js'),
|
|
93
|
+
import('../lib/rotate.js'),
|
|
94
|
+
import('../lib/versions.js'),
|
|
95
|
+
import('../lib/plugins.js'),
|
|
96
|
+
import('../lib/workflows.js'),
|
|
97
|
+
]);
|
|
98
|
+
const isValidAgent = (agent) => ALL_AGENT_IDS.includes(agent);
|
|
91
99
|
// Parse agent@version
|
|
92
100
|
const [rawAgent, rawVersion] = agentSpec.split('@');
|
|
93
101
|
let agent;
|
|
@@ -195,7 +203,7 @@ export function registerRunCommand(program) {
|
|
|
195
203
|
}
|
|
196
204
|
else {
|
|
197
205
|
console.error(chalk.red(`Unknown agent: ${rawAgent}`));
|
|
198
|
-
console.error(chalk.gray(`Available agents: ${
|
|
206
|
+
console.error(chalk.gray(`Available agents: ${ALL_AGENT_IDS.join(', ')}`));
|
|
199
207
|
console.error(chalk.gray(`Or add a profile: agents profiles add <name>`));
|
|
200
208
|
process.exit(1);
|
|
201
209
|
}
|
|
@@ -244,9 +252,21 @@ export function registerRunCommand(program) {
|
|
|
244
252
|
}
|
|
245
253
|
}
|
|
246
254
|
}
|
|
255
|
+
// Accept the four canonical modes plus 'full' as a permanent silent
|
|
256
|
+
// alias for 'skip' (rewritten downstream by normalizeMode in exec.ts).
|
|
247
257
|
const mode = options.mode;
|
|
248
|
-
if (!['plan', 'edit', 'full'].includes(mode)) {
|
|
249
|
-
console.error(chalk.red(`Invalid mode: ${mode}. Use
|
|
258
|
+
if (!['plan', 'edit', 'auto', 'skip', 'full'].includes(mode)) {
|
|
259
|
+
console.error(chalk.red(`Invalid mode: ${mode}. Use plan, edit, auto, or skip ('full' accepted as alias for skip).`));
|
|
260
|
+
process.exit(1);
|
|
261
|
+
}
|
|
262
|
+
// Surface capability errors as a clean CLI message instead of a stack
|
|
263
|
+
// trace from buildExecCommand. resolveMode degrades 'auto' silently and
|
|
264
|
+
// throws on unsupported 'plan'/'skip' — we catch and pretty-print.
|
|
265
|
+
try {
|
|
266
|
+
resolveMode(agent, normalizeMode(mode));
|
|
267
|
+
}
|
|
268
|
+
catch (err) {
|
|
269
|
+
console.error(chalk.red(err.message));
|
|
250
270
|
process.exit(1);
|
|
251
271
|
}
|
|
252
272
|
const effort = options.effort;
|
|
@@ -268,7 +288,7 @@ export function registerRunCommand(program) {
|
|
|
268
288
|
let secretsEnv = {};
|
|
269
289
|
for (const bundleName of options.secrets) {
|
|
270
290
|
try {
|
|
271
|
-
const bundle =
|
|
291
|
+
const { bundle, env: bundleEnv } = readAndResolveBundleEnv(bundleName, { caller: `agent ${agent}` });
|
|
272
292
|
const entries = describeBundle(bundle);
|
|
273
293
|
const counts = {};
|
|
274
294
|
for (const e of entries) {
|
|
@@ -276,7 +296,7 @@ export function registerRunCommand(program) {
|
|
|
276
296
|
}
|
|
277
297
|
const breakdown = Object.entries(counts).map(([k, v]) => `${v} ${k}`).join(', ');
|
|
278
298
|
console.log(chalk.gray(`[secrets] Resolved ${bundleName}: ${entries.length} keys (${breakdown})`));
|
|
279
|
-
secretsEnv = { ...secretsEnv, ...
|
|
299
|
+
secretsEnv = { ...secretsEnv, ...bundleEnv };
|
|
280
300
|
}
|
|
281
301
|
catch (err) {
|
|
282
302
|
console.error(chalk.red(err.message));
|
|
@@ -328,7 +348,7 @@ export function registerRunCommand(program) {
|
|
|
328
348
|
const [fbAgent, fbVersion] = entry.split('@');
|
|
329
349
|
if (!isValidAgent(fbAgent)) {
|
|
330
350
|
console.error(chalk.red(`Unknown fallback agent: ${fbAgent}`));
|
|
331
|
-
console.error(chalk.gray(`Available: ${
|
|
351
|
+
console.error(chalk.gray(`Available: ${ALL_AGENT_IDS.join(', ')}`));
|
|
332
352
|
process.exit(1);
|
|
333
353
|
}
|
|
334
354
|
if (fbAgent === agent) {
|
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Software Factory CLI
|
|
2
|
+
* Software Factory CLI — submits Linear issues to a remote orchestrator.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* agents factory submit <linear-ref> POST /factory/submit
|
|
7
|
-
*
|
|
8
|
-
* Everything else (planner pod, worker dispatch, PR-merged/CI-failed
|
|
9
|
-
* webhooks, retry caps, heartbeat reaper) lives server-side in
|
|
10
|
-
* `agents/prix/factory/service/src/factory.ts`, driven by the
|
|
11
|
-
* `factory-tick` k8s CronJob. The laptop is optional after submit.
|
|
12
|
-
*
|
|
13
|
-
* Future verbs (list / status / tail / cancel / message) are intentionally
|
|
14
|
-
* deferred until the matching server endpoints land; they'll be thin
|
|
15
|
-
* clients too. No supervisor, ledger, oracle, or `~/.agents/factory/`
|
|
16
|
-
* registry on the laptop -- ever.
|
|
4
|
+
* Requires FACTORY_FLOOR_URL pointing at a Factory-compatible endpoint.
|
|
5
|
+
* Beta-gated; enable with `agents beta enable factory`.
|
|
17
6
|
*/
|
|
18
7
|
import type { Command } from 'commander';
|
|
19
8
|
export declare function registerFactoryCommands(program: Command): void;
|
package/dist/commands/factory.js
CHANGED
|
@@ -51,8 +51,8 @@ export function registerFactoryCommands(program) {
|
|
|
51
51
|
.description('Software Factory -- submit Linear tickets to the cloud orchestrator.')
|
|
52
52
|
.addHelpText('after', `
|
|
53
53
|
Examples:
|
|
54
|
-
agents factory submit
|
|
55
|
-
agents factory submit https://linear.app/example/issue/
|
|
54
|
+
agents factory submit PROJ-123
|
|
55
|
+
agents factory submit https://linear.app/example/issue/PROJ-123
|
|
56
56
|
`);
|
|
57
57
|
factory.hook('preAction', () => {
|
|
58
58
|
if (enabled)
|
|
@@ -63,7 +63,7 @@ Examples:
|
|
|
63
63
|
});
|
|
64
64
|
factory
|
|
65
65
|
.command('submit <linear-ref>')
|
|
66
|
-
.description('Submit a Linear issue (
|
|
66
|
+
.description('Submit a Linear issue (PROJ-123 or URL) to the Software Factory.')
|
|
67
67
|
.option('--json', 'Output machine-readable JSON')
|
|
68
68
|
.action(async (ref, opts) => {
|
|
69
69
|
const result = await postFactorySubmit(ref);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agents feedback` — frictionless, in-CLI feedback. Opens a Discussion
|
|
3
|
+
* pre-filled with version + OS + agent inventory; falls back to printing the
|
|
4
|
+
* URL when no browser is available.
|
|
5
|
+
*/
|
|
6
|
+
import type { Command } from 'commander';
|
|
7
|
+
export declare function registerFeedbackCommand(program: Command): void;
|