@phnx-labs/agents-cli 1.20.32 → 1.20.34
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 +7 -0
- package/README.md +28 -2
- package/dist/commands/commands.js +3 -3
- package/dist/commands/computer-actions.js +1 -0
- package/dist/commands/computer.d.ts +23 -0
- package/dist/commands/computer.js +45 -3
- package/dist/commands/cost.js +2 -2
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.js +51 -2
- package/dist/commands/exec.js +56 -1
- package/dist/commands/hooks.js +3 -3
- package/dist/commands/import.js +1 -1
- package/dist/commands/inspect.js +13 -17
- package/dist/commands/mcp.js +3 -3
- package/dist/commands/permissions.js +3 -3
- package/dist/commands/rules.js +3 -3
- package/dist/commands/secrets-migrate.js +23 -11
- package/dist/commands/secrets.d.ts +20 -0
- package/dist/commands/secrets.js +53 -1
- package/dist/commands/sessions.js +18 -1
- package/dist/commands/skills.js +3 -3
- package/dist/commands/status.d.ts +12 -0
- package/dist/commands/status.js +81 -0
- package/dist/commands/sync.js +2 -2
- package/dist/commands/teams.js +77 -18
- package/dist/commands/usage.js +2 -2
- package/dist/commands/utils.d.ts +8 -0
- package/dist/commands/utils.js +20 -0
- package/dist/commands/versions.js +4 -3
- package/dist/commands/view.d.ts +39 -0
- package/dist/commands/view.js +217 -84
- package/dist/commands/workflows.js +3 -3
- package/dist/index.js +16 -2
- package/dist/lib/acp/harnesses.d.ts +1 -1
- package/dist/lib/acp/harnesses.js +2 -2
- package/dist/lib/agent-spec/index.d.ts +18 -0
- package/dist/lib/agent-spec/index.js +35 -0
- package/dist/lib/agent-spec/primitives.d.ts +28 -0
- package/dist/lib/agent-spec/primitives.js +57 -0
- package/dist/lib/agent-spec/provider.d.ts +2 -0
- package/dist/lib/agent-spec/provider.js +9 -0
- package/dist/lib/agent-spec/resolve.d.ts +33 -0
- package/dist/lib/agent-spec/resolve.js +174 -0
- package/dist/lib/agent-spec/types.d.ts +57 -0
- package/dist/lib/agent-spec/types.js +18 -0
- package/dist/lib/agents.d.ts +12 -0
- package/dist/lib/agents.js +115 -32
- package/dist/lib/browser/chrome.js +20 -0
- package/dist/lib/browser/drivers/ssh.d.ts +19 -0
- package/dist/lib/browser/drivers/ssh.js +18 -3
- package/dist/lib/crabbox/cli.d.ts +98 -0
- package/dist/lib/crabbox/cli.js +218 -0
- package/dist/lib/crabbox/lease.d.ts +41 -0
- package/dist/lib/crabbox/lease.js +73 -0
- package/dist/lib/crabbox/runtimes.d.ts +57 -0
- package/dist/lib/crabbox/runtimes.js +109 -0
- package/dist/lib/doctor-diff.js +29 -2
- package/dist/lib/drift-sync.d.ts +43 -0
- package/dist/lib/drift-sync.js +179 -0
- package/dist/lib/exec.d.ts +15 -0
- package/dist/lib/exec.js +21 -11
- package/dist/lib/hosts/dispatch.d.ts +27 -10
- package/dist/lib/hosts/dispatch.js +55 -19
- package/dist/lib/hosts/option.d.ts +14 -0
- package/dist/lib/hosts/option.js +19 -0
- package/dist/lib/hosts/passthrough.d.ts +30 -0
- package/dist/lib/hosts/passthrough.js +141 -0
- package/dist/lib/hosts/remote-cmd.d.ts +36 -0
- package/dist/lib/hosts/remote-cmd.js +56 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/platform/winpath.d.ts +31 -2
- package/dist/lib/platform/winpath.js +133 -24
- package/dist/lib/pwsh.d.ts +11 -0
- package/dist/lib/pwsh.js +13 -0
- 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/agent.d.ts +42 -1
- package/dist/lib/secrets/agent.js +89 -11
- package/dist/lib/secrets/bundles.js +61 -21
- package/dist/lib/secrets/filestore.js +31 -1
- package/dist/lib/secrets/index.d.ts +44 -1
- package/dist/lib/secrets/index.js +108 -10
- package/dist/lib/secrets/linux.d.ts +14 -0
- package/dist/lib/secrets/linux.js +21 -0
- package/dist/lib/secrets/windows.d.ts +74 -0
- package/dist/lib/secrets/windows.js +440 -0
- package/dist/lib/session/active.d.ts +8 -0
- package/dist/lib/session/active.js +18 -1
- package/dist/lib/session/provenance.d.ts +56 -0
- package/dist/lib/session/provenance.js +157 -0
- package/dist/lib/shims.d.ts +20 -0
- package/dist/lib/shims.js +53 -20
- package/dist/lib/ssh-exec.d.ts +22 -0
- package/dist/lib/ssh-exec.js +59 -2
- package/dist/lib/ssh-tunnel.d.ts +0 -5
- package/dist/lib/ssh-tunnel.js +65 -8
- package/dist/lib/startup/command-registry.d.ts +1 -0
- package/dist/lib/startup/command-registry.js +2 -0
- package/dist/lib/sync-status.d.ts +102 -0
- package/dist/lib/sync-status.js +135 -0
- package/dist/lib/teams/agents.d.ts +24 -0
- package/dist/lib/teams/agents.js +30 -1
- package/dist/lib/types.d.ts +20 -1
- package/dist/lib/usage.d.ts +30 -0
- package/dist/lib/usage.js +159 -2
- package/dist/lib/versions.d.ts +2 -4
- package/dist/lib/versions.js +7 -20
- package/package.json +2 -1
- package/dist/lib/agent-spec.d.ts +0 -36
- package/dist/lib/agent-spec.js +0 -157
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 1.20.34
|
|
6
|
+
|
|
7
|
+
**Test suite runs remotely on a crabbox VM (#525, #540)**
|
|
8
|
+
|
|
9
|
+
- `scripts/release.sh`'s test gate now runs `bun install && bun run build && bun run test` on a leased crabbox VM via `scripts/sandbox.sh` instead of freezing the local machine, matching CI's Build→Test order (crabbox's sync honors `.gitignore`, so the gitignored `dist/` is built on the box). A new `bun run test:remote` offloads the suite the same way for local dev. Publishing still happens locally — only the signed macOS keychain helper can be produced and notarized here, and crabbox boxes are Linux. Source: `scripts/sandbox.sh`, `scripts/release.sh`, `package.json`.
|
|
10
|
+
- `scripts/sandbox.sh` box acquisition is now robust: secrets load via `agents secrets export --plaintext` (the bare form now hard-errors), a missing `.crabbox.yaml` no longer aborts the script under `set -e`, and the agents-cli/claude install is gated to PR mode so test-mode runs match GitHub CI. Box selection gates on `crabbox status … ready=true` — skipping failed-bootstrap duds (which still report `status=running`) and warming a fresh box if none are ready — keyed on the stable `profile` label rather than an ephemeral slug. A dedicated `agents-cli` crabbox profile (`.crabbox.yaml`) isolates this repo's warm pool. Source: `scripts/sandbox.sh`, `.crabbox.yaml`.
|
|
11
|
+
|
|
5
12
|
## 1.20.31
|
|
6
13
|
|
|
7
14
|
**`agents sessions <id>`: a catch-up digest for switching between many agents (#502)**
|
package/README.md
CHANGED
|
@@ -230,6 +230,30 @@ Profile YAML has no secrets -- safe to `agents repo push` to a shared repo. `age
|
|
|
230
230
|
|
|
231
231
|
---
|
|
232
232
|
|
|
233
|
+
## Run on your own machines
|
|
234
|
+
|
|
235
|
+
Dispatch any read-only or config command -- and `agents run` itself -- to another machine over SSH. No daemon.
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# Enroll a machine (from ~/.ssh/config, or inline with user@address)
|
|
239
|
+
agents hosts add gpu-box
|
|
240
|
+
agents hosts check gpu-box # reachable? which agents-cli version?
|
|
241
|
+
|
|
242
|
+
# Run there instead of locally
|
|
243
|
+
agents run claude --host gpu-box "profile this build"
|
|
244
|
+
agents view claude --host gpu-box # inspect the remote install
|
|
245
|
+
agents sync --host gpu-box # make the remote machine current
|
|
246
|
+
|
|
247
|
+
# Your Tailscale fleet, auto-discovered
|
|
248
|
+
agents devices sync # ingest `tailscale status`
|
|
249
|
+
agents ssh mac-mini # hardened SSH: fails fast if offline,
|
|
250
|
+
# PowerShell on Windows, password-from-Keychain
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**Hosts** (`agents hosts`) are git-synced dispatch targets in `agents.yaml`; **devices** (`agents devices`) are your Tailscale machines in a local registry. Both ride SSH. See [docs/00-concepts.md](docs/00-concepts.md#devices--hosts).
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
233
257
|
## Teams
|
|
234
258
|
|
|
235
259
|
```bash
|
|
@@ -646,11 +670,13 @@ By default, secrets sync via iCloud Keychain to your other Macs. With `--no-iclo
|
|
|
646
670
|
|
|
647
671
|
Which DotAgents resources each agent CLI can load. Source of truth: [src/lib/agents.ts](src/lib/agents.ts) (`capabilities`); gates use `supports(agent, cap, version)` from [src/lib/capabilities.ts](src/lib/capabilities.ts). Full matrix also in [docs/00-concepts.md](docs/00-concepts.md).
|
|
648
672
|
|
|
673
|
+
> **† Gemini CLI is deprecated.** Google retired it for free, Pro, and Ultra tiers on **June 18, 2026** (announced at Google I/O 2026); the `gemini` command no longer serves requests on those tiers. agents-cli still manages existing installs, but warns on `agents add gemini` and `agents teams add … gemini`. New setups should use **Antigravity CLI** (`antigravity`), Google's official successor — see [the transition notice](https://developers.googleblog.com/an-important-update-transitioning-gemini-cli-to-antigravity-cli/).
|
|
674
|
+
|
|
649
675
|
| Agent | Versions | Hooks | MCP | Permissions | Skills | Commands | Plugins | Subagents | Rules | Workflows |
|
|
650
676
|
|-------|----------|-------|-----|-------------|--------|----------|---------|-----------|-------|-----------|
|
|
651
677
|
| Claude Code | yes | yes | yes | yes | yes | yes | yes | yes | `CLAUDE.md` | yes |
|
|
652
678
|
| Codex CLI | yes | >= 0.116.0 | yes | no | yes | < 0.117.0 · skills ($name, >= 0.117) | >= 0.128.0 | no | `AGENTS.md` | no |
|
|
653
|
-
| Gemini CLI | yes | >= 0.26.0 | yes | no | yes | yes (.toml) | no | no | `GEMINI.md` | no |
|
|
679
|
+
| Gemini CLI † | yes | >= 0.26.0 | yes | no | yes | yes (.toml) | no | no | `GEMINI.md` | no |
|
|
654
680
|
| Antigravity | yes | yes | yes | yes | yes | yes | yes | no | `AGENTS.md` | no |
|
|
655
681
|
| Grok Build | yes | yes | yes | yes | yes | skills ($name) | yes | no | `AGENTS.md` | no |
|
|
656
682
|
| OpenClaw | yes | yes | yes | no | yes | gateway | yes | yes | `workspace/AGENTS.md` | no |
|
|
@@ -672,7 +698,7 @@ Which DotAgents resources each agent CLI can load. Source of truth: [src/lib/age
|
|
|
672
698
|
|-------|----------|-------|---------------|
|
|
673
699
|
| Claude Code | yes | yes | yes |
|
|
674
700
|
| Codex CLI | yes | yes | yes |
|
|
675
|
-
| Gemini CLI | yes | yes | yes |
|
|
701
|
+
| Gemini CLI † | yes | yes | yes |
|
|
676
702
|
| Cursor | -- | yes | -- |
|
|
677
703
|
| OpenCode | -- | yes | -- |
|
|
678
704
|
| Grok Build | -- | yes | yes |
|
|
@@ -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 { listInstalledVersions, getGlobalDefault,
|
|
12
|
+
import { listInstalledVersions, getGlobalDefault, syncResourcesToVersion, promptAgentVersionSelection, getVersionHomePath, resolveInstalledAgentTargets, } from '../lib/versions.js';
|
|
13
13
|
import { recordVersionResources } from '../lib/state.js';
|
|
14
|
-
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, promptRemovalTargets, resolveAgentTargetsAutoInstalling, } from './utils.js';
|
|
14
|
+
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, promptRemovalTargets, resolveAgentTargetsAutoInstalling, resolveListFilterOrExit, } 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
|
|
@@ -59,7 +59,7 @@ When to use:
|
|
|
59
59
|
process.exit(1);
|
|
60
60
|
}
|
|
61
61
|
filterAgent = resolved;
|
|
62
|
-
filterVersion =
|
|
62
|
+
filterVersion = resolveListFilterOrExit(resolved, parts[1]);
|
|
63
63
|
}
|
|
64
64
|
const rows = buildCommandRows({ filterAgent, filterVersion });
|
|
65
65
|
spinner.stop();
|
|
@@ -485,6 +485,7 @@ export function registerActionCommands(program) {
|
|
|
485
485
|
.option('--bundle <id>', 'Bundle id (e.g. com.apple.TextEdit)')
|
|
486
486
|
.option('--path <p>', 'Path to the .app bundle')
|
|
487
487
|
.option('--name <s>', 'App name (resolved via /Applications and LaunchServices)')
|
|
488
|
+
.option('--host <device>', 'Drive a remote Windows device (requires `agents computer start --host <device>` first)')
|
|
488
489
|
.option('--json', 'Emit JSON')
|
|
489
490
|
.action(async (opts) => {
|
|
490
491
|
if (!opts.bundle && !opts.path && !opts.name) {
|
|
@@ -12,6 +12,29 @@ export declare function shouldBlockOffPlatform(opts: {
|
|
|
12
12
|
tcpConfigured: boolean;
|
|
13
13
|
host?: string;
|
|
14
14
|
}): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Sniff the image format from the leading magic bytes: PNG starts with the
|
|
17
|
+
* 8-byte signature `89 50 4E 47` ("\x89PNG"), JPEG with `FF D8 FF`. Returns the
|
|
18
|
+
* canonical file extension, or null for anything else.
|
|
19
|
+
*/
|
|
20
|
+
export declare function detectImageFormat(buf: Buffer): '.png' | '.jpg' | null;
|
|
21
|
+
/**
|
|
22
|
+
* Make the screenshot filename honest about its bytes. The two helper backends
|
|
23
|
+
* encode DIFFERENT formats and neither re-encodes to match the requested name:
|
|
24
|
+
* the macOS helper (ScreenCaptureKit) returns JPEG
|
|
25
|
+
* (packages/computer-helper/Sources/ComputerHelper/Screenshot.swift:207,212),
|
|
26
|
+
* the Windows helper returns PNG
|
|
27
|
+
* (packages/computer-helper-win/Screenshot.cs:33). So a fixed default extension
|
|
28
|
+
* cannot be correct for both — the only honest path is to sniff the real format
|
|
29
|
+
* and swap the extension to match. Pure so it's unit-testable.
|
|
30
|
+
*
|
|
31
|
+
* Returns the path to write to (caller's path with its extension corrected) and
|
|
32
|
+
* whether a correction was made. Unknown formats pass through unchanged.
|
|
33
|
+
*/
|
|
34
|
+
export declare function reconcileScreenshotExt(outPath: string, buf: Buffer): {
|
|
35
|
+
path: string;
|
|
36
|
+
corrected: boolean;
|
|
37
|
+
};
|
|
15
38
|
export declare function registerComputerCommand(program: Command): void;
|
|
16
39
|
export declare function registerComputerSubcommands(program: Command): void;
|
|
17
40
|
export { resolveHelperExec as resolveHelperPath };
|
|
@@ -33,6 +33,42 @@ export function shouldBlockOffPlatform(opts) {
|
|
|
33
33
|
return false; // remote path resolves its own endpoint
|
|
34
34
|
return true;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Sniff the image format from the leading magic bytes: PNG starts with the
|
|
38
|
+
* 8-byte signature `89 50 4E 47` ("\x89PNG"), JPEG with `FF D8 FF`. Returns the
|
|
39
|
+
* canonical file extension, or null for anything else.
|
|
40
|
+
*/
|
|
41
|
+
export function detectImageFormat(buf) {
|
|
42
|
+
if (buf.length >= 4 && buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47)
|
|
43
|
+
return '.png';
|
|
44
|
+
if (buf.length >= 3 && buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff)
|
|
45
|
+
return '.jpg';
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Make the screenshot filename honest about its bytes. The two helper backends
|
|
50
|
+
* encode DIFFERENT formats and neither re-encodes to match the requested name:
|
|
51
|
+
* the macOS helper (ScreenCaptureKit) returns JPEG
|
|
52
|
+
* (packages/computer-helper/Sources/ComputerHelper/Screenshot.swift:207,212),
|
|
53
|
+
* the Windows helper returns PNG
|
|
54
|
+
* (packages/computer-helper-win/Screenshot.cs:33). So a fixed default extension
|
|
55
|
+
* cannot be correct for both — the only honest path is to sniff the real format
|
|
56
|
+
* and swap the extension to match. Pure so it's unit-testable.
|
|
57
|
+
*
|
|
58
|
+
* Returns the path to write to (caller's path with its extension corrected) and
|
|
59
|
+
* whether a correction was made. Unknown formats pass through unchanged.
|
|
60
|
+
*/
|
|
61
|
+
export function reconcileScreenshotExt(outPath, buf) {
|
|
62
|
+
const actual = detectImageFormat(buf);
|
|
63
|
+
if (!actual)
|
|
64
|
+
return { path: outPath, corrected: false };
|
|
65
|
+
const cur = path.extname(outPath).toLowerCase();
|
|
66
|
+
const alreadyMatches = cur === actual || (actual === '.jpg' && (cur === '.jpg' || cur === '.jpeg'));
|
|
67
|
+
if (alreadyMatches)
|
|
68
|
+
return { path: outPath, corrected: false };
|
|
69
|
+
const base = outPath.slice(0, outPath.length - path.extname(outPath).length);
|
|
70
|
+
return { path: base + actual, corrected: true };
|
|
71
|
+
}
|
|
36
72
|
export function registerComputerCommand(program) {
|
|
37
73
|
const computer = program
|
|
38
74
|
.command('computer')
|
|
@@ -128,8 +164,8 @@ function registerScreenshotCommand(program) {
|
|
|
128
164
|
.option('--list', 'List the app\'s windows (id/title/layer/bounds) instead of capturing — reveals modals/popups')
|
|
129
165
|
.option('--window-id <n>', 'Capture a specific window by id (from --list)', (v) => parseInt(v, 10))
|
|
130
166
|
.option('--display', 'Capture the whole display the app is on (composites stacked modals)')
|
|
131
|
-
.option('--out <path>', 'Output JPEG
|
|
132
|
-
.option('--quality <n>', 'JPEG quality 1-100', (v) => parseInt(v, 10), 85)
|
|
167
|
+
.option('--out <path>', 'Output image path — extension auto-corrected to the encoded format (JPEG on macOS, PNG on a Windows --host)', './computer-screenshot.jpg')
|
|
168
|
+
.option('--quality <n>', 'JPEG quality 1-100 (macOS capture only; the Windows helper encodes lossless PNG and ignores this)', (v) => parseInt(v, 10), 85)
|
|
133
169
|
.option('--json', 'Emit JSON (metadata for captures; window list for --list)')
|
|
134
170
|
.action(async (opts) => {
|
|
135
171
|
const quality = Math.max(1, Math.min(100, opts.quality || 85));
|
|
@@ -176,7 +212,10 @@ function registerScreenshotCommand(program) {
|
|
|
176
212
|
process.exit(1);
|
|
177
213
|
}
|
|
178
214
|
const buf = Buffer.from(b64, 'base64');
|
|
179
|
-
|
|
215
|
+
// Sniff the real format and correct the extension so the filename never
|
|
216
|
+
// lies about its bytes (macOS -> JPEG, Windows helper -> PNG).
|
|
217
|
+
const requested = path.resolve(opts.out);
|
|
218
|
+
const { path: outPath, corrected } = reconcileScreenshotExt(requested, buf);
|
|
180
219
|
fs.writeFileSync(outPath, buf);
|
|
181
220
|
if (opts.json) {
|
|
182
221
|
// Drop the heavy base64 from the metadata echo; report where it went.
|
|
@@ -184,6 +223,9 @@ function registerScreenshotCommand(program) {
|
|
|
184
223
|
console.log(JSON.stringify(meta, null, 2));
|
|
185
224
|
}
|
|
186
225
|
else {
|
|
226
|
+
if (corrected) {
|
|
227
|
+
console.log(`note: bytes are ${path.extname(outPath).slice(1).toUpperCase()}; corrected extension from ${path.basename(requested)}`);
|
|
228
|
+
}
|
|
187
229
|
const origin = res.origin || [];
|
|
188
230
|
const originStr = origin.length === 2 ? `, origin [${origin.join(',')}], scale ${res.scale ?? '?'}` : '';
|
|
189
231
|
console.log(`saved: ${outPath} (${res.width ?? '?'}x${res.height ?? '?'}, ${buf.byteLength} bytes${originStr})`);
|
package/dist/commands/cost.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { addHostOption } from '../lib/hosts/option.js';
|
|
1
2
|
import chalk from 'chalk';
|
|
2
3
|
import { discoverSessions, parseTimeFilter } from '../lib/session/discover.js';
|
|
3
4
|
import { queryUsageRollup, topSessionsByCost, } from '../lib/session/db.js';
|
|
4
5
|
import { formatUsd, PRICING_VERSION } from '../lib/pricing/index.js';
|
|
5
6
|
import { formatDuration } from '../lib/session/render.js';
|
|
6
7
|
export function registerCostCommand(program) {
|
|
7
|
-
program
|
|
8
|
-
.command('cost')
|
|
8
|
+
addHostOption(program.command('cost'))
|
|
9
9
|
.description('Roll up $ cost and duration across local agent sessions')
|
|
10
10
|
.option('--json', 'Output the rollup as JSON')
|
|
11
11
|
.option('--since <time>', 'Only sessions newer than this (e.g., 7d, 4w, or ISO date)')
|
|
@@ -22,4 +22,14 @@
|
|
|
22
22
|
* apply pending sync.
|
|
23
23
|
*/
|
|
24
24
|
import type { Command } from 'commander';
|
|
25
|
+
/**
|
|
26
|
+
* Windows-only advisory lines. When the effective PowerShell execution policy
|
|
27
|
+
* blocks unsigned local `.ps1` scripts (`Restricted`/`AllSigned`), the generated
|
|
28
|
+
* `agents.ps1` launcher fails in PowerShell even when it is on PATH. Surface the
|
|
29
|
+
* remediation; the `.cmd` companion still works, so this is a warning, not an
|
|
30
|
+
* error, and doctor never auto-changes the policy. Pure — returns `[]` on
|
|
31
|
+
* non-Windows or a permissive policy, so it is testable without invoking
|
|
32
|
+
* PowerShell.
|
|
33
|
+
*/
|
|
34
|
+
export declare function execPolicyWarningLines(platform: NodeJS.Platform, policy: string | null): string[];
|
|
25
35
|
export declare function registerDoctorCommand(program: Command): void;
|
package/dist/commands/doctor.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { addHostOption } from '../lib/hosts/option.js';
|
|
1
2
|
import chalk from 'chalk';
|
|
2
3
|
import { checkAllClis } from '../lib/teams/agents.js';
|
|
3
4
|
import { AGENTS, ALL_AGENT_IDS, resolveAgentName, formatAgentError } from '../lib/agents.js';
|
|
@@ -11,6 +12,7 @@ import { unifiedDiff, colorizeUnifiedDiff } from '../lib/diff-text.js';
|
|
|
11
12
|
import { listCliStatus } from '../lib/cli-resources.js';
|
|
12
13
|
import { setHelpSections } from '../lib/help.js';
|
|
13
14
|
import { heal, healChangedAnything } from '../lib/heal.js';
|
|
15
|
+
import { blocksLocalScripts, getEffectiveExecutionPolicy } from '../lib/platform/winpath.js';
|
|
14
16
|
import * as fs from 'fs';
|
|
15
17
|
const AGENT_NAMES = Object.fromEntries(ALL_AGENT_IDS.map((id) => [id, AGENTS[id].name]));
|
|
16
18
|
// ─── overview mode (no target) ────────────────────────────────────────────────
|
|
@@ -207,6 +209,48 @@ function renderOverviewText(clis, syncRows, orphanRows, hostClis) {
|
|
|
207
209
|
for (const err of hostClis.errors) {
|
|
208
210
|
console.log(` ${chalk.red('err ')} ${chalk.gray(err.file)}: ${chalk.gray(err.reason)}`);
|
|
209
211
|
}
|
|
212
|
+
// On Windows a Restricted/AllSigned execution policy silently breaks the
|
|
213
|
+
// generated `agents.ps1` launcher — postinstall diagnoses it interactively,
|
|
214
|
+
// but a non-interactive install never sees that. Surface it here too.
|
|
215
|
+
renderExecPolicyAdvisory();
|
|
216
|
+
}
|
|
217
|
+
// ─── windows execution-policy advisory ─────────────────────────────────────────
|
|
218
|
+
/**
|
|
219
|
+
* Windows-only advisory lines. When the effective PowerShell execution policy
|
|
220
|
+
* blocks unsigned local `.ps1` scripts (`Restricted`/`AllSigned`), the generated
|
|
221
|
+
* `agents.ps1` launcher fails in PowerShell even when it is on PATH. Surface the
|
|
222
|
+
* remediation; the `.cmd` companion still works, so this is a warning, not an
|
|
223
|
+
* error, and doctor never auto-changes the policy. Pure — returns `[]` on
|
|
224
|
+
* non-Windows or a permissive policy, so it is testable without invoking
|
|
225
|
+
* PowerShell.
|
|
226
|
+
*/
|
|
227
|
+
export function execPolicyWarningLines(platform, policy) {
|
|
228
|
+
if (platform !== 'win32')
|
|
229
|
+
return [];
|
|
230
|
+
if (!blocksLocalScripts(policy))
|
|
231
|
+
return [];
|
|
232
|
+
return [
|
|
233
|
+
`PowerShell execution policy is ${policy} — it blocks the generated agents.ps1 launcher.`,
|
|
234
|
+
'Fix: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned',
|
|
235
|
+
'The agents.cmd shim still works regardless of the policy.',
|
|
236
|
+
];
|
|
237
|
+
}
|
|
238
|
+
function renderExecPolicyAdvisory() {
|
|
239
|
+
// Only probe the policy on Windows — getEffectiveExecutionPolicy() spawns
|
|
240
|
+
// powershell, which is a wasted (doomed) process on POSIX where the advisory
|
|
241
|
+
// never applies.
|
|
242
|
+
if (process.platform !== 'win32')
|
|
243
|
+
return;
|
|
244
|
+
const lines = execPolicyWarningLines(process.platform, getEffectiveExecutionPolicy());
|
|
245
|
+
if (lines.length === 0)
|
|
246
|
+
return;
|
|
247
|
+
console.log();
|
|
248
|
+
console.log(chalk.bold('Execution policy (Windows)'));
|
|
249
|
+
const [headline, ...rest] = lines;
|
|
250
|
+
console.log(` ${chalk.yellow('warn ')} ${headline}`);
|
|
251
|
+
for (const line of rest) {
|
|
252
|
+
console.log(chalk.gray(` ${line}`));
|
|
253
|
+
}
|
|
210
254
|
}
|
|
211
255
|
function parseTargetArg(arg) {
|
|
212
256
|
const at = arg.indexOf('@');
|
|
@@ -475,8 +519,7 @@ async function runFix(parsed, opts) {
|
|
|
475
519
|
}
|
|
476
520
|
// ─── command registration ────────────────────────────────────────────────────
|
|
477
521
|
export function registerDoctorCommand(program) {
|
|
478
|
-
const doctorCmd = program
|
|
479
|
-
.command('doctor [target]')
|
|
522
|
+
const doctorCmd = addHostOption(program.command('doctor [target]'))
|
|
480
523
|
.description('Diagnose CLI availability, sync status, and resource divergence (optionally for a specific agent[@version]).')
|
|
481
524
|
.option('--json', 'Output machine-readable JSON')
|
|
482
525
|
.option('--diff', 'In target mode, include unified diffs for divergent files')
|
|
@@ -547,6 +590,12 @@ export function registerDoctorCommand(program) {
|
|
|
547
590
|
return;
|
|
548
591
|
}
|
|
549
592
|
renderOverviewText(clis, syncRows, orphanRows, hostClis);
|
|
593
|
+
// Point at the interactive reconcile when anything is out of sync — the
|
|
594
|
+
// report shouldn't be a dead end. `agents status` runs the unified
|
|
595
|
+
// home-reading engine and offers to sync (opt-in, never auto-fires here).
|
|
596
|
+
if (syncRows.some((r) => r.status !== 'fresh')) {
|
|
597
|
+
console.log(chalk.gray('\nRun `agents status` to review and sync what has drifted.'));
|
|
598
|
+
}
|
|
550
599
|
return;
|
|
551
600
|
}
|
|
552
601
|
const parsed = parseTargetArg(target);
|
package/dist/commands/exec.js
CHANGED
|
@@ -136,7 +136,9 @@ export function registerRunCommand(program) {
|
|
|
136
136
|
.option('--host <name>', 'Offload this run onto a registered agent host over SSH instead of running locally. See `agents hosts`.')
|
|
137
137
|
.option('--remote-cwd <dir>', 'Working directory on the host for --host runs.')
|
|
138
138
|
.option('--no-follow', 'With --host, dispatch detached and return immediately (track via `agents hosts ps/logs`).')
|
|
139
|
-
.option('--any', 'With --host <cap> (a capability tag), pick any matching host instead of erroring when several match.')
|
|
139
|
+
.option('--any', 'With --host <cap> (a capability tag), pick any matching host instead of erroring when several match.')
|
|
140
|
+
.option('--lease [backend]', 'Invent a disposable cloud box for this run and tear it down after (via crabbox). Optional backend selects the cloud (hetzner/aws/do). Unlike --host, no machine is registered.')
|
|
141
|
+
.option('--keep-box', 'With --lease, keep the box after the run instead of stopping it.');
|
|
140
142
|
// `--on` and `--computer` are hidden aliases of `--host` — same behavior.
|
|
141
143
|
runCmd.addOption(new Option('--on <name>', 'Alias of --host.').hideHelp());
|
|
142
144
|
runCmd.addOption(new Option('--computer <name>', 'Alias of --host.').hideHelp());
|
|
@@ -191,6 +193,59 @@ export function registerRunCommand(program) {
|
|
|
191
193
|
// Use command.args (all positional strings) and strip the declared positional args from the front.
|
|
192
194
|
const declaredArgCount = prompt !== undefined ? 2 : 1;
|
|
193
195
|
const passthroughArgs = command.args.slice(declaredArgCount);
|
|
196
|
+
// --lease: invent a disposable cloud box for this run (via crabbox), run
|
|
197
|
+
// the agent there, then tear it down. Unlike --host, nothing is registered.
|
|
198
|
+
if (options.lease) {
|
|
199
|
+
if (prompt === undefined) {
|
|
200
|
+
console.error(chalk.red('A prompt is required for leased runs: agents run <agent> "<task>" --lease'));
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
const backend = typeof options.lease === 'string' ? options.lease : undefined;
|
|
204
|
+
const { detectSignedInRuntimes, pickRuntimes } = await import('../lib/crabbox/runtimes.js');
|
|
205
|
+
const { leaseAndRun } = await import('../lib/crabbox/lease.js');
|
|
206
|
+
const { confirm } = await import('@inquirer/prompts');
|
|
207
|
+
const detected = await detectSignedInRuntimes();
|
|
208
|
+
const runtimes = await pickRuntimes(detected);
|
|
209
|
+
if (runtimes.length === 0) {
|
|
210
|
+
console.error(chalk.yellow('No runtimes selected. Sign into one locally (e.g. run `claude` once) then retry.'));
|
|
211
|
+
process.exit(1);
|
|
212
|
+
}
|
|
213
|
+
// Security gate: copying auth tokens to an ephemeral cloud box is opt-in
|
|
214
|
+
// per run. Name the runtimes + accounts so the user sees what ships.
|
|
215
|
+
const names = runtimes
|
|
216
|
+
.map((id) => {
|
|
217
|
+
const d = detected.find((x) => x.id === id);
|
|
218
|
+
return `${d?.label ?? id}${d?.email ? ` (${d.email})` : ''}`;
|
|
219
|
+
})
|
|
220
|
+
.join(', ');
|
|
221
|
+
const ok = await confirm({
|
|
222
|
+
message: `Copy credentials for ${names} to a disposable cloud box, run there, then destroy it?`,
|
|
223
|
+
default: false,
|
|
224
|
+
});
|
|
225
|
+
if (!ok) {
|
|
226
|
+
console.error(chalk.yellow('Aborted — no credentials pushed, no box leased.'));
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
try {
|
|
230
|
+
const { exitCode, box, toreDown } = await leaseAndRun({
|
|
231
|
+
agent: agentSpec.split('@')[0],
|
|
232
|
+
prompt,
|
|
233
|
+
mode: options.mode,
|
|
234
|
+
model: options.model,
|
|
235
|
+
backend,
|
|
236
|
+
runtimes,
|
|
237
|
+
detected,
|
|
238
|
+
secretsBundle: process.env.AGENTS_LEASE_SECRETS_BUNDLE,
|
|
239
|
+
keep: options.keepBox,
|
|
240
|
+
});
|
|
241
|
+
console.error(chalk.gray(toreDown ? `Box ${box.slug} destroyed.` : `Box ${box.slug} kept${box.ip ? ` (${box.ip})` : ''}. Stop it: crabbox stop --id ${box.slug}`));
|
|
242
|
+
process.exit(exitCode === null ? 1 : exitCode);
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
console.error(chalk.red(err.message));
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
194
249
|
// --host/--on/--computer: offload this run onto a registered agent host
|
|
195
250
|
// over SSH instead of running locally. The three flags are aliases.
|
|
196
251
|
const hostGiven = [options.host, options.on, options.computer].filter((v) => !!v);
|
package/dist/commands/hooks.js
CHANGED
|
@@ -8,9 +8,9 @@ import { AGENTS, resolveAgentName, formatAgentError, agentLabel, } from '../lib/
|
|
|
8
8
|
import { supports, capableAgents } from '../lib/capabilities.js';
|
|
9
9
|
import { cloneRepo } from '../lib/git.js';
|
|
10
10
|
import { discoverHooksFromRepo, installHooksCentrally, listCentralHooks, listInstalledHooksWithScope, getHookInfo, parseHookManifest, iterHooksCapableVersions, removeHookFromVersion, } from '../lib/hooks.js';
|
|
11
|
-
import { listInstalledVersions, getGlobalDefault,
|
|
11
|
+
import { listInstalledVersions, getGlobalDefault, syncResourcesToVersion, promptAgentVersionSelection, getVersionHomePath, resolveInstalledAgentTargets, } from '../lib/versions.js';
|
|
12
12
|
import { recordVersionResources } from '../lib/state.js';
|
|
13
|
-
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, promptRemovalTargets, resolveAgentTargetsAutoInstalling, } from './utils.js';
|
|
13
|
+
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, promptRemovalTargets, resolveAgentTargetsAutoInstalling, resolveListFilterOrExit, } from './utils.js';
|
|
14
14
|
/** Register the `agents hooks` command tree (list, add, remove, sync, prune, view). */
|
|
15
15
|
export function registerHooksCommands(program) {
|
|
16
16
|
const hooksCmd = program.command('hooks')
|
|
@@ -61,7 +61,7 @@ When to use:
|
|
|
61
61
|
console.log(chalk.red(formatAgentError(agentName, [...capableAgents('hooks')])));
|
|
62
62
|
process.exit(1);
|
|
63
63
|
}
|
|
64
|
-
requestedVersion =
|
|
64
|
+
requestedVersion = resolveListFilterOrExit(agentId, parts[1]) ?? null;
|
|
65
65
|
}
|
|
66
66
|
// Load hook manifest for event display
|
|
67
67
|
const hookManifest = parseHookManifest();
|
package/dist/commands/import.js
CHANGED
|
@@ -263,7 +263,7 @@ When to use:
|
|
|
263
263
|
pointing at the existing install — nothing is copied or moved (except the
|
|
264
264
|
agent's config dir, which is moved into the version's home). Works for both
|
|
265
265
|
npm-style packages (claude, codex, gemini, opencode, openclaw) and
|
|
266
|
-
installScript-based agents (grok, antigravity, cursor, kiro, goose
|
|
266
|
+
installScript-based agents (grok, antigravity, cursor, kiro, goose).
|
|
267
267
|
`)
|
|
268
268
|
.action(runImport);
|
|
269
269
|
}
|
package/dist/commands/inspect.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* AGENT.md / the file itself) so users can click straight to the source.
|
|
13
13
|
*/
|
|
14
14
|
import { execSync } from 'child_process';
|
|
15
|
+
import { addHostOption } from '../lib/hosts/option.js';
|
|
15
16
|
import * as fs from 'fs';
|
|
16
17
|
import * as os from 'os';
|
|
17
18
|
import * as path from 'path';
|
|
@@ -19,6 +20,7 @@ import chalk from 'chalk';
|
|
|
19
20
|
import * as yaml from 'yaml';
|
|
20
21
|
import { AGENTS, getCliState, resolveAgentName } from '../lib/agents.js';
|
|
21
22
|
import { supports } from '../lib/capabilities.js';
|
|
23
|
+
import { resolveSingleAgentTarget, AgentSpecError } from '../lib/agent-spec/index.js';
|
|
22
24
|
import { readMeta, getUserAgentsDir, getSystemAgentsDir, getProjectAgentsDir, getEnabledExtraRepos, } from '../lib/state.js';
|
|
23
25
|
import { getVersionHomePath } from '../lib/versions.js';
|
|
24
26
|
import { getShimsDir, getVersionedAliasPath } from '../lib/shims.js';
|
|
@@ -68,8 +70,7 @@ const CAPABILITY_NAMES = [
|
|
|
68
70
|
];
|
|
69
71
|
// ─── Command registration ────────────────────────────────────────────────────
|
|
70
72
|
export function registerInspectCommand(program) {
|
|
71
|
-
const cmd = program
|
|
72
|
-
.command('inspect <target>')
|
|
73
|
+
const cmd = addHostOption(program.command('inspect <target>'))
|
|
73
74
|
.description('Inspect one installed agent at one version, or a DotAgents repo (user|system|project|alias|path) — paths, capabilities, resources, drill into any kind.')
|
|
74
75
|
.option('--brief', 'header + capabilities only; skip resources/sessions')
|
|
75
76
|
.option('--json', 'machine-readable JSON output');
|
|
@@ -125,25 +126,20 @@ export async function inspectAction(target, options) {
|
|
|
125
126
|
await renderSummary(agent, version, versionHome, options);
|
|
126
127
|
}
|
|
127
128
|
function parseTarget(target) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
// Route through the agent-spec engine: bare resolves project pin → global
|
|
130
|
+
// default → sole installed (the meta-only lookup here previously ignored
|
|
131
|
+
// project pins); @default/@latest/@oldest/@x.y.z all handled uniformly.
|
|
132
|
+
try {
|
|
133
|
+
const { agent, version } = resolveSingleAgentTarget(target);
|
|
134
|
+
return { agent, version };
|
|
134
135
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const def = meta.agents?.[agent];
|
|
139
|
-
if (!def) {
|
|
140
|
-
console.error(chalk.red(`No default version set for ${agent}.`));
|
|
141
|
-
console.error(chalk.gray(`Pass a version: agents inspect ${agent}@<version>`));
|
|
136
|
+
catch (e) {
|
|
137
|
+
if (e instanceof AgentSpecError) {
|
|
138
|
+
console.error(chalk.red(e.message));
|
|
142
139
|
process.exit(1);
|
|
143
140
|
}
|
|
144
|
-
|
|
141
|
+
throw e;
|
|
145
142
|
}
|
|
146
|
-
return { agent, version };
|
|
147
143
|
}
|
|
148
144
|
function pickDrillKind(options) {
|
|
149
145
|
const active = [];
|
package/dist/commands/mcp.js
CHANGED
|
@@ -7,9 +7,9 @@ import { readManifest, writeManifest, createDefaultManifest } from '../lib/manif
|
|
|
7
7
|
import { listMcpServerConfigs, discoverMcpConfigsFromRepo, installMcpConfigCentrally, } from '../lib/mcp.js';
|
|
8
8
|
import { cloneRepo } from '../lib/git.js';
|
|
9
9
|
import { getMcpDir } from '../lib/state.js';
|
|
10
|
-
import { getEffectiveHome, getGlobalDefault, listInstalledVersions, getVersionHomePath, resolveInstalledAgentTargets, resolveConfiguredAgentTargets,
|
|
10
|
+
import { getEffectiveHome, getGlobalDefault, listInstalledVersions, getVersionHomePath, resolveInstalledAgentTargets, resolveConfiguredAgentTargets, syncResourcesToVersion, } from '../lib/versions.js';
|
|
11
11
|
import { getUserAgentsDir } from '../lib/state.js';
|
|
12
|
-
import { isPromptCancelled, isInteractiveTerminal, requireInteractiveSelection, promptRemovalTargets, parseCommaSeparatedList, ensureAgentVersionsInstalled, resolveAgentTargetsAutoInstalling, resolveInstalledAgentTargetsAutoInstalling, VersionNotInstalledError, } from './utils.js';
|
|
12
|
+
import { isPromptCancelled, isInteractiveTerminal, requireInteractiveSelection, promptRemovalTargets, parseCommaSeparatedList, ensureAgentVersionsInstalled, resolveAgentTargetsAutoInstalling, resolveInstalledAgentTargetsAutoInstalling, VersionNotInstalledError, resolveListFilterOrExit, } from './utils.js';
|
|
13
13
|
import { showResourceList, buildTargetsSection, } from './resource-view.js';
|
|
14
14
|
/**
|
|
15
15
|
* Parse a comma-separated --agents string into validated agent IDs and
|
|
@@ -159,7 +159,7 @@ When to use:
|
|
|
159
159
|
process.exit(1);
|
|
160
160
|
}
|
|
161
161
|
filterAgent = resolved;
|
|
162
|
-
filterVersion =
|
|
162
|
+
filterVersion = resolveListFilterOrExit(resolved, parts[1]);
|
|
163
163
|
}
|
|
164
164
|
const rows = buildMcpRows({ filterAgent, filterVersion });
|
|
165
165
|
spinner.stop();
|
|
@@ -8,9 +8,9 @@ import { AGENTS, resolveAgentName, formatAgentError, agentLabel, } from '../lib/
|
|
|
8
8
|
import { cloneRepo } from '../lib/git.js';
|
|
9
9
|
import { capableAgents, isCapable } from '../lib/capabilities.js';
|
|
10
10
|
import { listInstalledPermissions, discoverPermissionsFromRepo, installPermissionSet, removePermissionSet, applyPermissionsToVersion, readAgentPermissions, exportPermissionsFromPath, getDefaultPermissionSet, computePermissionsDiff, mergePermissionSets, saveDefaultPermissionSet, containsBroadGrants, } from '../lib/permissions.js';
|
|
11
|
-
import { listInstalledVersions, getGlobalDefault, getVersionHomePath, promptAgentVersionSelection,
|
|
11
|
+
import { listInstalledVersions, getGlobalDefault, getVersionHomePath, promptAgentVersionSelection, } from '../lib/versions.js';
|
|
12
12
|
import { recordVersionResources } from '../lib/state.js';
|
|
13
|
-
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, resolveAgentTargetsAutoInstalling, } from './utils.js';
|
|
13
|
+
import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, resolveAgentTargetsAutoInstalling, resolveListFilterOrExit, } from './utils.js';
|
|
14
14
|
export function shouldRefuseBroadPermissions(permissions, allowBroadPermissions) {
|
|
15
15
|
return !allowBroadPermissions && permissions.some((perm) => containsBroadGrants(perm.set) !== null);
|
|
16
16
|
}
|
|
@@ -116,7 +116,7 @@ When to use:
|
|
|
116
116
|
console.log(chalk.red(formatAgentError(agentName, capableAgents('allowlist'))));
|
|
117
117
|
process.exit(1);
|
|
118
118
|
}
|
|
119
|
-
const requestedVersion =
|
|
119
|
+
const requestedVersion = resolveListFilterOrExit(agentId, parts[1]) ?? null;
|
|
120
120
|
if (!isCapable(agentId, 'allowlist')) {
|
|
121
121
|
console.log(chalk.yellow(`${AGENTS[agentId].name} does not support fine-grained permissions`));
|
|
122
122
|
return;
|
package/dist/commands/rules.js
CHANGED
|
@@ -11,7 +11,7 @@ import { listInstalledVersions, getGlobalDefault, resolveVersionAlias, syncResou
|
|
|
11
11
|
import { recordVersionResources, getActiveRulesPreset, setActiveRulesPreset } from '../lib/state.js';
|
|
12
12
|
import { discoverRulesLayers } from '../lib/rules/compose.js';
|
|
13
13
|
import * as yaml from 'yaml';
|
|
14
|
-
import { isPromptCancelled, formatPath, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, requireDestructiveArg, resolveAgentTargetsAutoInstalling, } from './utils.js';
|
|
14
|
+
import { isPromptCancelled, formatPath, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, requireDestructiveArg, resolveAgentTargetsAutoInstalling, resolveListFilterOrExit, } from './utils.js';
|
|
15
15
|
/** Register the `agents rules` command tree (list, add, view, remove). */
|
|
16
16
|
export function registerRulesCommands(program) {
|
|
17
17
|
const rulesCmd = program
|
|
@@ -51,7 +51,7 @@ Project rules & @-imports:
|
|
|
51
51
|
@path imports inside AGENTS.md/CLAUDE.md are resolved at session start by the agent
|
|
52
52
|
itself, not by agents-cli. Support is per-agent:
|
|
53
53
|
Inlined natively: claude, gemini
|
|
54
|
-
Literal text: codex, cursor, opencode, copilot, amp, kiro, goose
|
|
54
|
+
Literal text: codex, cursor, opencode, copilot, amp, kiro, goose
|
|
55
55
|
|
|
56
56
|
For rules that need to work across all agents, inline the content rather than using
|
|
57
57
|
@-imports — the second group will load '@path/to/file.md' as a literal string.
|
|
@@ -73,7 +73,7 @@ Project rules & @-imports:
|
|
|
73
73
|
console.log(chalk.red(formatAgentError(agentName)));
|
|
74
74
|
process.exit(1);
|
|
75
75
|
}
|
|
76
|
-
requestedVersion =
|
|
76
|
+
requestedVersion = resolveListFilterOrExit(agentId, parts[1]) ?? null;
|
|
77
77
|
}
|
|
78
78
|
const renderVersionRules = (agentId, version, isDefault, home) => {
|
|
79
79
|
const agent = AGENTS[agentId];
|