@phnx-labs/agents-cli 1.22.23 → 1.22.25

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.
Files changed (143) hide show
  1. package/CHANGELOG.md +359 -0
  2. package/README.md +19 -8
  3. package/dist/bin/agents +0 -0
  4. package/dist/commands/attach.d.ts +2 -0
  5. package/dist/commands/attach.js +32 -7
  6. package/dist/commands/cloud.js +9 -5
  7. package/dist/commands/defaults.js +2 -0
  8. package/dist/commands/doctor.d.ts +24 -0
  9. package/dist/commands/doctor.js +105 -9
  10. package/dist/commands/exec.js +99 -44
  11. package/dist/commands/feed.d.ts +23 -0
  12. package/dist/commands/feed.js +65 -2
  13. package/dist/commands/focus.d.ts +34 -3
  14. package/dist/commands/focus.js +301 -57
  15. package/dist/commands/go.d.ts +14 -1
  16. package/dist/commands/go.js +49 -5
  17. package/dist/commands/insights.js +6 -2
  18. package/dist/commands/inspect.js +39 -5
  19. package/dist/commands/menubar.js +14 -1
  20. package/dist/commands/models.js +1 -0
  21. package/dist/commands/modes.d.ts +12 -0
  22. package/dist/commands/modes.js +147 -0
  23. package/dist/commands/routines.d.ts +3 -0
  24. package/dist/commands/routines.js +70 -47
  25. package/dist/commands/run-cloud.js +1 -1
  26. package/dist/commands/secrets-sync.js +11 -13
  27. package/dist/commands/secrets.d.ts +2 -0
  28. package/dist/commands/secrets.js +54 -17
  29. package/dist/commands/sessions-browser.d.ts +36 -1
  30. package/dist/commands/sessions-browser.js +165 -19
  31. package/dist/commands/sessions-resume.d.ts +2 -0
  32. package/dist/commands/sessions-resume.js +28 -12
  33. package/dist/commands/sessions.d.ts +23 -1
  34. package/dist/commands/sessions.js +58 -61
  35. package/dist/commands/setup-secrets.js +1 -1
  36. package/dist/commands/setup-watchdog.js +5 -10
  37. package/dist/commands/setup.js +1 -1
  38. package/dist/commands/sync.js +246 -42
  39. package/dist/commands/teams.js +3 -2
  40. package/dist/commands/view.js +2 -0
  41. package/dist/commands/watchdog.d.ts +3 -4
  42. package/dist/commands/watchdog.js +26 -66
  43. package/dist/index.js +38 -2
  44. package/dist/lib/agent-modes.d.ts +49 -0
  45. package/dist/lib/agent-modes.js +70 -0
  46. package/dist/lib/agents.js +126 -21
  47. package/dist/lib/cloud/cursor.d.ts +79 -0
  48. package/dist/lib/cloud/cursor.js +228 -0
  49. package/dist/lib/cloud/registry.js +2 -0
  50. package/dist/lib/cloud/types.d.ts +7 -2
  51. package/dist/lib/cloud/types.js +14 -0
  52. package/dist/lib/crabbox/cli.d.ts +2 -2
  53. package/dist/lib/crabbox/config.d.ts +7 -8
  54. package/dist/lib/crabbox/config.js +14 -14
  55. package/dist/lib/crabbox/lease.d.ts +11 -4
  56. package/dist/lib/crabbox/lease.js +40 -8
  57. package/dist/lib/crabbox/setup-copy.d.ts +5 -0
  58. package/dist/lib/crabbox/setup-copy.js +17 -1
  59. package/dist/lib/daemon.js +27 -1
  60. package/dist/lib/device-config.js +7 -0
  61. package/dist/lib/devices/doctor-findings.d.ts +7 -1
  62. package/dist/lib/devices/doctor-findings.js +40 -1
  63. package/dist/lib/doctor-diff.d.ts +3 -0
  64. package/dist/lib/doctor-diff.js +15 -13
  65. package/dist/lib/event-stream.d.ts +3 -1
  66. package/dist/lib/event-stream.js +14 -1
  67. package/dist/lib/events.d.ts +9 -0
  68. package/dist/lib/events.js +58 -0
  69. package/dist/lib/exec.d.ts +15 -3
  70. package/dist/lib/exec.js +112 -19
  71. package/dist/lib/feed-outcome.d.ts +3 -0
  72. package/dist/lib/feed-outcome.js +18 -10
  73. package/dist/lib/feed.d.ts +4 -0
  74. package/dist/lib/hooks/cache.js +36 -3
  75. package/dist/lib/hooks.d.ts +19 -7
  76. package/dist/lib/hooks.js +88 -38
  77. package/dist/lib/hosts/passthrough.d.ts +21 -0
  78. package/dist/lib/hosts/passthrough.js +39 -12
  79. package/dist/lib/hosts/session-index.d.ts +4 -0
  80. package/dist/lib/hosts/session-index.js +7 -0
  81. package/dist/lib/manifest.d.ts +12 -2
  82. package/dist/lib/manifest.js +60 -5
  83. package/dist/lib/mcp.js +5 -1
  84. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  85. package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +5 -1
  86. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  87. package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
  88. package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +15 -2
  89. package/dist/lib/menubar/install-menubar.d.ts +52 -2
  90. package/dist/lib/menubar/install-menubar.js +128 -6
  91. package/dist/lib/menubar/snapshot.d.ts +15 -0
  92. package/dist/lib/menubar/snapshot.js +40 -0
  93. package/dist/lib/plugins.js +13 -1
  94. package/dist/lib/refresh.d.ts +5 -0
  95. package/dist/lib/refresh.js +37 -33
  96. package/dist/lib/resource-inventory.d.ts +79 -0
  97. package/dist/lib/resource-inventory.js +122 -0
  98. package/dist/lib/resources/mcp.js +3 -0
  99. package/dist/lib/resources.js +8 -5
  100. package/dist/lib/routine-process-cleanup.d.ts +9 -0
  101. package/dist/lib/routine-process-cleanup.js +73 -0
  102. package/dist/lib/run-defaults.d.ts +2 -0
  103. package/dist/lib/run-defaults.js +23 -2
  104. package/dist/lib/runner.js +27 -22
  105. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  106. package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +2 -0
  107. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  108. package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
  109. package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +13 -1
  110. package/dist/lib/secrets/bundles.js +158 -85
  111. package/dist/lib/secrets/filestore.d.ts +7 -3
  112. package/dist/lib/secrets/filestore.js +25 -8
  113. package/dist/lib/secrets/index.js +34 -8
  114. package/dist/lib/secrets/rc-hygiene.d.ts +14 -0
  115. package/dist/lib/secrets/rc-hygiene.js +14 -1
  116. package/dist/lib/secrets/reaper.d.ts +10 -0
  117. package/dist/lib/secrets/reaper.js +50 -15
  118. package/dist/lib/secrets/sync-passphrase.d.ts +27 -0
  119. package/dist/lib/secrets/sync-passphrase.js +78 -0
  120. package/dist/lib/session/active.d.ts +4 -0
  121. package/dist/lib/session/db.js +8 -2
  122. package/dist/lib/session/recovery.d.ts +37 -0
  123. package/dist/lib/session/recovery.js +95 -0
  124. package/dist/lib/session/remote-list.d.ts +2 -0
  125. package/dist/lib/session/remote-list.js +1 -0
  126. package/dist/lib/session/session-cache.d.ts +4 -4
  127. package/dist/lib/session/session-cache.js +4 -4
  128. package/dist/lib/shims.d.ts +2 -2
  129. package/dist/lib/shims.js +45 -6
  130. package/dist/lib/signin-badge.js +2 -0
  131. package/dist/lib/startup/command-registry.d.ts +16 -0
  132. package/dist/lib/startup/command-registry.js +44 -0
  133. package/dist/lib/sync-umbrella.d.ts +5 -0
  134. package/dist/lib/sync-umbrella.js +5 -4
  135. package/dist/lib/teams/agents.js +1 -1
  136. package/dist/lib/teams/parsers.d.ts +1 -1
  137. package/dist/lib/tmux/session.d.ts +4 -2
  138. package/dist/lib/tmux/session.js +5 -5
  139. package/dist/lib/types.d.ts +3 -1
  140. package/dist/lib/versions.js +16 -1
  141. package/dist/lib/watchdog/service.d.ts +17 -0
  142. package/dist/lib/watchdog/service.js +39 -0
  143. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,364 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.22.25
