@phnx-labs/agents-cli 1.20.87 → 1.20.89

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 (94) hide show
  1. package/CHANGELOG.md +323 -0
  2. package/README.md +12 -4
  3. package/dist/bin/agents +0 -0
  4. package/dist/commands/commands.js +7 -7
  5. package/dist/commands/doctor.d.ts +0 -19
  6. package/dist/commands/doctor.js +219 -305
  7. package/dist/commands/exec.js +7 -19
  8. package/dist/commands/factory.js +26 -2
  9. package/dist/commands/funnel.js +16 -1
  10. package/dist/commands/inspect.js +3 -5
  11. package/dist/commands/menubar.js +117 -34
  12. package/dist/commands/routines.js +25 -3
  13. package/dist/commands/secrets-rotate-passphrase.d.ts +17 -0
  14. package/dist/commands/secrets-rotate-passphrase.js +96 -0
  15. package/dist/commands/secrets.js +2 -0
  16. package/dist/commands/sessions.d.ts +7 -1
  17. package/dist/commands/sessions.js +40 -12
  18. package/dist/commands/ssh.js +3 -3
  19. package/dist/commands/usage.d.ts +3 -2
  20. package/dist/commands/usage.js +2 -9
  21. package/dist/commands/webhook.js +7 -2
  22. package/dist/lib/agents.d.ts +31 -1
  23. package/dist/lib/agents.js +55 -0
  24. package/dist/lib/command-skills.d.ts +10 -0
  25. package/dist/lib/command-skills.js +14 -0
  26. package/dist/lib/commands.js +28 -2
  27. package/dist/lib/daemon.d.ts +29 -0
  28. package/dist/lib/daemon.js +75 -6
  29. package/dist/lib/devices/doctor-findings.d.ts +167 -0
  30. package/dist/lib/devices/doctor-findings.js +893 -0
  31. package/dist/lib/devices/fleet-divergence.d.ts +22 -0
  32. package/dist/lib/devices/fleet-divergence.js +34 -10
  33. package/dist/lib/devices/fleet-inventory.d.ts +17 -6
  34. package/dist/lib/devices/fleet-inventory.js +56 -8
  35. package/dist/lib/events.d.ts +1 -1
  36. package/dist/lib/exec.d.ts +14 -3
  37. package/dist/lib/exec.js +41 -8
  38. package/dist/lib/factory/snapshot.d.ts +78 -0
  39. package/dist/lib/factory/snapshot.js +209 -0
  40. package/dist/lib/fs-atomic.d.ts +14 -1
  41. package/dist/lib/fs-atomic.js +35 -3
  42. package/dist/lib/funnel.d.ts +1 -0
  43. package/dist/lib/funnel.js +8 -0
  44. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  45. package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
  46. package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +2 -2
  47. package/dist/lib/menubar/install-menubar.d.ts +53 -2
  48. package/dist/lib/menubar/install-menubar.js +183 -28
  49. package/dist/lib/platform/process.d.ts +2 -0
  50. package/dist/lib/platform/process.js +5 -3
  51. package/dist/lib/project-resources.js +34 -20
  52. package/dist/lib/resources.d.ts +8 -0
  53. package/dist/lib/resources.js +34 -1
  54. package/dist/lib/routines-placement.d.ts +2 -1
  55. package/dist/lib/routines-placement.js +8 -4
  56. package/dist/lib/routines.d.ts +57 -1
  57. package/dist/lib/routines.js +74 -1
  58. package/dist/lib/runner.d.ts +16 -1
  59. package/dist/lib/runner.js +58 -16
  60. package/dist/lib/sandbox.d.ts +2 -0
  61. package/dist/lib/sandbox.js +38 -0
  62. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  63. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  64. package/dist/lib/secrets/bundles.js +9 -34
  65. package/dist/lib/secrets/filestore.d.ts +152 -34
  66. package/dist/lib/secrets/filestore.js +676 -123
  67. package/dist/lib/secrets/rc-hygiene.d.ts +0 -6
  68. package/dist/lib/secrets/rc-hygiene.js +0 -24
  69. package/dist/lib/session/active.d.ts +6 -6
  70. package/dist/lib/session/active.js +6 -6
  71. package/dist/lib/session/discover.d.ts +5 -0
  72. package/dist/lib/session/discover.js +137 -1
  73. package/dist/lib/session/parse.d.ts +2 -0
  74. package/dist/lib/session/parse.js +76 -37
  75. package/dist/lib/session/remote-active.d.ts +4 -1
  76. package/dist/lib/session/remote-active.js +8 -2
  77. package/dist/lib/session/sync/agents.js +0 -0
  78. package/dist/lib/session/types.d.ts +1 -1
  79. package/dist/lib/session/types.js +1 -1
  80. package/dist/lib/session/viewing-in.d.ts +31 -0
  81. package/dist/lib/session/viewing-in.js +47 -0
  82. package/dist/lib/staleness/detectors/commands.js +14 -5
  83. package/dist/lib/staleness/types.d.ts +2 -0
  84. package/dist/lib/staleness/writers/commands.js +13 -7
  85. package/dist/lib/state.d.ts +17 -0
  86. package/dist/lib/state.js +30 -2
  87. package/dist/lib/triggers/handlers.d.ts +95 -0
  88. package/dist/lib/triggers/handlers.js +384 -0
  89. package/dist/lib/triggers/webhook.d.ts +10 -2
  90. package/dist/lib/triggers/webhook.js +65 -11
  91. package/dist/lib/usage.d.ts +72 -1
  92. package/dist/lib/usage.js +21 -27
  93. package/dist/lib/versions.js +30 -13
  94. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,328 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.20.89
