@phnx-labs/agents-cli 1.22.26 → 1.22.28
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 +293 -0
- package/README.md +80 -27
- package/dist/bin/agents +0 -0
- package/dist/commands/bench.d.ts +2 -0
- package/dist/commands/bench.js +101 -0
- package/dist/commands/doctor.js +24 -10
- package/dist/commands/exec.js +71 -26
- package/dist/commands/hosts.js +4 -3
- package/dist/commands/insights.js +39 -5
- package/dist/commands/output.js +100 -25
- package/dist/commands/perf.d.ts +10 -0
- package/dist/commands/perf.js +14 -6
- package/dist/commands/projects.js +24 -10
- package/dist/commands/resume.d.ts +11 -0
- package/dist/commands/resume.js +51 -0
- package/dist/commands/routines.js +31 -4
- package/dist/commands/run-account-picker.d.ts +37 -0
- package/dist/commands/run-account-picker.js +101 -17
- package/dist/commands/secrets.js +86 -2
- package/dist/commands/sessions-picker.js +12 -7
- package/dist/commands/sessions.d.ts +73 -7
- package/dist/commands/sessions.js +391 -49
- package/dist/commands/ssh.js +184 -11
- package/dist/commands/teams.js +22 -11
- package/dist/index.js +16 -20
- package/dist/lib/activity.js +45 -99
- package/dist/lib/auth-health.d.ts +47 -3
- package/dist/lib/auth-health.js +74 -15
- package/dist/lib/bench/index.d.ts +4 -0
- package/dist/lib/bench/index.js +4 -0
- package/dist/lib/bench/runner.d.ts +16 -0
- package/dist/lib/bench/runner.js +111 -0
- package/dist/lib/bench/schema.d.ts +5 -0
- package/dist/lib/bench/schema.js +91 -0
- package/dist/lib/bench/storage.d.ts +5 -0
- package/dist/lib/bench/storage.js +32 -0
- package/dist/lib/bench/types.d.ts +40 -0
- package/dist/lib/bench/types.js +1 -0
- package/dist/lib/claude-account-token.d.ts +2 -0
- package/dist/lib/claude-account-token.js +56 -3
- package/dist/lib/cloud/host.js +1 -0
- package/dist/lib/crabbox/cli.d.ts +2 -0
- package/dist/lib/crabbox/cli.js +2 -0
- package/dist/lib/crabbox/lease.js +7 -1
- package/dist/lib/daemon.js +20 -0
- package/dist/lib/devices/connect.d.ts +2 -0
- package/dist/lib/devices/connect.js +7 -0
- package/dist/lib/devices/doctor-findings.d.ts +4 -1
- package/dist/lib/devices/doctor-findings.js +15 -1
- package/dist/lib/devices/harness-inventory.d.ts +97 -0
- package/dist/lib/devices/harness-inventory.js +0 -0
- package/dist/lib/devices/registry.d.ts +2 -0
- package/dist/lib/devices/resolve-target.d.ts +1 -0
- package/dist/lib/devices/resolve-target.js +9 -2
- package/dist/lib/devices/ssh-config.js +3 -0
- package/dist/lib/devices/windows-ssh-enrollment.d.ts +20 -0
- package/dist/lib/devices/windows-ssh-enrollment.js +98 -0
- package/dist/lib/events.d.ts +1 -1
- package/dist/lib/events.js +2 -2
- package/dist/lib/exec.js +18 -8
- package/dist/lib/fleet/apply.js +9 -7
- package/dist/lib/fleet/remote-login.d.ts +4 -3
- package/dist/lib/fleet/remote-login.js +11 -9
- package/dist/lib/gemini-settings.d.ts +0 -1
- package/dist/lib/gemini-settings.js +12 -7
- package/dist/lib/git.d.ts +9 -3
- package/dist/lib/git.js +39 -22
- package/dist/lib/hooks/profile.d.ts +12 -1
- package/dist/lib/hooks/profile.js +6 -1
- package/dist/lib/hooks.d.ts +8 -5
- package/dist/lib/hooks.js +14 -7
- package/dist/lib/hosts/dispatch.d.ts +10 -0
- package/dist/lib/hosts/dispatch.js +85 -25
- package/dist/lib/hosts/logs.js +11 -1
- package/dist/lib/hosts/passthrough.d.ts +27 -0
- package/dist/lib/hosts/passthrough.js +19 -10
- package/dist/lib/hosts/progress.d.ts +12 -1
- package/dist/lib/hosts/progress.js +41 -8
- package/dist/lib/hosts/providers/devices.js +1 -0
- package/dist/lib/hosts/ready.d.ts +45 -4
- package/dist/lib/hosts/ready.js +124 -20
- package/dist/lib/hosts/reconcile.d.ts +2 -1
- package/dist/lib/hosts/reconcile.js +24 -7
- package/dist/lib/hosts/reconnect.d.ts +45 -12
- package/dist/lib/hosts/reconnect.js +94 -36
- package/dist/lib/hosts/registry.d.ts +2 -2
- package/dist/lib/hosts/registry.js +4 -5
- package/dist/lib/hosts/remote-cmd.d.ts +17 -0
- package/dist/lib/hosts/remote-cmd.js +29 -0
- package/dist/lib/hosts/tasks.d.ts +3 -0
- package/dist/lib/hosts/types.d.ts +1 -0
- package/dist/lib/hosts/types.js +3 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/install-menubar.d.ts +9 -6
- package/dist/lib/menubar/install-menubar.js +20 -9
- package/dist/lib/menubar/snapshot.js +15 -2
- package/dist/lib/models.d.ts +42 -6
- package/dist/lib/models.js +55 -153
- package/dist/lib/perf/db.js +16 -3
- package/dist/lib/perf/types.d.ts +12 -1
- package/dist/lib/pricing/cost.d.ts +9 -0
- package/dist/lib/pricing/cost.js +24 -0
- package/dist/lib/pricing/index.d.ts +1 -1
- package/dist/lib/pricing/index.js +1 -1
- package/dist/lib/project-probe.d.ts +22 -3
- package/dist/lib/project-probe.js +105 -17
- package/dist/lib/project-status.d.ts +9 -0
- package/dist/lib/project-status.js +15 -0
- package/dist/lib/redact.js +8 -3
- package/dist/lib/refresh.js +22 -11
- package/dist/lib/remote-agents-json.d.ts +32 -0
- package/dist/lib/remote-agents-json.js +47 -16
- package/dist/lib/resource-profiles.js +1 -2
- package/dist/lib/rotate.d.ts +22 -0
- package/dist/lib/rotate.js +26 -0
- package/dist/lib/routine-notify-owner.d.ts +102 -0
- package/dist/lib/routine-notify-owner.js +232 -0
- package/dist/lib/routines.d.ts +10 -0
- package/dist/lib/runner.d.ts +9 -1
- package/dist/lib/runner.js +182 -17
- package/dist/lib/sandbox.d.ts +0 -2
- package/dist/lib/sandbox.js +2 -19
- 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 +19 -3
- package/dist/lib/secrets/agent.js +61 -22
- package/dist/lib/secrets/audit.d.ts +1 -1
- package/dist/lib/secrets/audit.js +2 -0
- package/dist/lib/secrets/bundles.d.ts +3 -3
- package/dist/lib/secrets/bundles.js +15 -5
- package/dist/lib/secrets/filestore.d.ts +2 -0
- package/dist/lib/secrets/filestore.js +4 -0
- package/dist/lib/secrets/lease.d.ts +25 -0
- package/dist/lib/secrets/lease.js +44 -0
- package/dist/lib/secrets/session-store.d.ts +7 -0
- package/dist/lib/secrets/session-store.js +21 -0
- package/dist/lib/self-update.d.ts +20 -5
- package/dist/lib/self-update.js +93 -16
- package/dist/lib/session/active.d.ts +49 -0
- package/dist/lib/session/active.js +175 -11
- package/dist/lib/session/bash-command.d.ts +16 -0
- package/dist/lib/session/bash-command.js +65 -0
- package/dist/lib/session/db.d.ts +23 -2
- package/dist/lib/session/db.js +86 -20
- package/dist/lib/session/discover.d.ts +21 -1
- package/dist/lib/session/discover.js +124 -32
- package/dist/lib/session/insights.d.ts +19 -0
- package/dist/lib/session/insights.js +78 -10
- package/dist/lib/session/recovery.d.ts +17 -1
- package/dist/lib/session/recovery.js +111 -4
- package/dist/lib/session/remote-bundle.js +1 -1
- package/dist/lib/session/remote-list.d.ts +10 -9
- package/dist/lib/session/remote-list.js +25 -23
- package/dist/lib/session/resume-owner.d.ts +55 -0
- package/dist/lib/session/resume-owner.js +69 -0
- package/dist/lib/session/team-filter.d.ts +65 -0
- package/dist/lib/session/team-filter.js +98 -3
- package/dist/lib/session/types.d.ts +33 -0
- package/dist/lib/smart-launch.d.ts +31 -5
- package/dist/lib/smart-launch.js +43 -7
- package/dist/lib/ssh-exec.d.ts +27 -0
- package/dist/lib/ssh-exec.js +34 -1
- package/dist/lib/ssh-tunnel.d.ts +3 -2
- package/dist/lib/ssh-tunnel.js +25 -16
- package/dist/lib/staleness/detectors/skills.d.ts +2 -0
- package/dist/lib/staleness/detectors/skills.js +17 -2
- package/dist/lib/staleness/index.d.ts +10 -1
- package/dist/lib/staleness/index.js +28 -3
- package/dist/lib/startup/command-registry.d.ts +1 -0
- package/dist/lib/startup/command-registry.js +2 -0
- package/dist/lib/teams/agents.d.ts +1 -0
- package/dist/lib/teams/agents.js +38 -11
- package/dist/lib/teams/placement-probe.d.ts +1 -1
- package/dist/lib/teams/placement-probe.js +24 -24
- package/dist/lib/teams/remoteWorktree.d.ts +11 -7
- package/dist/lib/teams/remoteWorktree.js +29 -27
- package/dist/lib/tmux/session.d.ts +8 -0
- package/dist/lib/tmux/session.js +22 -0
- package/dist/lib/types.d.ts +2 -0
- package/dist/lib/versions.d.ts +1 -0
- package/dist/lib/versions.js +40 -22
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,298 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.22.28
|
|
4
|
+
|
|
5
|
+
- **`agents run` / `agents teams` `--device`/`--host`: fail loud when a pinned harness version is not installed on the target (RUSH-2313).** A concrete pin like `codex@0.145.0` is checked against the remote `agents view --json` listing during `ensureHostReady` *before* the run is marked dispatched. Missing pins exit non-zero naming the box, the pin, what is installed there, and `agents ssh <box> -- agents add <agent>@<ver>` — so detached fleet drains no longer print `Dispatched` and then die only in the remote log. Aliases (`@latest` / …) still resolve on the remote; a bare agent name still only warns. Source: `apps/cli/src/lib/hosts/ready.ts`, `dispatch.ts`, `teams/agents.ts`.
|
|
6
|
+
|
|
7
|
+
- **fix: Windows-host e2e suites can resolve `win-mini` again under the hermetic device registry.** `tests/setup.ts` (RUSH-2042 / #1572) redirects `AGENTS_DEVICES_DIR` to an empty fork-private directory so unit fixtures never leak into the real fleet registry. The live `ssh-tunnel.e2e` / `browser/drivers/ssh.e2e` suites still need a real `DeviceProfile` for `AGENTS_TEST_WIN_HOST`, so after #1572 every `tests-windows-host-e2e.yml` run failed immediately with `Unknown device 'win-mini'` — even on a tailnet-joined runner that could ssh to the box. The setup file now seeds the private registry from the real fleet entry (or synthesizes one from `ssh -G <host>`) when `AGENTS_TEST_WIN_HOST` is set; the real registry is never written. Source: `apps/cli/tests/seed-e2e-win-host.ts`, `apps/cli/tests/setup.ts`.
|
|
8
|
+
|
|
9
|
+
- **OpenCode timeout-sample spool dir is Windows-safe (#1869).** The generated
|
|
10
|
+
`agents-cli-hooks.ts` plugin used `PERF_SPOOL.slice(0, PERF_SPOOL.lastIndexOf("/"))`
|
|
11
|
+
to mkdir the perf spool parent. On Windows `getPerfDir()` is backslash-separated,
|
|
12
|
+
so `lastIndexOf("/")` returned -1 and the slice dropped one character — the
|
|
13
|
+
sample write was fail-silent and never landed. The plugin now imports
|
|
14
|
+
`node:path` and uses `path.dirname(PERF_SPOOL)`. Source: `apps/cli/src/lib/hooks.ts`.
|
|
15
|
+
|
|
16
|
+
- **Bash-command classifier: single-source tool registry + broader unwrap (#1889).** The embedded Python activity-log hook (`ACTIVITY_LOG_HOOK_SCRIPT` in `activity.ts`) hand-duplicated `bash-command.ts`'s `TOOL_REGISTRY` and `VALUE_FLAGS` with a "keep them in sync" comment — the two had already drifted (Python was missing `rmdir`, and `agents`/`linear` two-level tools). Both tables are now generated from the TypeScript source (`pythonToolRegistryLiteral` / `pythonValueFlagsLiteral`) at module load. Separately, `unwrapCommand` (and the matching Python `_unwrap_command`) now peels `export VAR=…`, `set -euo pipefail`, `for`/`until` loop bodies, `if`/`then` branches, and `(command)` subshell prefixes that previously classified as `other`. Source: `apps/cli/src/lib/session/bash-command.ts`, `apps/cli/src/lib/activity.ts`.
|
|
17
|
+
|
|
18
|
+
- **Active-session polls skip re-parsing quiet transcripts (#2047).** `computeLiveSignals` (the per-session tail/parse behind `agents sessions --active` and the menu-bar badge tick) now memoizes by transcript path + mtime + `pidAlive` inside the process, so a 30s poll no longer re-tails every live session whose file has not changed. Positive Claude transcript-path resolutions are also memoized while the file still exists, avoiding a full walk of every Claude version-home `projects/` tree per pid per tick. Source: `apps/cli/src/lib/session/active.ts`.
|
|
19
|
+
|
|
20
|
+
- perf(sessions): throttle headless `ps`/`lsof` scan + memoize process table across an active-session poll (#2047)
|
|
21
|
+
|
|
22
|
+
- **`agents routines devices --set` / `--clear` no longer abort when a fleet peer is offline (#2118).** Pinning a routine used to fan out pause/resume to every registered device and throw on the first unreachable one — often *after* the pin had already succeeded on the target — so a single asleep laptop made fleet pins unusable and the error looked like the pin failed. Offline peers are now skipped with a warning; the command exits non-zero only when a *selected* target device cannot be reached. Source: `apps/cli/src/commands/routines.ts`.
|
|
23
|
+
|
|
24
|
+
- **`agents models claude` no longer lists a per-cloud bare-minor id as a plain catalog entry (#2233).** The id-scan fallback (`scanClaudeCatalogIds`, used when the structured alias/perCloud maps yield fewer than two models) used to surface short forms like `claude-opus-4-1` that only appear as a `foundry:` / cloud-scoped field next to a real firstParty id (`claude-opus-4-1-20250805`). `dropBareLegacyIds` now drops **any** id that is a dash-boundary prefix of a more-specific sibling also present in the scan — covering both the bare-major `.includes("claude-opus-4")` artifacts (#1892) and these bare-minor cloud-metadata values — while keeping genuine bare currents with no sibling (`claude-sonnet-5`) and not collapsing `claude-opus-4-1` into `claude-opus-4-10`. Source: `apps/cli/src/lib/models.ts`.
|
|
25
|
+
|
|
26
|
+
- **Menu-bar dropdown density toggle removed.** The `Density: Auto/Rich/Compact` footer item and the whole rich/compact rendering fork are gone; the dropdown now always renders the rich rows (session/work titles, expanded Routines and Recent sections). Removes the `menubarDensity` UserDefaults key and `MENUBAR_DENSITY` env override, and updates the menu-bar docs to match. Source: `apps/cli/menubar/Sources/MenubarHelper/StatusItemController.swift`, `apps/cli/docs/menubar.md`.
|
|
27
|
+
|
|
28
|
+
- **The macOS secrets broker can now hold an explicit key subset under its own lease id and expiry (RUSH-2255).** `agents secrets lease <bundle> --keys K1,K2 --for 8h` authenticates once, stores only those resolved values in broker memory and the restart session, and reports lease metadata without exposing values. Unknown, missing, and expired keys fail closed. Source: `apps/cli/src/{commands/secrets.ts,lib/secrets/{agent,lease,session-store}.ts}`.
|
|
29
|
+
|
|
30
|
+
- **Scoped leases can now be listed and revoked by id (RUSH-2256).** `agents secrets leases` shows bundle, keys, and remaining lifetime; `agents secrets revoke <lease-id>` wipes exactly that broker grant and its restart session. Source: `apps/cli/src/{commands/secrets.ts,lib/secrets/{agent,session-store}.ts}`.
|
|
31
|
+
|
|
32
|
+
- **Fleet devices accept an explicit SSH private-key path (RUSH-2265).** `agents devices set <name> --auth key --identity-file <path>` stores the path on that device and every shared SSH invocation passes it to OpenSSH with `-i`, so devices no longer depend on whichever key the ambient ssh agent happens to offer. Switching a device from password to key auth also removes stale password-bundle metadata from the registry.
|
|
33
|
+
|
|
34
|
+
- **Detached agent dispatch now runs on Windows OpenSSH hosts (RUSH-2267).** Headless `agents run … --host <windows>` launches through a hidden PowerShell process, preserves actor/session/env context, and uses durable Windows-native log, follow, reconcile, stop, and cleanup operations.
|
|
35
|
+
|
|
36
|
+
- **`agents repo pull` fast-forwards a clean behind-only checkout instead of failing with "Cannot rebase onto multiple branches" (RUSH-2282).** After fetch, a 1-behind tree integrates via `merge --ff-only` against the tracking ref; only genuinely diverged histories enter rebase. Avoids re-running `git pull --rebase` on a multi-entry `FETCH_HEAD` (common after bare fetch when the remote has several branches, or under concurrent fleet fetch). Source: `apps/cli/src/lib/git.ts` `pullRepo`.
|
|
37
|
+
|
|
38
|
+
- **`agents perf` splits intentional deny (exit 2) from crashes (exit 1) — hook health is readable again (RUSH-2294).** Deny-by-design guards (`ask-user-question-guard`, `plan-html-reminder`, `git-guard`, …) exit 2 on purpose; the warehouse previously counted any nonzero exit as `errorCount`, so a working guard read as a "92%-error" hook. Exit 0 = allow, exit 2 = `blockCount`/`blockRate`, exit 1 / other = `errorCount`/`errorRate`. The hooks table column is now `ERR/BLOCK/TO` (`err:…% block:…% to:…%`). JSON rows gain `blockCount`/`blockRate`. Source: `apps/cli/src/lib/perf/db.ts`, `apps/cli/src/lib/hooks/profile.ts`, `apps/cli/src/commands/perf.ts`.
|
|
39
|
+
|
|
40
|
+
- **Claude launches reuse an unchanged file-backed setup-token instead of decrypting it on every exec (RUSH-2317).** The process-lifetime cache is isolated by version home and invalidates from the encrypted credential file's identity, ctime, mtime, and size; token rotation is picked up on the next launch, missing per-account tokens are negatively cached, and plaintext tokens remain memory-only. Source: `apps/cli/src/lib/claude-account-token.ts`, `apps/cli/src/lib/secrets/filestore.ts`.
|
|
41
|
+
|
|
42
|
+
- **Repeated full session listings reuse stable transcript membership (RUSH-2318).** The process briefly caches settled transcript directories by mtime+size, rereads recently changed directories, and expires every entry within the filesystem timestamp-precision window, avoiding burst-time repeat reads without hiding filesystem-only creates or deletes. Source: `apps/cli/src/lib/session/db.ts`.
|
|
43
|
+
|
|
44
|
+
- **`agents sync --yes` drops ~1s/agent of dead work and reuses still-fresh fingerprints (RUSH-2320).** Measured on a real install: `getActuallySyncedResources` was ~1055 ms/agent on the unattended path that never reads it; `buildManifest` re-hashed every file (~716 ms) after a no-op force sync; the guard-hit path spent ~12 ms building inventories it then discarded. Unattended sync now skips the interactive inventory, the skills detector is stat-first on size before any content read, `buildManifest` carries still-fresh fingerprints from the previous manifest, and `syncResourcesToVersion` runs its no-change guard before pattern expansion (accepting a caller-supplied `available` inventory so multi-version fan-out does not re-scan). Source: `apps/cli/src/lib/refresh.ts`, `apps/cli/src/lib/versions.ts`, `apps/cli/src/lib/staleness/`.
|
|
45
|
+
|
|
46
|
+
- **fix: `agents run <agent>` no longer dead-ends when every account is logged out — it launches so you can sign in.** A harness with one installed, signed-out version had no reachable login path at all: `agents run cursor` exited with `no healthy cursor account under strategy 'balanced' — excluded: 2026.07.23 (signed_out)`, the `agents run cursor@` account picker marked the logged-out row `disabled` and offered only `No usable accounts — cancel`, and `agents use cursor` only set a default. The zero-healthy guard (RUSH-2132) treated a missing login like an exhausted account, but they are opposites — a throttled account must not be launched, while a signed-out one is fixed precisely BY launching, since the harness's own TUI is the login surface. On a human-facing terminal run (a real TTY and no `--json`), a single sign-in-recoverable account now launches directly (naming the version and the login command) and several open the account picker with auth-blocked rows selectable and labelled `launch to sign in`; `rate_limited` / `out_of_credits` still fail loud, and off a TTY — or under `--json` — both classes keep the exact watchdog-parsed error, now with the harness's login command alongside `--strategy pinned`. Source: `apps/cli/src/lib/rotate.ts` (`isSignInRecoverable`, `signInRecoverableCandidates`), `apps/cli/src/commands/run-account-picker.ts` (`pickSignInLaunchVersion`), `apps/cli/src/commands/exec.ts`. (RUSH-2334)
|
|
47
|
+
|
|
48
|
+
- **`sessions --active` no longer shows retained dead/queued rows, and every process row now carries its PID (RUSH-2336).** Bare `--active` (CLI table/JSON, the interactive browser, `focus`, and the menu bar) previously kept a row alive as long as its pid wasn't *known* dead — so a queued-but-not-started row, or a process of genuinely unverified liveness, could still show up. The canonical selector (`isRunningLiveSession`) now excludes `queued`/`closed`/`crashed` outright (still reachable via `--queued`/`--closed`/`--crashed`) and requires a real process row to positively verify its machine, a positive pid, and `pidAlive === true`; a cloud row stays active on its provider + task id alone. Every process-backed `--active --json` row now guarantees `machine`/`pid`/`pidAlive: true`, and the human CLI row and the menu bar's session detail both show the matching `machine:pid` (or `provider · taskId` for cloud) locator. Source: `apps/cli/src/commands/sessions.ts`, `apps/cli/src/lib/menubar/snapshot.ts`, `apps/cli/menubar/Sources/MenubarHelper/`.
|
|
49
|
+
|
|
50
|
+
- **`agents projects status` card scans faster: grouped warnings, a fleet health summary, and a truthful `dead` label (RUSH-2337).** On a busy fleet the card printed each host's git drift twice — once in the inline `fleet` table, then again as one 2-line block per host in the warnings footer (18 lines for 3 facts) — and read `dead 41 finished or lost (41 crashed)`, which contradicts itself when every dead session is a crash. Now: (1) the warnings footer **groups by root cause** — all behind hosts collapse to one warning listing each with its count (`4 hosts behind origin/main — mac-mini ↓172, yosemite-m2 ↓217, …`) under one shared remediation, dirty/missing the same, a lone host keeps its full sentence, grouped per probed path so two repos never merge (mirrors doctor's `emitGroup`); (2) a one-line **fleet health summary** (`6/13 clean · 4 behind · 4 dirty · 1 missing`) sits above the per-host table, which keeps its branch/drift detail; (3) the `dead` row names the status directly when singular (`dead 41 crashed`); (4) the fleet-wide rollup carries a `fleet snapshot · as of HH:MM` stamp; (5) `linear` shows a completion percent (`468/547 done (86%)`). Source: apps/cli/src/lib/project-probe.ts, apps/cli/src/lib/project-status.ts, apps/cli/src/commands/projects.ts, apps/cli/docs/11-projects.md.
|
|
51
|
+
|
|
52
|
+
## 1.22.27
|
|
53
|
+
|
|
54
|
+
- **`agents sessions --teams` groups sessions by team (RUSH-1997).** Instead of one flat list with a `[team/handle]` tag, `--teams` now prints a report grouped by team: each team names its spawner (the orchestrator session that created it) and spawn time, and every teammate row shows its mode + handle. Team-flagged spawns that carry no teammate `meta.json` — headless `agents run` sessions, or teammates whose team record aged out — sink into a trailing `(no team)` bucket, so a real `agents teams` teammate and a bare SDK spawn are never shown as the same thing. `--teams --flat`/`--tree` keep the plain inline table, and a search query keeps the interactive picker. `TeamOrigin` (also on `--teams --json`) now carries the teammate's `startedAt` spawn time and a `source` (`meta` = teammate, `entrypoint` = bare spawn). Source: `apps/cli/src/lib/session/team-filter.ts`, `apps/cli/src/commands/sessions.ts`.
|
|
55
|
+
|
|
56
|
+
- **`agents run --device auto` and `agents teams add --device auto` now choose from live fleet health instead of 14-day launch affinity (RUSH-2001).** The picker probes candidates in parallel, excludes unreachable, overloaded, and missing-agent machines, prefers signed-in candidates with the lowest normalized load, and keeps execution local when no remote is better. Remote readiness now uses `agents view --json`, preserving the installed/sign-in split instead of treating every remote sign-in state as unknown. Source: `apps/cli/src/lib/smart-launch.ts`, `apps/cli/src/lib/teams/placement-probe.ts`, `apps/cli/src/lib/hosts/ready.ts`, `apps/cli/src/commands/exec.ts`, `apps/cli/src/commands/teams.ts`.
|
|
57
|
+
|
|
58
|
+
- **`agents devices harnesses` / `agents devices accounts` — per-device harness + account readiness (RUSH-2003).** Two new fleet lenses: `harnesses` lists every installed `agent@version` across the fleet with its account, signed-in state, quota (highest usage-window utilization; `*` = cached snapshot), and a single `ready` verdict (signed in AND not rate-limited); `accounts` collapses that to one row per account, naming which harnesses share it. Both SSH-probe each online device (bounded like `fleet ping`, so one unreachable box can't stall the glance) and read the daemon-warmed usage cache — `--refresh` (`--live`) forces a live quota read. Scope with `--agents <csv>` / `--device <csv>`; `--json` emits per-host rows (harnesses) or account groups (accounts). Source: `apps/cli/src/lib/devices/harness-inventory.ts`, `apps/cli/src/commands/ssh.ts`.
|
|
59
|
+
|
|
60
|
+
- **A session that ran on another device now resumes ON that device, and a typo'd
|
|
61
|
+
command with `--host` says `unknown command` (RUSH-2022).** Two bugs found while
|
|
62
|
+
recovering ~15 sessions after a machine crash, both of which sent recovery down the
|
|
63
|
+
wrong path.
|
|
64
|
+
|
|
65
|
+
(1) **`agents resume <id>` restarted a remote session locally.** The harness keeps its
|
|
66
|
+
conversation state on the machine that produced the session, but nothing checked which
|
|
67
|
+
machine that was — so a peer-owned session started the agent here, against state this
|
|
68
|
+
box had never seen (`sessions-resume.ts` even swapped in `process.cwd()` when the
|
|
69
|
+
recorded directory did not exist locally). `agents resume` now re-runs itself on the
|
|
70
|
+
owning device over SSH; `--here` overrides. The bare `agents sessions` picker routes
|
|
71
|
+
the same way, and `agents sessions attach` hops as an **attach** (its detach record and
|
|
72
|
+
the headless process it stops both live on the owner). The multi-select
|
|
73
|
+
`agents sessions resume` inherits it: each tab it opens runs the canonical
|
|
74
|
+
`agents resume <id>`, which now routes itself, and its no-tab-backend path routes
|
|
75
|
+
explicitly. Root cause of
|
|
76
|
+
the population that made this common: a run dispatched with `agents run --device
|
|
77
|
+
<box>` was indexed with no origin machine at all, so the index claimed the dispatching
|
|
78
|
+
box; it now records `<box>`, which also means such a run finally shows up under
|
|
79
|
+
`agents sessions --host <box>`. Source: `apps/cli/src/lib/session/resume-owner.ts`,
|
|
80
|
+
`apps/cli/src/lib/hosts/session-index.ts`, `apps/cli/src/commands/resume.ts`.
|
|
81
|
+
|
|
82
|
+
The hop carries its "don't route again" pin as an exported env var, not a flag, so it
|
|
83
|
+
works against a peer still on an older CLI. Sessions indexed *before* this release keep
|
|
84
|
+
their old machine tag — re-dispatch or a fresh scan corrects them.
|
|
85
|
+
|
|
86
|
+
(2) **The `--host`/`--device` router answered for commands that do not exist.** It runs
|
|
87
|
+
before commander parses, so `agents session resume --host <box>` (one letter off
|
|
88
|
+
`sessions`, which *does* accept `--host`) reported `` `agents session` does not support
|
|
89
|
+
--host/--device `` — a true statement about a command nobody typed and the opposite of
|
|
90
|
+
the truth for the one they meant. Unknown names now fall through to `unknown command
|
|
91
|
+
'<name>'` with a did-you-mean, and the spellcheck can suggest the lazily-registered
|
|
92
|
+
groups (`sessions`/`teams`/`cloud`/…) it previously could not see. A real command with
|
|
93
|
+
no remote semantics still gets the flag-support error. Source:
|
|
94
|
+
`apps/cli/src/lib/hosts/passthrough.ts`, `apps/cli/src/lib/startup/command-registry.ts`.
|
|
95
|
+
|
|
96
|
+
- **`agents publish` is in the lazy command table.** `commands/packages.ts` registers it at
|
|
97
|
+
top level but the registry did not list it, so it only resolved through the
|
|
98
|
+
unknown-command fallback that loads the whole command tree. Found by the new test that
|
|
99
|
+
pins the command-name set against the real tree.
|
|
100
|
+
|
|
101
|
+
- **A mistyped command keeps its `--host`.** The distance-1 auto-correct now runs *before*
|
|
102
|
+
the router instead of after commander gave up, so `agents docto --host <box>` corrects to
|
|
103
|
+
`doctor` **and** runs on `<box>` — previously the corrected command re-parsed locally with
|
|
104
|
+
a `--host` it did not accept. Four routing-table entries naming commands that do not exist
|
|
105
|
+
(`cli`, `packages`, `versions`, `daemon`) were removed; a test now keeps both routing
|
|
106
|
+
tables to real command names.
|
|
107
|
+
|
|
108
|
+
- **Cross-machine `agents … --json` fan-out caps each peer's stdout at 16 MiB
|
|
109
|
+
instead of buffering it unbounded (RUSH-2065).** The shared fan-out
|
|
110
|
+
(`gatherRemoteAgentsJson`, behind `agents sessions --active`, `agents feed`, and
|
|
111
|
+
every other fleet-wide JSON sweep) streamed each peer's output into memory with
|
|
112
|
+
no ceiling, under one `Promise.all` — so a single peer returning a corrupt or
|
|
113
|
+
pathologically large payload could retain ~170 MB and OOM the whole sweep. Each
|
|
114
|
+
peer's capture now stops and SIGKILLs the connection once it would exceed the
|
|
115
|
+
ceiling, treating that box as unreachable (reported in `skipped`) so the rest of
|
|
116
|
+
the fleet still renders. The bound and the UTF-8-safe accumulator now live once
|
|
117
|
+
in `apps/cli/src/lib/ssh-exec.ts`, shared with the `agents sessions` browse
|
|
118
|
+
fan-out that already had the guard. Source: `apps/cli/src/lib/remote-agents-json.ts`,
|
|
119
|
+
`apps/cli/src/lib/ssh-exec.ts`, `apps/cli/src/lib/session/remote-list.ts`.
|
|
120
|
+
|
|
121
|
+
- **Auth-health probes once per account, not once per version home (RUSH-2111).**
|
|
122
|
+
The daemon's every-3-minute auth-health refresh fanned `probeLocalFleetAuth`
|
|
123
|
+
over *every* installed version home at once, so a box with several Claude homes
|
|
124
|
+
signed into one account fired that many concurrent requests at the same
|
|
125
|
+
provider OAuth endpoint — racing its rate limit into a `429` that then parked
|
|
126
|
+
the whole box's usage reads behind a `Retry-After` penalty (`usage-backoff.ts`
|
|
127
|
+
survives that penalty; this removes its cause). Installs are now grouped by
|
|
128
|
+
account and the live probe runs once per (agent, account), fanning the one
|
|
129
|
+
verdict out to each home's per-version cache row. Homes with no resolvable
|
|
130
|
+
account are still probed individually. Source: `apps/cli/src/lib/auth-health.ts`.
|
|
131
|
+
|
|
132
|
+
- **Fallback-chain agents now receive their own active rules preset before dispatch (RUSH-2129).** `runWithFallback` resolves each attempted entry's harness/version home and runs the same skip-fast preset synchronization as the primary `agents run` path, so a rate-limit handoff cannot launch against stale rules. Source: `apps/cli/src/lib/exec.ts`, `apps/cli/src/lib/rules/run-sync.ts`.
|
|
133
|
+
|
|
134
|
+
- **Gemini hard-deprecation: routines daemon can no longer execute a legacy Gemini routine (RUSH-2202).** RUSH-2060 gated `agents add`/`import`/`sync`/`run`/`routines add` against a hard-deprecated harness, but the routines daemon's own executor (`runner.ts`) had no equivalent gate — a Gemini routine written before RUSH-2060, or synced/edited on disk directly, would still fire and try to build a `gemini …` command against a backend Google retired. `executeJob`/`executeJobDetached` now reject a hard-deprecated agent up front, before any version/account resolution or sandbox prep, and record a `failed` run with the same deprecation message every other entry point already shows. Also removed the now-unreachable Gemini model-catalog extractor (`models.ts`), Factory's Gemini model-catalog fetch (`agentModels.ts`), and the dead Gemini sandbox-config writer (`sandbox.ts`/`gemini-settings.ts` — its generic JSON helpers stay, since Antigravity's permission writer reuses them), plus a stale `profiles.md` doc line still listing `gemini` as a live profile agent. Source: `apps/cli/src/lib/runner.ts`, `apps/cli/src/lib/models.ts`, `apps/cli/src/lib/sandbox.ts`, `apps/cli/src/lib/gemini-settings.ts`, `apps/factory/src/core/agentModels.ts`.
|
|
135
|
+
|
|
136
|
+
- **Routine transcripts now archive as `origin='routine'` sessions (RUSH-2271).** A
|
|
137
|
+
Claude (and Codex) routine writes its transcript to the per-version `CLAUDE_CONFIG_DIR`
|
|
138
|
+
/ `CODEX_HOME` home, not the sandbox overlay the archiver scanned — so routine runs
|
|
139
|
+
were indexed as ordinary `origin='cli'` sessions and never linked to their routine or
|
|
140
|
+
run. `archiveRoutineTranscripts` now reads the same per-version home `buildExecEnv`
|
|
141
|
+
writes to (re-pointed to each failover attempt's account as the chain advances), scoped
|
|
142
|
+
by a pre-spawn baseline so it copies only that run's transcript out of the shared home,
|
|
143
|
+
and `agents sessions --routine` shows them again. Kimi relocates too but its
|
|
144
|
+
routine-archive discovery reader is a separate follow-up. Source:
|
|
145
|
+
`apps/cli/src/lib/runner.ts`, `apps/cli/src/lib/routines.ts`.
|
|
146
|
+
|
|
147
|
+
- **Release lease detects a holder killed from outside (RUSH-2274).** An externally
|
|
148
|
+
killed release (SIGKILL, a severed ssh, a rebooted box) left its lease on `origin`
|
|
149
|
+
and `scripts/release-lease.sh status` read `held` for up to the 30-minute TTL with
|
|
150
|
+
nothing actually releasing. The lease now records the holding `host`, `pid`, and
|
|
151
|
+
that pid's start time, and `status` reports `holder-alive=yes|no|unknown`. A holder
|
|
152
|
+
that is provably gone is reclaimed by the next `claim` immediately instead of
|
|
153
|
+
waiting out the TTL, and a new `release-lease.sh clear` drops such a lease without
|
|
154
|
+
starting a release. A live holder is never taken at any age, an unprobeable one
|
|
155
|
+
(another box, or a lease from an older release) still falls back to the TTL, and a
|
|
156
|
+
reused pid or an unreaped zombie counts as dead rather than as a live release.
|
|
157
|
+
Source: `apps/cli/scripts/release-lease.sh`, `apps/cli/scripts/release.sh`.
|
|
158
|
+
|
|
159
|
+
- **`agents output` and the session index no longer under-count Windows hosts
|
|
160
|
+
(RUSH-2286).** A Windows box could report zero token burn / zero sessions even
|
|
161
|
+
when it was actively used, because two per-harness scanners in
|
|
162
|
+
`session/discover.ts` failed on Windows: the OpenClaw scan gated on `which
|
|
163
|
+
openclaw`, which is POSIX-only (`which` throws ENOENT on Windows, so the whole
|
|
164
|
+
OpenClaw scan silently returned before indexing anything), and the Grok scanner
|
|
165
|
+
recovered a session's version from `summary.grok_home` with a `/`-only regex
|
|
166
|
+
that never matched a backslash-separated Windows path. The OpenClaw presence
|
|
167
|
+
check now uses the cross-platform `hasCommand`, its `openclaw` invocations route
|
|
168
|
+
through `execFileShellSpec` so a Windows `.cmd`/`.ps1` shim actually launches,
|
|
169
|
+
and the Grok version regex normalizes separators first. Separately, JSON relayed
|
|
170
|
+
from a Windows peer over SSH (`agents output --host <win> --json`,
|
|
171
|
+
`agents sessions … --json`) is now stripped of any PowerShell `#< CLIXML`
|
|
172
|
+
banner before parsing (`stripClixml` in `hosts/remote-cmd.ts`), so a fleet-wide
|
|
173
|
+
rollup that folds in a Windows box no longer drops it on a `JSON.parse` failure.
|
|
174
|
+
The banner strip is applied at every remote-`--json` boundary a Windows peer's
|
|
175
|
+
output flows through: the `remote-agents-json` fan-out, the session
|
|
176
|
+
`remote-list` list/payload/tool-search parsers, the `--host` fleet passthrough
|
|
177
|
+
(`agents view --host all`), and `agents output`'s per-device fetch.
|
|
178
|
+
Source: `apps/cli/src/lib/session/discover.ts`,
|
|
179
|
+
`apps/cli/src/lib/hosts/remote-cmd.ts`, `apps/cli/src/lib/hosts/passthrough.ts`,
|
|
180
|
+
`apps/cli/src/lib/remote-agents-json.ts`,
|
|
181
|
+
`apps/cli/src/lib/session/remote-list.ts`, `apps/cli/src/commands/output.ts`.
|
|
182
|
+
|
|
183
|
+
- **`agents output` now reports the burn split and a `--pricing no-cache` scenario (RUSH-2287).**
|
|
184
|
+
The productivity rollup collapsed token burn into a single counter. It now
|
|
185
|
+
breaks the burn into uncached **input** / **cache-read** / **cache-write** tokens
|
|
186
|
+
wherever the harness records a per-message cache split (Claude, Codex, Gemini,
|
|
187
|
+
Droid) — a `burn split:` line in the text report and the three counts on `burn`
|
|
188
|
+
and every `breakdown` row in `--json`. New `--pricing no-cache` reprices cached
|
|
189
|
+
tokens at the model's full input rate to model "what would this cost with caching
|
|
190
|
+
off?"; the text report leads with that figure (breakdown column `burn(nc)`) while
|
|
191
|
+
`--json` always carries **both** `costUsd` and `costUsdNoCache` so a dashboard can
|
|
192
|
+
choose. The saving is surfaced in actual mode too (`caching: actual $X vs no-cache
|
|
193
|
+
$Y`). Backed by four new session columns (`input_tokens`, `cache_read_tokens`,
|
|
194
|
+
`cache_write_tokens`, `cost_usd_nocache`, schema v37) populated at scan time;
|
|
195
|
+
pre-upgrade sessions show total-only until re-scanned. Source:
|
|
196
|
+
`apps/cli/src/commands/output.ts`, `apps/cli/src/lib/session/{db,discover}.ts`,
|
|
197
|
+
`apps/cli/src/lib/pricing/cost.ts`.
|
|
198
|
+
|
|
199
|
+
- **Routine failures now reach the owner's phone, not just the local desktop (RUSH-2288).**
|
|
200
|
+
A `failed`/`timeout` routine finish, or a pre-spawn failure such as `auth_failed`, now
|
|
201
|
+
also pings the owner over the same channel stack `agents notify` uses (the
|
|
202
|
+
`owner.channels` in `humans.yaml`, or the legacy `notify.owner`), delivered in-process by
|
|
203
|
+
the daemon — no shelling out to `ssh mac-mini agents notify`. This closes the gap where a
|
|
204
|
+
failed scheduled routine on a headless fleet box was invisible, and specifically covers
|
|
205
|
+
the `auth_failed` case the per-routine `agents notify` prompt can never send (its agent
|
|
206
|
+
never spawned). If the primary owner channel cannot deliver from the box, the daemon walks
|
|
207
|
+
the remaining configured channels as fallbacks (Telegram and intrusive/voice channels are
|
|
208
|
+
excluded). Green routines of any kind stay silent, the existing desktop thresholds are
|
|
209
|
+
unchanged, and delivery is deduped per job+runId. Source:
|
|
210
|
+
`apps/cli/src/lib/routine-notify-owner.ts`, `apps/cli/src/lib/daemon.ts`.
|
|
211
|
+
|
|
212
|
+
- Add `agents bench list`, `agents bench run`, and `agents bench results`: benchmark cells fan out through the existing `agents run` path with isolated fixture copies, bounded concurrency, custom harness names, wall-time/exit/token capture, and durable JSON results under `~/.agents/.history/bench/` (RUSH-2302, RUSH-2303).
|
|
213
|
+
|
|
214
|
+
- **New user quickstart: install, harnesses, teams, fleet.** `apps/cli/docs/QUICKSTART.md` walks a fresh install through `agents setup`, adding and logging into harnesses, a minimal `agents teams` smoke test, and setting up a fleet (`agents devices sync`, `agents devices set-interactive`, `agents apply`) — linked from `docs/README.md` and the root README's Quickstart. Docs only — no runtime change. Source: `apps/cli/docs/QUICKSTART.md`, `apps/cli/docs/README.md`, `README.md`.
|
|
215
|
+
|
|
216
|
+
- **`agents insights` detects agent silent stalls (model goes idle until you resume).**
|
|
217
|
+
When the assistant is last to speak and the next user message is ≥5 minutes later,
|
|
218
|
+
facets count duration-bucketed `silent stall: 5-15m` / `15-60m` / `1h+` friction
|
|
219
|
+
signals; resume nudges (`continue`, `keep going`, …) after that silence also count
|
|
220
|
+
as `resume after silent stall`. Report, actions, `--narrative`, and
|
|
221
|
+
`/sessions-insights` instruct models to call these out (not reframe as "user was
|
|
222
|
+
slow"). Extractor version bumped to 5 so cached facets recompute. Source:
|
|
223
|
+
`apps/cli/src/lib/session/insights.ts`, `commands/insights.ts`,
|
|
224
|
+
`docs/06-observability.md`.
|
|
225
|
+
|
|
226
|
+
- **`agents insights` splits silent stalls by harness and model.** The By-agent/account
|
|
227
|
+
table now shows per-group stall and resume-nudge counts (so laziness is visible without
|
|
228
|
+
`--json`). Stalls are also attributed to the model that last spoke
|
|
229
|
+
(`silentStallsByModel`, "Silent stalls by model" section). Extractor version 6.
|
|
230
|
+
Source: `apps/cli/src/lib/session/insights.ts`, `commands/insights.ts`.
|
|
231
|
+
|
|
232
|
+
- **Redact Claude OAuth setup-tokens (`sk-ant-oat01-…`) from logs and exports, and reject a malformed one before it reaches the auth header (#1767).** The log redactor masked API keys (`sk-ant-api03-…`) but not OAuth setup-tokens — the generic `sk-` rule can't reach an `oat01` token because the hyphen after `ant` breaks its run — so a captured setup-token could leak verbatim into a run log or session export. `resolveClaudeSetupToken` also now validates the stored value: a corrupt `auth` bundle entry (e.g. a captured `claude setup-token` TTY banner+ANSI blob, the exact #1767 shape) is refused instead of being injected as `CLAUDE_CODE_OAUTH_TOKEN` → an invalid `Authorization: Bearer` header that crashes the run; the caller falls back to the normal login. Source: `apps/cli/src/lib/redact.ts`, `apps/cli/src/lib/claude-account-token.ts`.
|
|
233
|
+
|
|
234
|
+
- **Stop the interactive host auto-reconnect spinning forever on a flapping link
|
|
235
|
+
(#1884).** A reattach only refills the retry budget now if it reached the host
|
|
236
|
+
**and** held the remote pane for at least 10 seconds. Before, the budget refilled
|
|
237
|
+
on the preflight probe alone, so a link that reconnected and dropped the user
|
|
238
|
+
straight back out — or an attach that died at TTY negotiation every time — printed
|
|
239
|
+
`Reconnecting … (attempt 1/6)` on every cycle forever and `MAX_ATTEMPTS` bounded
|
|
240
|
+
nothing. A link that keeps dropping now spends the budget and gives up with a
|
|
241
|
+
message that says so ("kept dropping again within 10 seconds of getting back in"),
|
|
242
|
+
distinct from the unreachable-host "couldn't reconnect". A session that blinks all
|
|
243
|
+
day and reconnects into a working pane each time is unaffected. Source:
|
|
244
|
+
`apps/cli/src/lib/hosts/reconnect.ts`, `docs/hosts.md`.
|
|
245
|
+
|
|
246
|
+
- **`agents models claude` no longer lists bare legacy ids that 404 (#1892).** The
|
|
247
|
+
native-binary id-scan fallback (`scanClaudeCatalogIds`, used when the curated maps
|
|
248
|
+
come up empty) is now word-boundary anchored and matches the id body atomically, so
|
|
249
|
+
it can't scrape a bare-major prefix (`claude-sonnet-4`) out of the binary's own dotted
|
|
250
|
+
`claude-sonnet-4.6` "Typo in model ID" troubleshooting string, out of a suffix-glued
|
|
251
|
+
token (`claude-opus-4-1x`), or out of a token glued to a preceding identifier char. The
|
|
252
|
+
existing `dropBareLegacyIds` sibling-drop still removes the standalone
|
|
253
|
+
`.includes("claude-opus-4")` prefix-check artifacts; genuine bare currents
|
|
254
|
+
(`claude-sonnet-5`) are kept. Catalog output is unchanged across all shipped Claude
|
|
255
|
+
binaries. Source: `apps/cli/src/lib/models.ts`.
|
|
256
|
+
|
|
257
|
+
- **Make ended-session focus open the correct recovery target (#2108).** `agents sessions focus <id>` now reaps metadata-less dead tmux panes, proves the indexed transcript belongs to the exact active version home before native resume, launches Claude from the transcript's original project directory, and passes replacement-version `/continue` as an interactive positional prompt. Source: `apps/cli/src/lib/session/recovery.ts`, `apps/cli/src/lib/tmux/session.ts`, `apps/cli/src/lib/exec.ts`.
|
|
258
|
+
|
|
259
|
+
- **The multi-install warning now inventories copies outside `PATH` and flags
|
|
260
|
+
legacy installs that can corrupt the shared macOS helper bundle (#2147).**
|
|
261
|
+
Discovery covers NVM, fnm, Volta, Bun, common npm global prefixes, and npm's
|
|
262
|
+
`_npx` cache in addition to resolving every `agents` entry on `PATH`. Dev
|
|
263
|
+
installs are no longer hidden: a copy without the atomic
|
|
264
|
+
`app-bundle-install` module is labelled `unsafe legacy helper installer —
|
|
265
|
+
remove this copy`, because invoking it can still replace a live `.app` with a
|
|
266
|
+
partial bundle. Source: `apps/cli/src/lib/self-update.ts`,
|
|
267
|
+
`apps/cli/src/index.ts`.
|
|
268
|
+
|
|
269
|
+
- **Newest signed agents-cli install owns the menu-bar helper (#2210).** On multi-install Macs (e.g. Homebrew + nvm), a newer release now takes over the helper immediately and an older install can no longer reclaim or downgrade it. Equal-version foreign installs keep the existing owner; missing-helper, Developer-ID repair, and unversioned legacy cooldown behavior are unchanged. Source: `apps/cli/src/lib/menubar/install-menubar.ts`.
|
|
270
|
+
|
|
271
|
+
- **Layered resource listing is ~40% faster.** `getActiveResourceProfile()` read
|
|
272
|
+
`agents.yaml` twice per call — once up front, then again inside
|
|
273
|
+
`getActiveResourceProfileName()` — and `listResources()` calls it once per
|
|
274
|
+
resolved resource, so a listing paid two memoized `readMeta()` round-trips
|
|
275
|
+
(`ensureAgentsDir()` plus four `stat`s each) for every entry. Reading it only
|
|
276
|
+
after the profile name is known drops one of them. Measured on `yosemite-s1`
|
|
277
|
+
against the real `~/.agents`: one pass over all eight resource kinds (135
|
|
278
|
+
entries) went 10.52 ms → 6.23 ms, and `agents doctor --json` spends ~243 ms in
|
|
279
|
+
this path across 95 listings. No behavior change: the read count is never
|
|
280
|
+
higher on any path and is unchanged whenever a profile name resolves — the one
|
|
281
|
+
saved read is the up-front one that the `if (!name) return null;` guard now
|
|
282
|
+
skips. The `ensureAgentsDir()` side effect is unchanged because
|
|
283
|
+
`getActiveResourceProfileName()` always reaches `readMeta()`, via
|
|
284
|
+
`brand.ts` `listBrands()` when a brand is set and via
|
|
285
|
+
`resource-profiles.ts` otherwise. Source:
|
|
286
|
+
`apps/cli/src/lib/resource-profiles.ts`.
|
|
287
|
+
|
|
288
|
+
- **Routine session discovery now supports an interactive picker and fuzzy names (RUSH-1998).** `agents sessions --routine` opens a routine picker on a TTY with each routine's last run, run count, and latest-run session count; the selected sessions are grouped by run ID and timestamp. `--routine <name>` accepts exact, substring, or unambiguous typo matches, and `--routines` is an alias for the same session filter.
|
|
289
|
+
|
|
290
|
+
- **Secret leases now have one scoped, time-boxed domain model (RUSH-2254).** A lease names one bundle, an explicit validated key subset, an absolute expiry, harness scope, and sleep-persistence posture. Durations use the broker's 1-minute to 30-day safety bounds, duplicate keys normalize once, unknown keys fail closed, and expired leases cannot project values. Source: `apps/cli/src/lib/secrets/lease.ts`.
|
|
291
|
+
|
|
292
|
+
- **Fleet devices accept an explicit SSH private-key path (RUSH-2265).** `agents devices set <name> --auth key --identity-file <path>` stores the path on that device and every shared SSH invocation passes it to OpenSSH with `-i`, so devices no longer depend on whichever key the ambient ssh agent happens to offer. Switching a device from password to key auth also removes stale password-bundle metadata from the registry.
|
|
293
|
+
|
|
294
|
+
- **`agents doctor` diagnoses Windows OpenSSH public-key enrollment (RUSH-2266).** On Windows it reads the effective `AuthorizedKeysFile`, selects the ProgramData administrator file or per-user profile file, verifies a public-key record is present, and checks that the administrator file grants `FullControl` to only `SYSTEM` and `Administrators`. The audit is read-only and never reads or prints private keys or passwords; fleet doctor forwards a locally authored summary and directs operators to run doctor on that box for details.
|
|
295
|
+
|
|
3
296
|
## 1.22.26
|
|
4
297
|
|
|
5
298
|
- Make bare `agents setup` a re-runnable onboarding hub with live capability status and direct access to browser, computer, secrets, fleet, share, watchdog, and preference wizards.
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<a href="https://github.com/phnx-labs/agents-cli"><img src="https://img.shields.io/badge/github-phnx--labs%2Fagents--cli-blue?style=flat-square" alt="github" /></a>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
|
-
**
|
|
14
|
+
**A framework for running a distributed agent factory.** Dispatch Claude, Codex, Antigravity, Grok, and more across your own machines, in parallel, on your existing subscriptions. Measure every run with `agents perf` / `agents insights`, fold what you learn back into `AGENTS.md` and skills, then put the loop on a schedule with routines and monitors. Spawn parallel teams in isolated terminals or dispatch to the cloud for a PR. Watch live state across the fleet, nudge stalled runs, and message agents mid-flight. Store secrets behind Touch ID, drive real browsers and Electron apps, and steer the whole fleet from a menu bar — all from one CLI.
|
|
15
15
|
|
|
16
16
|
<p align="center">
|
|
17
17
|
<a href="https://github.com/anthropics/claude-code" title="Claude Code"><img src="assets/harnesses/anthropic.svg" height="32" alt="Claude Code" /></a>
|
|
@@ -52,26 +52,33 @@ agents run claude "explain this repo" # run any agent on your existing subscrip
|
|
|
52
52
|
|
|
53
53
|
`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.
|
|
54
54
|
|
|
55
|
+
Full path -- installing harnesses, logging in, smoke-testing `agents teams`, and setting up your own fleet: [`apps/cli/docs/QUICKSTART.md`](apps/cli/docs/QUICKSTART.md).
|
|
56
|
+
|
|
55
57
|
Already installed? `agents upgrade` updates agents-cli itself to the latest version (`agents upgrade 1.2.3` for a specific version or dist-tag, `-y` to skip the confirm prompt). The command is `upgrade` on every platform -- there is no `agents update` (on macOS, `agents helper update` is a different command that reinstalls the keychain helper, not agents-cli).
|
|
56
58
|
|
|
57
59
|
Source: [github.com/phnx-labs/agents-cli](https://github.com/phnx-labs/agents-cli)
|
|
58
60
|
|
|
59
61
|
Also available as `ag` -- all commands work with both `agents` and `ag`.
|
|
60
62
|
|
|
61
|
-
- [
|
|
63
|
+
- [Factory loop](#factory-loop)
|
|
62
64
|
- [One config, every agent](#one-config-every-agent)
|
|
63
65
|
- [Run any agent](#run-any-agent)
|
|
64
66
|
- [Sessions across agents](#sessions-across-agents)
|
|
65
67
|
- [Control the fleet](#control-the-fleet)
|
|
66
68
|
- [Sync the fleet](#sync-the-fleet)
|
|
67
|
-
- [
|
|
69
|
+
- [Pin versions per project](#pin-versions-per-project)
|
|
70
|
+
- [Run open models through Claude Code](#run-open-models-through-claude-code-experimental)
|
|
71
|
+
- [Run on your own machines](#run-on-your-own-machines)
|
|
68
72
|
- [Teams](#teams)
|
|
69
73
|
- [Cloud](#cloud)
|
|
70
74
|
- [Workflows](#workflows)
|
|
75
|
+
- [Plugins](#plugins)
|
|
76
|
+
- [Make it yours](#make-it-yours)
|
|
71
77
|
- [Browser](#browser)
|
|
72
78
|
- [Secrets](#secrets)
|
|
73
79
|
- [Routines](#routines)
|
|
74
80
|
- [Monitors](#monitors)
|
|
81
|
+
- [Share](#share)
|
|
75
82
|
- [PTY](#pty)
|
|
76
83
|
- [Portable setup](#portable-setup)
|
|
77
84
|
- [Menu bar](#menu-bar)
|
|
@@ -82,34 +89,35 @@ Also available as `ag` -- all commands work with both `agents` and `ag`.
|
|
|
82
89
|
|
|
83
90
|
---
|
|
84
91
|
|
|
85
|
-
##
|
|
92
|
+
## Factory loop
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
# This project needs claude@2.0.65 -- newer versions changed tool calling.
|
|
89
|
-
agents use claude@2.0.65 -p
|
|
90
|
-
|
|
91
|
-
# The monorepo uses codex@0.116.0 across the team.
|
|
92
|
-
agents use codex@0.116.0 -p
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
This creates an `agents.yaml` at the project root:
|
|
96
|
-
|
|
97
|
-
```yaml
|
|
98
|
-
# agents.yaml (commit this to your repo)
|
|
99
|
-
agents:
|
|
100
|
-
claude: "2.0.65"
|
|
101
|
-
codex: "0.116.0"
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
Think `requirements.txt` for CLI coding agents, on steroids. A shim reads `agents.yaml` from the project root and routes `claude` / `codex` / `antigravity` / `grok` (and others) to the right version automatically. Each version gets its own isolated home -- switching backs up config and re-syncs resources.
|
|
94
|
+
The same loop whether it's one agent on your laptop or a fleet across a dozen machines: dispatch work, measure what happened, fold the lesson back into the harness, then put it on a schedule.
|
|
105
95
|
|
|
106
96
|
```bash
|
|
107
|
-
|
|
108
|
-
agents
|
|
109
|
-
agents add
|
|
110
|
-
agents
|
|
97
|
+
# Dispatch a team across the fleet -- each teammate in its own worktree
|
|
98
|
+
agents teams create checkout --devices yosemite-s0,yosemite-s1
|
|
99
|
+
agents teams add checkout claude "Owns: app/payments/*" --name payments
|
|
100
|
+
agents teams add checkout codex "Write tests for the new code" --name qa --after payments
|
|
101
|
+
agents teams start checkout --watch
|
|
102
|
+
|
|
103
|
+
# Measure what happened -- latency, friction, dead-weight skills
|
|
104
|
+
agents perf commands --days 7 # slowest CLI entrypoints
|
|
105
|
+
agents insights --since 30d # friction, harness comparison, ranked actions
|
|
106
|
+
|
|
107
|
+
# Fold the lesson back into the harness -- every agent picks it up next run
|
|
108
|
+
agents rules add ~/lessons/payments-review.md --agents claude
|
|
109
|
+
agents skills add ~/skills/payments-review --agents claude
|
|
110
|
+
|
|
111
|
+
# Put it on a schedule so it runs itself
|
|
112
|
+
agents routines add nightly-payments-audit \
|
|
113
|
+
--schedule "0 2 * * *" --agent claude --prompt "Audit payments/* for regressions"
|
|
114
|
+
|
|
115
|
+
# Steer the fleet this loop runs on from the menu bar
|
|
116
|
+
agents menubar setup
|
|
111
117
|
```
|
|
112
118
|
|
|
119
|
+
`agents perf` reads a disposable warehouse at `~/.agents/.cache/perf/perf.db` -- hook, command, and run timing rollups, deletable any time. `agents insights` (alias `agents sessions insights`) is deterministic and offline: it caches per-session facets, compares harnesses, and ranks actions by evidence count -- no model call unless you pass `--narrative`. Routines put any of this on a cron ([Routines](#routines)); monitors fire it on a change instead of a clock ([Monitors](#monitors)); the menu bar is the always-on control surface for the fleet these commands drive ([Menu bar](#menu-bar)).
|
|
120
|
+
|
|
113
121
|
---
|
|
114
122
|
|
|
115
123
|
## One config, every agent
|
|
@@ -370,7 +378,7 @@ agents resume 019fd0c8-b3e9-77a2-a1a4-444698c4d897 # original harness/version/d
|
|
|
370
378
|
agents run auto --resume 019fd0c8-b3e9-77a2-a1a4-444698c4d897 # adapt if its account is unavailable
|
|
371
379
|
```
|
|
372
380
|
|
|
373
|
-
`agents sessions resume` reopens several sessions in whatever terminal you're in -- auto-detected across iTerm, Ghostty, tmux, and the VSCodium agent-terminal, or forced with `--iterm` / `--ghostty` / `--tmux` / `--vscodium`. `agents resume <id>` resumes one session without requiring you to name its harness: exact IDs take a local SQLite fast path, then resolve fleet-wide and recover on the source device. If the origin version is installed, signed in, and
|
|
381
|
+
`agents sessions resume` reopens several sessions in whatever terminal you're in -- auto-detected across iTerm, Ghostty, tmux, and the VSCodium agent-terminal, or forced with `--iterm` / `--ghostty` / `--tmux` / `--vscodium`. `agents resume <id>` resumes one session without requiring you to name its harness: exact IDs take a local SQLite fast path, then resolve fleet-wide and recover on the source device. If the origin version is installed, signed in, healthy, and still owns the indexed transcript, its isolated home performs native resume. Claude launches that native resume from the original project directory recorded before the first turn, so its `projects/<cwd-key>` lookup reaches the conversation even when the session later changed directories. Otherwise a healthy version of the **same harness** starts with `/continue <id>`, which reads the indexed transcript even when the old version home is retained under version trash or the same version number was reinstalled into a new home. It never native-resumes from a different isolated home. Back them with **tmux** and the runs turn durable: detach, close your editor, reboot the GUI -- the session is still alive to `agents tmux attach`. The whole `agents tmux` subsystem (persistent multiplexer sessions that survive editor restarts and can be shared with other tools) sits underneath.
|
|
374
382
|
|
|
375
383
|
### Send an agent to the background — and bring it back
|
|
376
384
|
|
|
@@ -462,6 +470,36 @@ See [docs/fleet.md](apps/cli/docs/fleet.md) for the manifest schema and reconcil
|
|
|
462
470
|
|
|
463
471
|
---
|
|
464
472
|
|
|
473
|
+
## Pin versions per project
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
# This project needs claude@2.0.65 -- newer versions changed tool calling.
|
|
477
|
+
agents use claude@2.0.65 -p
|
|
478
|
+
|
|
479
|
+
# The monorepo uses codex@0.116.0 across the team.
|
|
480
|
+
agents use codex@0.116.0 -p
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
This creates an `agents.yaml` at the project root:
|
|
484
|
+
|
|
485
|
+
```yaml
|
|
486
|
+
# agents.yaml (commit this to your repo)
|
|
487
|
+
agents:
|
|
488
|
+
claude: "2.0.65"
|
|
489
|
+
codex: "0.116.0"
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
Think `requirements.txt` for CLI coding agents, on steroids. A shim reads `agents.yaml` from the project root and routes `claude` / `codex` / `antigravity` / `grok` (and others) to the right version automatically. Each version gets its own isolated home -- switching backs up config and re-syncs resources.
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
agents add claude@2.0.65 # Install a specific version
|
|
496
|
+
agents add codex@latest # Install latest
|
|
497
|
+
agents add codex@oldest # Install the oldest published version
|
|
498
|
+
agents view # See everything installed
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
465
503
|
## Run open models through Claude Code (experimental)
|
|
466
504
|
|
|
467
505
|
> **Note:** Profiles are experimental, but available by default — no enable step needed.
|
|
@@ -546,6 +584,9 @@ agents fleet status # online/offline rollup + NEEDS ATTENTIO
|
|
|
546
584
|
agents fleet status --verbose # full per-device auth/CLI/sync/version grid
|
|
547
585
|
agents fleet status --live # force a live resource probe (alias of --refresh)
|
|
548
586
|
agents fleet status --json --strict # scriptable fleet health gate
|
|
587
|
+
agents devices harnesses # per device: agent@version · account · signed · quota · ready
|
|
588
|
+
agents devices accounts # same, one row per account (which harnesses share it)
|
|
589
|
+
agents devices harnesses --agents claude,codex --json # scoped, machine-readable
|
|
549
590
|
agents doctor --check --devices # CI drift gate across every registered device
|
|
550
591
|
|
|
551
592
|
# Your Tailscale fleet, auto-discovered
|
|
@@ -594,6 +635,18 @@ endpoint — e.g. codex/grok — benign), `◐degraded` (soft/self-healing: expi
|
|
|
594
635
|
rate-limited), and `○revoked` (server rejected — re-login now). Only `○` means a real
|
|
595
636
|
re-login is needed. Run `agents fleet ping` to force a live re-verification across the fleet.
|
|
596
637
|
|
|
638
|
+
`agents devices harnesses` answers "what can each box actually run right now?" — one row
|
|
639
|
+
per installed `agent@version` across the fleet with its **account**, **signed-in**,
|
|
640
|
+
**quota** (highest usage-window utilization; `*` = from the cached snapshot), and a single
|
|
641
|
+
**ready** verdict (signed in AND not rate-limited). It SSH-probes each online device
|
|
642
|
+
(bounded, so one unreachable box can't stall the glance) and reuses the daemon-warmed usage
|
|
643
|
+
cache, so it never blocks on a per-account network fetch — pass `--refresh` (`--live`) for a
|
|
644
|
+
live quota read. `agents devices accounts` is the same data through the **identity lens**:
|
|
645
|
+
one row per account, collapsing the installs that share it (e.g. five claude versions on one
|
|
646
|
+
email) and naming which harnesses use it — the fast way to see which accounts are logged in
|
|
647
|
+
and healthy across every machine. Scope either with `--agents <csv>` / `--device <csv>`, and
|
|
648
|
+
add `--json` for the machine-readable per-host rows.
|
|
649
|
+
|
|
597
650
|
**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 and feed one host pool: devices appear in `agents hosts list` and capability routing without a second enrollment. On `--host` runs every `agents run` option is either forwarded (`--effort --env --timeout --loop …`), rejected loud (`--secrets` never crosses SSH implicitly), or consumed locally — nothing silently drops. See [docs/00-concepts.md](apps/cli/docs/00-concepts.md#devices--hosts).
|
|
598
651
|
|
|
599
652
|
Every `--host` command rides one multiplexed SSH engine, tuned for driving a fleet from a small laptop: the first call to a machine opens a control socket and every later call reuses it (no repeat TCP+auth handshake), connections carry keepalive so a dropped link dies in ~45 s instead of zombying, and following a remote run polls in a single round-trip per cycle. Measured against a Tailscale-relayed host: repeated calls **~6–7× faster**, dispatch readiness **~2×**, and the follow loop **~21× faster with 50% fewer local ssh spawns**. Design: [docs/09-ssh-transport.md](apps/cli/docs/09-ssh-transport.md) · reproduce: `node scripts/bench-ssh.mjs <host>`.
|
package/dist/bin/agents
CHANGED
|
Binary file
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { detectSignedInRuntimes } from "../lib/crabbox/runtimes.js";
|
|
5
|
+
import { listRuns, loadRun, loadTask, runCells, saveRun, } from "../lib/bench/index.js";
|
|
6
|
+
import { setHelpSections } from "../lib/help.js";
|
|
7
|
+
const TASKS_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../bench/tasks");
|
|
8
|
+
function csv(value) {
|
|
9
|
+
return (value
|
|
10
|
+
?.split(",")
|
|
11
|
+
.map((item) => item.trim())
|
|
12
|
+
.filter(Boolean) ?? []);
|
|
13
|
+
}
|
|
14
|
+
function taskIds(root = TASKS_ROOT) {
|
|
15
|
+
if (!fs.existsSync(root))
|
|
16
|
+
return [];
|
|
17
|
+
return fs
|
|
18
|
+
.readdirSync(root, { withFileTypes: true })
|
|
19
|
+
.filter((entry) => entry.isDirectory() &&
|
|
20
|
+
fs.existsSync(path.join(root, entry.name, "task.json")))
|
|
21
|
+
.map((entry) => entry.name)
|
|
22
|
+
.sort();
|
|
23
|
+
}
|
|
24
|
+
function renderResult(result) {
|
|
25
|
+
console.log(`Run ${result.run_id}${result.task_id ? ` · ${result.task_id}` : ""}`);
|
|
26
|
+
for (const cell of result.cells)
|
|
27
|
+
console.log(`${cell.status === "passed" ? "PASS" : "FAIL"} ${cell.agent}${cell.model ? `/${cell.model}` : ""} ${cell.wall_ms} ms exit ${cell.exit ?? "spawn-error"}`);
|
|
28
|
+
}
|
|
29
|
+
export function registerBenchCommand(program) {
|
|
30
|
+
const bench = program
|
|
31
|
+
.command("bench")
|
|
32
|
+
.description("Run the same task across agent and model cells, with isolated fixtures and durable JSON results.");
|
|
33
|
+
setHelpSections(bench, {
|
|
34
|
+
examples: `agents bench list\nagents bench run hello-repo --agent claude,codex --model cheap,default\nagents bench results --json`,
|
|
35
|
+
notes: `Task definitions live under apps/cli/bench/tasks/<id>/task.json. Custom harness names accepted by agents run are valid --agent values.`,
|
|
36
|
+
});
|
|
37
|
+
bench
|
|
38
|
+
.command("list")
|
|
39
|
+
.description("List available benchmark tasks.")
|
|
40
|
+
.option("--json", "Emit JSON.")
|
|
41
|
+
.action((options) => {
|
|
42
|
+
const tasks = taskIds();
|
|
43
|
+
if (options.json)
|
|
44
|
+
console.log(JSON.stringify(tasks, null, 2));
|
|
45
|
+
else if (tasks.length === 0)
|
|
46
|
+
console.log("No benchmark tasks installed.");
|
|
47
|
+
else
|
|
48
|
+
tasks.forEach((id) => console.log(id));
|
|
49
|
+
});
|
|
50
|
+
bench
|
|
51
|
+
.command("results [run-id]")
|
|
52
|
+
.description("Show one saved run, or list saved runs newest first.")
|
|
53
|
+
.option("--json", "Emit JSON.")
|
|
54
|
+
.action((runId, options) => {
|
|
55
|
+
const value = runId ? loadRun(runId) : listRuns();
|
|
56
|
+
if (options.json)
|
|
57
|
+
console.log(JSON.stringify(value, null, 2));
|
|
58
|
+
else if (Array.isArray(value)) {
|
|
59
|
+
if (value.length === 0)
|
|
60
|
+
console.log("No benchmark results yet.");
|
|
61
|
+
else
|
|
62
|
+
value.forEach(renderResult);
|
|
63
|
+
}
|
|
64
|
+
else
|
|
65
|
+
renderResult(value);
|
|
66
|
+
});
|
|
67
|
+
bench
|
|
68
|
+
.command("run [task-id]")
|
|
69
|
+
.description("Run one task or prompt across an agent × model matrix.")
|
|
70
|
+
.option("--prompt <text>", "Prompt to benchmark instead of a house task.")
|
|
71
|
+
.option("--agent <names>", "Comma-separated native agents or custom harness names. Defaults to signed-in native agents.")
|
|
72
|
+
.option("--model <models>", "Comma-separated model tiers or concrete model ids.")
|
|
73
|
+
.option("--concurrency <n>", "Maximum cells running at once.", "3")
|
|
74
|
+
.option("--json", "Emit the saved JSON result.")
|
|
75
|
+
.action(async (taskId, options) => {
|
|
76
|
+
if (!!taskId === !!options.prompt)
|
|
77
|
+
throw new Error("Pass exactly one of <task-id> or --prompt.");
|
|
78
|
+
const task = taskId ? loadTask(taskId, TASKS_ROOT) : undefined;
|
|
79
|
+
const prompt = options.prompt ?? task.prompt;
|
|
80
|
+
let agents = csv(options.agent);
|
|
81
|
+
if (agents.length === 0)
|
|
82
|
+
agents = (await detectSignedInRuntimes())
|
|
83
|
+
.filter((runtime) => runtime.signedIn)
|
|
84
|
+
.map((runtime) => runtime.id);
|
|
85
|
+
if (agents.length === 0)
|
|
86
|
+
throw new Error("No signed-in native agents found. Pass --agent <name>.");
|
|
87
|
+
const models = csv(options.model);
|
|
88
|
+
const cells = agents.flatMap((agent) => models.length > 0
|
|
89
|
+
? models.map((model) => ({ agent, model }))
|
|
90
|
+
: [{ agent }]);
|
|
91
|
+
const concurrency = Number(options.concurrency);
|
|
92
|
+
const result = await runCells({ task, prompt, cells, concurrency });
|
|
93
|
+
saveRun(result);
|
|
94
|
+
if (options.json)
|
|
95
|
+
console.log(JSON.stringify(result, null, 2));
|
|
96
|
+
else
|
|
97
|
+
renderResult(result);
|
|
98
|
+
if (result.cells.some((cell) => cell.status === "failed"))
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
});
|
|
101
|
+
}
|