4
+
5
+ ---
6
+ issue: 2108
7
+ type: fixed
8
+ ---
9
+
10
+ `agents sessions focus ... --active` now excludes closed and crashed registry rows; explicit lifecycle filters such as `--closed` and `--crashed` still select them. Per-device `latest` / `oldest` selectors also wait for the peer's filtered index result instead of widening to live rows whose version is unknown.
11
+
12
+ - **`agents doctor` now reports the file-store master key when it is live in the
13
+ process environment, not just when it is exported from a shell rc file
14
+ (RUSH-1968).** `rc-hygiene.ts` scans FILES, which leaves a real hole: a value
15
+ inherited by a long-lived process outlives the rc line that set it, so an operator
16
+ who deletes `~/.zshenv:8` gets a clean `rc-secret-export` while every shell, editor
17
+ and agent started before the edit still carries the key and hands it to everything
18
+ they spawn. Confirmed on `yosemite-s1`, which has zero rc exports and still had the
19
+ value in its environment. The new `env-secret-export` warning names that state and
20
+ says the deletion is not sufficient; like every other finding it reports only that
21
+ the variable is set, never its value. Expected inside a release sign context
22
+ (`headless-sign-context.sh` sets it deliberately), which the message says so an
23
+ operator on the home base does not chase it. Source:
24
+ `apps/cli/src/lib/secrets/rc-hygiene.ts` (`masterPassphraseInEnv`),
25
+ `apps/cli/src/lib/devices/doctor-findings.ts`, `apps/cli/src/commands/doctor.ts`.
26
+
27
+ - **`agents doctor --devices` now reports a remote box's secret hygiene, and its
28
+ inventory probe no longer times out on a slow box (RUSH-1968).** The fan-out ran
29
+ each remote's own `doctor --json` but parsed only `.fleet`, discarding the
30
+ `findings` the remote had already computed — so a leaking box read as clean from
31
+ anywhere but itself. The remote's `rc-secret-export` / `env-secret-export` rows
32
+ now ride back, but the remote contributes exactly one thing: the **kind**. Severity,
33
+ message and remediation are generated locally, and `device` is overwritten with the
34
+ name that was dialled. Each of those matters separately — a remediation is a command
35
+ a human copies and runs, a message is the one place a secret value could re-enter a
36
+ readout that otherwise never prints one, a severity decides the CRITICAL section, and
37
+ a device name decides which box gets blamed. The cost is detail: the fleet row names
38
+ the box and the kind, and says to run `agents doctor` there for the file and line.
39
+ Only those two kinds forward — sign-in and divergence rows are recomputed centrally
40
+ and would otherwise double.
41
+
42
+ Separately, the probe's 30s timeout was below the real cost of the command it
43
+ runs — `doctor --json` measures 57s on `yosemite-m0` and 136s on an idle box — so
44
+ every slow device silently contributed nothing at all: no inventory, no sign-in,
45
+ no divergence. Raised to 180s, matching `ChildProcess.doctorTimeout`, which was set
46
+ to 180 for this same command for this same reason. Source:
47
+ `apps/cli/src/commands/doctor.ts` (`asRemoteSecretFindings`, `probeFleetInventory`).
48
+
49
+ - **Feed and menu-bar session counts now use the `agents sessions --active` lifecycle model (RUSH-1993).**
50
+ Feed outcome headers count distinct mailbox agents in every state, so repeated
51
+ open blocks from one agent cannot make `needs you` exceed `agents`. Feed rows
52
+ replace generic `terminal` with a known host app and label routine-spawned
53
+ sessions as `routine:<name>`. The menu-bar snapshot backfills the same routine
54
+ metadata as active-session JSON and renders the full canonical status set
55
+ (`working`, `waiting`, `idle`, `queued`, `orphan`, `crashed`, `closed`,
56
+ `abandoned`, `unknown`) without reclassifying warm rows from attention files.
57
+ Source: `apps/cli/src/commands/feed.ts`, `apps/cli/src/commands/sessions.ts`,
58
+ `apps/cli/src/lib/feed-outcome.ts`, `apps/cli/src/lib/menubar/snapshot.ts`,
59
+ `apps/cli/menubar/Sources/MenubarHelper/{LocalState,StatusItemController}.swift`.
60
+
61
+ - **A typo'd command with `--host` said the opposite of the truth (RUSH-2022).** The
62
+ `--host`/`--device` router runs before commander parses, so `agents session resume
63
+ --host <box>` (one letter off `sessions`, which *does* accept `--host`) reported
64
+ `` `agents session` does not support --host/--device `` — a true statement about a
65
+ command nobody typed. Unknown names now fall through to `unknown command '<name>'`
66
+ with a did-you-mean, and the spellcheck can suggest the lazily-registered groups
67
+ (`sessions`/`teams`/`cloud`/…) it previously could not see. A real command with no
68
+ remote semantics still gets the flag-support error. Source:
69
+ `apps/cli/src/lib/hosts/passthrough.ts`, `apps/cli/src/lib/startup/command-registry.ts`.
70
+
71
+ - **`agents publish` is in the lazy command table.** `commands/packages.ts` registers it
72
+ at top level but the registry did not list it, so it only resolved through the
73
+ unknown-command fallback that loads the whole command tree. Found by the new test
74
+ that pins the command-name set against the real tree.
75
+
76
+ - **A mistyped command keeps its `--host`.** The distance-1 auto-correct now re-checks
77
+ routing after correcting the name, so `agents docto --host <box>` corrects to
78
+ `doctor` **and actually routes to `<box>`** — previously the corrected command
79
+ re-parsed locally with a `--host` it silently dropped (a regression caught in review:
80
+ it used to fail loudly with the wrong message, corrected-but-unrouted made it fail
81
+ silently instead). `apps/cli/src/index.ts`.
82
+
83
+ - **Cursor now supports `--mode plan` headless and interactive (RUSH-2101).** The
84
+ capability registry previously listed only `edit` and `skip`, so `agents run cursor --mode plan`
85
+ and routine jobs silently degraded to writable `edit`. `cursor-agent` has supported `--plan`
86
+ since the 2026-01-16 CLI release; the registry, `AGENT_COMMANDS` flag mapping, and the routine
87
+ runner now forward it correctly. Source: `apps/cli/src/lib/agents.ts`, `apps/cli/src/lib/exec.ts`,
88
+ `apps/cli/src/lib/runner.ts`.
89
+
90
+ - **`agents sessions resume` picker now filters in-memory on every keystroke instead of re-querying the database (RUSH-2212).** The `filter` callback in the multi-select picker was calling `filterSessionsByQuery`, which runs a full-text search scan against `sessions.db` on every character typed. It now uses the same cheap in-memory substring match (`sessionMatchesQuery`) the session browser already applies, so the picker stays responsive regardless of library size. Source: `apps/cli/src/commands/sessions-resume.ts`.
91
+
92
+ ---
93
+ type: minor
94
+ ---
95
+
96
+ Add Cursor Cloud Agents as a native cloud provider so `agents run cursor --cloud` and `agents cloud run --agent cursor` dispatch through Cursor's v1 REST API, with status, streaming, cancellation, and follow-up runs.
97
+
98
+ - **A starved `coreauthd` can no longer hang `secrets list` forever (RUSH-2233).**
99
+ The keychain helper's `list` runs two passes, and the data-protection pass omits
100
+ `kSecUseAuthenticationUI: …Fail` on purpose (that flag drops every biometry-ACL
101
+ item even when authentication is healthy). Omitting it means the query still
102
+ reaches LocalAuthentication/`coreauthd`, which has no deadline of its own — a
103
+ wedged `coreauthd` left `SecItemCopyMatching` blocked for the life of the
104
+ process. That is *why* helpers accumulated for the bounded-spawn + reaper work
105
+ in RUSH-2231/2232 to clean up. The pass now runs on a background thread behind
106
+ a 3-second wait: on timeout the helper logs one line to stderr, skips the pass,
107
+ and prints whatever the file-keychain pass produced — the same handling the
108
+ screen-locked `errSecInteractionNotAllowed` case already got. Set
109
+ `AGENTS_KEYCHAIN_LIST_TIMEOUT_MS` to override the deadline;
110
+ `AGENTS_KEYCHAIN_BOUNDED_TEST=1` runs the helper's headless self-test for the
111
+ bounded wait. Source: `apps/cli/src/lib/secrets/keychain-helper.swift`.
112
+
113
+ - **Use one three-minute AGI Menu snapshot and one watchdog executor (RUSH-2260).**
114
+ The menu bar now reads routines, 40 indexed recent sessions, the daemon-warmed
115
+ active-session cache, and persisted watchdog state in one subprocess every three
116
+ minutes; `doctor --json` remains independently limited to 15 minutes. The menu no
117
+ longer executes watchdog ticks. The daemon is the sole automatic watchdog executor,
118
+ warms active sessions on the same three-minute cadence, is gated by device-local
119
+ `watchdog.enabled`, and cleans failed/timeout routine process groups that are still
120
+ alive before they can overlap a replacement run. Source:
121
+ `apps/cli/src/lib/menubar/snapshot.ts`, `apps/cli/src/lib/daemon.ts`,
122
+ `apps/cli/src/lib/routine-process-cleanup.ts`.
123
+
124
+ - **Add Warp Agent CLI (Oz) as a harness (RUSH-2261).** `warp` is now a
125
+ first-class harness: `agents add warp`, `agents run warp`, `agents teams add
126
+ <team> warp`, resource sync, and `agents view` all work. The CLI command is
127
+ `oz` (the shared Warp binary); install is self-updating via
128
+ `brew install --cask oz` (macOS) / `oz-stable` apt|yum|pacman (Linux), config
129
+ lives under `~/.warp/`, the rules/context file is `AGENTS.md`, and auth is
130
+ `oz login` (browser OAuth) or a `WARP_API_KEY` token for headless/CI.
131
+ Capabilities are truthful and gated by `supports()`: MCP (Claude
132
+ `.mcp.json` schema at `~/.warp/.mcp.json`, stdio + http with headers) and
133
+ skills are on; hooks, allowlist, commands, plugins, subagents, workflows, and
134
+ memory are off (Oz exposes no matching install surface). Sessions are not
135
+ indexed — Oz stores conversations server-side (retrieved with auth via
136
+ `oz run conversation get <id>`), so there is no local transcript for
137
+ `agents sessions`. No usage bar — Oz exposes no usage/limits endpoint.
138
+ Source: `apps/cli/src/lib/{agents,exec,mcp}.ts`.
139
+
140
+ `scripts/release.sh` now runs orchestration in a fresh release-owned worktree, so a dirty shared checkout or feature branch no longer blocks or contaminates a release.
141
+
142
+ - **Plugin discovery warns instead of silently skipping a directory with no
143
+ `.claude-plugin/plugin.json` (RUSH-2270).** A `plugins/<name>/` directory missing
144
+ (or with a malformed) manifest was invisible to `agents plugins list`/`info`/`sync`,
145
+ `agents doctor`, and the marketplace materialize-into-version-homes step, with zero
146
+ diagnostic anywhere in the chain — no `agents sync`/`agents repo pull` could
147
+ surface it, since discovery dropped it before any of those ran. Found via a real
148
+ case: the `work` plugin merged to `phnx-labs/.agents-system` without its manifest
149
+ and sat invisible for a full merge cycle; the same fix run against this box's own
150
+ `~/.agents/plugins/duck` found it missing one too. `discoverPluginsInDir` now
151
+ writes one `agents-cli:` warning to stderr naming the directory and the missing
152
+ manifest path, matching the existing advisory-not-fatal pattern
153
+ `syncMarketplaceManifest` already uses for a malformed (as opposed to missing)
154
+ manifest. Source: `apps/cli/src/lib/plugins.ts`.
155
+
156
+ - **Muse login is recognized under `providers.meta` (balanced no longer signed_out).**
157
+ Live `muse login` writes `~/.config/muse/auth.json` as
158
+ `{ schema_version, providers: { meta: { access_token, user_email, … } } }`.
159
+ The presence detector only walked one object level, so it never saw the token
160
+ under `providers.meta` and reported signed-out after a successful OAuth —
161
+ `agents run muse` under balanced then failed with "excluded: 0.1.0
162
+ (signed_out)". Detection now recurses into nested provider slots and surfaces
163
+ `user_email` when present. Source: `apps/cli/src/lib/agents.ts`.
164
+
165
+ - **File-backed secret resolution now fails on decryption errors instead of treating unreadable ciphertext as an absent value (RUSH-2264).** A wrong `AGENTS_SECRETS_PASSPHRASE` or tampered encrypted value now reports the affected file-store item and stops before launching a consumer with an empty secret such as `HCLOUD_TOKEN`. Source: `apps/cli/src/lib/secrets/filestore.ts`, `apps/cli/src/lib/secrets/bundles.ts`.
166
+
167
+ ## 1.22.24
168
+
169
+ - **`agents run --lease` now shares one warm pool across repositories by default (RUSH-2225).** Repo sandbox/CI `profile:` labels no longer split lease reuse into one idle box per repo; a dedicated lease pool is explicit with `.crabbox.yaml` `leaseProfile:`. An empty pool keeps its newly warmed box for later callers. Concurrent runs attach with crabbox `--reclaim` and launch with separate working trees, agent homes, and credential files, so callers share compute without clobbering run state. Switching repos re-syncs the checkout, trading cache latency for lower idle-compute cost. Source: `apps/cli/src/lib/crabbox/config.ts`, `apps/cli/src/lib/crabbox/lease.ts`, `apps/cli/src/commands/exec.ts`.
170
+
171
+ - **`agents sessions focus` recovers dead panes and shares the sessions browser's selectors (GH-2108).** A retained tmux `remain-on-exit` pane is probed through `#{pane_dead}` immediately before attach, so dead or missing panes no longer open a `Pane is dead` screen. `focus` accepts session ids, topic/path searches, `agent@version` selectors (including per-device `latest`/`oldest`), device, project/time, team/routine, skill/plugin, favorites, and the complete live-state union. Focus, resume, attach, and `run --resume` now use one recovery decision on the origin device: a healthy exact origin performs native resume; otherwise balanced selection chooses a healthy version of the same harness and sends `/continue <id>` to read the indexed transcript, including transcripts retained under version trash. Host-dispatched rows persist the dispatch host as their origin, and `attach` routes its detach-record cleanup there before resuming. No usable same-harness version fails with the device, origin version, and account-health reason. Source: `apps/cli/src/commands/focus.ts`, `apps/cli/src/commands/sessions-browser.ts`, `apps/cli/src/lib/session/recovery.ts`.
172
+
173
+ - **`agents secrets setup` no longer tells you to set `AGENTS_SECRETS_PASSPHRASE`, and
174
+ `docs/secrets.md` stops recommending the shell-rc export it flags as a leak
175
+ (RUSH-1968).** The file-backend note read `set AGENTS_SECRETS_PASSPHRASE for headless
176
+ encrypted-file reads`, implying a requirement; headless reads have worked with no
177
+ passphrase since the store began auto-provisioning a 0600 machine-local key, so it now
178
+ says so and names the real path. The docs were worse than merely stale: they called an
179
+ rc export *"Recommended for shared/CI machines"* and the 0600 key file *"identical to"*
180
+ it, which is how a master key ended up in `~/.zshenv` on seven worker boxes. That
181
+ equivalence is inverted — the key file is read by one process, an rc export is inherited
182
+ by every child and readable from `/proc/<pid>/environ` — and the section also named a
183
+ pre-#479 key path (`~/.agents/.cache/secrets/.passphrase`, now
184
+ `~/.agents/.secrets-key/passphrase`) and a TTY prompt step `getPassphrase` no longer
185
+ has. A new `docs-hygiene.test.ts` pins those claims against the shipped doc so the
186
+ advice cannot drift back. Source: `apps/cli/docs/secrets.md`,
187
+ `apps/cli/src/commands/setup-secrets.ts`, `apps/cli/src/lib/secrets/filestore.ts`.
188
+
189
+ - **`agents secrets push`/`pull`, `agents sync --secrets`, and `agents secrets
190
+ export --to-file` / `import --from-file` read `AGENTS_SYNC_PASSPHRASE` now;
191
+ `AGENTS_SECRETS_PASSPHRASE` is the file store's master key and nothing else
192
+ (RUSH-1968).** One variable meant two different secrets: the local file store's master
193
+ key, and the passphrase that seals a bundle for transport. The store stopped needing a
194
+ passphrase once it auto-provisioned a machine-local key, but headless `push`/`pull`
195
+ still hard-failed without one — so the only way to get unattended sync on a worker box
196
+ was to export the **master key** fleet-wide, handing every same-user process the key to
197
+ the whole store. Splitting them means a box that only needs headless sync sets
198
+ `AGENTS_SYNC_PASSPHRASE` and never has the master key in its environment. The old name
199
+ still works for sync as a deprecated fallback — warned exactly once per process, so a
200
+ `push --all` over many bundles does not flood stderr — so scripted CI and release
201
+ automation keep working across the upgrade. The headless error now names the new
202
+ variable (`A sync passphrase is required. Run from a TTY, or set
203
+ AGENTS_SYNC_PASSPHRASE.`), and `agents sync`'s skip line with it — it previously read
204
+ `no passphrase available`, naming nothing an operator could act on. Note the legacy
205
+ fallback only works where that value is also the store's master key, since the old name
206
+ still keys the store; that coupling is the thing being retired. Resolution moved to
207
+ one chokepoint so the once-per-process promise holds rather than being per-call-site. Also
208
+ corrects `SEC-29a`, which claimed the variable applied "exclusively" to the file and
209
+ age-vault backends: the age-vault backend never reads it (it is gated by `agents
210
+ login`), and sync plus the portable `--to-file` envelope were two more consumers — the
211
+ new `SEC-29b` states the split as a normative invariant. Source:
212
+ `apps/cli/src/lib/secrets/sync-passphrase.ts`, `apps/cli/src/commands/secrets-sync.ts`,
213
+ `apps/cli/src/commands/sync.ts`, `apps/cli/src/lib/sync-umbrella.ts`.
214
+
215
+ - Added `--team` as an alias for `agents sessions --teams`. (RUSH-1995)
216
+ - Added absolute `agents secrets unlock --until <date>` expiry, mutually exclusive with relative `--ttl`. (RUSH-1960)
217
+ - Added persisted per-agent-version reasoning effort defaults and surfaced them in `agents view`. (RUSH-2005)
218
+
219
+ - **`agents feed` no longer crashes when the session index is locked (RUSH-2006).**
220
+ Outcome enrichment calls `discoverSessions` against `sessions.db`; under concurrent
221
+ scanner/daemon pressure that open can throw `SQLITE_BUSY` / "database is locked"
222
+ and take down the whole feed. A lock error now degrades to an empty meta set with a
223
+ stderr warning so blocks still render. Source: `apps/cli/src/commands/feed.ts`.
224
+
225
+ - **`agents events --event` / filtered activity reads no longer miss matches under
226
+ `--limit` (RUSH-2093).** The unified reader capped activity records *before*
227
+ applying the event-type filter, so a rare match older than the newest-N routine
228
+ rows (e.g. one `pr.opened` under twenty `file.edited`) was silently dropped. Event
229
+ types are now passed into `readRecentActivity` so the cap counts matching rows; a
230
+ non-`activity` `--module` skips the activity half entirely. Source:
231
+ `apps/cli/src/lib/event-stream.ts`.
232
+
233
+ - **`agents mcp add` no longer strips comments from `agents.yaml`.** The
234
+ write path (`writeManifest` / `serializeManifest` in `src/lib/manifest.ts`)
235
+ used plain `yaml.stringify`, which dropped every hand-written comment on
236
+ every add. It now round-trips via `yaml.parseDocument` and edits only the
237
+ keys that changed — the same approach `serializeCentral` already uses for
238
+ the central meta file (RUSH-2090).
239
+
240
+ - **Hook cache refresh is now single-flight, backs off on failure, and logs its
241
+ real exit code (RUSH-2121).** The background refresh in the hook cache shim
242
+ acquires an atomic `mkdir` lock, so concurrent hook invocations no longer
243
+ stampede into N parallel refreshes; a persistently-failing refresh records a
244
+ failure timestamp and is skipped until a 60s backoff elapses instead of
245
+ re-firing on every invocation; and the refresh now emits a `hook.cache.refresh`
246
+ event carrying the subshell's real exit code instead of a hardcoded `0`.
247
+ Source: `apps/cli/src/lib/hooks/cache.ts`.
248
+
249
+ - **`agents sync --host all` no longer fails every peer with `unknown option
250
+ '--json'`.** Fleet fan-out injects `--json` on each remote so the roster can
251
+ parse per-device results, but `sync` never registered the flag. Register
252
+ `--json` on `agents sync` and emit a machine-readable umbrella/agent/repo
253
+ payload so peers accept the flag and return parseable stdout (RUSH-2216).
254
+ Source: `apps/cli/src/commands/sync.ts`.
255
+
256
+ - **A wedged keychain can no longer pile up `agents` processes (RUSH-2231, RUSH-2232).**
257
+ A stalled macOS `coreauthd` used to hang the signed keychain helper's XPC receive
258
+ forever, so every secrets-touching `agents` command blocked and dozens of helper
259
+ processes plus their `<defunct>` zombies accumulated and made the machine sluggish.
260
+ Two fixes: **(Layer 1)** every keychain-helper `spawnSync` is now bounded and
261
+ hard-killed (SIGKILL) on timeout — 8s for never-prompt verbs (`has`/`set`/`delete`/
262
+ `list*`), 60s for the may-prompt reads (`get`/`get-batch`/`migrate-*`) — surfacing a
263
+ typed timeout error and arming the read back-off instead of hanging.
264
+ **(Layer 3)** the daemon reaps the backlog: a 5-minute tick kills orphaned helpers
265
+ (reparented to PID 1, past a 30s grace) and, two-sweep-debounced, the helper child of
266
+ an `agents` proc stuck past 90s (child first, escalating to the parent only if it
267
+ stays wedged) — never touching a process whose start-time can't be captured or whose
268
+ path doesn't match the helper. Any keychain touch now also opportunistically starts
269
+ the daemon so the reaper runs even on a secrets-only box. Source:
270
+ `apps/cli/src/lib/secrets/index.ts`, `apps/cli/src/lib/secrets/reaper.ts`,
271
+ `apps/cli/src/lib/daemon.ts`.
272
+
273
+ - **`agents inspect` and `agents doctor` now report harness-scoped hook inventory as capable, on-disk, wired, and unmanaged state.** Their JSON output carries the same state sets from `getResourceInventory`, so a harness with hook files or native wiring no longer collapses to a misleading `Hooks (0)` summary. Inventory is keyed by agent harness and installed version, not by configured model. Source: `apps/cli/src/lib/resource-inventory.ts`, `apps/cli/src/commands/inspect.ts`, `apps/cli/src/lib/doctor-diff.ts`.
274
+
275
+ - **Fix: the keychain-helper reaper never reaped on macOS.** The daemon reaper shelled `ps -o etimes` — a GNU/Linux procps keyword that macOS `ps` rejects with a non-zero exit — so `execFileSync` threw on every tick and `reapOrphanedKeychainProcesses` returned `reaped: 0` on its only supported platform, leaving orphaned/wedged `Agents CLI` helper processes to pile up. Switched to the portable BSD `etime` keyword (`[[dd-]hh:]mm:ss`) with a parser to seconds. This also un-quarantines the darwin integration test that #2153 had to `it.skip` to unblock releases: that test's symlink fixture was correct all along — it read `reaped: 0` only because the reaper's own `ps etimes` call threw before parsing anything. Verified on macOS 15.4.1: 20/20 reaper tests pass, the integration test reaping a real orphaned sleeper. Source: `apps/cli/src/lib/secrets/reaper.ts`, `reaper.test.ts`.
276
+
277
+ - **`agents modes [agent[@version]]` lists the permission modes a harness accepts.** The modes analog of `agents models`: for Claude / Codex / Cursor / …, shows which `--mode plan|edit|auto|skip` values work, the native CLI flags, the native default (`*`), any configured `run.defaults` mode, and degrade notes (e.g. plan→edit on Antigravity). `agents inspect` also prints the mode list next to capabilities, and `agents run --help` / `agents models` point at the new command. Source: `apps/cli/src/commands/modes.ts`, `apps/cli/src/lib/agent-modes.ts`.
278
+
279
+ - **`agents insights --all` now works as an alias for `--since all`.** It previously
280
+ exited with `unknown option '--all'` — a hard failure in the middle of a report the
281
+ user asked for, on the spelling most people reach for first. An explicit `--since`
282
+ still wins, so `--all --since 7d` resolves to 7d rather than silently contradicting
283
+ itself. Source: `apps/cli/src/commands/insights.ts`.
284
+
285
+ - **Coexisting agents-cli installs no longer fight over the menu-bar helper.** The
286
+ helper lives at one path in Application Support, but every install on the box runs
287
+ the startup self-heal, and both the version stamp and the plist's baked
288
+ `AGENTS_ENTRY` record whichever copy acted last — so each copy read the others'
289
+ marks as drift and recopied the app bundle over them. Recopying replaces the
290
+ executable under the running helper and kills it, launchd `KeepAlive` restarts it,
291
+ and the next copy repeats it: a new pid every 5-15 seconds, 578 launches in one
292
+ observed helper log, and a status item that never stayed visible while
293
+ `agents menubar status` still reported `running: yes` (a pid always existed). The
294
+ plist's `AGENTS_ENTRY` is now treated as the owner and only the owner reinstalls
295
+ freely; a same-install upgrade keeps its entry path, so `npm update` still installs
296
+ the new helper normally. Another install still gets there — immediately if the
297
+ recorded owner is gone from disk, otherwise at most once an hour — so a stale copy
298
+ that merely still sits on disk can't freeze the menu bar for whichever install the
299
+ user actually upgrades. Repairs (a missing helper executable, a Developer-ID heal)
300
+ are never gated, and `agents menubar setup` bypasses the gate as the immediate
301
+ manual fix. An ad-hoc/dev-signed build never wins the timed takeover — recopying
302
+ an un-notarized bundle over a good one gets it rejected as "damaged" — though it
303
+ can still adopt a helper whose owner is gone. Two installs that are both invoked
304
+ regularly still trade ownership at the cooldown, so the helper restarts about once
305
+ an hour until one is removed; that is bounded rather than converged, and the real
306
+ fix remains a single install. `agents menubar status` no longer promises that a
307
+ stale helper "runs on next `agents` startup", which is not guaranteed on a
308
+ multi-install box. Fixes #2109. Source:
309
+ `apps/cli/src/lib/menubar/install-menubar.ts`.
310
+
311
+ - **Muse Code global binary is visible to `agents view` / `isVersionInstalled`.**
312
+ Muse installs a single self-updating launcher at `~/.local/bin/muse` (same
313
+ shape as droid), but `getBinaryPath` still resolved a version-home
314
+ `node_modules/.bin/muse` that never exists. After `agents import muse` /
315
+ `agents add muse`, version dirs now resolve to that global path so managed
316
+ view, collapse, and live-version bookkeeping match what actually executes;
317
+ install no longer writes a self-referential shim symlink. Source:
318
+ `apps/cli/src/lib/versions.ts`.
319
+
320
+ - **Muse multi-version isolation matches Claude/Codex (XDG pin, not bare symlink).**
321
+ Claude/Codex isolate per version with `CLAUDE_CONFIG_DIR` / `CODEX_HOME`.
322
+ Muse has no dedicated config env; it reads `$XDG_CONFIG_HOME/muse` and
323
+ `$XDG_DATA_HOME/muse`. After `agents import muse`, `~/.config/muse` is a
324
+ symlink into the version home — Muse refuses that path with
325
+ `Agent Definition filesystem source failed: SymlinkOrReparse` and exits 1
326
+ (the Zion `agents run muse@0.1.0` failure). Managed launches now pin
327
+ `XDG_CONFIG_HOME` + `XDG_DATA_HOME` into the version home from `buildExecEnv`,
328
+ the main shim, and versioned aliases (`muse@0.1.0`), the same way Claude pins
329
+ `CLAUDE_CONFIG_DIR`. Muse is also listed in `CONFIG_ENV_ISOLATED_AGENTS` so
330
+ `--isolated` installs are honest. Source: `apps/cli/src/lib/{exec,shims}.ts`.
331
+
332
+ - **Scheduled routines now run on a per-account `claude setup-token` when one is
333
+ provisioned, instead of throwing it away.** `buildRoutineSpawnEnv` unconditionally
334
+ deleted `CLAUDE_CODE_OAUTH_TOKEN`, so even after `buildExecEnv` injected a long-lived,
335
+ non-rotating setup-token from the reserved file-backed `auth` bundle
336
+ (`resolveClaudeSetupToken`), a routine still fell back to the version home's rotating
337
+ `.credentials.json` login. With one Claude account signed into several version homes
338
+ (or several fleet boxes), that rotating login is the single-use-refresh-token
339
+ revocation storm — one home's refresh silently revokes every sibling copy, so an
340
+ unattended routine keeps landing on a just-revoked token and dies with `auth_failed:
341
+ OAuth access token has been revoked` / `Please run /login`, even though `agents view`
342
+ shows the account healthy. The delete now distinguishes the two flavours: a
343
+ per-account setup-token (keyed to this home's own account) is re-asserted and KEPT; an
344
+ inherited *ambient* token (a shared value the daemon env happened to carry — the
345
+ RUSH-1822 fleet-logout path) is still stripped so a routine never runs on it.
346
+ Provision the token with `/fleet:mint-auth`. Source:
347
+ `apps/cli/src/lib/runner.ts` (`buildRoutineSpawnEnv`).
348
+
349
+ - **Resolved secrets no longer appear in `ps` for tmux-launched agents
350
+ (RUSH-2100).** An interactive `agents run` wraps the agent in tmux via
351
+ `exec env K=V … <agent>`, which put the entire exec env — every resolved
352
+ secrets-bundle value — into the pane's command line, readable by any process of
353
+ the same user. On one fleet box six live processes carried
354
+ `AGENTS_SECRETS_PASSPHRASE`, the key that decrypts every file-backed bundle on
355
+ that machine. The pane now sources a `0600` env file and unlinks it before
356
+ `exec`, so only the file path is argv-visible; a missing file aborts the pane
357
+ rather than launching half-configured. Every key routes through the file, not a
358
+ curated "secret-bearing" subset, so a newly added credential is covered without
359
+ anyone maintaining a list. Source: `apps/cli/src/lib/exec.ts`,
360
+ `apps/cli/docs/specifications.md` (SEC-8a).
361
+
3
362
  ## 1.22.23
4
363
 
5
364
  - **Daemon-warmed cross-surface session-status cache (RUSH-2062).** Menubar,
package/README.md CHANGED
@@ -35,6 +35,8 @@
35
35
  <a href="https://dev.meta.ai/docs/muse-code" title="Meta Muse Code"><strong>Muse</strong></a>
36
36
  &nbsp;&nbsp;&nbsp;&nbsp;
37
37
  <a href="https://omp.sh" title="Oh My Pi"><strong>Pi</strong></a>
38
+ &nbsp;&nbsp;&nbsp;&nbsp;
39
+ <a href="https://docs.warp.dev/reference/cli" title="Warp Agent CLI (Oz)"><strong>Warp</strong></a>
38
40
  </p>
39
41
 
40
42
  https://agents-cli.sh/demo.mp4
@@ -147,6 +149,13 @@ agents run antigravity "Write tests for the fixed code"
147
149
 
148
150
  Each resolves to the project-pinned version with skills, MCP servers, and permissions already synced. Single-typo names auto-correct across every command — `agents view cladue` resolves to `claude`, `agents add codx@latest` to `codex`.
149
151
 
152
+ `agents run claude "task" --lease` reuses one shared warm crabbox pool across
153
+ repositories by default. Concurrent runs share the box but execute in isolated
154
+ `~/workspaces/<repo>-<run>` directories with separate agent homes and credential
155
+ files. Add `leaseProfile: private-hot-box` to
156
+ `.crabbox.yaml` only when a repo intentionally needs a dedicated warm pool;
157
+ cross-repo reuse trades re-sync latency for lower idle-compute cost.
158
+
150
159
  ### Rate-limited? Keep working.
151
160
 
152
161
  ```bash
@@ -303,6 +312,7 @@ agents sessions --idle # stopped between turns (fleet-wide)
303
312
  agents sessions --orphan # agent outlived its terminal client
304
313
  agents sessions --crashed # terminal and agent disappeared uncleanly
305
314
  agents sessions focus a1b2c3d4 # jump back into one — attach in place, or resume
315
+ agents sessions focus claude@latest --device yosemite-s0 # pick latest there
306
316
  ```
307
317
 
308
318
  On a terminal, `agents sessions --active` (and a bare `agents sessions`) open the **interactive session browser** — one filter you drive with single keys, re-pulled live across the fleet:
@@ -313,7 +323,7 @@ On a terminal, `agents sessions --active` (and a bare `agents sessions`) open th
313
323
  | `r` | running only | `--active` |
314
324
  | `f` | favorites only | `--favorites` |
315
325
  | `*` | star / unstar the highlighted session | `agents sessions favorite <id>` |
316
- | `c` | team sessions | `--teams` |
326
+ | `c` | team sessions | `--team` (alias: `--teams`) |
317
327
  | `a` | agent (cycles) | `-a` |
318
328
  | `d` | device (cycles) | `--device` |
319
329
  | `p` | this repo ↔ all dirs | `--all` |
@@ -332,7 +342,7 @@ Filters **stack** (they AND together), the active set shows in the header, and t
332
342
  | --- | --- |
333
343
  | ![sessions browser, preview hidden](assets/demos/sessions-preview-before.png) | ![sessions browser, preview open with a links line](assets/demos/sessions-preview-after.png) |
334
344
 
335
- Each live session resolves to `working`, `waiting_input` (with why -- a question, a plan review, or a permission prompt), `idle`, or a lifecycle state such as `orphaned`, `crashed`, `closed`, `abandoned`, `queued`, or `unknown`. Pass the matching flag (`--working`, `--idle`, `--waiting`, `--orphan`, `--crashed`, `--closed`, `--abandoned`, `--queued`, `--unknown`) directly; each implies `--active`, and several flags form a union. The fleet fan-out is already the default; `--local` opts out. `--all` instead widens historical directory and time scope. Rows also carry badges for the PR, worktree, and ticket. `agents sessions focus [id]` attaches the live pane in place -- the tmux split locally or over SSH, or its Ghostty tab -- and falls back to a fresh tab + resume when the terminal is gone.
345
+ Each live session resolves to `working`, `waiting_input` (with why -- a question, a plan review, or a permission prompt), `idle`, or a lifecycle state such as `orphaned`, `crashed`, `closed`, `abandoned`, `queued`, or `unknown`. Pass the matching flag (`--working`, `--idle`, `--waiting`, `--orphan`, `--crashed`, `--closed`, `--abandoned`, `--queued`, `--unknown`) directly; each implies `--active`, and several flags form a union. The fleet fan-out is already the default; `--local` opts out. `--all` instead widens historical directory and time scope. Rows also carry badges for the PR, worktree, and ticket. `agents sessions focus [selector]` accepts the same agent/version, device, time, team, project, skill/plugin, favorite, and live-state filters as the session browser. A unique id focuses directly; an agent/version or text selector always opens the preview picker. Immediately before attach it checks the tmux pane process: a living pane is joined in place, while a dead/missing pane enters recovery instead of showing tmux's `Pane is dead` screen.
336
346
 
337
347
  Landing on a session cold? `agents sessions <id>` prints a catch-up digest: an inferred title, files changed grouped by directory (created / modified / deleted), a histogram of which tools did the work (including parsed Bash commands -- `git`, `npm`, `ffmpeg`, `ssh`, and so on), and the last test verdict -- the signals to reload a task in seconds.
338
348
 
@@ -351,11 +361,11 @@ agents resume 019fd0c8-b3e9-77a2-a1a4-444698c4d897 # original harness/version/d
351
361
  agents run auto --resume 019fd0c8-b3e9-77a2-a1a4-444698c4d897 # adapt if its account is unavailable
352
362
  ```
353
363
 
354
- `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 restore the source harness, version, device, cwd, and recorded launch mode. 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.
364
+ `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 healthy, its isolated home performs native resume. 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. 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.
355
365
 
356
366
  ### Send an agent to the background — and bring it back
357
367
 
358
- Running 30 agents and drowning in terminal tabs? `agents sessions detach <id>` stops a session's interactive process and keeps it working **headless** in the background -- it drives its task to done unattended, no tab, lower cost. `agents sessions attach <id>` brings it back: version-pinned resume into a live TUI, the same session and full history (including whatever it did while backgrounded).
368
+ Running 30 agents and drowning in terminal tabs? `agents sessions detach <id>` stops a session's interactive process and keeps it working **headless** in the background -- it drives its task to done unattended, no tab, lower cost. `agents sessions attach <id>` brings it back through the same origin-device recovery decision: native resume in the exact healthy origin home, or same-harness `/continue` when that home is unavailable, with the full indexed history (including whatever it did while backgrounded).
359
369
 
360
370
  ```
361
371
  agents sessions detach a1b2c3d4 # go headless in the background, keep working
@@ -404,7 +414,7 @@ agents watchdog --nudge # actually inject "Continue." into the stalled split
404
414
  agents watchdog --watch # daemon loop: a tick every --interval
405
415
  ```
406
416
 
407
- `agents watchdog` detects a stalled session, resolves the *exact* terminal split it lives in (tmux, iTerm, VSCodium, or a raw pty), and injects a nudge -- `Continue.` by default, or set `--text`. It's dry by default; `--nudge` acts on a single tick, and `agents watchdog on|off` enables or disables the built-in routine on this device. `agents setup watchdog` chooses devices. Steer a single run with `agents watchdog policy <id> off | keep | handsoff`.
417
+ `agents watchdog` detects a stalled session, resolves the *exact* terminal split it lives in (tmux, iTerm, VSCodium, or a raw pty), and injects a nudge -- `Continue.` by default, or set `--text`. It's dry by default; `--nudge` acts on a single tick. `agents watchdog on|off` controls the device-local daemon pass, which runs once every three minutes. Steer a single run with `agents watchdog policy <id> off | keep | handsoff`.
408
418
 
409
419
  A stalled session whose tail shows a hard account limit ("You've hit your weekly limit · resets …") is **rotated in place** instead of nudged: the watchdog gates on the same healthy-account selection `agents run auto` makes (zero healthy → one skip event per cooldown window, terminal untouched), injects the harness's exit sequence, relaunches `agents run auto --interactive --session-id <uuid>` in the *same* tab, then replays the old session's resume once the new TUI is live. Default on; `agents watchdog rotate off` disables it (nudging stays on).
410
420
 
@@ -608,10 +618,10 @@ Team state is observable via `agents teams list --json` / `agents teams status -
608
618
 
609
619
  ## Cloud
610
620
 
611
- Some work shouldn't tie up your laptop. `agents cloud run` hands a task to a managed provider that clones the repo, plans, implements, tests, and opens a PR -- while your terminal stays free. A fifth provider, `host`, dispatches the same way onto machines you own: `agents cloud run "…" --host gpu-box` (tasks track in `agents cloud ps` and `agents hosts ps` alike).
621
+ Some work shouldn't tie up your laptop. `agents cloud run` hands a task to a managed provider that clones the repo, plans, implements, tests, and opens a PR -- while your terminal stays free. The `host` provider dispatches the same way onto machines you own: `agents cloud run "…" --host gpu-box` (tasks track in `agents cloud ps` and `agents hosts ps` alike).
612
622
 
613
623
  <p align="center">
614
- <img src="assets/cloud.svg" alt="agents cloud run dispatches one prompt to a managed provider (Rush, Codex, Factory, or Antigravity) that clones, plans, tests, and opens a pull request while you keep working" width="100%" />
624
+ <img src="assets/cloud.svg" alt="agents cloud run dispatches one prompt to a managed provider (Rush, Codex, Cursor, Factory, or Antigravity) that runs while you keep working" width="100%" />
615
625
  </p>
616
626
 
617
627
  ```bash
@@ -625,7 +635,7 @@ agents cloud message <id> "also update the changelog" # steer it mid-run
625
635
  agents cloud cancel <id>
626
636
  ```
627
637
 
628
- Four managed backends behind one interface (`agents cloud providers`):
638
+ Five managed backends behind one interface (`agents cloud providers`):
629
639
 
630
640
  | Provider | What runs | Notes |
631
641
  |---|---|---|
@@ -633,6 +643,7 @@ Four managed backends behind one interface (`agents cloud providers`):
633
643
  | `codex` | A pre-built Codex Cloud environment | Target it with `--env`. |
634
644
  | `factory` | `droid exec` on a cloud VM | Computer-use; pick the box with `--computer`. |
635
645
  | `antigravity` | Gemini managed agents | Antigravity harness in a remote sandbox. |
646
+ | `cursor` | Cursor Cloud Agents | v1 REST API with repo, status, SSE, cancel, and follow-up runs. |
636
647
 
637
648
  Auto-routes each `--agent` to its native cloud, or pin the backend with `--provider`. Instead of dispatching now, register a run as an **event trigger** with `--on pull_request` (also `push`, `issue_comment`, `workflow_run`) -- it persists as a trigger-bound routine that fires on the event. `--json` on every subcommand for scripting.
638
649
 
Binary file
@@ -6,5 +6,7 @@
6
6
  * history, the exact inverse of `agents sessions detach`.
7
7
  */
8
8
  import type { Command } from 'commander';
9
+ import type { SessionMeta } from '../lib/session/types.js';
9
10
  export declare function registerAttachCommand(program: Command): void;
10
11
  export declare function attachAction(id: string): Promise<void>;
12
+ export declare function attachRecoveryArgs(session: Pick<SessionMeta, 'id'>): string[];
@@ -1,6 +1,7 @@
1
1
  import chalk from 'chalk';
2
- import { discoverSessions } from '../lib/session/discover.js';
3
- import { resumeSessionInPlace } from './sessions.js';
2
+ import { runOnPeer } from '../lib/session/remote-list.js';
3
+ import { sessionRecoveryPeer } from '../lib/session/recovery.js';
4
+ import { resolveSessionMetadataValue, resumeSessionInPlace } from './sessions.js';
4
5
  import { readDetachRecord, clearDetachRecord, isHeadlessAlive } from '../lib/session/detached.js';
5
6
  export function registerAttachCommand(program) {
6
7
  program
@@ -12,16 +13,37 @@ export function registerAttachCommand(program) {
12
13
  });
13
14
  }