4
+
5
+ - **Webhook handler layer for one-off agent/workflow/command/routine triggers.**
6
+ Routines still fire from signed webhooks, but a new `~/.agents/webhooks/*.yml`
7
+ layer can also run one-off actions: `run.agent`, `run.workflow`, `run.command`,
8
+ or delegate to an existing `routine`. Handlers support the same source/event/
9
+ action/label/repo/branch filters as routine triggers, plus Linear
10
+ `stateTo`/`stateFrom` state-change filters. Prompts and commands can use
11
+ `{{issue.identifier}}`, `{{updatedFrom.state.name}}`, etc. The receiver emits
12
+ `webhook.received`, `webhook.authorized`, `webhook.rejected`, `webhook.matched`,
13
+ `webhook.fired`, `webhook.handler.start`, and `webhook.handler.end` events.
14
+ Source: `apps/cli/src/lib/triggers/handlers.ts`,
15
+ `apps/cli/src/lib/triggers/webhook.ts`, `apps/cli/src/lib/routines.ts`,
16
+ `apps/cli/src/commands/routines.ts`, `apps/cli/docs/03-routines.md`.
17
+
18
+ - **`agents routines add` gains `--state-to` and `--state-from` filters for Linear
19
+ triggers.** A Linear routine or handler can now fire only on a specific state
20
+ transition (for example `--state-to Plan`), instead of on every issue update.
21
+
22
+ - **Values substituted into `run.command` are shell-quoted.** A webhook context is
23
+ built from an external payload, and fields like `issue.title` or a GitHub
24
+ `pull_request` title are free text any outside contributor can set — pasted raw
25
+ into a shell command they would be a command-injection sink. Substituted values
26
+ are now single-quoted (POSIX `sh`), so a payload stays one inert argument while
27
+ the operator's own template keeps its pipes, redirects, and `&&`. On Windows,
28
+ where `exec` runs through `cmd.exe` and these quoting rules do not hold, a
29
+ `run.command` containing `{{…}}` is refused with a clear error rather than run.
30
+ `run.prompt` is unaffected — it never reaches a shell.
31
+ Source: `apps/cli/src/lib/routines.ts` (`substituteWebhookCommand`,
32
+ `assertShellSubstitutionSupported`), `apps/cli/src/lib/triggers/handlers.ts`.
33
+
34
+ - **The `Cmd-Shift-O` quick-dispatch bar now lists the repo's open Linear tickets,
35
+ and dispatches one on a click (RUSH-2098).** The panel only captured NEW work;
36
+ it now also shows what already exists. Switching the repo dropdown switches the
37
+ Linear project (the repo name is matched against `linear projects` reduced to
38
+ lowercase alphanumerics, so `agents-cli` finds "Agents CLI" with nothing to
39
+ configure; a worktree resolves to its parent repo, and a repo that matches no
40
+ project says so and lets you pick one, remembered per repo). Rows are ranked
41
+ urgent-first — Linear priority, then overdue, then in progress, then newest —
42
+ and typing filters them, so an existing ticket surfaces before Return files a
43
+ duplicate. Clicking a row (or `⌘1`–`⌘5`) dispatches that ticket to the selected
44
+ agents in the picked repo: **Run** claims it and implements it, **Plan** posts a
45
+ plan as a ticket comment. `⌘`-click opens it in Linear instead. The list renders
46
+ from a 90-second warm cache so the panel still appears instantly. Source:
47
+ `apps/cli/menubar/Sources/MenubarHelper/LinearTickets.swift`,
48
+ `apps/cli/menubar/Sources/MenubarHelper/PromptPanel.swift`,
49
+ `apps/cli/menubar/Sources/MenubarHelper/AgentsCLI.swift`.
50
+
51
+ - **Fixed: a menu-bar dispatch whose child printed more than ~64 KiB hung forever
52
+ and never notified.** The helper read a monitored child's stdout only from the
53
+ process-termination handler, so a child that filled the pipe buffer blocked on
54
+ write, never exited, and the completion callback never fired — two `linear`
55
+ processes were left wedged by a single ticket fetch. Both monitored paths (the
56
+ ticket agent and `linear create`) now drain stdout, and feed stdin, on a
57
+ background queue while the child runs. Source:
58
+ `apps/cli/menubar/Sources/MenubarHelper/AgentsCLI.swift`.
59
+
60
+ - **The daemon warns when it was launched from an ephemeral root.** A daemon
61
+ started from a temp dir (`/tmp`, `/var/folders`, `/dev/shm`) or a git worktree
62
+ resolves its own job modules by dynamic `import()` rooted at the launch entry
63
+ (`getAgentsBinPath` → `process.argv[1]`). When that directory is later removed
64
+ — a `/tmp` cleanup, a review/verify checkout teardown, `git worktree remove` —
65
+ the long-lived daemon keeps ENOENT-ing on every routine's imports
66
+ (`auto-dispatch.ts`, `routines-placement.ts`, `devices/fleet.ts`), silently
67
+ wedging until restart. `anchorDaemonCwd` already rescues the cwd, but nothing
68
+ can re-root a deleted module tree. `runDaemon` now calls
69
+ `warnEphemeralDaemonRoot` at startup, so the risk is logged the moment the
70
+ daemon comes up — including a direct `agents __daemon-run` that never passes
71
+ through the launch-time `validateDaemonBinary` check. That launch-time check is
72
+ also broadened from git-worktree-only to any ephemeral root via the shared
73
+ `describeEphemeralDaemonRoot` predicate. The fix for a wedged daemon is
74
+ unchanged: run it from the globally installed binary
75
+ (`npm i -g @phnx-labs/agents-cli`) so its entry roots at a stable version home.
76
+ Source: `apps/cli/src/lib/daemon.ts`
77
+ (`describeEphemeralDaemonRoot`, `warnEphemeralDaemonRoot`, `validateDaemonBinary`).
78
+
79
+ - **A `README.md` / `AGENTS.md` sitting in a resource directory is no longer
80
+ installed as a resource.** `listResources` skipped only dotfiles, so every `.md`
81
+ beside the actual resources was materialized as one: `commands/README.md` — which
82
+ the system repo has shipped for months — installed a bogus `/README` slash command
83
+ into every agent home, and adding per-directory `AGENTS.md` docs would have added
84
+ `/AGENTS`, `/CLAUDE`, and `/GEMINI` alongside it. `README`, `AGENTS`, `CLAUDE`, and
85
+ `GEMINI` are now filtered from both `listResources` and `resolveResource` for every
86
+ kind **except `rules`**, where `AGENTS.md` *is* the resource (the composed ruleset
87
+ that syncs as each agent's memory file). The check tests `!entry.isDirectory()`
88
+ rather than `isFile()`, because a `Dirent` for a symlink reports
89
+ `isFile() === false` and `CLAUDE.md`/`GEMINI.md` are symlinks to `AGENTS.md` by
90
+ convention — a resource *directory* named `agents/` is still a real resource.
91
+ Verified against the real installed layers: 30 commands with `README` leaking
92
+ before, 29 with none after.
93
+ - **`agents commands list` and the command picker no longer offer a name that
94
+ cannot be opened.** `listCentralCommands` and `discoverCommands`
95
+ (`src/lib/commands.ts`) run their own `readdirSync` scans rather than going
96
+ through `listResources`, so they kept offering `README` while
97
+ `agents commands view README` answered "not found" — a listed-but-unopenable
98
+ name. Both now share the one exported `isDirectoryDoc` predicate, so every
99
+ enumerator agrees. Verified: 27 names with `README` before, 26 with none after.
100
+ - **`agents commands add/remove/view` no longer suggest `README` as the example
101
+ command name.** With `README` reserved as a directory doc, the six hardcoded
102
+ examples in the help text and non-interactive hints named a command that can never
103
+ exist. They now use `plan`, which actually ships.
104
+
105
+ - **File-backed secrets bundles no longer require `AGENTS_SECRETS_PASSPHRASE` on
106
+ macOS.** The encrypted file store now silently auto-provisions a stable
107
+ machine-local key (a 0600 file under `~/.agents/.secrets-key/`, kept outside the
108
+ encrypted store) on first use on **every** platform, macOS included — no prompt,
109
+ no Touch ID, nothing to set or remember. Previously a file-backed bundle on a Mac
110
+ hard-failed unless `AGENTS_SECRETS_PASSPHRASE` was exported, which blocked
111
+ headless reads (e.g. the `auth` bundle the usage/auth reader consults) and
112
+ frequently hung. Setting `AGENTS_SECRETS_PASSPHRASE` still works and takes
113
+ precedence — use it to hold the key off disk or to share one bundle's ciphertext
114
+ across boxes under a common key. Source: `apps/cli/src/lib/secrets/filestore.ts`,
115
+ `apps/cli/src/lib/secrets/bundles.ts`.
116
+
117
+ - **Menu-bar & daemon notifications now use the current agents-cli mark, not the
118
+ legacy logo.** A desktop notification from the menu-bar helper or the routines
119
+ daemon showed the old `assets/logo.png` gradient "A" — outdated, and blank in the
120
+ notification's left-hand app-icon slot. `MenubarHelper.app`'s `AppIcon.icns` is
121
+ now generated from the current brand mark (`assets/app-icon.svg` → `app-icon.png`:
122
+ the lime-tile lowercase `a` shared with the agi-cli web favicon and the menu-bar
123
+ glyph), which drives both the notification's right-hand `contentImage` and its
124
+ left-hand app icon. The installer also registers the bundle with LaunchServices
125
+ (`lsregister -f`) at its `~/Library/Application Support` path so the OS can resolve
126
+ that app icon. Source: `apps/cli/menubar/scripts/build.sh`,
127
+ `apps/cli/src/lib/menubar/install-menubar.ts`, `assets/app-icon.svg`.
128
+
129
+ - **The menu bar is a single instance, always.** Two copies of the helper could
130
+ run at once — launchd's `KeepAlive` service plus a LaunchServices/`open` launch
131
+ of the same `.app` — putting two agents marks in the menu bar, and the second
132
+ copy could hold `Cmd-Shift-V`/`Cmd-Shift-O` (`RegisterEventHotKey` is
133
+ first-come). The helper now takes an `flock` on
134
+ `~/.agents/.cache/state/menubar.lock` at launch and holds it for its lifetime;
135
+ a helper that cannot take the lock pops the **running** helper's menu open and
136
+ exits 0, since re-launching a menu-bar app means "show me the one I already
137
+ have". An `flock` rather than a pid file: the kernel releases it when the
138
+ holder dies, so a `SIGKILL`ed helper cannot leave a stale "already running"
139
+ that blocks every later launch. Source:
140
+ `apps/cli/menubar/Sources/MenubarHelper/SingleInstance.swift`,
141
+ `apps/cli/menubar/Sources/MenubarHelper/StatusItemController.swift`.
142
+
143
+ - **`agents menubar setup` configures the menu bar end-to-end.** One idempotent
144
+ command for a machine that is wrong — never configured, helper down, or showing
145
+ a duplicate icon. It ends every running helper, installs/refreshes the bundle,
146
+ checks its code signature, writes the launchd login item (`RunAtLoad` +
147
+ `KeepAlive`), clears a previous `agents menubar disable`, and verifies exactly
148
+ one helper came back up — reporting each as its own step and exiting nonzero if
149
+ it cannot reach that state. `--check` reports without changing; `--json` emits
150
+ the step list. Source: `apps/cli/src/commands/menubar.ts`,
151
+ `apps/cli/src/lib/menubar/install-menubar.ts`.
152
+
153
+ - **`agents menubar status` now shows a duplicate.** Live helper processes were
154
+ collapsed to a boolean `running`, so two copies of the *installed* bundle — the
155
+ duplicate a user actually sees — reported as healthy. `--json` now carries an
156
+ `instances` array (copies of the installed bundle) beside the existing
157
+ `foreignInstances`, and the text readout names every extra pid and points at
158
+ `agents menubar setup`. Source:
159
+ `apps/cli/src/lib/menubar/install-menubar.ts` (`classifyMenubarProcesses`).
160
+
161
+ - **Quick-dispatch ticket list: one-row filter + sort, and a scrollable list.**
162
+ The ticket controls sit on a single row of popups next to the Linear project
163
+ (project · filter · sort) — not a chip matrix or two-column block. Quick filter
164
+ options: All open, Todo, Doing, Backlog, P1 only, P2 only, Overdue. Quick sort
165
+ options: Urgent first, Newest, Oldest, Due date, Priority (flat list, no
166
+ status grouping). Filter and sort picks are remembered across summons. Ticket
167
+ rows scroll inside a fixed viewport so more than five matches stay reachable
168
+ without growing the panel. Source:
169
+ `apps/cli/menubar/Sources/MenubarHelper/LinearTickets.swift`,
170
+ `apps/cli/menubar/Sources/MenubarHelper/PromptPanel.swift`.
171
+
172
+ - **`release.sh` now takes a release lease, and refuses to bump past an
173
+ unpublished tag.** Releases run from whichever fleet box an agent happens to be
174
+ on, so two agents could enter the pipeline at once; the collision only surfaced
175
+ at the publish gate (`merged tree != built tree -- refusing to publish`), after
176
+ one run had already merged and tagged, leaving the version merged but unshipped.
177
+ A new `scripts/release-lease.sh` holds mutual exclusion on `origin` as an orphan
178
+ commit at `refs/release-lock/held` — a second claimant's push can never be a
179
+ fast-forward, so git's rejection *is* the failed lock acquisition. The lease is
180
+ claimed before the first mutation and dropped by the existing cleanup trap on
181
+ every exit path. Because a healthy release routinely outlives any sane
182
+ expiry — the CI matrix alone has run 57 minutes and release 1.20.77 took 186
183
+ minutes — the lease is **renewed** by a background renewer for the whole run,
184
+ and the squash-merge, the tag, and the publish each **verify** ownership first,
185
+ failing closed if it can no longer be proven. A lease that stops being renewed
186
+ is reclaimable after 30 minutes, and reclaiming names the dead holder instead
187
+ of silently overwriting it. Separately,
188
+ `release.sh` now refuses to cut a new version while an older `v*` tag exists
189
+ that npm never received, and points at the re-run that finishes it — bumping
190
+ past an unpublished tag is what turned a one-version gap into npm 1.20.78 vs
191
+ main 1.20.81. Source: `apps/cli/scripts/release-lease.sh`,
192
+ `apps/cli/scripts/release.sh`.
193
+
194
+ - **`agents funnel down` disables a public Funnel port from the same wrapper used
195
+ to enable ingress.** Webhook ingress now has a complete local receiver runbook:
196
+ keep GitHub/Linear signing keys in `agents secrets`, bind the receiver to
197
+ `127.0.0.1`, expose it with `agents funnel up`, rotate one source secret at a
198
+ time, and turn the public port off with `agents funnel down` before stopping or
199
+ moving the receiver. Source: `apps/cli/src/commands/funnel.ts`,
200
+ `apps/cli/src/lib/funnel.ts`, `apps/cli/docs/03-routines.md`.
201
+
202
+ - **New `agents secrets rotate-passphrase` re-keys the encrypted file store under
203
+ a new master passphrase, atomically (RUSH-1975).** Until now there was no
204
+ supported way to rotate the file-store passphrase — `rekey` only renames macOS
205
+ keychain service names and `rotate <bundle> <key>` replaces a single secret
206
+ value, so a leaked passphrase (RUSH-1968) could only be remediated by a
207
+ hand-rolled non-atomic script or an export-to-plaintext round-trip (the exact
208
+ exposure being fixed). The new command decrypts every `<item>.enc` under the
209
+ current key, re-encrypts under a freshly generated one, and swaps both the
210
+ ciphertext and the 0600 key file by directory rename after verifying every item
211
+ round-trips. A crash at any point self-heals on the next *rotate* run to a single
212
+ readable store — content-aware recovery probes which key actually decrypts the
213
+ live store (not merely which files are present) and classifies the WHOLE store:
214
+ it completes the rotation forward or rolls back only when one key opens every
215
+ item, and if a later `secrets set` contaminated a crashed rotation into a MIXED
216
+ store (items under two keys at once, or a store dir recreated by an interstitial
217
+ write after the crash left it absent, so its backup holds items the live dir does
218
+ not) it refuses with an actionable error and preserves every recovery artifact
219
+ rather than sweeping the only copy of a key or the backed-up ciphertext — so a
220
+ crash anywhere in the swap can never orphan the store, even when a write landed in
221
+ between. The rotation and every store write run under
222
+ one cross-process lock, so a `secrets set` or a second rotation can never
223
+ interleave with a swap in the first place. No plaintext secret or passphrase is
224
+ ever written to disk, argv, or a log. Items
225
+ that don't decrypt under the current key (orphan caches, stale test artifacts)
226
+ are carried through verbatim, never re-keyed. Dry-run by default (`--commit` to
227
+ apply). A dry run never re-keys, but it *does* heal an interrupted rotation —
228
+ that is how a crashed store becomes readable again without re-keying it — and it
229
+ says so instead of claiming nothing was written. Refuses while the secrets-agent
230
+ holds live unlocks or while
231
+ `AGENTS_SECRETS_PASSPHRASE` is exported in the environment, unless `--force`.
232
+ Headless-safe and Linux-first. Source: `apps/cli/src/lib/secrets/filestore.ts`,
233
+ `apps/cli/src/commands/secrets-rotate-passphrase.ts`.
234
+
235
+ - **`agents sessions --active --json` now reports who is watching each session.**
236
+ The `viewingIn` field carries the same string the table prints — `codium tab 3`,
237
+ `ghostty tab 2`, or `detached` for a live tmux pane with **no client attached**
238
+ (its terminal was closed or crashed). It is `null` both for a session that isn't
239
+ tmux-hosted and for one whose pane the locator could not resolve — `detached` is
240
+ claimed only when the pane was actually located, so absence of evidence is never
241
+ reported as evidence of absence. Previously the JSON path returned
242
+ before the locator pass ran, so the field never appeared and a machine consumer
243
+ could not tell a session someone is looking at from an orphaned one — which is
244
+ exactly what the Factory extension's `Agents: Resume` picker ranks by. The JSON
245
+ path resolves tmux clients only — no osascript — so scriptable output keeps the
246
+ cheapness the old ordering was protecting; a Ghostty-attached client resolves as
247
+ `ghostty` without its tab number. Peers running an older CLI that still emits the
248
+ `{app, tab}` object are normalized at the fan-out boundary, so a mixed-version
249
+ fleet sweep stays correct. Source: `apps/cli/src/lib/session/viewing-in.ts`
250
+ (`viewingInLabel`, `parseViewingIn`), `apps/cli/src/commands/sessions.ts`
251
+ (`serializeActiveSessionsForJson`, `enrichTmuxLocators`),
252
+ `apps/cli/src/lib/session/remote-active.ts`.
253
+
254
+ - **Webhook handlers gain `run.env` and `host` placement.** A handler can now
255
+ inject environment variables into the process it spawns (`run.env`), and choose
256
+ where that run executes (`host`). `host` takes a device name (`yosemite-s0`), or
257
+ `fleet` to pick any eligible online worker, or `fleet/<platform>` /
258
+ `<platform>/fleet` (also a bare `linux` / `macos` / `windows`) to restrict that
259
+ pick to one platform. A fleet expression that matches no eligible device fails
260
+ loudly rather than silently falling back to the local machine, so `fleet/linux`
261
+ can never land on a macOS box. Omitting `host` runs locally, as before.
262
+ Source: `apps/cli/src/lib/triggers/handlers.ts` (`resolveHandlerHost`),
263
+ `apps/cli/src/lib/routines-placement.ts` (`pickFleetDevice` platform filter),
264
+ `apps/cli/src/lib/routines.ts` (`JobConfig.env`), `apps/cli/src/lib/runner.ts`.
265
+
266
+ ## 1.20.88
267
+
268
+ - **`agents doctor` redesigned into a prioritized, fleet-aware, per-version
269
+ readout (RUSH-2069).** Comprehensive by default (no `--verbose`): a top
270
+ `✗ CRITICAL — needs you now (N)` section lists every critical across the whole
271
+ fleet worst-first (`device · harness@version · account · message → remediation`),
272
+ then a `─── by computer ───` section gives each device its warnings plus a
273
+ compact accounts/versions line showing every installed version and its account
274
+ (provable ✓ / ✗). A single-machine `agents doctor` collapses to the CRITICAL
275
+ section plus one `▸ <machine>` block. Severity: provable logged-out, a missing
276
+ hook/plugin, a broken CLI, and a never-synced version whose declared resources
277
+ are therefore absent are CRITICAL; drift, version-skew, repo-behind/-drift,
278
+ orphans, and an unprovable logout are WARNINGS. Sign-in is
279
+ now probed **per installed version** (each version's own home + the global
280
+ credential via the new `credentialPresence`), so a per-version logged-out claim
281
+ is made only when both are absent, agents with no inspectable identity never
282
+ report logged-out, and the login remediation is
283
+ version-targeted (`agents run <agent>@<version>` for the isolated set;
284
+ gemini/antigravity/droid/cursor say the login is shared). Older fleet boxes that
285
+ can't report per-version sign-in surface an "older agents-cli — upgrade"
286
+ warning. The readout is de-duplicated so one root cause is one line: a version's
287
+ missing hooks/plugins and drifted resources collapse to a count plus two
288
+ examples (`32 hooks missing (incl. 'a', 'b')`), the same problem on several
289
+ versions of one agent reads as `claude (5 versions)` with an agent-wide fix
290
+ (isolated copies stay on their own line, since the sweep skips them), every
291
+ orphan row on a machine folds into one cleanup-only line, and a version that
292
+ already listed its drifted resources no longer also says "sources changed since
293
+ last sync". The two advisories that predate the redesign are findings now, not
294
+ separate blocks: credential-shaped exports in shell rc files (RUSH-1968) and the
295
+ Windows execution policy that blocks `agents.ps1`. The duplicate-version-home
296
+ hook check keeps its text output too — differing copies are critical, identical
297
+ ones a warning, one row per agent rather than one per hook — and so does the
298
+ Host CLIs check, as a `host CLIs` warning naming `agents cli install <name>`.
299
+ Remediations reach every version in their row: a row collapsed across versions
300
+ uses `agents sync <agent>@all --yes` (a bare `agents sync <agent>` would fix only
301
+ the default version), a cross-device resource gap says `agents repo pull` rather
302
+ than the central-to-home `agents doctor --fix`, and a diverged config repo names
303
+ its own alias instead of always saying `user`.
304
+ `agents doctor --json` adds a `findings` array and a per-version
305
+ `fleet.signIn` map; the existing `clis`/`sync`/`orphans`/`fleet`/`signIn`/`repos`
306
+ fields are unchanged. Source: `apps/cli/src/lib/devices/doctor-findings.ts`,
307
+ `apps/cli/src/lib/devices/fleet-inventory.ts`, `apps/cli/src/lib/agents.ts`,
308
+ `apps/cli/src/commands/doctor.ts`.
309
+
310
+ - **Run Cursor routines safely (RUSH-2080).** Routines configured with `agent: cursor` now reuse the same-device login under the default sandbox, trust the configured workspace without `--yolo`, warn when a requested read-only plan is elevated to writable edit mode (including `loop:` jobs), and record successful runs correctly. Source: `apps/cli/src/lib/runner.ts`.
311
+
312
+ - **`agents sessions` now discovers, indexes, and renders Cursor agent transcripts (RUSH-2081).**
313
+ Cursor writes its conversation to `projects/<encoded-cwd>/agent-transcripts/<uuid>/<uuid>.jsonl`
314
+ and metadata to `chats/<workspace-hash>/<uuid>/meta.json`. Discovery starts from the transcript
315
+ and joins metadata by UUID, so abandoned chats with no transcript never become empty rows.
316
+ Cursor is installed outside agents-cli's managed version homes, so users with any managed
317
+ agent version must pass `--unmanaged` to include Cursor rows.
318
+ Source: `apps/cli/src/lib/session/discover.ts`, `apps/cli/src/lib/session/parse.ts`.
319
+
320
+ - **Fix Cursor usage and account inspection (RUSH-2082).** `agents usage` now derives support from the usage library so Cursor, Grok, and future usage sources cannot drift from the command, and `agents run cursor@` can inspect Cursor's active account. Source: `apps/cli/src/commands/usage.ts`, `apps/cli/src/lib/agents.ts`.
321
+
322
+ - **Sync Cursor commands to the IDE and cursor-agent CLI (RUSH-2083).** Shared commands now remain available as typed IDE slash commands and are also generated as Agent Skills for cursor-agent, while preserving user-authored files in `.cursor/commands/`. Source: `apps/cli/src/lib/command-skills.ts`.
323
+
324
+ - **Daemon routines resolve `agents` on `~/.local/bin` installs.** The generated daemon service (systemd + launchd) now puts the `agents` shim's own directory on `PATH`, not only the Node runtime dir. On a box where the shim lives outside the Node bin dir (a `~/.local/bin` global install, a separate npm prefix), the daemon's `PATH` previously carried only the Node dir, so every scheduled `command` routine — the always-on watchdog included — shelled out to a bare `agents` that resolved to nothing and died with `exit 127`. Source: `apps/cli/src/lib/daemon.ts`.
325
+
3
326
  ## 1.20.87
4
327
 
5
328
  - **`agents devices enable|disable|prefer|unprefer <name>` control which machines
package/README.md CHANGED
@@ -165,7 +165,7 @@ agents run codex@ "review this branch"
165
165
 
166
166
  A trailing `@` opens an account picker before either an interactive or prompt-based run. Each installed version shows its account identity, exact version, login state, plan, and every available session, weekly, or monthly limit. Logged-out, rate-limited, and out-of-credit accounts remain visible with the reason they cannot be selected; signed-in accounts whose provider does not expose quota data stay selectable and say `limits unavailable`. The choice pins only that run and does not change your default version.
167
167
 
168
- Account selection is available for Claude, Codex, Antigravity, Grok, Kimi, Droid, and OpenCode. It requires a terminal and cannot be combined with `--resume`, `--strategy`/`--balanced`, `--lease`, or `--host`/`--device`; profiles and workflows must use their concrete host agent instead.
168
+ Account selection is available for Claude, Codex, Gemini, Cursor, Antigravity, Grok, Kimi, Droid, and OpenCode. It requires a terminal and cannot be combined with `--resume`, `--strategy`/`--balanced`, `--lease`, or `--host`/`--device`; profiles and workflows must use their concrete host agent instead.
169
169
 
170
170
  ### Chain agents
171
171
 
@@ -1002,16 +1002,24 @@ Other useful commands: `agents doctor` checks CLI availability and resource sync
1002
1002
  On macOS, `agents-cli` puts a status item in your menu bar -- a live glance at what your agents are doing, plus a Spotlight-style bar for filing work without breaking focus.
1003
1003
 
1004
1004
  ```bash
1005
- agents menubar enable # install + launch at login
1005
+ agents menubar setup # configure end-to-end: one instance, started at login
1006
1006
  agents menubar status # is it installed and running?
1007
1007
  ```
1008
1008
 
1009
+ There is only ever **one** agents mark: the helper takes a lock at launch, so a
1010
+ second copy surfaces the running one's menu and exits instead of adding a
1011
+ duplicate icon. `agents menubar setup` is the recovery command when a machine is
1012
+ already wrong -- it ends any duplicate, installs the bundle, wires the login
1013
+ item, and verifies exactly one helper came back up.
1014
+
1009
1015
  The dropdown surfaces a **NEEDS YOU** queue (agents waiting on a question, a plan review, or a permission prompt), the running roster, and a routines summary -- the same live state as `agents sessions --active`, one click away.
1010
1016
 
1011
1017
  ### Quick-issue bar (⌘⇧O)
1012
1018
 
1013
1019
  Press `Cmd-Shift-O` anywhere for a thin capture surface: type a one-line note, `Cmd-V` to paste, and attach one or more recent screenshots (double-click a thumbnail to preview it in full). Submit, and a headless agent picks the right project from your recent sessions, investigates, and files the Linear ticket itself -- you never leave what you were doing.
1014
1020
 
1021
+ The bar also lists the **open Linear tickets of the repo you picked**, urgent first. Switching the repo switches the Linear project; typing filters the list, so an existing ticket shows up before you file a duplicate; and clicking a row (or `⌘1`-`⌘5`) dispatches that ticket to the selected agents -- **Run** implements it, **Plan** posts a plan as a ticket comment.
1022
+
1015
1023
  <p align="center">
1016
1024
  <img src="assets/menubar-quickissue.svg" alt="The Cmd-Shift-O quick-issue bar: a one-line note with attached screenshot thumbnails that a headless agent turns into a filed Linear ticket" width="100%" />
1017
1025
  </p>
@@ -1116,7 +1124,7 @@ Which DotAgents resources each agent CLI can load. Source of truth: [src/lib/age
1116
1124
  | Antigravity | yes | yes | yes | yes | yes | yes | yes | no | `AGENTS.md` | no |
1117
1125
  | Grok Build | yes | yes | yes | yes | yes | skills ($name) | yes | no | `AGENTS.md` | no |
1118
1126
  | OpenClaw | yes | yes | yes | no | yes | gateway | yes | yes | `workspace/AGENTS.md` | no |
1119
- | Cursor | yes | no | yes | no | yes | yes | no | no | `.cursorrules` | no |
1127
+ | Cursor | yes | yes | yes | yes | yes | IDE + skills ($name) | yes | >= 2026.1.22 | `.cursorrules` | no |
1120
1128
  | OpenCode | yes | no | yes | >= 1.1.1 | yes | yes | no | no | `AGENTS.md` | no |
1121
1129
  | Copilot | yes | no | yes | no | yes | yes | no | no | `AGENTS.md` | no |
1122
1130
  | Amp | yes | no | yes | no | yes | yes | no | no | `AGENTS.md` | no |
@@ -1125,7 +1133,7 @@ Which DotAgents resources each agent CLI can load. Source of truth: [src/lib/age
1125
1133
  | Roo Code | yes | no | yes | no | yes | yes | no | no | `AGENTS.md` | no |
1126
1134
  | Droid | yes | yes | yes | >= 0.57.5 | >= 0.26.0 | yes | yes | yes | `AGENTS.md` | no |
1127
1135
 
1128
- **Legend:** `yes` / `no` = synced or skipped at install time. `skills ($name)` = no file-based slash-command dir; behavior ships as a generated skill invoked with `$command`. `gateway` = OpenClaw resolves slash commands at runtime, not from synced files. Version suffixes are enforced at sync time — out-of-range versions are skipped with a clear message.
1136
+ **Legend:** `yes` / `no` = synced or skipped at install time. `skills ($name)` = no file-based slash-command dir; behavior ships as a generated skill invoked with `$command`. `IDE + skills ($name)` = an IDE command file plus a generated skill for the CLI. `gateway` = OpenClaw resolves slash commands at runtime, not from synced files. Version suffixes are enforced at sync time — out-of-range versions are skipped with a clear message.
1129
1137
 
1130
1138
  **Host CLIs** (`agents cli`) are separate: YAML manifests under `~/.agents/cli/` install binaries onto your PATH (`gh`, `higgsfield`, etc.). They are not copied into per-agent version homes.
1131
1139
 
package/dist/bin/agents CHANGED
Binary file
@@ -35,7 +35,7 @@ Examples:
35
35
  agents commands add
36
36
 
37
37
  # Install specific commands by name
38
- agents commands add --names README,debug --agents codex@0.116.0
38
+ agents commands add --names plan,debug --agents codex@0.116.0
39
39
 
40
40
  When to use:
41
41
  - Project setup: 'agents commands add gh:team/commands' to sync everyone's workflow
@@ -90,7 +90,7 @@ Examples:
90
90
  agents commands add
91
91
 
92
92
  # Install specific commands to a single version
93
- agents commands add --names README,debug --agents codex@0.116.0
93
+ agents commands add --names plan,debug --agents codex@0.116.0
94
94
 
95
95
  # Pull commands from GitHub and sync to all installed agents
96
96
  agents commands add gh:user/repo --agents claude,codex,cursor
@@ -125,7 +125,7 @@ Examples:
125
125
  else {
126
126
  if (!isInteractiveTerminal()) {
127
127
  requireInteractiveSelection('Selecting commands from ~/.agents/commands/', [
128
- 'agents commands add --names README,debug --agents codex',
128
+ 'agents commands add --names plan,debug --agents codex',
129
129
  'agents commands add gh:user/repo --agents codex',
130
130
  ]);
131
131
  }
@@ -272,7 +272,7 @@ Examples:
272
272
  .addHelpText('after', `
273
273
  Examples:
274
274
  # Remove a command by name
275
- agents commands remove README
275
+ agents commands remove plan
276
276
 
277
277
  # Interactive: pick commands to remove
278
278
  agents commands remove
@@ -305,7 +305,7 @@ Examples:
305
305
  }
306
306
  if (!isInteractiveTerminal()) {
307
307
  requireInteractiveSelection('Selecting commands to remove', [
308
- 'agents commands remove README',
308
+ 'agents commands remove plan',
309
309
  ]);
310
310
  }
311
311
  try {
@@ -422,7 +422,7 @@ Examples:
422
422
  .addHelpText('after', `
423
423
  Examples:
424
424
  # View a specific command
425
- agents commands view README
425
+ agents commands view plan
426
426
 
427
427
  # Interactive picker
428
428
  agents commands view
@@ -437,7 +437,7 @@ Examples:
437
437
  }
438
438
  if (!isInteractiveTerminal()) {
439
439
  requireInteractiveSelection('Selecting a command to view', [
440
- 'agents commands view README',
440
+ 'agents commands view plan',
441
441
  ]);
442
442
  }
443
443
  try {
@@ -22,30 +22,11 @@
22
22
  * apply pending sync.
23
23
  */
24
24
  import type { Command } from 'commander';
25
- import { type FleetDivergenceReport } from '../lib/devices/fleet-divergence.js';
26
25
  import { type VersionResourceReport } from '../lib/doctor-diff.js';
27
26
  import { type DuplicateVersionHook } from '../lib/hooks.js';
28
27
  import { type SyncStatusRow, type OrphanRow } from '../lib/drift.js';
29
28
  import { type FetchStatusMarker } from '../lib/auto-pull.js';
30
29
  export declare function wrapLine(prefix: string, text: string, width?: number): string[];
31
- /**
32
- * Windows-only advisory lines. When the effective PowerShell execution policy
33
- * blocks unsigned local `.ps1` scripts (`Restricted`/`AllSigned`), the generated
34
- * `agents.ps1` launcher fails in PowerShell even when it is on PATH. Surface the
35
- * remediation; the `.cmd` companion still works, so this is a warning, not an
36
- * error, and doctor never auto-changes the policy. Pure — returns `[]` on
37
- * non-Windows or a permissive policy, so it is testable without invoking
38
- * PowerShell.
39
- */
40
- export declare function execPolicyWarningLines(platform: NodeJS.Platform, policy: string | null): string[];
41
- /**
42
- * Render the cross-device divergence section for `agents doctor --devices`
43
- * (RUSH-2027): a clean all-clear when the fleet agrees, otherwise the specific
44
- * gaps — a resource/version present here but missing on a box, or a diverged
45
- * config repo — grouped by device, each a plain-language line. Devices that
46
- * couldn't be compared (offline / older CLI) are named so the readout is honest.
47
- */
48
- export declare function renderFleetDivergence(report: FleetDivergenceReport): string[];
49
30
  export type IssueSeverity = 'critical' | 'warning' | 'info';
50
31
  /**
51
32
  * One triaged health finding. `severity`/`category`/`subject`/`impact`/`fix` are