@phnx-labs/agents-cli 1.20.71 → 1.20.73
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 +325 -1
- package/README.md +40 -4
- package/dist/bin/agents +0 -0
- package/dist/commands/activity.d.ts +12 -0
- package/dist/commands/activity.js +68 -0
- package/dist/commands/apply.d.ts +13 -0
- package/dist/commands/apply.js +28 -3
- package/dist/commands/browser.js +1 -1
- package/dist/commands/cloud.js +21 -11
- package/dist/commands/commands.js +2 -0
- package/dist/commands/doctor.js +8 -4
- package/dist/commands/events.d.ts +11 -10
- package/dist/commands/events.js +30 -21
- package/dist/commands/exec.d.ts +34 -0
- package/dist/commands/exec.js +337 -39
- package/dist/commands/feed.d.ts +13 -0
- package/dist/commands/feed.js +130 -29
- package/dist/commands/hq.d.ts +2 -0
- package/dist/commands/hq.js +58 -0
- package/dist/commands/lease.d.ts +19 -0
- package/dist/commands/lease.js +138 -11
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +123 -0
- package/dist/commands/logs.js +39 -10
- package/dist/commands/mcp.js +2 -0
- package/dist/commands/mine.d.ts +27 -0
- package/dist/commands/mine.js +207 -0
- package/dist/commands/monitors.js +79 -49
- package/dist/commands/plugins.js +1 -0
- package/dist/commands/profiles.js +158 -0
- package/dist/commands/repo.js +2 -60
- package/dist/commands/resource-view.d.ts +2 -0
- package/dist/commands/resource-view.js +8 -0
- package/dist/commands/resources.d.ts +5 -0
- package/dist/commands/resources.js +95 -0
- package/dist/commands/routines.d.ts +2 -0
- package/dist/commands/routines.js +139 -37
- package/dist/commands/secrets.js +234 -47
- package/dist/commands/send.d.ts +15 -0
- package/dist/commands/send.js +62 -0
- package/dist/commands/sessions-tail.d.ts +1 -0
- package/dist/commands/sessions-tail.js +20 -9
- package/dist/commands/sessions.d.ts +6 -0
- package/dist/commands/sessions.js +26 -3
- package/dist/commands/setup-mine.d.ts +18 -0
- package/dist/commands/setup-mine.js +106 -0
- package/dist/commands/setup-share.js +2 -2
- package/dist/commands/setup.js +3 -1
- package/dist/commands/share.d.ts +8 -1
- package/dist/commands/share.js +122 -37
- package/dist/commands/skills.js +2 -0
- package/dist/commands/ssh.d.ts +9 -0
- package/dist/commands/ssh.js +196 -26
- package/dist/commands/status.js +8 -2
- package/dist/commands/subagents.js +3 -1
- package/dist/commands/sync.js +1 -1
- package/dist/commands/teams.js +11 -2
- package/dist/commands/uninstall.d.ts +11 -0
- package/dist/commands/uninstall.js +158 -0
- package/dist/commands/utils.d.ts +29 -0
- package/dist/commands/utils.js +24 -0
- package/dist/commands/versions.js +120 -11
- package/dist/index.js +83 -12
- package/dist/lib/activity.d.ts +124 -0
- package/dist/lib/activity.js +542 -0
- package/dist/lib/agents.js +16 -5
- package/dist/lib/artifact-actions.d.ts +1 -1
- package/dist/lib/artifact-actions.js +1 -1
- package/dist/lib/ask-classifier.d.ts +2 -1
- package/dist/lib/ask-classifier.js +3 -3
- package/dist/lib/auth-health.d.ts +32 -4
- package/dist/lib/auth-health.js +40 -1
- package/dist/lib/auto-pull.js +8 -1
- package/dist/lib/brand.d.ts +40 -0
- package/dist/lib/brand.js +122 -0
- package/dist/lib/browser/drivers/ssh.js +4 -7
- package/dist/lib/browser/service.js +6 -8
- package/dist/lib/channels/providers/index.d.ts +2 -0
- package/dist/lib/channels/providers/index.js +20 -0
- package/dist/lib/channels/providers/mailbox.d.ts +2 -0
- package/dist/lib/channels/providers/mailbox.js +26 -0
- package/dist/lib/channels/providers/openclaw-telegram.d.ts +2 -0
- package/dist/lib/channels/providers/openclaw-telegram.js +34 -0
- package/dist/lib/channels/providers/rush.d.ts +6 -0
- package/dist/lib/channels/providers/rush.js +55 -0
- package/dist/lib/channels/registry.d.ts +42 -0
- package/dist/lib/channels/registry.js +20 -0
- package/dist/lib/channels/resolve.d.ts +11 -0
- package/dist/lib/channels/resolve.js +12 -0
- package/dist/lib/cli-resources.d.ts +18 -0
- package/dist/lib/cli-resources.js +53 -4
- package/dist/lib/cloud/codex.js +6 -3
- package/dist/lib/cloud/factory.d.ts +1 -0
- package/dist/lib/cloud/factory.js +10 -4
- package/dist/lib/cloud/rush.d.ts +3 -1
- package/dist/lib/cloud/rush.js +6 -1
- package/dist/lib/cloud/types.d.ts +2 -0
- package/dist/lib/codex-home.d.ts +35 -0
- package/dist/lib/codex-home.js +136 -0
- package/dist/lib/crabbox/cli.d.ts +44 -0
- package/dist/lib/crabbox/cli.js +120 -20
- package/dist/lib/crabbox/lease.d.ts +52 -1
- package/dist/lib/crabbox/lease.js +117 -16
- package/dist/lib/crabbox/progress.d.ts +31 -0
- package/dist/lib/crabbox/progress.js +76 -0
- package/dist/lib/crabbox/runtimes.d.ts +4 -0
- package/dist/lib/crabbox/runtimes.js +33 -8
- package/dist/lib/crabbox/setup-copy.d.ts +87 -0
- package/dist/lib/crabbox/setup-copy.js +127 -0
- package/dist/lib/daemon.d.ts +14 -5
- package/dist/lib/daemon.js +52 -9
- package/dist/lib/drive-sync.js +6 -3
- package/dist/lib/event-stream.d.ts +36 -0
- package/dist/lib/event-stream.js +68 -0
- package/dist/lib/events.d.ts +1 -1
- package/dist/lib/exec.d.ts +11 -0
- package/dist/lib/exec.js +23 -2
- package/dist/lib/feed-policy.d.ts +1 -1
- package/dist/lib/feed-policy.js +14 -9
- package/dist/lib/feed-ranking.d.ts +32 -0
- package/dist/lib/feed-ranking.js +224 -0
- package/dist/lib/feed.d.ts +35 -2
- package/dist/lib/feed.js +66 -3
- package/dist/lib/fleet/auth-sync.d.ts +53 -0
- package/dist/lib/fleet/auth-sync.js +92 -0
- package/dist/lib/fleet/remote-login.d.ts +187 -0
- package/dist/lib/fleet/remote-login.js +556 -0
- package/dist/lib/format.d.ts +30 -3
- package/dist/lib/format.js +34 -5
- package/dist/lib/fs-atomic.d.ts +7 -2
- package/dist/lib/fs-atomic.js +8 -12
- package/dist/lib/git.d.ts +16 -0
- package/dist/lib/git.js +79 -2
- package/dist/lib/heal.js +11 -3
- package/dist/lib/hosts/logs.d.ts +12 -0
- package/dist/lib/hosts/logs.js +18 -0
- package/dist/lib/hosts/progress.d.ts +28 -10
- package/dist/lib/hosts/progress.js +79 -22
- package/dist/lib/hosts/remote-cmd.js +4 -0
- package/dist/lib/hq/floor.d.ts +87 -0
- package/dist/lib/hq/floor.js +226 -0
- package/dist/lib/menubar/install-menubar.js +14 -20
- package/dist/lib/notify.d.ts +1 -0
- package/dist/lib/notify.js +3 -3
- package/dist/lib/open-url.d.ts +2 -0
- package/dist/lib/open-url.js +19 -0
- package/dist/lib/openclaw-keychain.d.ts +56 -0
- package/dist/lib/openclaw-keychain.js +236 -0
- package/dist/lib/overdue.js +10 -0
- package/dist/lib/permissions.d.ts +44 -1
- package/dist/lib/permissions.js +284 -7
- package/dist/lib/project-launch.d.ts +6 -12
- package/dist/lib/project-launch.js +13 -228
- package/dist/lib/project-resources.d.ts +7 -0
- package/dist/lib/project-resources.js +291 -0
- package/dist/lib/pty-client.d.ts +27 -0
- package/dist/lib/pty-client.js +136 -10
- package/dist/lib/refresh.js +14 -10
- package/dist/lib/resource-profiles.d.ts +26 -0
- package/dist/lib/resource-profiles.js +157 -0
- package/dist/lib/resources/permissions.js +7 -1
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.d.ts +1 -1
- package/dist/lib/resources.js +32 -3
- package/dist/lib/routines.d.ts +11 -0
- package/dist/lib/routines.js +56 -15
- package/dist/lib/runner.d.ts +1 -0
- package/dist/lib/runner.js +66 -5
- package/dist/lib/secrets/bundles.d.ts +16 -3
- package/dist/lib/secrets/bundles.js +206 -37
- package/dist/lib/secrets/icloud-import.d.ts +2 -2
- package/dist/lib/secrets/icloud-import.js +9 -6
- package/dist/lib/secrets/mcp.js +1 -1
- package/dist/lib/secrets/vault-age-helper.d.ts +1 -0
- package/dist/lib/secrets/vault-age-helper.js +34 -0
- package/dist/lib/secrets/vault.d.ts +49 -0
- package/dist/lib/secrets/vault.js +397 -0
- package/dist/lib/self-heal/checks/path.js +3 -1
- package/dist/lib/self-heal/checks/shadowing.js +10 -2
- package/dist/lib/self-heal/checks/shims.js +19 -11
- package/dist/lib/session/cloud.d.ts +2 -2
- package/dist/lib/session/cloud.js +2 -2
- package/dist/lib/session/db.d.ts +4 -0
- package/dist/lib/session/db.js +44 -7
- package/dist/lib/session/discover.d.ts +2 -0
- package/dist/lib/session/discover.js +114 -3
- package/dist/lib/session/stream-render.d.ts +3 -0
- package/dist/lib/session/stream-render.js +130 -0
- package/dist/lib/session/types.d.ts +6 -0
- package/dist/lib/share/analytics.d.ts +13 -0
- package/dist/lib/share/analytics.js +45 -0
- package/dist/lib/share/config.d.ts +19 -5
- package/dist/lib/share/config.js +44 -8
- package/dist/lib/share/provision.d.ts +58 -6
- package/dist/lib/share/provision.js +97 -22
- package/dist/lib/share/publish.d.ts +36 -13
- package/dist/lib/share/publish.js +55 -8
- package/dist/lib/share/worker-template.js +83 -17
- package/dist/lib/shims.d.ts +36 -0
- package/dist/lib/shims.js +120 -16
- package/dist/lib/ssh-exec.d.ts +14 -0
- package/dist/lib/ssh-exec.js +57 -0
- package/dist/lib/staleness/detectors/hooks.js +25 -1
- package/dist/lib/staleness/detectors/permissions.js +66 -0
- package/dist/lib/staleness/detectors/workflows.js +20 -0
- package/dist/lib/staleness/writers/hooks.js +58 -4
- package/dist/lib/staleness/writers/permissions.js +2 -2
- package/dist/lib/staleness/writers/skills.js +1 -1
- package/dist/lib/staleness/writers/sources.d.ts +10 -1
- package/dist/lib/staleness/writers/sources.js +68 -1
- package/dist/lib/star-nudge.d.ts +45 -0
- package/dist/lib/star-nudge.js +91 -0
- package/dist/lib/startup/command-registry.d.ts +7 -1
- package/dist/lib/startup/command-registry.js +19 -3
- package/dist/lib/state.d.ts +2 -0
- package/dist/lib/state.js +3 -0
- package/dist/lib/subagents-registry.d.ts +2 -0
- package/dist/lib/subagents-registry.js +3 -0
- package/dist/lib/teams/parsers.js +214 -6
- package/dist/lib/teams/supervisor.d.ts +7 -0
- package/dist/lib/teams/supervisor.js +2 -1
- package/dist/lib/template.d.ts +1 -1
- package/dist/lib/template.js +1 -1
- package/dist/lib/triggers/webhook.js +36 -3
- package/dist/lib/types.d.ts +73 -0
- package/dist/lib/uninstall.d.ts +84 -0
- package/dist/lib/uninstall.js +347 -0
- package/dist/lib/usage.d.ts +13 -1
- package/dist/lib/usage.js +32 -14
- package/dist/lib/version.d.ts +40 -0
- package/dist/lib/version.js +94 -16
- package/dist/lib/versions.d.ts +27 -0
- package/dist/lib/versions.js +248 -79
- package/dist/lib/workflows.d.ts +2 -0
- package/dist/lib/workflows.js +88 -0
- package/package.json +2 -1
- package/dist/commands/daemon.d.ts +0 -10
- package/dist/commands/daemon.js +0 -121
|
@@ -23,6 +23,12 @@ import { machineId, normalizeHost } from '../lib/machine-id.js';
|
|
|
23
23
|
import { loadDevices } from '../lib/devices/registry.js';
|
|
24
24
|
import { setHelpSections } from '../lib/help.js';
|
|
25
25
|
import { isInteractiveTerminal, requireInteractiveSelection } from './utils.js';
|
|
26
|
+
function stdoutJson(payload) {
|
|
27
|
+
process.stdout.write(JSON.stringify(payload) + '\n');
|
|
28
|
+
}
|
|
29
|
+
function stderrLine(message) {
|
|
30
|
+
process.stderr.write(message + '\n');
|
|
31
|
+
}
|
|
26
32
|
/** A one-line human label for what a monitor watches. */
|
|
27
33
|
function sourceLabel(source) {
|
|
28
34
|
switch (source.type) {
|
|
@@ -70,7 +76,7 @@ function ownerLabel(monitor) {
|
|
|
70
76
|
function ensureDaemonRunning() {
|
|
71
77
|
if (isDaemonRunning()) {
|
|
72
78
|
signalDaemonReload();
|
|
73
|
-
|
|
79
|
+
stderrLine(chalk.gray('Daemon reloaded'));
|
|
74
80
|
return;
|
|
75
81
|
}
|
|
76
82
|
const result = startDaemon();
|
|
@@ -79,22 +85,22 @@ function ensureDaemonRunning() {
|
|
|
79
85
|
console.log(chalk.gray('Stop anytime with: agents routines stop'));
|
|
80
86
|
}
|
|
81
87
|
else {
|
|
82
|
-
|
|
88
|
+
stderrLine(chalk.yellow('Could not start the daemon. Start it manually with: agents routines start'));
|
|
83
89
|
}
|
|
84
90
|
}
|
|
85
91
|
/** Validate a single device name against the registered fleet; exit on miss. */
|
|
86
92
|
async function validateDevice(name) {
|
|
87
93
|
const normalized = normalizeHost(name.trim());
|
|
88
94
|
if (!normalized) {
|
|
89
|
-
|
|
95
|
+
stderrLine(chalk.red('device name must be non-empty'));
|
|
90
96
|
process.exit(1);
|
|
91
97
|
}
|
|
92
98
|
const registry = await loadDevices();
|
|
93
99
|
const registered = new Set(Object.keys(registry).map((k) => normalizeHost(k)));
|
|
94
100
|
if (!registered.has(normalized)) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
101
|
+
stderrLine(chalk.red(`Unknown device: ${normalized}`));
|
|
102
|
+
stderrLine(chalk.gray(`Registered: ${[...registered].sort().join(', ') || '(none)'}`));
|
|
103
|
+
stderrLine(chalk.gray('Enroll devices with: agents devices sync'));
|
|
98
104
|
process.exit(1);
|
|
99
105
|
}
|
|
100
106
|
return normalized;
|
|
@@ -126,7 +132,7 @@ function buildSource(options) {
|
|
|
126
132
|
const raw = String(options.on);
|
|
127
133
|
const [src, event] = raw.includes(':') ? raw.split(':', 2) : ['github', raw];
|
|
128
134
|
if (src !== 'github' && src !== 'linear') {
|
|
129
|
-
|
|
135
|
+
stderrLine(chalk.red('--on source must be github or linear'));
|
|
130
136
|
process.exit(1);
|
|
131
137
|
}
|
|
132
138
|
const webhook = { source: src, event };
|
|
@@ -143,11 +149,11 @@ function buildSource(options) {
|
|
|
143
149
|
chosen.push({ type: 'webhook', source: { type: 'webhook', webhook } });
|
|
144
150
|
}
|
|
145
151
|
if (chosen.length === 0) {
|
|
146
|
-
|
|
152
|
+
stderrLine(chalk.red('A source is required: --watch, --poll, --poll-http, --ws, --watch-file, --watch-device, or --on'));
|
|
147
153
|
process.exit(1);
|
|
148
154
|
}
|
|
149
155
|
if (chosen.length > 1) {
|
|
150
|
-
|
|
156
|
+
stderrLine(chalk.red(`Exactly one source is allowed; got ${chosen.map((c) => c.type).join(', ')}`));
|
|
151
157
|
process.exit(1);
|
|
152
158
|
}
|
|
153
159
|
return chosen[0].source;
|
|
@@ -162,7 +168,7 @@ function buildCondition(options) {
|
|
|
162
168
|
if (options.every)
|
|
163
169
|
modes.push('every');
|
|
164
170
|
if (modes.length > 1) {
|
|
165
|
-
|
|
171
|
+
stderrLine(chalk.red('--on-change, --match, and --every are mutually exclusive'));
|
|
166
172
|
process.exit(1);
|
|
167
173
|
}
|
|
168
174
|
const mode = modes[0] ?? (options.match ? 'match' : 'on-change');
|
|
@@ -196,11 +202,11 @@ function buildAction(options) {
|
|
|
196
202
|
if (options.webhookOut)
|
|
197
203
|
chosen.push({ type: 'webhook-out', url: options.webhookOut });
|
|
198
204
|
if (chosen.length === 0) {
|
|
199
|
-
|
|
205
|
+
stderrLine(chalk.red('An action is required: --run <agent> --prompt, --routine, --notify, or --webhook-out'));
|
|
200
206
|
process.exit(1);
|
|
201
207
|
}
|
|
202
208
|
if (chosen.length > 1) {
|
|
203
|
-
|
|
209
|
+
stderrLine(chalk.red(`Exactly one action is allowed; got ${chosen.map((c) => c.type).join(', ')}`));
|
|
204
210
|
process.exit(1);
|
|
205
211
|
}
|
|
206
212
|
return chosen[0];
|
|
@@ -209,7 +215,7 @@ function buildAction(options) {
|
|
|
209
215
|
async function pickMonitor(message, alternatives = []) {
|
|
210
216
|
const monitors = listMonitors();
|
|
211
217
|
if (monitors.length === 0) {
|
|
212
|
-
|
|
218
|
+
stderrLine(chalk.yellow('No monitors configured'));
|
|
213
219
|
return null;
|
|
214
220
|
}
|
|
215
221
|
if (!isInteractiveTerminal()) {
|
|
@@ -227,7 +233,7 @@ async function pickMonitor(message, alternatives = []) {
|
|
|
227
233
|
}
|
|
228
234
|
catch (err) {
|
|
229
235
|
if (err instanceof Error && (err.name === 'ExitPromptError' || err.message.includes('User force closed'))) {
|
|
230
|
-
|
|
236
|
+
stderrLine(chalk.gray('Cancelled'));
|
|
231
237
|
return null;
|
|
232
238
|
}
|
|
233
239
|
throw err;
|
|
@@ -322,16 +328,16 @@ export function registerMonitorsCommands(program) {
|
|
|
322
328
|
parsed = yaml.parse(fs.readFileSync(resolved, 'utf-8'));
|
|
323
329
|
}
|
|
324
330
|
catch (err) {
|
|
325
|
-
|
|
331
|
+
stderrLine(chalk.red(`Invalid YAML: ${err.message}`));
|
|
326
332
|
process.exit(1);
|
|
327
333
|
}
|
|
328
334
|
const name = parsed?.name || path.basename(resolved).replace(/\.ya?ml$/, '');
|
|
329
335
|
const config = { enabled: true, ...parsed, name };
|
|
330
336
|
const errors = validateMonitor(config);
|
|
331
337
|
if (errors.length > 0) {
|
|
332
|
-
|
|
338
|
+
stderrLine(chalk.red('Validation errors:'));
|
|
333
339
|
for (const err of errors)
|
|
334
|
-
|
|
340
|
+
stderrLine(chalk.red(` - ${err}`));
|
|
335
341
|
process.exit(1);
|
|
336
342
|
}
|
|
337
343
|
writeMonitor(config);
|
|
@@ -340,8 +346,8 @@ export function registerMonitorsCommands(program) {
|
|
|
340
346
|
return;
|
|
341
347
|
}
|
|
342
348
|
if (!nameOrPath) {
|
|
343
|
-
|
|
344
|
-
|
|
349
|
+
stderrLine(chalk.red('Monitor name is required'));
|
|
350
|
+
stderrLine(chalk.gray('Usage: agents monitors add <name> --poll "<cmd>" 30s --match fail --run claude --prompt "..."'));
|
|
345
351
|
process.exit(1);
|
|
346
352
|
}
|
|
347
353
|
const source = buildSource(options);
|
|
@@ -357,7 +363,7 @@ export function registerMonitorsCommands(program) {
|
|
|
357
363
|
let device;
|
|
358
364
|
let devices;
|
|
359
365
|
if (options.device && options.devices) {
|
|
360
|
-
|
|
366
|
+
stderrLine(chalk.red('--device (single owner) and --devices (allowlist) are mutually exclusive'));
|
|
361
367
|
process.exit(1);
|
|
362
368
|
}
|
|
363
369
|
if (options.device)
|
|
@@ -371,13 +377,13 @@ export function registerMonitorsCommands(program) {
|
|
|
371
377
|
// --run-on with no owner pin would fire from every daemon → duplicate actions.
|
|
372
378
|
if (options.runOn && !device && !devices) {
|
|
373
379
|
device = machineId();
|
|
374
|
-
|
|
380
|
+
stderrLine(chalk.gray(`--run-on set with no --device/--devices: pinned owner to this machine (${device}).`));
|
|
375
381
|
}
|
|
376
382
|
let rateLimit;
|
|
377
383
|
if (options.rateLimit) {
|
|
378
384
|
const m = String(options.rateLimit).match(/^(\d+)\/(.+)$/);
|
|
379
385
|
if (!m) {
|
|
380
|
-
|
|
386
|
+
stderrLine(chalk.red('--rate-limit must be N/<interval>, e.g. 5/1m'));
|
|
381
387
|
process.exit(1);
|
|
382
388
|
}
|
|
383
389
|
rateLimit = { max: parseInt(m[1], 10), per: m[2] };
|
|
@@ -395,15 +401,15 @@ export function registerMonitorsCommands(program) {
|
|
|
395
401
|
};
|
|
396
402
|
const errors = validateMonitor(config);
|
|
397
403
|
if (errors.length > 0) {
|
|
398
|
-
|
|
404
|
+
stderrLine(chalk.red('Validation errors:'));
|
|
399
405
|
for (const err of errors)
|
|
400
|
-
|
|
406
|
+
stderrLine(chalk.red(` - ${err}`));
|
|
401
407
|
process.exit(1);
|
|
402
408
|
}
|
|
403
409
|
// Coverage lint (Anthropic's "silence is not success"): warn when a --match
|
|
404
410
|
// names only a success-shaped token with no failure branch.
|
|
405
411
|
if (condition.mode === 'match' && condition.match && /^(issued|success|ok|pass(ed)?|done|ready)$/i.test(condition.match)) {
|
|
406
|
-
|
|
412
|
+
stderrLine(chalk.yellow(` Note: --match '${condition.match}' only fires on success — it stays silent if the source breaks or never matches.`));
|
|
407
413
|
}
|
|
408
414
|
writeMonitor(config);
|
|
409
415
|
console.log(chalk.green(`Monitor '${nameOrPath}' added`));
|
|
@@ -432,7 +438,7 @@ export function registerMonitorsCommands(program) {
|
|
|
432
438
|
lastFiredAt: state?.lastFiredAt ?? null,
|
|
433
439
|
};
|
|
434
440
|
});
|
|
435
|
-
|
|
441
|
+
stdoutJson(payload);
|
|
436
442
|
return;
|
|
437
443
|
}
|
|
438
444
|
if (monitors.length === 0) {
|
|
@@ -456,7 +462,8 @@ export function registerMonitorsCommands(program) {
|
|
|
456
462
|
monitorsCmd
|
|
457
463
|
.command('view [name]')
|
|
458
464
|
.description('Show a monitor’s full YAML config plus its current watched-state and recent fires.')
|
|
459
|
-
.
|
|
465
|
+
.option('--json', 'Emit machine-readable JSON')
|
|
466
|
+
.action(async (name, options) => {
|
|
460
467
|
if (!name) {
|
|
461
468
|
name = (await pickMonitor('Select monitor to view', ['agents monitors view <name>'])) ?? undefined;
|
|
462
469
|
if (!name)
|
|
@@ -464,12 +471,24 @@ export function registerMonitorsCommands(program) {
|
|
|
464
471
|
}
|
|
465
472
|
const monitor = readMonitor(name);
|
|
466
473
|
if (!monitor) {
|
|
467
|
-
|
|
474
|
+
stderrLine(chalk.red(`Monitor '${name}' not found`));
|
|
468
475
|
process.exit(1);
|
|
469
476
|
}
|
|
477
|
+
const state = readState(name);
|
|
478
|
+
const recentFires = listFires(name).slice(-5);
|
|
479
|
+
if (options.json) {
|
|
480
|
+
stdoutJson({
|
|
481
|
+
name,
|
|
482
|
+
monitor,
|
|
483
|
+
owner: ownerLabel(monitor),
|
|
484
|
+
runsHere: monitorRunsOnThisDevice(monitor),
|
|
485
|
+
state,
|
|
486
|
+
recentFires,
|
|
487
|
+
});
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
470
490
|
console.log(chalk.bold(`Monitor: ${name}\n`));
|
|
471
491
|
console.log(yaml.stringify(monitor));
|
|
472
|
-
const state = readState(name);
|
|
473
492
|
if (state) {
|
|
474
493
|
console.log(chalk.bold('Watched state'));
|
|
475
494
|
console.log(chalk.gray(` last seen: ${state.lastSeenAt}`));
|
|
@@ -477,10 +496,9 @@ export function registerMonitorsCommands(program) {
|
|
|
477
496
|
console.log(chalk.gray(` last fired: ${state.lastFiredAt}`));
|
|
478
497
|
console.log(chalk.gray(` last value: ${state.lastValue.replace(/\s+/g, ' ').slice(0, 120)}`));
|
|
479
498
|
}
|
|
480
|
-
|
|
481
|
-
if (fires.length > 0) {
|
|
499
|
+
if (recentFires.length > 0) {
|
|
482
500
|
console.log(chalk.bold('\nRecent fires'));
|
|
483
|
-
for (const f of
|
|
501
|
+
for (const f of recentFires) {
|
|
484
502
|
console.log(` ${chalk.gray(f.firedAt)} ${f.action ?? '?'} ${f.ok === false ? chalk.red('failed') : chalk.green('ok')}`);
|
|
485
503
|
}
|
|
486
504
|
}
|
|
@@ -489,7 +507,8 @@ export function registerMonitorsCommands(program) {
|
|
|
489
507
|
monitorsCmd
|
|
490
508
|
.command('test [name]')
|
|
491
509
|
.description('DRY-RUN: evaluate the source once and print the emitted event + whether it would fire. No action is taken.')
|
|
492
|
-
.
|
|
510
|
+
.option('--json', 'Emit machine-readable JSON')
|
|
511
|
+
.action(async (name, options) => {
|
|
493
512
|
if (!name) {
|
|
494
513
|
name = (await pickMonitor('Select monitor to test', ['agents monitors test <name>'])) ?? undefined;
|
|
495
514
|
if (!name)
|
|
@@ -497,12 +516,24 @@ export function registerMonitorsCommands(program) {
|
|
|
497
516
|
}
|
|
498
517
|
const monitor = readMonitor(name);
|
|
499
518
|
if (!monitor) {
|
|
500
|
-
|
|
519
|
+
stderrLine(chalk.red(`Monitor '${name}' not found`));
|
|
501
520
|
process.exit(1);
|
|
502
521
|
}
|
|
522
|
+
const { observation, decision } = await evaluateMonitorOnce(monitor);
|
|
523
|
+
const wouldFire = Boolean(decision?.fire);
|
|
524
|
+
if (options.json) {
|
|
525
|
+
stdoutJson({
|
|
526
|
+
name,
|
|
527
|
+
dryRun: true,
|
|
528
|
+
monitor,
|
|
529
|
+
observation,
|
|
530
|
+
decision,
|
|
531
|
+
wouldFire,
|
|
532
|
+
});
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
503
535
|
console.log(chalk.bold(`Dry-run: ${name}\n`));
|
|
504
536
|
console.log(chalk.gray(` ${sourceLabel(monitor.source)} · [${monitor.condition.mode}] · ${actionLabel(monitor.action)}\n`));
|
|
505
|
-
const { observation, decision } = await evaluateMonitorOnce(monitor);
|
|
506
537
|
if (!observation) {
|
|
507
538
|
console.log(chalk.yellow('No observation — this source is push-only (ws/webhook) or produced nothing this tick.'));
|
|
508
539
|
return;
|
|
@@ -511,7 +542,6 @@ export function registerMonitorsCommands(program) {
|
|
|
511
542
|
console.log(observation.raw.split('\n').slice(0, 20).map((l) => ` ${l}`).join('\n'));
|
|
512
543
|
if (observation.meta)
|
|
513
544
|
console.log(chalk.gray(` meta: ${JSON.stringify(observation.meta)}`));
|
|
514
|
-
const wouldFire = Boolean(decision?.fire);
|
|
515
545
|
console.log('');
|
|
516
546
|
console.log(`Would fire: ${wouldFire ? chalk.green('yes') : chalk.gray('no')}`);
|
|
517
547
|
if (decision?.event) {
|
|
@@ -560,15 +590,15 @@ export function registerMonitorsCommands(program) {
|
|
|
560
590
|
return;
|
|
561
591
|
const errors = validateMonitor(monitor);
|
|
562
592
|
if (errors.length > 0) {
|
|
563
|
-
|
|
593
|
+
stderrLine(chalk.yellow('\nWarning: monitor has validation errors:'));
|
|
564
594
|
for (const err of errors)
|
|
565
|
-
|
|
595
|
+
stderrLine(chalk.yellow(` - ${err}`));
|
|
566
596
|
}
|
|
567
597
|
else {
|
|
568
598
|
console.log(chalk.green(`\nMonitor '${name}' saved`));
|
|
569
599
|
if (isDaemonRunning()) {
|
|
570
600
|
signalDaemonReload();
|
|
571
|
-
|
|
601
|
+
stderrLine(chalk.gray('Daemon reloaded'));
|
|
572
602
|
}
|
|
573
603
|
}
|
|
574
604
|
});
|
|
@@ -587,14 +617,14 @@ export function registerMonitorsCommands(program) {
|
|
|
587
617
|
}
|
|
588
618
|
const run = options.run ? listRuns(name).find((r) => r.runId === options.run) : getLatestRun(name);
|
|
589
619
|
if (!run) {
|
|
590
|
-
|
|
591
|
-
|
|
620
|
+
stderrLine(chalk.yellow(`No action runs found for monitor '${name}'`));
|
|
621
|
+
stderrLine(chalk.gray(' (notify / webhook-out actions have no run log — see: agents monitors runs)'));
|
|
592
622
|
return;
|
|
593
623
|
}
|
|
594
624
|
const logPath = path.join(getRunDir(name, run.runId), 'stdout.log');
|
|
595
625
|
if (options.full) {
|
|
596
626
|
if (!fs.existsSync(logPath)) {
|
|
597
|
-
|
|
627
|
+
stderrLine(chalk.yellow(`Log not found: ${logPath}`));
|
|
598
628
|
return;
|
|
599
629
|
}
|
|
600
630
|
console.log(chalk.gray(`Run: ${run.runId}\n`));
|
|
@@ -628,7 +658,7 @@ export function registerMonitorsCommands(program) {
|
|
|
628
658
|
}
|
|
629
659
|
const fires = listFires(name);
|
|
630
660
|
if (fires.length === 0) {
|
|
631
|
-
|
|
661
|
+
stderrLine(chalk.yellow(`No fires recorded for monitor '${name}'`));
|
|
632
662
|
return;
|
|
633
663
|
}
|
|
634
664
|
console.log(chalk.bold(`Fire history: ${name}\n`));
|
|
@@ -656,7 +686,7 @@ export function registerMonitorsCommands(program) {
|
|
|
656
686
|
signalDaemonReload();
|
|
657
687
|
}
|
|
658
688
|
catch (err) {
|
|
659
|
-
|
|
689
|
+
stderrLine(chalk.red(err.message));
|
|
660
690
|
process.exit(1);
|
|
661
691
|
}
|
|
662
692
|
});
|
|
@@ -676,7 +706,7 @@ export function registerMonitorsCommands(program) {
|
|
|
676
706
|
signalDaemonReload();
|
|
677
707
|
}
|
|
678
708
|
catch (err) {
|
|
679
|
-
|
|
709
|
+
stderrLine(chalk.red(err.message));
|
|
680
710
|
process.exit(1);
|
|
681
711
|
}
|
|
682
712
|
});
|
|
@@ -688,7 +718,7 @@ export function registerMonitorsCommands(program) {
|
|
|
688
718
|
.option('--clear', 'Remove the owner pin so the monitor runs on every device')
|
|
689
719
|
.action(async (name, options) => {
|
|
690
720
|
if (options.set !== undefined && options.clear) {
|
|
691
|
-
|
|
721
|
+
stderrLine(chalk.red('--set and --clear are mutually exclusive'));
|
|
692
722
|
process.exit(1);
|
|
693
723
|
}
|
|
694
724
|
if (!name) {
|
|
@@ -698,7 +728,7 @@ export function registerMonitorsCommands(program) {
|
|
|
698
728
|
}
|
|
699
729
|
const monitor = readMonitor(name);
|
|
700
730
|
if (!monitor) {
|
|
701
|
-
|
|
731
|
+
stderrLine(chalk.red(`Monitor '${name}' not found`));
|
|
702
732
|
process.exit(1);
|
|
703
733
|
}
|
|
704
734
|
if (options.clear) {
|
|
@@ -737,11 +767,11 @@ export function registerMonitorsCommands(program) {
|
|
|
737
767
|
console.log(chalk.green(`Monitor '${name}' removed`));
|
|
738
768
|
if (isDaemonRunning()) {
|
|
739
769
|
signalDaemonReload();
|
|
740
|
-
|
|
770
|
+
stderrLine(chalk.gray('Daemon reloaded'));
|
|
741
771
|
}
|
|
742
772
|
}
|
|
743
773
|
else {
|
|
744
|
-
|
|
774
|
+
stderrLine(chalk.red(`Monitor '${name}' not found`));
|
|
745
775
|
process.exit(1);
|
|
746
776
|
}
|
|
747
777
|
});
|
package/dist/commands/plugins.js
CHANGED
|
@@ -493,6 +493,7 @@ Examples:
|
|
|
493
493
|
// agents plugins install <spec>
|
|
494
494
|
pluginsCmd
|
|
495
495
|
.command('install <spec>')
|
|
496
|
+
.alias('add')
|
|
496
497
|
.description('Install a plugin from a git URL or local path (format: name@source or source)')
|
|
497
498
|
.option('--allow-exec-surfaces', 'Allow installing plugins that ship executable surfaces')
|
|
498
499
|
.addHelpText('after', `
|
|
@@ -14,6 +14,9 @@ import { getPreset, listPresets, expandPreset } from '../lib/profiles-presets.js
|
|
|
14
14
|
import { hasKeychainToken, keychainItemName, setKeychainToken, deleteKeychainToken, } from '../lib/secrets/profiles.js';
|
|
15
15
|
import { isInteractiveTerminal } from './utils.js';
|
|
16
16
|
import { getAgentsInvocation } from '../lib/daemon.js';
|
|
17
|
+
import { getActiveResourceProfileName, getResourceProfilePreset, listResourceProfileNames, setActiveResourceProfile, upsertResourceProfilePreset, validateResourceProfileName, } from '../lib/resource-profiles.js';
|
|
18
|
+
import { AGENTS } from '../lib/agents.js';
|
|
19
|
+
import { listInstalledVersions, syncResourcesToVersion } from '../lib/versions.js';
|
|
17
20
|
/**
|
|
18
21
|
* Pure helper: builds a Profile from collected wizard inputs. Extracted so the
|
|
19
22
|
* shape of preset->profile mapping for the `create` wizard is unit-testable
|
|
@@ -69,8 +72,141 @@ function renderProfileRow(p) {
|
|
|
69
72
|
const provider = p.provider || (p.auth?.keychainItem?.split('.')[1]) || '-';
|
|
70
73
|
return `${chalk.cyan(p.name.padEnd(16))} ${host.padEnd(14)} ${provider.padEnd(12)} ${chalk.gray(model)}`;
|
|
71
74
|
}
|
|
75
|
+
function splitList(value) {
|
|
76
|
+
if (value === undefined)
|
|
77
|
+
return undefined;
|
|
78
|
+
return value.split(',').map((part) => part.trim()).filter(Boolean);
|
|
79
|
+
}
|
|
80
|
+
function buildResourceProfileFromOptions(existing, opts) {
|
|
81
|
+
const next = { ...(existing ?? {}) };
|
|
82
|
+
if (opts.description !== undefined)
|
|
83
|
+
next.description = opts.description || undefined;
|
|
84
|
+
const keys = ['commands', 'skills', 'hooks', 'subagents', 'plugins', 'workflows', 'permissions', 'mcp'];
|
|
85
|
+
for (const key of keys) {
|
|
86
|
+
const parsed = splitList(opts[key]);
|
|
87
|
+
if (parsed !== undefined)
|
|
88
|
+
next[key] = parsed;
|
|
89
|
+
}
|
|
90
|
+
const secrets = splitList(opts.secrets);
|
|
91
|
+
if (secrets !== undefined)
|
|
92
|
+
next.secrets = secrets;
|
|
93
|
+
if (opts.rules !== undefined)
|
|
94
|
+
next.rules = opts.rules || undefined;
|
|
95
|
+
return next;
|
|
96
|
+
}
|
|
97
|
+
function printResourceProfile(name, preset, activeName) {
|
|
98
|
+
const activeMark = activeName === name ? '*' : ' ';
|
|
99
|
+
const description = preset.description ? ` ${chalk.gray(preset.description)}` : '';
|
|
100
|
+
console.log(`${activeMark} ${chalk.cyan(name)}${description}`);
|
|
101
|
+
}
|
|
102
|
+
function syncInstalledVersionsForActiveProfile(cwd) {
|
|
103
|
+
let synced = 0;
|
|
104
|
+
for (const agent of Object.keys(AGENTS)) {
|
|
105
|
+
for (const version of listInstalledVersions(agent)) {
|
|
106
|
+
syncResourcesToVersion(agent, version, undefined, { cwd, force: true });
|
|
107
|
+
synced++;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return synced;
|
|
111
|
+
}
|
|
112
|
+
function registerResourceProfileCommands(program) {
|
|
113
|
+
const cmd = program
|
|
114
|
+
.command('profile')
|
|
115
|
+
.description('Activate top-level resource profiles across commands, skills, hooks, rules, MCP, permissions, and secrets.');
|
|
116
|
+
cmd
|
|
117
|
+
.command('list')
|
|
118
|
+
.alias('ls')
|
|
119
|
+
.description('List top-level resource profiles')
|
|
120
|
+
.action(() => {
|
|
121
|
+
const names = listResourceProfileNames();
|
|
122
|
+
if (names.length === 0) {
|
|
123
|
+
console.log(chalk.gray('No resource profiles configured.'));
|
|
124
|
+
console.log(chalk.gray('Try: agents profile set work --skills user:code-review --secrets work'));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const active = getActiveResourceProfileName();
|
|
128
|
+
for (const name of names) {
|
|
129
|
+
printResourceProfile(name, getResourceProfilePreset(name), active);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
cmd
|
|
133
|
+
.command('status')
|
|
134
|
+
.description('Show the active top-level resource profile')
|
|
135
|
+
.action(() => {
|
|
136
|
+
const active = getActiveResourceProfileName();
|
|
137
|
+
if (!active) {
|
|
138
|
+
console.log(chalk.gray('No resource profile active.'));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const preset = getResourceProfilePreset(active);
|
|
142
|
+
console.log(chalk.bold(active));
|
|
143
|
+
if (!preset) {
|
|
144
|
+
console.log(chalk.red('Configured active profile is missing from profiles.presets.'));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (preset.description)
|
|
148
|
+
console.log(chalk.gray(preset.description));
|
|
149
|
+
for (const [key, value] of Object.entries(preset)) {
|
|
150
|
+
if (key === 'description')
|
|
151
|
+
continue;
|
|
152
|
+
console.log(`${key}: ${Array.isArray(value) ? value.join(', ') : value}`);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
cmd
|
|
156
|
+
.command('set <name>')
|
|
157
|
+
.alias('define')
|
|
158
|
+
.description('Create or update a top-level resource profile')
|
|
159
|
+
.option('--description <text>', 'Free-form description')
|
|
160
|
+
.option('--commands <patterns>', 'Comma-separated command selectors, e.g. system:commit,user:*')
|
|
161
|
+
.option('--skills <patterns>', 'Comma-separated skill selectors')
|
|
162
|
+
.option('--hooks <patterns>', 'Comma-separated hook selectors')
|
|
163
|
+
.option('--subagents <patterns>', 'Comma-separated subagent selectors')
|
|
164
|
+
.option('--plugins <patterns>', 'Comma-separated plugin selectors')
|
|
165
|
+
.option('--workflows <patterns>', 'Comma-separated workflow selectors')
|
|
166
|
+
.option('--permissions <patterns>', 'Comma-separated permission group selectors')
|
|
167
|
+
.option('--mcp <patterns>', 'Comma-separated MCP server selectors')
|
|
168
|
+
.option('--rules <preset>', 'Rules preset to compose while active')
|
|
169
|
+
.option('--secrets <names>', 'Comma-separated secrets bundles, or "*"')
|
|
170
|
+
.action((name, opts) => {
|
|
171
|
+
try {
|
|
172
|
+
validateResourceProfileName(name);
|
|
173
|
+
const preset = buildResourceProfileFromOptions(getResourceProfilePreset(name), opts);
|
|
174
|
+
upsertResourceProfilePreset(name, preset);
|
|
175
|
+
console.log(chalk.green(`Profile '${name}' saved.`));
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
console.error(chalk.red(err.message));
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
cmd
|
|
183
|
+
.command('use <name>')
|
|
184
|
+
.description('Activate a top-level resource profile and reconcile installed versions')
|
|
185
|
+
.action((name) => {
|
|
186
|
+
try {
|
|
187
|
+
setActiveResourceProfile(name);
|
|
188
|
+
const synced = syncInstalledVersionsForActiveProfile(process.cwd());
|
|
189
|
+
console.log(chalk.green(`Profile '${name}' active.`));
|
|
190
|
+
console.log(chalk.gray(`Reconciled ${synced} installed version${synced === 1 ? '' : 's'}.`));
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
console.error(chalk.red(err.message));
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
cmd
|
|
198
|
+
.command('clear')
|
|
199
|
+
.description('Clear the active top-level resource profile and reconcile installed versions')
|
|
200
|
+
.action(() => {
|
|
201
|
+
setActiveResourceProfile(null);
|
|
202
|
+
const synced = syncInstalledVersionsForActiveProfile(process.cwd());
|
|
203
|
+
console.log(chalk.green('Resource profile cleared.'));
|
|
204
|
+
console.log(chalk.gray(`Reconciled ${synced} installed version${synced === 1 ? '' : 's'}.`));
|
|
205
|
+
});
|
|
206
|
+
}
|
|
72
207
|
/** Register the `agents profiles` command tree. */
|
|
73
208
|
export function registerProfilesCommands(program) {
|
|
209
|
+
registerResourceProfileCommands(program);
|
|
74
210
|
const cmd = program
|
|
75
211
|
.command('profiles')
|
|
76
212
|
.description('Named bundles of (host CLI, endpoint, model, auth) — run Kimi/DeepSeek/Qwen/etc through Claude Code without a proxy.')
|
|
@@ -142,6 +278,28 @@ Examples:
|
|
|
142
278
|
# Fully remove the OpenRouter key from Keychain
|
|
143
279
|
agents profiles logout openrouter
|
|
144
280
|
`);
|
|
281
|
+
cmd
|
|
282
|
+
.command('use <name>')
|
|
283
|
+
.description('Alias for `agents profile use <name>`')
|
|
284
|
+
.action((name) => {
|
|
285
|
+
try {
|
|
286
|
+
setActiveResourceProfile(name);
|
|
287
|
+
const synced = syncInstalledVersionsForActiveProfile(process.cwd());
|
|
288
|
+
console.log(chalk.green(`Profile '${name}' active.`));
|
|
289
|
+
console.log(chalk.gray(`Reconciled ${synced} installed version${synced === 1 ? '' : 's'}.`));
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
console.error(chalk.red(err.message));
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
cmd
|
|
297
|
+
.command('status')
|
|
298
|
+
.description('Alias for `agents profile status`')
|
|
299
|
+
.action(() => {
|
|
300
|
+
const active = getActiveResourceProfileName();
|
|
301
|
+
console.log(active ? active : chalk.gray('No resource profile active.'));
|
|
302
|
+
});
|
|
145
303
|
cmd
|
|
146
304
|
.command('list')
|
|
147
305
|
.alias('ls')
|
package/dist/commands/repo.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as fs from 'fs';
|
|
|
6
6
|
import * as path from 'path';
|
|
7
7
|
import * as os from 'os';
|
|
8
8
|
import simpleGit from 'simple-git';
|
|
9
|
-
import {
|
|
9
|
+
import { input } from '@inquirer/prompts';
|
|
10
10
|
import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
|
|
11
11
|
import { setHelpSections } from '../lib/help.js';
|
|
12
12
|
import { itemPicker } from '../lib/picker.js';
|
|
@@ -843,66 +843,8 @@ export function registerRepoCommands(program) {
|
|
|
843
843
|
continue;
|
|
844
844
|
}
|
|
845
845
|
}
|
|
846
|
-
if (t.alias === 'system') {
|
|
846
|
+
if (t.alias === 'system' && alias !== 'system') {
|
|
847
847
|
// Skip system repo unless explicitly requested
|
|
848
|
-
if (alias !== 'system')
|
|
849
|
-
continue;
|
|
850
|
-
// User explicitly asked for system repo — show status and offer to pull
|
|
851
|
-
try {
|
|
852
|
-
const git = simpleGit(t.dir);
|
|
853
|
-
await git.fetch();
|
|
854
|
-
const status = await git.status();
|
|
855
|
-
const behind = status.behind ?? 0;
|
|
856
|
-
if (behind === 0) {
|
|
857
|
-
console.log(chalk.green('Up to date'));
|
|
858
|
-
}
|
|
859
|
-
else {
|
|
860
|
-
// Count changed resources by type
|
|
861
|
-
const diff = await git.diff(['--name-only', 'HEAD..@{upstream}']);
|
|
862
|
-
const files = diff.split('\n').filter(Boolean);
|
|
863
|
-
const counts = {};
|
|
864
|
-
for (const f of files) {
|
|
865
|
-
if (f.startsWith('skills/'))
|
|
866
|
-
counts['skills'] = (counts['skills'] || 0) + 1;
|
|
867
|
-
else if (f.startsWith('commands/'))
|
|
868
|
-
counts['commands'] = (counts['commands'] || 0) + 1;
|
|
869
|
-
else if (f.startsWith('hooks/'))
|
|
870
|
-
counts['hooks'] = (counts['hooks'] || 0) + 1;
|
|
871
|
-
else if (f.startsWith('rules/'))
|
|
872
|
-
counts['rules'] = (counts['rules'] || 0) + 1;
|
|
873
|
-
else
|
|
874
|
-
counts['other'] = (counts['other'] || 0) + 1;
|
|
875
|
-
}
|
|
876
|
-
const parts = [];
|
|
877
|
-
if (counts['skills'])
|
|
878
|
-
parts.push(`${counts['skills']} skill${counts['skills'] > 1 ? 's' : ''}`);
|
|
879
|
-
if (counts['commands'])
|
|
880
|
-
parts.push(`${counts['commands']} command${counts['commands'] > 1 ? 's' : ''}`);
|
|
881
|
-
if (counts['hooks'])
|
|
882
|
-
parts.push(`${counts['hooks']} hook${counts['hooks'] > 1 ? 's' : ''}`);
|
|
883
|
-
if (counts['rules'])
|
|
884
|
-
parts.push(`${counts['rules']} rule${counts['rules'] > 1 ? 's' : ''}`);
|
|
885
|
-
if (counts['other'])
|
|
886
|
-
parts.push(`${counts['other']} other`);
|
|
887
|
-
const summary = parts.length > 0 ? parts.join(', ') : `${behind} update${behind > 1 ? 's' : ''}`;
|
|
888
|
-
console.log(chalk.yellow(`${summary} available`));
|
|
889
|
-
if (isInteractiveTerminal()) {
|
|
890
|
-
const doPull = await confirm({ message: 'Pull now?', default: true });
|
|
891
|
-
if (doPull) {
|
|
892
|
-
const result = await pullRepo(t.dir);
|
|
893
|
-
if (result.success) {
|
|
894
|
-
console.log(chalk.green('Updated'));
|
|
895
|
-
}
|
|
896
|
-
else {
|
|
897
|
-
console.log(chalk.red(result.error || 'Pull failed'));
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
catch (err) {
|
|
904
|
-
console.log(chalk.red(err.message));
|
|
905
|
-
}
|
|
906
848
|
continue;
|
|
907
849
|
}
|
|
908
850
|
const spinner = ora(`Pulling ${formatRepoTarget(t.alias, t.dir)}...`).start();
|
|
@@ -33,6 +33,8 @@ export interface ResourceViewOptions {
|
|
|
33
33
|
/** When the user specified agent or agent@version, we scope per-agent. */
|
|
34
34
|
filterAgent?: AgentId;
|
|
35
35
|
filterVersion?: string;
|
|
36
|
+
/** Emit machine-readable JSON instead of the picker/table (for agents/scripts). */
|
|
37
|
+
json?: boolean;
|
|
36
38
|
}
|
|
37
39
|
/** Display a resource list: interactive picker in TTY mode, plain table otherwise. */
|
|
38
40
|
export declare function showResourceList(opts: ResourceViewOptions): Promise<void>;
|