14
15
  export async function attachAction(id) {
15
- const q = id.toLowerCase();
16
- // Rich meta carries the pinned version + origin cwd the resume needs.
17
- const metas = await discoverSessions({ all: true, since: '90d', limit: 2000 });
18
- const meta = metas.find((m) => m.id === id) ?? metas.find((m) => m.id.toLowerCase().startsWith(q));
19
- if (!meta) {
16
+ const outcome = await resolveSessionMetadataValue(id);
17
+ if (outcome.kind === 'partial') {
18
+ console.error(chalk.red(`Could not resolve session while these devices were unavailable: ${outcome.failedPeers.join(', ')}`));
19
+ process.exitCode = 2;
20
+ return;
21
+ }
22
+ if (outcome.kind === 'not-found') {
20
23
  console.error(chalk.red(`No session matching "${id}".`));
21
24
  console.error(chalk.gray(' See your sessions: agents sessions'));
22
25
  process.exitCode = 1;
23
26
  return;
24
27
  }
28
+ if (outcome.kind === 'ambiguous') {
29
+ console.error(chalk.red(`"${id}" matches ${outcome.candidates.length} sessions. Pass the full session id.`));
30
+ process.exitCode = 1;
31
+ return;
32
+ }
33
+ const meta = outcome.session;
34
+ // Route the WHOLE attach operation to the origin, not just its eventual
35
+ // resume. The detach record and headless PID are device-local; clearing them
36
+ // here would leave the real background continuation running beside a second
37
+ // process on the owning machine.
38
+ const peer = sessionRecoveryPeer(meta);
39
+ if (peer) {
40
+ const routed = await runOnPeer(attachRecoveryArgs(meta), peer, { tty: true });
41
+ if (routed === 'no-target') {
42
+ console.error(chalk.red(`Cannot attach ${meta.shortId}: origin device ${peer} is not a registered reachable peer.`));
43
+ process.exitCode = 1;
44
+ }
45
+ return;
46
+ }
25
47
  // If it's backgrounded, stop the headless continuation first so two processes
26
48
  // don't resume the same transcript at once.
27
49
  const rec = readDetachRecord(meta.id);
@@ -39,3 +61,6 @@ export async function attachAction(id) {
39
61
  console.log(chalk.gray(`Attaching ${meta.agent} ${meta.id.slice(0, 8)} — resuming interactively…`));
40
62
  await resumeSessionInPlace(meta);
41
63
  }
64
+ export function attachRecoveryArgs(session) {
65
+ return ['sessions', 'attach', session.id];
66
+ }
@@ -25,14 +25,15 @@ export function statusColor(status) {
25
25
  export function registerCloudCommands(program) {
26
26
  const cloud = program
27
27
  .command('cloud', { hidden: true })
28
- .description('Dispatch and manage cloud agent tasks across providers (Rush, Codex, Factory, Antigravity).')
28
+ .description('Dispatch and manage cloud agent tasks across providers (Rush, Codex, Cursor, Factory, Antigravity, Host).')
29
29
  .addHelpText('after', `
30
30
  Each agent runs in its own cloud. Pass --agent and the provider is auto-selected
31
- (claude→rush, codex→codex, droid→factory, antigravity→antigravity); --provider overrides.
31
+ (claude→rush, codex→codex, cursor→cursor, droid→factory, antigravity→antigravity); --provider overrides.
32
32
 
33
33
  Providers:
34
34
  rush Rush Cloud — Claude against a GitHub repo + branch → PR
35
35
  codex Codex Cloud — runs in a pre-built Codex environment (--env)
36
+ cursor Cursor Cloud Agents — v1 REST API, with optional GitHub repos
36
37
  factory Factory Droid Computer — droid exec on a cloud VM (--computer)
37
38
  antigravity Gemini Managed Agents — Antigravity harness in a remote sandbox
38
39
 
@@ -49,6 +50,9 @@ Examples:
49
50
  # Codex Cloud against a saved environment
50
51
  agents cloud run "add pytest fixtures for the new billing module" --provider codex --env env_a1b2c3 --agent codex --timeout 30m
51
52
 
53
+ # Cursor Cloud Agents against a GitHub repository
54
+ agents cloud run "fix the flaky parser test" --agent cursor --repo acme/example
55
+
52
56
  # Factory pod targeting a specific computer (Droid)
53
57
  agents cloud run "QA the new onboarding flow end-to-end" --provider factory --computer linux-vm-1 --agent droid
54
58
 
@@ -74,9 +78,9 @@ Examples:
74
78
  cloud
75
79
  .command('run [prompt]')
76
80
  .description('Dispatch a task to a cloud agent.')
77
- .option('--provider <id>', 'Cloud backend: rush, codex, factory, antigravity, host (overrides agent auto-routing)')
78
- .option('--agent <name>', 'Agent to run: claude, codex, droid, antigravity (auto-routes to its native cloud)')
79
- .option('--repo <owner/repo>', 'GitHub repository. Repeatable for multi-repo dispatch (Rush Cloud only).', (value, previous) => {
81
+ .option('--provider <id>', 'Cloud backend: rush, codex, cursor, factory, antigravity, host (overrides agent auto-routing)')
82
+ .option('--agent <name>', 'Agent to run: claude, codex, cursor, droid, antigravity (auto-routes to its native cloud)')
83
+ .option('--repo <owner/repo>', 'GitHub repository. Repeatable for multi-repo dispatch (Rush or Cursor Cloud).', (value, previous) => {
80
84
  const acc = Array.isArray(previous) ? previous : [];
81
85
  acc.push(value);
82
86
  return acc;
@@ -47,11 +47,13 @@ export function registerDefaultsCommands(program) {
47
47
  .description('Set defaults for an agent/version selector')
48
48
  .option('--mode <mode>', "Default mode: plan, edit, auto, skip. 'full' accepted as alias for skip.")
49
49
  .option('--model <model>', 'Default model or model alias, forwarded via --model')
50
+ .option('--effort <effort>', 'Default reasoning effort: low, medium, high, xhigh, max, or auto')
50
51
  .action((selector, options) => {
51
52
  try {
52
53
  const entry = setRunDefault(selector, {
53
54
  ...(options.mode !== undefined ? { mode: options.mode } : {}),
54
55
  ...(options.model !== undefined ? { model: options.model } : {}),
56
+ ...(options.effort !== undefined ? { effort: options.effort } : {}),
55
57
  });
56
58
  console.log(chalk.green('Set run default:'));
57
59
  console.log(` ${formatRunDefaultEntry(entry)}`);