@phnx-labs/agents-cli 1.22.69 → 1.22.70
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 +16 -0
- package/README.md +3 -8
- package/dist/commands/accounts.js +23 -7
- package/dist/commands/exec.js +2 -2
- package/dist/commands/import.js +2 -2
- package/dist/commands/models.js +2 -2
- package/dist/commands/permissions.js +2 -2
- package/dist/commands/rules.js +1 -1
- package/dist/commands/send.js +9 -3
- package/dist/commands/traces.js +1 -1
- package/dist/lib/account-capabilities.js +0 -2
- package/dist/lib/account-registry.d.ts +3 -3
- package/dist/lib/account-registry.js +25 -7
- package/dist/lib/acp/client.d.ts +1 -1
- package/dist/lib/acp/client.js +12 -1
- package/dist/lib/acp/harnesses.js +1 -1
- package/dist/lib/add-dir.js +0 -2
- package/dist/lib/agent-cli-commands.js +0 -2
- package/dist/lib/agent-spec/agents.d.ts +1 -1
- package/dist/lib/agent-spec/agents.js +2 -83
- package/dist/lib/browser/ipc.js +9 -1
- package/dist/lib/browser/remote-control.d.ts +6 -3
- package/dist/lib/browser/remote-control.js +6 -3
- package/dist/lib/browser/service.d.ts +4 -1
- package/dist/lib/browser/service.js +7 -1
- package/dist/lib/channels/registry.d.ts +6 -0
- package/dist/lib/channels/send.d.ts +11 -2
- package/dist/lib/channels/send.js +11 -2
- package/dist/lib/cloud/rush.d.ts +10 -2
- package/dist/lib/cloud/rush.js +15 -9
- package/dist/lib/daemon/daemon.js +28 -8
- package/dist/lib/daemon/runner.js +6 -2
- package/dist/lib/exec.d.ts +2 -2
- package/dist/lib/exec.js +3 -34
- package/dist/lib/feed-broadcast.d.ts +12 -29
- package/dist/lib/feed-broadcast.js +28 -27
- package/dist/lib/hooks/install.js +0 -87
- package/dist/lib/installations/strategies.js +1 -1
- package/dist/lib/mcp-registry.js +0 -13
- package/dist/lib/mcp.js +2 -2
- package/dist/lib/model-tiers.js +1 -1
- package/dist/lib/models.js +0 -63
- package/dist/lib/notify.d.ts +11 -0
- package/dist/lib/notify.js +17 -4
- package/dist/lib/owner-message.d.ts +46 -3
- package/dist/lib/owner-message.js +26 -6
- package/dist/lib/permissions-registry.d.ts +0 -2
- package/dist/lib/permissions-registry.js +3 -50
- package/dist/lib/permissions.d.ts +3 -17
- package/dist/lib/permissions.js +4 -73
- package/dist/lib/rush-session.d.ts +19 -0
- package/dist/lib/rush-session.js +24 -0
- package/dist/lib/secrets/drivers/rush.js +2 -1
- package/dist/lib/session/cloud.js +2 -1
- package/dist/lib/sink-format.d.ts +34 -0
- package/dist/lib/sink-format.js +17 -0
- package/dist/lib/staleness/detectors/permissions.js +0 -20
- package/dist/lib/staleness/writers/commands.js +1 -1
- package/dist/lib/staleness/writers/hooks.js +2 -2
- package/dist/lib/subagents-registry.js +2 -12
- package/dist/lib/subagents.d.ts +0 -10
- package/dist/lib/subagents.js +0 -37
- package/dist/lib/types.d.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.22.70
|
|
4
|
+
|
|
5
|
+
- **`agents browser stop --profile` is now gated by the remote-control consent gate (PHNX-3317).** `stop --profile <name>` (no `--task`) is handled entirely by `bindTask`'s early return in `ipc.ts`, so it never reached `resolveOrCreateTask` — the one chokepoint every other page/close/attach verb's `assertRemoteControlAllowedForRequest` gate runs through — and `case 'stop'` called `BrowserService.stopProfile()` directly with no consent check at all. That left one destructive fleet-remote path (kills the profile's browser process, clears its runtime dir) reachable from `browser --device <device> stop --profile` even with `remote-control off` on the target. `stopProfile()` now takes the same `{ fleetRemote, actor }` opts as `start`/`showUrl`/`resolveOrCreateTask` and asserts the gate first; a local (non-fleet-remote) call is unaffected. Source: `cli/src/lib/browser/service.ts`, `cli/src/lib/browser/ipc.ts`.
|
|
6
|
+
|
|
7
|
+
- **The PHNX-2939 headless-account regression test now genuinely exercises the headless path (PHNX-3352).** The real-macOS-keychain test in `account-registry.keychain.test.ts` set `AGENTS_RUNTIME='test-headless-account-launch'`, a made-up value `isHeadlessSecretsContext()` never matches — its set is exactly `headless`/`teams`/`terminal` — so the resolve never entered the headless keychain guard and the test passed identically with OR without the PHNX-2939 biometry-ACL fix, reproducing nothing. It now sets `AGENTS_RUNTIME='headless'` and asserts `isHeadlessSecretsContext()` is `true` before resolving, so the test fails against the pre-fix code (a direct `getKeychainToken` read of the policy-`never`, no-ACL account item is rejected as if it required Touch ID) and passes only because the fix routes through the bundle path that attests `silentNoAcl`. Source: `cli/src/lib/account-registry.keychain.test.ts`.
|
|
8
|
+
|
|
9
|
+
- **`agents daemon stop` reclaims a stale `browser.sock` when the daemon vanishes mid-stop (PHNX-3618).** `stopDaemonLocked` captured the browser IPC socket's inode ONLY when a live pid resolved (`pid !== null && browserSock ? …`). If the daemon died in the window between the CLI liveness precheck (`isDaemonRunning()` was true) and the locked read, `resolveLiveDaemonPid()` returned null, so the owner was never captured — and the socket the daemon's ungraceful death left on disk hit the else branch, was reported "browser IPC socket ownership could not be verified", and was left behind, so the next daemon start raced a dead binding. The socket inode is now captured **independently of the pid**, and the stale binding is reclaimed once no live daemon — the signalled target OR any successor for this state dir — is proven to own it. PHNX-3607's never-delete-a-successor invariant is preserved: a successor that rebinds during the stop gets a new inode (identity no longer matches) or shows up as a survivor, and in either case its socket is left untouched. Source: `cli/src/lib/daemon/daemon.ts`.
|
|
10
|
+
|
|
11
|
+
- **`agents run --cloud` no longer rejects a non-expiring Phoenix bearer (PHNX-3645).** A Rush session stores `expires_at: 0` for an opaque Phoenix `pid_` bearer, which by contract means NON-EXPIRING. Three freshness checks read that `0` as an absolute timestamp — `new Date(0)` = 1970-01-01 — and refused a valid, fresh session with `Rush session expired at 1970-01-01`, so no Phoenix-authed box could dispatch a cloud run, push/pull secrets over Rush, or list cloud sessions. The `expires_at === 0` (and missing) special-case now lives in one place, `isRushSessionExpired` (`cli/src/lib/rush-session.ts`), which cloud dispatch, the secrets Rush driver, and the cloud session source all route through — mirroring rush/cli's own `isFresh` (RUSH-1310, PHNX-3637). Source: `cli/src/lib/rush-session.ts`, `cli/src/lib/cloud/rush.ts`, `cli/src/lib/secrets/drivers/rush.ts`, `cli/src/lib/session/cloud.ts`.
|
|
12
|
+
|
|
13
|
+
- **Owner alerts now render per destination — Slack gets tappable links, iMessage stays plain (PHNX-3698).** `agents notify` / `agents send --to owner` (and an important `feed post` that fans out to the owner) resolve every channel in `owner.policy.normal` and composed ONE plain string for all of them, so a Slack owner destination received a wall of prose with no `<url|label>` links and no tappable session crumb — the labeled-link support already in `composeBroadcastMessage` never fired on the path the owner actually uses. The owner fan-out (`sendToOwner`) now re-renders the body PER destination, keyed on each channel's resolved provider (the same `notify.transports` remap delivery uses): a Slack destination turns every `TEAM-N` key the post names into `<https://linear.app/<ws>/issue/<KEY>|<KEY>>` and the `Sent from claude/<id> on <host>` crumb into `<https://prix.dev/console/sessions/<full-id>|claude/<id>>` (the 8-char crumb upgraded to the full indexed id first), while iMessage / owner-scoped rush / desktop / `command:` sinks stay the plain human sentence with no URLs. Each delivery echoes the exact body it sent, so `agents notify --dry-run --json` now shows the two different bodies. Source: `cli/src/lib/notify.ts`, `cli/src/lib/owner-message.ts`, `cli/src/lib/sink-format.ts`, `cli/src/lib/feed-broadcast.ts`, `cli/src/lib/channels/send.ts`, `cli/src/commands/send.ts`.
|
|
14
|
+
|
|
15
|
+
- **A release no longer starves waiting for the tip of `main` to be attested (PHNX-3705).** `release.sh` phase 2 required an attestation for `origin/main`'s tree *as of the instant the release ran*, but `attest-main.yml` produces that by running the full suite — minutes of work. On a repo where agents merge continuously, main advances faster than attestation completes, so every release lost the race and died at `missing exact attestation key`. Measured 2026-09-01: six merges to `main` in ~30 minutes with attest-main runs still pending or superseded; the tip was never attested long enough to release from, which also makes the R2 bar (ordinary release under 60s) unreachable by construction. The release does not need *the tip* — it needs a green base to cut the release commit from and derive the release-tree attestation against (PHNX-3696), and any attested **ancestor** serves. Phase 2 now requires an attestation for the tree it is **actually releasing from** (`$BASE_SHA`) rather than the live remote tip, and `derive_release_attestation` inherits from that same commit — the release commit's real parent — instead of the tip. New `cli/scripts/release-attested-base.sh` resolves the newest attested commit at or below `origin/<default>` (bounded lookback, fails closed when none is found), `release-worktree.sh` cuts the release worktree from it and says so on stderr when it is behind the tip, and `release.sh`'s base check now requires an *ancestor* of the remote tip rather than the tip exactly. The supply-chain guarantee is unchanged: the published tarball is still bound to a tree whose suite passed, and `derive`'s allowlist still fails closed on any code file — the release simply ships from a slightly older tree than the tip, which was always true of an attested tree. Source: `cli/scripts/release-attested-base.sh`, `cli/scripts/release-worktree.sh`, `cli/scripts/release.sh`.
|
|
16
|
+
|
|
17
|
+
- **Docs: sign-in unlocks managed sharing, not only team spaces; `traces setup` marked advanced/self-host.** The README said signing in unlocks "the one thing" — team spaces — which predated managed, private-by-default sharing; it now names both hosted surfaces (team spaces AND `agents artifacts share`/`agents traces sync` on our storage with zero Cloudflare setup, private by default when signed in). The `agents traces setup` command description no longer reads as a normal user step — it is now labeled advanced/self-host, since `agents auth login` syncs to the managed endpoint with no setup. Source: `README.md`, `cli/src/commands/traces.ts`, `cli/docs/command-index.{md,json}`.
|
|
18
|
+
|
|
3
19
|
## 1.22.69
|
|
4
20
|
|
|
5
21
|
- **`agents monitors` no longer fires an action on a poll FAILURE (PHNX-3510).** An `[on-change]` monitor treated a failing poll — a `gh pr list … | jq` that intermittently printed `GraphQL: API rate limit already exceeded …` — as a value change: the empty→error→empty flap read as two changes and dispatched a full agent run each time on a premise that was false (~10 sessions burned re-verifying two already-merged PRs). A command/poll source now flags a snapshot that exited non-zero, or whose output matches a transport/auth/rate-limit error shape (caught even on exit 0, since a pipe to jq swallows the failing half's exit code), as an *observation failure*: the engine skips it, leaves watched-state untouched, does not fire, and records it as a failed check so a sustained streak escalates to the owner as a drought. `agents monitors test` labels a failed poll and reports `Would fire: no`. Note: a non-zero exit is now an observation failure rather than a watchable value — a monitor that wants to watch a command's success/failure should emit a stable token (`… && echo UP || echo DOWN`, always exit 0) so the state it cares about diffs as a value; sustained failures still reach the owner via the drought escalation. Source: `cli/src/lib/monitors/sources/failure.ts`, `cli/src/lib/monitors/sources/command.ts`, `cli/src/lib/monitors/engine.ts`, `cli/docs/automation.md`.
|
package/README.md
CHANGED
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
|
|
35
35
|
<a href="https://dev.meta.ai/docs/muse-code" title="Meta Muse Code"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/harnesses/muse.svg"><img src="assets/harnesses/muse-light.svg" height="32" alt="Meta Muse Code" /></picture></a>
|
|
36
36
|
|
|
37
|
-
<a href="https://omp.sh" title="Oh My Pi"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/harnesses/pi.svg"><img src="assets/harnesses/pi-light.svg" height="32" alt="Oh My Pi" /></picture></a>
|
|
38
37
|
|
|
39
38
|
<a href="https://docs.warp.dev/reference/cli" title="Warp Agent CLI (Oz)"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/harnesses/warp.svg"><img src="assets/harnesses/warp-light.svg" height="32" alt="Warp Agent CLI" /></picture></a>
|
|
40
39
|
</p>
|
|
@@ -54,7 +53,7 @@ agents setup status # readiness for browser, computer, fleet,
|
|
|
54
53
|
agents run claude "explain this repo" # run any agent on your existing subscription
|
|
55
54
|
```
|
|
56
55
|
|
|
57
|
-
Everything here — and every other command in this README — is free and needs no account; the optional `agents auth login`
|
|
56
|
+
Everything here — and every other command in this README — is free and needs no account; the optional `agents auth login` unlocks the hosted surfaces — [team spaces](#sign-in) and managed, private-by-default sharing (`agents artifacts share` / `agents traces sync` with no Cloudflare setup). `agents setup` is interactive and idempotent -- safe to re-run on any machine. Once core setup exists, it opens a status-aware menu for browser, computer, secrets, fleet, share, watchdog, and device preferences; each choice delegates to the same wizard available under `agents setup <capability>`. In CI or another non-TTY, bare setup prints the checklist without prompting. The `agi-cli.sh` one-liner installs this same canonical `@phnx-labs/agents-cli` package. Prefer bun? `bun install -g @phnx-labs/agents-cli` works too.
|
|
58
57
|
|
|
59
58
|
The command surface teaches setup through `agents setup` and group-level `--help`.
|
|
60
59
|
The durable system model starts at [`cli/docs/README.md`](cli/docs/README.md).
|
|
@@ -1090,7 +1089,7 @@ agents browser profiles create cloud \
|
|
|
1090
1089
|
|
|
1091
1090
|
## Sign in
|
|
1092
1091
|
|
|
1093
|
-
Signing in is **optional**. Every local feature — `agents run`, sessions, teams, fleet dispatch, secrets, browser, computer — works with no account.
|
|
1092
|
+
Signing in is **optional**. Every local feature — `agents run`, sessions, teams, fleet dispatch, secrets, browser, computer — works with no account. Signing in unlocks the hosted surfaces: **team spaces** (`agents auth space`) and **managed sharing** — `agents artifacts share` and `agents traces sync` publish to our storage with **zero Cloudflare setup**, and a signed-in `agents artifacts share` is **private by default** (`me`, owner-only) unless you pass `--visibility org`/`public`. `agents auth` signs this machine in to **Phoenix ID**, the Phoenix Labs account layer behind these hosted surfaces. Sign-in is Google-only and runs a device-code flow: the CLI shows a code, your browser confirms it, and the CLI picks the session up.
|
|
1094
1093
|
|
|
1095
1094
|
```bash
|
|
1096
1095
|
agents auth login # shows a code, opens a Phoenix-branded page
|
|
@@ -1602,7 +1601,6 @@ Which DotAgents resources each agent CLI can load. Source of truth: [src/lib/age
|
|
|
1602
1601
|
| OpenCode | yes | no | yes | >= 1.1.1 | yes | yes | no | no | `AGENTS.md` | no |
|
|
1603
1602
|
| Copilot | yes | no | yes | no | yes | yes | no | no | `AGENTS.md` | no |
|
|
1604
1603
|
| Amp | yes | no | yes | no | yes | yes | no | no | `AGENTS.md` | no |
|
|
1605
|
-
| Kiro | yes | no | yes | >= 2.8.0 | yes | yes | no | >= 1.23.0 | `AGENTS.md` | no |
|
|
1606
1604
|
| Goose | yes | no | yes | no | no | no | no | no | `AGENTS.md` | no |
|
|
1607
1605
|
| Roo Code | yes | no | yes | no | yes | yes | no | no | `AGENTS.md` | no |
|
|
1608
1606
|
| Droid | yes | yes | yes | >= 0.57.5 | >= 0.26.0 | yes | yes | yes | `AGENTS.md` | no |
|
|
@@ -1623,17 +1621,14 @@ Which DotAgents resources each agent CLI can load. Source of truth: [src/lib/age
|
|
|
1623
1621
|
| Antigravity | -- | yes | -- |
|
|
1624
1622
|
| Copilot | -- | -- | yes |
|
|
1625
1623
|
| OpenClaw, Amp, Goose, Roo | -- | -- | -- |
|
|
1626
|
-
| Kiro | -- | -- | -- |
|
|
1627
1624
|
|
|
1628
1625
|
### Version-gated sync
|
|
1629
1626
|
|
|
1630
1627
|
| Capability | Agent | Gate |
|
|
1631
1628
|
|------------|-------|------|
|
|
1632
1629
|
| Hooks | Codex | >= 0.116.0 |
|
|
1633
|
-
| Subagents | Kiro | >= 1.23.0 |
|
|
1634
1630
|
| Skills | Droid | >= 0.26.0 |
|
|
1635
1631
|
| Permissions | Droid | >= 0.57.5 |
|
|
1636
|
-
| Permissions | Kiro | >= 2.8.0 |
|
|
1637
1632
|
| File-based commands | Codex | < 0.117.0 (0.117+ uses command-as-skill) |
|
|
1638
1633
|
| Plugins | Codex | >= 0.128.0 |
|
|
1639
1634
|
|
|
@@ -1649,7 +1644,7 @@ Claude Code, Codex CLI, Antigravity, Grok Build, and others each have their own
|
|
|
1649
1644
|
|
|
1650
1645
|
### Is it free?
|
|
1651
1646
|
|
|
1652
|
-
Yes — every feature, with no account and no signup. `agents run`, sessions, teams, fleet dispatch, secrets, browser, and computer automation all work the moment you install. The optional `agents auth login`
|
|
1647
|
+
Yes — every feature, with no account and no signup. `agents run`, sessions, teams, fleet dispatch, secrets, browser, and computer automation all work the moment you install. The optional `agents auth login` unlocks the hosted surfaces — team spaces (`agents auth space`) and managed, private-by-default sharing (`agents artifacts share` / `agents traces sync`, no Cloudflare setup); there are no paid tiers. This developer tool is entirely free because we believe developers should have the best tools — fast and robust — so they can create the best products for their users.
|
|
1653
1648
|
|
|
1654
1649
|
### Is this like `nvm` / `mise` / `asdf` for AI agents?
|
|
1655
1650
|
|
|
@@ -336,7 +336,10 @@ export async function listSwitchableAccounts(agent) {
|
|
|
336
336
|
*/
|
|
337
337
|
export function setDefaultAccount(agentRaw, name) {
|
|
338
338
|
const agent = parseHarness(agentRaw);
|
|
339
|
-
|
|
339
|
+
// Scope to the harness this default is FOR: a bare identity (`<email>`) matches
|
|
340
|
+
// every harness that identity is signed into, so an un-scoped lookup resolved
|
|
341
|
+
// the wrong row and then rejected it as "is a <other> login" just below.
|
|
342
|
+
const account = findUnifiedAccount(name, readMeta(), undefined, agent);
|
|
340
343
|
if (!account)
|
|
341
344
|
throw new Error(`Unknown account '${name}'.`);
|
|
342
345
|
if (account.kind === 'provider') {
|
|
@@ -519,14 +522,19 @@ agents run codex#work`,
|
|
|
519
522
|
.action(async (name, target, _o, command) => {
|
|
520
523
|
await runAccountsAction(command, async () => {
|
|
521
524
|
const meta = readMeta();
|
|
522
|
-
|
|
525
|
+
// Validate the target exists before mutating any binding — and resolve it
|
|
526
|
+
// FIRST so the account lookup can be scoped to the harness being attached
|
|
527
|
+
// to. `identityLabel` defaults to the login's email, so a bare identity
|
|
528
|
+
// (`muqsitnawaz@gmail.com`) matches every harness that identity is signed
|
|
529
|
+
// into; un-scoped this resolved whichever row the store ordered first and
|
|
530
|
+
// then rejected it below as "is a <other> login".
|
|
531
|
+
const t = classifyAttachTarget(target);
|
|
532
|
+
const targetAgent = t.kind === 'profile' ? t.profile.host.agent : t.agent;
|
|
533
|
+
const account = findUnifiedAccount(name, meta, undefined, targetAgent);
|
|
523
534
|
if (!account)
|
|
524
535
|
throw new Error(`Unknown account '${name}'.`);
|
|
525
536
|
if (account.kind === 'native')
|
|
526
537
|
assertNativeAccountNameable(account.agent);
|
|
527
|
-
// Validate the target exists before mutating any binding.
|
|
528
|
-
const t = classifyAttachTarget(target);
|
|
529
|
-
const targetAgent = t.kind === 'profile' ? t.profile.host.agent : t.agent;
|
|
530
538
|
if (account.kind === 'native') {
|
|
531
539
|
// A provider-backed profile injects provider env at spawn, which would run
|
|
532
540
|
// under a different credential than the native identity claims — refuse it.
|
|
@@ -572,7 +580,7 @@ agents run codex#work`,
|
|
|
572
580
|
// Provider account: it must be able to authenticate the target's harness.
|
|
573
581
|
getAccountProvider(account.provider).envFor(targetAgent, account.auth);
|
|
574
582
|
}
|
|
575
|
-
bindAccount(name, target);
|
|
583
|
+
bindAccount(name, target, targetAgent);
|
|
576
584
|
writeClaudeInteractiveOauthToken(t, targetAgent, account.kind === 'native' && account.agent === 'claude' ? account.identityLabel : undefined);
|
|
577
585
|
console.log(chalk.green(`Attached ${account.name} to ${target}.`));
|
|
578
586
|
});
|
|
@@ -581,7 +589,15 @@ agents run codex#work`,
|
|
|
581
589
|
.description('Remove one account attachment')
|
|
582
590
|
.action(async (name, target, _o, command) => {
|
|
583
591
|
await runAccountsAction(command, () => {
|
|
584
|
-
|
|
592
|
+
// Classify the target first so the unbind is scoped to the right harness
|
|
593
|
+
// for a colliding identity selector (same as the attach path).
|
|
594
|
+
let targetAgent;
|
|
595
|
+
try {
|
|
596
|
+
const t = classifyAttachTarget(target);
|
|
597
|
+
targetAgent = t.kind === 'profile' ? t.profile.host.agent : t.agent;
|
|
598
|
+
}
|
|
599
|
+
catch { /* an unresolvable target still unbinds by whatever row matches */ }
|
|
600
|
+
unbindAccount(name, target, targetAgent);
|
|
585
601
|
// With the binding gone, no setup-token resolves for this version home, so this
|
|
586
602
|
// clears any .oauth_token the attach left behind (else interactive runs would keep
|
|
587
603
|
// authenticating as the just-detached account).
|
package/dist/commands/exec.js
CHANGED
|
@@ -2244,7 +2244,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2244
2244
|
const { pickSessionInteractive } = await import('./sessions.js');
|
|
2245
2245
|
const { buildContinuePrompt } = await import('../lib/loop.js');
|
|
2246
2246
|
// Freshen the index for this agent before any lookup (incremental, cached).
|
|
2247
|
-
// AgentId is wider than SessionAgentId (amp/
|
|
2247
|
+
// AgentId is wider than SessionAgentId (amp/goose/copilot keep no transcripts);
|
|
2248
2248
|
// those simply yield no matches and fall through to the not-found error.
|
|
2249
2249
|
const sessionAgent = agent;
|
|
2250
2250
|
if (!resolvedResumeSource)
|
|
@@ -2723,7 +2723,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
|
|
|
2723
2723
|
process.exit(1);
|
|
2724
2724
|
}
|
|
2725
2725
|
// Default CLI mode is the generic 'plan'. Agents without a read-only
|
|
2726
|
-
// mode (antigravity,
|
|
2726
|
+
// mode (antigravity, …) degrade via resolveMode to their
|
|
2727
2727
|
// safest native mode (modes[0], typically edit). That covers both the
|
|
2728
2728
|
// implicit default and an explicit `--mode plan`, so multi-agent
|
|
2729
2729
|
// scripts can pass a uniform plan flag without per-agent branching.
|
package/dist/commands/import.js
CHANGED
|
@@ -56,7 +56,7 @@ async function runImport(agentArg, opts) {
|
|
|
56
56
|
if (!opts.isolated) {
|
|
57
57
|
assertIsolationBoundary(agentId, 'adopt your existing install');
|
|
58
58
|
}
|
|
59
|
-
// installScript-based agents (Grok, Antigravity, Cursor,
|
|
59
|
+
// installScript-based agents (Grok, Antigravity, Cursor, Goose, Roo)
|
|
60
60
|
// don't have an npm package; their binary lives wherever the curl/brew
|
|
61
61
|
// installer dropped it. We adopt by symlinking that PATH binary directly
|
|
62
62
|
// into the version's `node_modules/.bin/`. No package.json walk.
|
|
@@ -345,7 +345,7 @@ When to use:
|
|
|
345
345
|
pointing at the existing install — nothing is copied or moved (except the
|
|
346
346
|
agent's config dir, which is moved into the version's home). Works for both
|
|
347
347
|
npm-style packages (claude, codex, opencode, openclaw) and
|
|
348
|
-
installScript-based agents (grok, antigravity, cursor,
|
|
348
|
+
installScript-based agents (grok, antigravity, cursor, goose).
|
|
349
349
|
`)
|
|
350
350
|
.action((...args) => withIsolationBoundary(() => runImport(...args)));
|
|
351
351
|
}
|
package/dist/commands/models.js
CHANGED
|
@@ -18,13 +18,13 @@ import { terminalWidth, truncateToWidth, stringWidth } from '../lib/session/widt
|
|
|
18
18
|
import { wrapJoined } from './inspect.js';
|
|
19
19
|
import { setHelpSections } from '../lib/help.js';
|
|
20
20
|
import { formatRunDefaultEntry, listRunDefaults, parseRunDefaultSelector, setRunDefault, } from '../lib/run-defaults.js';
|
|
21
|
-
const MODEL_CAPABLE_AGENTS = ['claude', 'codex', 'opencode', 'cursor', 'openclaw', 'antigravity', 'kimi', 'grok', 'droid'
|
|
21
|
+
const MODEL_CAPABLE_AGENTS = ['claude', 'codex', 'opencode', 'cursor', 'openclaw', 'antigravity', 'kimi', 'grok', 'droid'];
|
|
22
22
|
/**
|
|
23
23
|
* Agents that don't necessarily install under ~/.agents/versions (cursor ships
|
|
24
24
|
* via a curl script). For these, fall back to the PATH binary and synthesize
|
|
25
25
|
* a version label from the install path so cache keys stay stable.
|
|
26
26
|
*/
|
|
27
|
-
const PATH_ONLY_AGENTS = new Set(['cursor'
|
|
27
|
+
const PATH_ONLY_AGENTS = new Set(['cursor']);
|
|
28
28
|
/** Derive a version label from the PATH-installed binary location for agents without managed versions. */
|
|
29
29
|
function fallbackPathVersion(agent) {
|
|
30
30
|
const src = locateModelSource(agent, 'unresolved');
|
|
@@ -377,8 +377,8 @@ Examples:
|
|
|
377
377
|
//
|
|
378
378
|
// This used to hardcode `.json`/`.jsonc`/`.toml` plus a `.claude`/
|
|
379
379
|
// `.opencode`/`.codex` substring, which excluded the ten other harnesses
|
|
380
|
-
// the CLI writes -- and excluded
|
|
381
|
-
//
|
|
380
|
+
// the CLI writes -- and excluded hermes twice over, since
|
|
381
|
+
// its config is YAML. The registry already answers this by matching
|
|
382
382
|
// each harness's own declared path, so ask it (RUSH-2676).
|
|
383
383
|
const isAgentConfig = detectPermissionAgentFromPath(localPath) !== null;
|
|
384
384
|
if (isAgentConfig) {
|
package/dist/commands/rules.js
CHANGED
|
@@ -52,7 +52,7 @@ Project rules & @-imports:
|
|
|
52
52
|
@path imports inside AGENTS.md/CLAUDE.md are resolved at session start by the agent
|
|
53
53
|
itself, not by agents-cli. Support is per-agent:
|
|
54
54
|
Inlined natively: claude
|
|
55
|
-
Literal text: codex, cursor, opencode, copilot, amp,
|
|
55
|
+
Literal text: codex, cursor, opencode, copilot, amp, goose
|
|
56
56
|
|
|
57
57
|
For rules that need to work across all agents, inline the content rather than using
|
|
58
58
|
@-imports — the second group will load '@path/to/file.md' as a literal string.
|
package/dist/commands/send.js
CHANGED
|
@@ -3,7 +3,7 @@ import { die } from '../lib/format.js';
|
|
|
3
3
|
import { setHelpSections } from '../lib/help.js';
|
|
4
4
|
import { readMeta } from '../lib/state.js';
|
|
5
5
|
import { sendMessage, isOwnerAlias } from '../lib/channels/send.js';
|
|
6
|
-
import {
|
|
6
|
+
import { ownerMessageComposer } from '../lib/owner-message.js';
|
|
7
7
|
import { fireTraceSyncInBackground } from '../lib/run-trace-sync.js';
|
|
8
8
|
function mergeAttachments(opts) {
|
|
9
9
|
const list = [...(opts.attach ?? []), ...(opts.attachment ?? [])];
|
|
@@ -30,6 +30,7 @@ async function runSend(positionalText, opts, ownerMode) {
|
|
|
30
30
|
// the SAME composer as an important `feed post` (PHNX-3698): short-shaped body,
|
|
31
31
|
// TEAM-N keys linkified, session crumb as a tappable console URL — instead of a
|
|
32
32
|
// raw dump. A non-owner send (explicit --channel/--to) is delivered verbatim.
|
|
33
|
+
let ownerCompose;
|
|
33
34
|
if (ownerMode || isOwnerAlias(opts.to)) {
|
|
34
35
|
const flagged = opts.text?.trim() ?? '';
|
|
35
36
|
const positional = (positionalText ?? '').trim();
|
|
@@ -38,7 +39,12 @@ async function runSend(positionalText, opts, ownerMode) {
|
|
|
38
39
|
// loud with the "pass the message once" error rather than composing a guess.
|
|
39
40
|
const bothDiffer = flagged !== '' && positional !== '' && flagged !== positional;
|
|
40
41
|
if (raw && !bothDiffer) {
|
|
41
|
-
|
|
42
|
+
// Resolve the context once, then let each owner destination render its own
|
|
43
|
+
// format: the envelope carries the plain default (for --json and dry-run
|
|
44
|
+
// display), while ownerCompose hands sendToOwner the mrkdwn variant for a
|
|
45
|
+
// Slack owner destination and plain for iMessage (PHNX-3698).
|
|
46
|
+
ownerCompose = ownerMessageComposer(raw);
|
|
47
|
+
input = { ...input, text: ownerCompose('plain'), positionalText: undefined };
|
|
42
48
|
// The console URL in the composed body only resolves once this session's
|
|
43
49
|
// trace shard is uploaded; fire that now so the tapped link isn't a 404.
|
|
44
50
|
// A --dry-run resolves + composes but MUST NOT act (its documented contract),
|
|
@@ -46,7 +52,7 @@ async function runSend(positionalText, opts, ownerMode) {
|
|
|
46
52
|
fireTraceSyncInBackground({ disabled: Boolean(opts.dryRun) });
|
|
47
53
|
}
|
|
48
54
|
}
|
|
49
|
-
const out = await sendMessage(input, meta);
|
|
55
|
+
const out = await sendMessage(input, meta, ownerCompose);
|
|
50
56
|
if ('error' in out) {
|
|
51
57
|
die(out.error);
|
|
52
58
|
}
|
package/dist/commands/traces.js
CHANGED
|
@@ -182,7 +182,7 @@ export function registerTracesCommands(program) {
|
|
|
182
182
|
.description("Sync this device's derived, redacted trajectories to your Phoenix account");
|
|
183
183
|
const setupCmd = tracesCmd
|
|
184
184
|
.command('setup')
|
|
185
|
-
.description('Provision
|
|
185
|
+
.description('(advanced) Provision a self-hosted Cloudflare Worker + R2 bucket for traces — NOT required; `agents auth login` syncs to the managed endpoint with zero setup')
|
|
186
186
|
.option('--bundle <name>', 'secrets bundle holding the Cloudflare API token', DEFAULT_CF_BUNDLE)
|
|
187
187
|
.option('--worker <name>', 'Worker name', DEFAULT_WORKER_NAME)
|
|
188
188
|
.option('--bucket <name>', 'R2 bucket name', DEFAULT_BUCKET_NAME)
|
|
@@ -35,10 +35,8 @@ export const NATIVE_ACCOUNT_CAPABILITIES = {
|
|
|
35
35
|
copilot: { inspection: 'none', scope: 'unsupported', status: 'unsupported' },
|
|
36
36
|
openclaw: { inspection: 'none', scope: 'unsupported', status: 'unsupported' },
|
|
37
37
|
amp: { inspection: 'none', scope: 'unsupported', status: 'unsupported' },
|
|
38
|
-
kiro: { inspection: 'none', scope: 'unsupported', status: 'unsupported' },
|
|
39
38
|
goose: { inspection: 'none', scope: 'unsupported', status: 'unsupported' },
|
|
40
39
|
hermes: { inspection: 'none', scope: 'unsupported', status: 'unsupported' },
|
|
41
|
-
pi: { inspection: 'none', scope: 'unsupported', status: 'unsupported' },
|
|
42
40
|
warp: { inspection: 'none', scope: 'unsupported', status: 'unsupported' },
|
|
43
41
|
};
|
|
44
42
|
export function nativeAccountCapability(agent) {
|
|
@@ -54,12 +54,12 @@ export declare function listNativeAccounts(meta: Pick<Meta, 'accounts' | 'device
|
|
|
54
54
|
* running before the body, so callers that only need a native lookup must be
|
|
55
55
|
* able to omit it.
|
|
56
56
|
*/
|
|
57
|
-
export declare function findUnifiedAccount(nameOrId: string, meta: Pick<Meta, 'accounts' | 'deviceAccounts'>, doc?: AccountRegistryDocument): UnifiedAccount | null;
|
|
57
|
+
export declare function findUnifiedAccount(nameOrId: string, meta: Pick<Meta, 'accounts' | 'deviceAccounts'>, doc?: AccountRegistryDocument, preferAgent?: AgentId): UnifiedAccount | null;
|
|
58
58
|
export declare function addNativeAccount(name: string, agent: AgentId, identityKey: string, identityLabel: string | undefined, scope: 'version' | 'device'): NativeAccount;
|
|
59
59
|
/** Create or replace the version-independent label for one native identity. */
|
|
60
60
|
export declare function labelNativeAccount(agent: AgentId, identityKey: string, identityLabel: string | undefined, label: string | undefined, scope: 'version' | 'device'): NativeAccount;
|
|
61
|
-
export declare function bindAccount(nameOrId: string, target: string): UnifiedAccount;
|
|
62
|
-
export declare function unbindAccount(nameOrId: string, target: string): void;
|
|
61
|
+
export declare function bindAccount(nameOrId: string, target: string, preferAgent?: AgentId): UnifiedAccount;
|
|
62
|
+
export declare function unbindAccount(nameOrId: string, target: string, preferAgent?: AgentId): void;
|
|
63
63
|
/** Every target bound to `accountId`: this box's device-doc bindings merged over
|
|
64
64
|
* the fleet-shared central bindings (PHNX-3315). */
|
|
65
65
|
export declare function accountBindings(accountId: string, meta: Pick<Meta, 'accounts' | 'deviceAccounts'>): string[];
|
|
@@ -159,9 +159,18 @@ export function listNativeAccounts(meta) {
|
|
|
159
159
|
* running before the body, so callers that only need a native lookup must be
|
|
160
160
|
* able to omit it.
|
|
161
161
|
*/
|
|
162
|
-
export function findUnifiedAccount(nameOrId, meta, doc) {
|
|
162
|
+
export function findUnifiedAccount(nameOrId, meta, doc, preferAgent) {
|
|
163
163
|
const needle = nameOrId.toLowerCase();
|
|
164
|
-
const
|
|
164
|
+
const matches = listNativeAccounts(meta).filter(account => account.id === nameOrId || account.name.toLowerCase() === needle || account.identityLabel?.toLowerCase() === needle);
|
|
165
|
+
// `identityLabel` defaults to the login's own identifier (the email), so ONE
|
|
166
|
+
// selector legitimately matches several harnesses: `muqsitnawaz@gmail.com` is a
|
|
167
|
+
// claude login AND a codex login. Un-scoped, `.find()` returned whichever row the
|
|
168
|
+
// merged store happened to order first, so `agents run claude#<email>` died with
|
|
169
|
+
// "Account 'personal' is a codex login and cannot authenticate the claude harness"
|
|
170
|
+
// while that identity's own claude login sat right there. Prefer the harness being
|
|
171
|
+
// launched; fall back to the first match so a management lookup with no harness in
|
|
172
|
+
// hand (rename/remove/view) behaves exactly as before.
|
|
173
|
+
const native = matches.find(account => account.agent === preferAgent) ?? matches[0];
|
|
165
174
|
if (native)
|
|
166
175
|
return native;
|
|
167
176
|
const provider = findAccount(nameOrId, doc ?? readAccountRegistry());
|
|
@@ -253,9 +262,13 @@ export function labelNativeAccount(agent, identityKey, identityLabel, label, sco
|
|
|
253
262
|
});
|
|
254
263
|
return { ...matches[0], name: resolvedLabel, identityLabel, scope: rowScope };
|
|
255
264
|
}
|
|
256
|
-
export function bindAccount(nameOrId, target) {
|
|
265
|
+
export function bindAccount(nameOrId, target, preferAgent) {
|
|
257
266
|
const meta = readMeta();
|
|
258
|
-
|
|
267
|
+
// Scope to the harness being bound to: a bare identity selector matches every
|
|
268
|
+
// harness it is signed into, so without this the binding could persist against
|
|
269
|
+
// a different harness's row than the caller validated (the attach command
|
|
270
|
+
// resolves `targetAgent` and passes it here).
|
|
271
|
+
const account = findUnifiedAccount(nameOrId, meta, undefined, preferAgent);
|
|
259
272
|
if (!account)
|
|
260
273
|
throw new Error(`Unknown account '${nameOrId}'.`);
|
|
261
274
|
// A binding follows its account: one that targets a device-scoped native login
|
|
@@ -275,9 +288,11 @@ export function bindAccount(nameOrId, target) {
|
|
|
275
288
|
}
|
|
276
289
|
return account;
|
|
277
290
|
}
|
|
278
|
-
export function unbindAccount(nameOrId, target) {
|
|
291
|
+
export function unbindAccount(nameOrId, target, preferAgent) {
|
|
279
292
|
const meta = readMeta();
|
|
280
|
-
|
|
293
|
+
// Same scoping as bindAccount: detach the row on the harness the caller means,
|
|
294
|
+
// not whichever the store happened to order first for a colliding identity.
|
|
295
|
+
const account = findUnifiedAccount(nameOrId, meta, undefined, preferAgent);
|
|
281
296
|
if (!account)
|
|
282
297
|
throw new Error(`Unknown account '${nameOrId}'.`);
|
|
283
298
|
const inCentral = meta.accounts?.bindings?.[target] === account.id;
|
|
@@ -527,7 +542,10 @@ export function resolveSpawnAccount(explicit, agent, version, meta, opts = {}) {
|
|
|
527
542
|
const selection = resolveAccountSelection(explicit, agent, meta, { useDefault: opts.useDefault, target });
|
|
528
543
|
if (!selection)
|
|
529
544
|
return null;
|
|
530
|
-
|
|
545
|
+
// Scope the lookup to the harness being launched: a bare identity selector
|
|
546
|
+
// (`claude#muqsitnawaz@gmail.com`) matches every harness that identity is signed
|
|
547
|
+
// into, and only this one can authenticate the spawn.
|
|
548
|
+
const unified = findUnifiedAccount(selection.id, meta, undefined, agent);
|
|
531
549
|
if (!unified) {
|
|
532
550
|
// A stale per-harness default is a preference, not a hard requirement: the
|
|
533
551
|
// machine stays runnable by falling back to balanced rotation. Bindings and
|
package/dist/lib/acp/client.d.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { type SessionNotification } from '@zed-industries/agent-client-protocol';
|
|
13
13
|
import type { AgentId } from '../types.js';
|
|
14
|
-
import type
|
|
14
|
+
import { type ExecMode } from '../exec.js';
|
|
15
15
|
export interface AcpRunOptions {
|
|
16
16
|
agent: AgentId;
|
|
17
17
|
prompt: string;
|
package/dist/lib/acp/client.js
CHANGED
|
@@ -15,6 +15,7 @@ import { promises as fs } from 'fs';
|
|
|
15
15
|
import * as path from 'path';
|
|
16
16
|
import { ClientSideConnection, ndJsonStream, } from '@zed-industries/agent-client-protocol';
|
|
17
17
|
import { getAcpSpec, supportsAcp } from './harnesses.js';
|
|
18
|
+
import { buildExecEnv } from '../exec.js';
|
|
18
19
|
const PROTOCOL_VERSION = 1;
|
|
19
20
|
/**
|
|
20
21
|
* Runs a single prompt turn against an ACP-capable agent and streams updates
|
|
@@ -25,10 +26,20 @@ export async function runAcp(opts) {
|
|
|
25
26
|
throw new Error(`Agent '${opts.agent}' does not support ACP. Use direct exec instead.`);
|
|
26
27
|
}
|
|
27
28
|
const spec = getAcpSpec(opts.agent);
|
|
29
|
+
// Build the harness's exec env the SAME way `agents run` does, instead of
|
|
30
|
+
// handing it a raw process.env. buildExecEnv is what injects the per-account
|
|
31
|
+
// `CLAUDE_CODE_OAUTH_TOKEN` on a worker device (gated by device role: a
|
|
32
|
+
// headed/personal box still defers to its native login). Without this, an ACP
|
|
33
|
+
// launch inherited no setup-token and fell through to the version home's
|
|
34
|
+
// copied native `.credentials.json` — which expires in ~15h and 401s once its
|
|
35
|
+
// refresh chain dies, exactly the "logged out on a worker" report (PHNX-3681).
|
|
36
|
+
// A verified precedence test shows the env token wins over a present
|
|
37
|
+
// `.credentials.json`, so injecting here is sufficient — the stale file no
|
|
38
|
+
// longer decides the session.
|
|
28
39
|
const child = spawn(spec.command, spec.args, {
|
|
29
40
|
cwd: opts.cwd,
|
|
30
41
|
stdio: ['pipe', 'pipe', 'inherit'],
|
|
31
|
-
env:
|
|
42
|
+
env: buildExecEnv({ agent: opts.agent, cwd: opts.cwd, mode: opts.mode, effort: 'auto', interactive: true }),
|
|
32
43
|
});
|
|
33
44
|
const stream = ndJsonStream(Writable.toWeb(child.stdin), Readable.toWeb(child.stdout));
|
|
34
45
|
const client = buildClient(opts);
|
|
@@ -52,7 +52,7 @@ export const ACP_HARNESSES = {
|
|
|
52
52
|
},
|
|
53
53
|
// antigravity: no documented ACP support (May 2026).
|
|
54
54
|
// goose: ACP over HTTP via `goosed`, not a clean stdio subcommand.
|
|
55
|
-
// copilot
|
|
55
|
+
// copilot: excluded for now (not installed in the reference environment,
|
|
56
56
|
// no local verification possible).
|
|
57
57
|
// amp: not on the ACP agents list.
|
|
58
58
|
};
|
package/dist/lib/add-dir.js
CHANGED
|
@@ -33,11 +33,9 @@ export const ADD_DIR_STRATEGY = {
|
|
|
33
33
|
// No multi-root CLI surface today (single --dir / project path).
|
|
34
34
|
opencode: 'none',
|
|
35
35
|
gemini: 'none',
|
|
36
|
-
pi: 'none',
|
|
37
36
|
openclaw: 'none',
|
|
38
37
|
copilot: 'none',
|
|
39
38
|
amp: 'none',
|
|
40
|
-
kiro: 'none',
|
|
41
39
|
goose: 'none',
|
|
42
40
|
antigravity: 'none',
|
|
43
41
|
droid: 'none',
|
|
@@ -104,7 +104,7 @@ export declare const MANAGED_AGENT_IDS: AgentId[];
|
|
|
104
104
|
* `curl … | sh` / `brew install` script that carries NO version token — the
|
|
105
105
|
* installer can only ever fetch the *current* release, and the binary then keeps
|
|
106
106
|
* itself up to date in place (droid, grok, antigravity, cursor, hermes,
|
|
107
|
-
*
|
|
107
|
+
* goose). There is no semver to pin, so agents-cli must not model these as
|
|
108
108
|
* having multiple installable version-homes the way it does for npm-packaged
|
|
109
109
|
* agents (claude, codex, kimi, …).
|
|
110
110
|
*
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Core agent configuration and detection module.
|
|
3
3
|
*
|
|
4
4
|
* Defines the canonical registry of current and legacy AI coding agents (Claude,
|
|
5
|
-
* Codex, Gemini, Cursor, OpenCode, OpenClaw, Copilot, Amp,
|
|
5
|
+
* Codex, Gemini, Cursor, OpenCode, OpenClaw, Copilot, Amp, Goose, Grok)
|
|
6
6
|
* with their CLI commands, config paths, capability flags, and MCP integration
|
|
7
7
|
* points.
|
|
8
8
|
*
|
|
@@ -413,52 +413,6 @@ export const AGENTS = {
|
|
|
413
413
|
supportsHooks: true,
|
|
414
414
|
capabilities: { hooks: { since: '0.3.130' }, mcp: true, mcpHttp: false, mcpHeaders: false, allowlist: { since: '1.1.1' }, skills: true, commands: true, plugins: true, subagents: true, rules: { file: 'AGENTS.md' }, workflows: false, memory: false, modes: ['plan', 'edit'], interactiveRepl: true },
|
|
415
415
|
},
|
|
416
|
-
// Oh My Pi (`omp`, omp.sh) — a Bun-based, terminal-first coding agent that runs
|
|
417
|
-
// against many model providers (OpenRouter, OpenAI, Anthropic, xAI, DeepSeek,
|
|
418
|
-
// Ollama, LM Studio, …). It is Claude-compatible: it natively discovers
|
|
419
|
-
// `.claude/commands`, `.mcp.json`, and Claude-shaped subagents, and keeps its
|
|
420
|
-
// own native resources under `~/.omp/agent/` (config dir reported by
|
|
421
|
-
// `omp config path`). configDir points AT the agent dir (not `~/.omp`) so the
|
|
422
|
-
// rules file lands at `~/.omp/agent/AGENTS.md`, the user context file omp reads.
|
|
423
|
-
pi: {
|
|
424
|
-
id: 'pi',
|
|
425
|
-
name: 'Pi',
|
|
426
|
-
sessionDir: null,
|
|
427
|
-
sessionFileExt: null,
|
|
428
|
-
versionStdoutMatch: 'semver',
|
|
429
|
-
unmanagedBinary: 'path',
|
|
430
|
-
mcpRegister: 'cli',
|
|
431
|
-
mcpAddHttp: 'transport',
|
|
432
|
-
mcpAddStdio: 'simple',
|
|
433
|
-
mcpConfigWrite: 'json-mcpServers',
|
|
434
|
-
color: 'magenta',
|
|
435
|
-
cliCommand: 'omp',
|
|
436
|
-
npmPackage: '@oh-my-pi/pi-coding-agent',
|
|
437
|
-
configDir: path.join(HOME, '.omp', 'agent'),
|
|
438
|
-
commandsDir: path.join(HOME, '.omp', 'agent', 'commands'),
|
|
439
|
-
commandsSubdir: 'commands',
|
|
440
|
-
skillsDir: path.join(HOME, '.omp', 'agent', 'skills'),
|
|
441
|
-
hooksDir: 'hooks',
|
|
442
|
-
instructionsFile: 'AGENTS.md',
|
|
443
|
-
format: 'markdown',
|
|
444
|
-
variableSyntax: '$ARGUMENTS',
|
|
445
|
-
// omp hooks are per-tool JS/TS extension modules discovered from
|
|
446
|
-
// `~/.omp/agent/hooks/{pre,post}/<tool>.<ext>` (loaded as HookFactory code),
|
|
447
|
-
// NOT the event->shell-command registrations agents-cli's hook sync writes.
|
|
448
|
-
// The two models don't map, so hooks stay off (capabilities.hooks:false).
|
|
449
|
-
supportsHooks: false,
|
|
450
|
-
// MCP: omp reads `.mcp.json` with the Claude `{ "mcpServers": {...} }` schema
|
|
451
|
-
// at user scope (`~/.omp/agent/.mcp.json`) and project scope (`<root>/.mcp.json`),
|
|
452
|
-
// stdio + http + sse with headers. skills (`~/.omp/agent/skills/<name>/SKILL.md`),
|
|
453
|
-
// commands (`~/.omp/agent/commands/*.md`), and subagents (`~/.omp/agent/agents/*.md`,
|
|
454
|
-
// Claude-shaped) are all native. allowlist is OFF: omp gates approval per-TOOL
|
|
455
|
-
// only (`tools.approval` record: allow|prompt|deny) with no command/path/domain
|
|
456
|
-
// patterns, so agents-cli's granular permission format has nothing to map to.
|
|
457
|
-
// plugins are npm packages / TS modules, not the Claude marketplace manifest.
|
|
458
|
-
// interactiveRepl: true — bare `omp` runs the TUI; `omp -p` is the one-shot
|
|
459
|
-
// form that answers a prompt and exits (upstream README, "Four entry points").
|
|
460
|
-
capabilities: { hooks: false, mcp: true, mcpHttp: true, mcpHeaders: true, allowlist: false, skills: true, commands: true, plugins: false, subagents: true, rules: { file: 'AGENTS.md' }, workflows: false, memory: false, modes: ['plan', 'edit', 'skip'], interactiveRepl: true },
|
|
461
|
-
},
|
|
462
416
|
openclaw: {
|
|
463
417
|
id: 'openclaw',
|
|
464
418
|
name: 'OpenClaw',
|
|
@@ -560,39 +514,6 @@ export const AGENTS = {
|
|
|
560
514
|
// interactiveRepl: false — amp requires a prompt; bare invocation exits immediately.
|
|
561
515
|
capabilities: { hooks: false, mcp: true, mcpHttp: false, mcpHeaders: false, allowlist: false, skills: true, commands: true, plugins: false, subagents: false, rules: { file: 'AGENTS.md' }, workflows: false, memory: false, modes: ['plan', 'edit'], interactiveRepl: false },
|
|
562
516
|
},
|
|
563
|
-
kiro: {
|
|
564
|
-
id: 'kiro',
|
|
565
|
-
name: 'Kiro',
|
|
566
|
-
sessionDir: null,
|
|
567
|
-
sessionFileExt: null,
|
|
568
|
-
versionStdoutMatch: 'semver',
|
|
569
|
-
unmanagedBinary: 'path',
|
|
570
|
-
mcpRegister: 'cli',
|
|
571
|
-
mcpAddHttp: 'transport',
|
|
572
|
-
mcpAddStdio: 'simple',
|
|
573
|
-
mcpConfigWrite: 'json-mcpServers',
|
|
574
|
-
color: 'greenBright',
|
|
575
|
-
cliCommand: 'kiro-cli',
|
|
576
|
-
npmPackage: '',
|
|
577
|
-
installScript: 'brew install --cask kiro-cli',
|
|
578
|
-
configDir: path.join(HOME, '.kiro'),
|
|
579
|
-
commandsDir: path.join(HOME, '.kiro', 'commands'),
|
|
580
|
-
commandsSubdir: 'commands',
|
|
581
|
-
skillsDir: path.join(HOME, '.kiro', 'skills'),
|
|
582
|
-
// Hooks: v3 standalone files under ~/.kiro/hooks/*.json
|
|
583
|
-
// (`{ "version": "v1", "hooks": [...] }`). Fixed PreToolUse/PostToolUse
|
|
584
|
-
// firing in kiro-cli 0.10; fully stable by 2.6.1. Launch always passes
|
|
585
|
-
// --v3 (see AGENT_COMMANDS.kiro) so the standalone files actually load.
|
|
586
|
-
// See registerHooksForKiro.
|
|
587
|
-
hooksDir: 'hooks',
|
|
588
|
-
instructionsFile: 'AGENTS.md',
|
|
589
|
-
format: 'markdown',
|
|
590
|
-
variableSyntax: '$ARGUMENTS',
|
|
591
|
-
supportsHooks: true,
|
|
592
|
-
// interactiveRepl: false — kiro-cli requires a prompt for coding sessions; bare
|
|
593
|
-
// invocation does not open a persistent REPL.
|
|
594
|
-
capabilities: { hooks: { since: '0.10.0' }, mcp: true, mcpHttp: false, mcpHeaders: false, allowlist: { since: '2.8.0' }, skills: true, commands: true, plugins: false, subagents: { since: '1.23.0' }, rules: { file: 'AGENTS.md' }, workflows: false, memory: false, modes: ['edit'], interactiveRepl: false },
|
|
595
|
-
},
|
|
596
517
|
goose: {
|
|
597
518
|
id: 'goose',
|
|
598
519
|
name: 'Goose',
|
|
@@ -1117,7 +1038,7 @@ export const MANAGED_AGENT_IDS = ALL_AGENT_IDS.filter((id) => !AGENTS[id].deprec
|
|
|
1117
1038
|
* `curl … | sh` / `brew install` script that carries NO version token — the
|
|
1118
1039
|
* installer can only ever fetch the *current* release, and the binary then keeps
|
|
1119
1040
|
* itself up to date in place (droid, grok, antigravity, cursor, hermes,
|
|
1120
|
-
*
|
|
1041
|
+
* goose). There is no semver to pin, so agents-cli must not model these as
|
|
1121
1042
|
* having multiple installable version-homes the way it does for npm-packaged
|
|
1122
1043
|
* agents (claude, codex, kimi, …).
|
|
1123
1044
|
*
|
|
@@ -3029,8 +2950,6 @@ export const AGENT_NAME_ALIASES = {
|
|
|
3029
2950
|
gh: 'copilot',
|
|
3030
2951
|
amp: 'amp',
|
|
3031
2952
|
sourcegraph: 'amp',
|
|
3032
|
-
kiro: 'kiro',
|
|
3033
|
-
'kiro-cli': 'kiro',
|
|
3034
2953
|
goose: 'goose',
|
|
3035
2954
|
'block-goose': 'goose',
|
|
3036
2955
|
antigravity: 'antigravity',
|
package/dist/lib/browser/ipc.js
CHANGED
|
@@ -736,7 +736,15 @@ export class BrowserIPCServer {
|
|
|
736
736
|
};
|
|
737
737
|
}
|
|
738
738
|
if (request.profile) {
|
|
739
|
-
|
|
739
|
+
try {
|
|
740
|
+
await this.service.stopProfile(request.profile, {
|
|
741
|
+
fleetRemote: request.fleetRemote,
|
|
742
|
+
actor: request.actor,
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
catch (err) {
|
|
746
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
747
|
+
}
|
|
740
748
|
return { ok: true };
|
|
741
749
|
}
|
|
742
750
|
return {
|