@phnx-labs/agents-cli 1.20.90 → 1.20.92

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 (112) hide show
  1. package/CHANGELOG.md +276 -0
  2. package/README.md +1 -1
  3. package/dist/bin/agents +0 -0
  4. package/dist/commands/activity.d.ts +72 -6
  5. package/dist/commands/activity.js +198 -49
  6. package/dist/commands/beta.js +1 -0
  7. package/dist/commands/doctor.js +4 -2
  8. package/dist/commands/exec.d.ts +14 -0
  9. package/dist/commands/exec.js +144 -14
  10. package/dist/commands/feed.js +77 -4
  11. package/dist/commands/hooks.js +22 -6
  12. package/dist/commands/perf.d.ts +14 -0
  13. package/dist/commands/perf.js +221 -0
  14. package/dist/commands/projects.d.ts +12 -0
  15. package/dist/commands/projects.js +358 -0
  16. package/dist/commands/routines.js +30 -24
  17. package/dist/commands/secrets.d.ts +43 -4
  18. package/dist/commands/secrets.js +217 -32
  19. package/dist/commands/send.d.ts +5 -1
  20. package/dist/commands/send.js +1 -1
  21. package/dist/commands/sessions-picker.d.ts +15 -0
  22. package/dist/commands/sessions-picker.js +107 -13
  23. package/dist/commands/sessions-resume.d.ts +2 -0
  24. package/dist/commands/sessions-resume.js +9 -1
  25. package/dist/commands/sessions.d.ts +10 -5
  26. package/dist/commands/sessions.js +65 -27
  27. package/dist/index.js +19 -3
  28. package/dist/lib/activity.d.ts +80 -13
  29. package/dist/lib/activity.js +418 -74
  30. package/dist/lib/beta.d.ts +1 -1
  31. package/dist/lib/beta.js +1 -1
  32. package/dist/lib/catchup.d.ts +105 -0
  33. package/dist/lib/catchup.js +160 -0
  34. package/dist/lib/channels/providers/desktop.d.ts +49 -0
  35. package/dist/lib/channels/providers/desktop.js +132 -0
  36. package/dist/lib/channels/providers/index.js +2 -0
  37. package/dist/lib/daemon.js +74 -13
  38. package/dist/lib/devices/registry.d.ts +14 -0
  39. package/dist/lib/devices/registry.js +37 -0
  40. package/dist/lib/events.d.ts +12 -0
  41. package/dist/lib/events.js +122 -9
  42. package/dist/lib/exec.js +10 -0
  43. package/dist/lib/feed-broadcast.d.ts +47 -0
  44. package/dist/lib/feed-broadcast.js +65 -1
  45. package/dist/lib/feed-post.d.ts +10 -0
  46. package/dist/lib/feed-post.js +9 -3
  47. package/dist/lib/feed.d.ts +47 -1
  48. package/dist/lib/feed.js +38 -0
  49. package/dist/lib/hooks/cache.d.ts +2 -0
  50. package/dist/lib/hooks/cache.js +24 -4
  51. package/dist/lib/hosts/remote-cmd.js +4 -0
  52. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  53. package/dist/lib/menubar/install-menubar.d.ts +14 -4
  54. package/dist/lib/menubar/install-menubar.js +20 -6
  55. package/dist/lib/overdue.d.ts +14 -0
  56. package/dist/lib/overdue.js +37 -1
  57. package/dist/lib/perf/db.d.ts +25 -0
  58. package/dist/lib/perf/db.js +290 -0
  59. package/dist/lib/perf/spool.d.ts +18 -0
  60. package/dist/lib/perf/spool.js +79 -0
  61. package/dist/lib/perf/types.d.ts +45 -0
  62. package/dist/lib/perf/types.js +2 -0
  63. package/dist/lib/project-key.d.ts +44 -0
  64. package/dist/lib/project-key.js +79 -0
  65. package/dist/lib/project-root.js +16 -0
  66. package/dist/lib/project-status.d.ts +69 -0
  67. package/dist/lib/project-status.js +101 -0
  68. package/dist/lib/projects.d.ts +138 -0
  69. package/dist/lib/projects.js +301 -0
  70. package/dist/lib/remote-agents-json.d.ts +9 -0
  71. package/dist/lib/remote-agents-json.js +11 -5
  72. package/dist/lib/routines-project.js +6 -0
  73. package/dist/lib/routines.d.ts +30 -1
  74. package/dist/lib/routines.js +11 -0
  75. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  76. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  77. package/dist/lib/secrets/list-filter.d.ts +94 -0
  78. package/dist/lib/secrets/list-filter.js +245 -0
  79. package/dist/lib/session/bash-command.d.ts +53 -0
  80. package/dist/lib/session/bash-command.js +364 -0
  81. package/dist/lib/session/digest.d.ts +13 -0
  82. package/dist/lib/session/digest.js +48 -1
  83. package/dist/lib/session/discover.d.ts +1 -2
  84. package/dist/lib/session/discover.js +7 -24
  85. package/dist/lib/session/highlights.d.ts +82 -0
  86. package/dist/lib/session/highlights.js +251 -0
  87. package/dist/lib/session/parse.js +23 -1
  88. package/dist/lib/session/relative-time.d.ts +37 -0
  89. package/dist/lib/session/relative-time.js +96 -8
  90. package/dist/lib/session/remote-list.js +5 -2
  91. package/dist/lib/session/render.d.ts +9 -9
  92. package/dist/lib/session/render.js +112 -73
  93. package/dist/lib/session/types.d.ts +4 -1
  94. package/dist/lib/ssh-exec.d.ts +6 -0
  95. package/dist/lib/ssh-exec.js +10 -1
  96. package/dist/lib/startup/command-registry.d.ts +2 -0
  97. package/dist/lib/startup/command-registry.js +4 -0
  98. package/dist/lib/state.d.ts +11 -0
  99. package/dist/lib/state.js +16 -0
  100. package/dist/lib/terminal/backends/index.d.ts +10 -2
  101. package/dist/lib/terminal/backends/index.js +14 -2
  102. package/dist/lib/terminal/backends/terminal-app.d.ts +13 -0
  103. package/dist/lib/terminal/backends/terminal-app.js +73 -0
  104. package/dist/lib/terminal/index.d.ts +2 -1
  105. package/dist/lib/terminal/index.js +2 -1
  106. package/dist/lib/terminal/preferred.d.ts +89 -0
  107. package/dist/lib/terminal/preferred.js +87 -0
  108. package/dist/lib/terminal/run-surface.d.ts +82 -0
  109. package/dist/lib/terminal/run-surface.js +146 -0
  110. package/dist/lib/terminal/types.d.ts +1 -1
  111. package/dist/lib/types.d.ts +1 -1
  112. package/package.json +4 -1
package/CHANGELOG.md CHANGED
@@ -1,7 +1,283 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.20.92
4
+
5
+ - **`agents sessions` rows show creation time as well as last activity (RUSH-2107).**
6
+ The trailing time cell used to carry one unlabeled "X ago" — last activity — so a
7
+ row could not say when the session began or how long it had been alive. It now
8
+ reads `3d → 1 hour ago`: the compact creation age, then the last-activity label the
9
+ listing sorts by. Both the interactive picker and the flat/tree listings render it.
10
+ A session that ran for under a minute keeps a single field (the two halves would
11
+ name the same moment), and a terminal too narrow for both drops the creation age
12
+ rather than squeezing the topic below its floor, so rows never wrap. The picker's
13
+ detail pane spells the same facts out as `created X ago · last active Y ago ·
14
+ lasted Z`, and now derives them from the indexed session metadata when no local
15
+ transcript exists — so **remote** and not-yet-indexed sessions report their timing
16
+ instead of showing none. Source: `apps/cli/src/lib/session/relative-time.ts`,
17
+ `apps/cli/src/commands/sessions.ts`, `apps/cli/src/commands/sessions-picker.ts`.
18
+
19
+ - **Stop fleet health probes from orphaning remote processes on timeout (RUSH-2114).** `sshExecAsync` now uses a direct ssh connection whenever a `timeoutMs` is set, because a control-master outlives the local client and keeps the remote command running after we kill it. `agents doctor` also normalizes host names before excluding the local machine, so `zion.local` can no longer be self-SSH'd. Source: `apps/cli/src/lib/ssh-exec.ts`, `apps/cli/src/commands/doctor.ts`.
20
+ - **Harden menubar install against Gatekeeper rejection.** `ensureValidSignature` now checks `spctl --assess`; a Developer-ID-signed but un-notarized bundle is stripped of quarantine and re-signed ad-hoc so the launchd service does not crash-loop with "app is damaged". The release build script gained optional notarization via `MENUBAR_HELPER_NOTARIZE` and `MENUBAR_HELPER_NOTARIZE_KEYCHAIN_PROFILE`. Source: `apps/cli/src/lib/menubar/install-menubar.ts`, `apps/cli/menubar/scripts/build.sh`.
21
+
22
+ - **`agents activity` now shows the whole fleet, grouped by project.** The
23
+ question the command answers is "what are my agents doing", and agents run on
24
+ every box — but it read only the local logs unless you remembered
25
+ `--devices-all`, and printed one flat newest-first stream. Both defaults are
26
+ inverted: every run fans `activity --json` out to each reachable device and
27
+ merges the peers' streams host-tagged, then buckets them by project, one level,
28
+ no sub-grouping. `--local` scopes back to this machine, `-H/--host` to named
29
+ boxes, and `--flat` (or `--group-by none`) restores the single stream;
30
+ `--devices-all`/`--hosts-all` remain accepted so existing scripts keep working.
31
+ A peer answering the fan-out still carries the recursion guard, so it never
32
+ re-fans the fleet.
33
+
34
+ - **Each project header names the machines its work ran on.** A bucket reads
35
+ `▸ agents-cli 12 events · 4 milestones · zion, yosemite-s0` — up to three
36
+ machines by name plus a `+N` tail, so a project touched by a dozen boxes stays
37
+ one scannable line; individual rows keep their own `[host]` tag. Peers that
38
+ never answered are reported once at the end (`· 2 devices unreachable: …`)
39
+ rather than a line each above the timeline, so a missing machine is visible but
40
+ not noisy.
41
+
42
+ - **A project is now the repository, not whatever directory the agent sat in.**
43
+ A cwd resolves to the git repository containing it, so `<repo>/apps/cli` files
44
+ under `<repo>` instead of `cli`, and a worktree under
45
+ `<repo>/.agents/worktrees/<slug>` folds back into the repo it branched from.
46
+ A directory in no repo groups as itself, and a dotfiles repo at `$HOME` is not
47
+ treated as a project. The `agents sessions` overview and `agents feed post` now
48
+ share this one resolver (`lib/project-key.ts`), so a project reads identically
49
+ everywhere instead of each view folding cwds its own way.
50
+
51
+ - **`--limit` is spent on milestones, not on collapsed churn.** The default view
52
+ rolls routine `file.edited` work up to a count, so a plain slice let one busy
53
+ machine's 40 file edits hide every other device's PRs behind a single
54
+ `file edited ×40` line. The cap now bounds the milestones shown, with the
55
+ routine events inside that window riding along for the counts. `--all` still
56
+ shows routine work inline and caps every event.
57
+
58
+ - **The activity header no longer carries other subsystems' hook warnings.**
59
+ Registering the activity-log hooks surfaced every unresolved entry in the hook
60
+ manifest — a missing `inject-session-id` script, someone else's half-installed
61
+ plugin — printing five wrapped yellow lines above the timeline on every run.
62
+ Those are `agents doctor`'s job; only a failure that would leave the activity
63
+ log unwritten is reported here.
64
+
65
+ - **The menu bar's New Session opens in the terminal you actually work in.** It
66
+ hardcoded AppleScript at Terminal.app, so a Ghostty or iTerm user got a
67
+ Terminal.app window every time. It now shells `agents run <agent> --terminal`,
68
+ and the CLI resolves the terminal from the user's own live sessions — the host
69
+ app `agents sessions --active` already attributes every session to
70
+ (`ActiveSession.host`). Order: the terminal the caller is in, then the host of
71
+ the most recent live session, then the first available backend. Hosts map to
72
+ backends only where the engine can really drive them, so an undrivable host
73
+ (Warp, kitty, Cursor) falls through instead of opening the wrong app. A
74
+ tmux-hosted session (every interactive `agents run`) resolves to the app its
75
+ attached tmux client is in, via the same resolver behind
76
+ `agents sessions`' "viewing in Ghostty tab 2" — without that it would name the
77
+ multiplexer and no terminal at all. Source:
78
+ `apps/cli/src/lib/terminal/preferred.ts`,
79
+ `apps/cli/src/lib/terminal/backends/terminal-app.ts`,
80
+ `apps/cli/menubar/Sources/MenubarHelper/AgentsCLI.swift`.
81
+
82
+ - **`agents run <agent> --terminal` opens a run in a real terminal tab.** For a
83
+ caller that cannot host a TUI (the menu bar, a script). Without a value the
84
+ terminal is detected as above; `--terminal <backend>` forces one
85
+ (`iterm | ghostty | terminal | tmux | vscodium-agent`) and errors on an unknown
86
+ id rather than silently auto-detecting. The tab re-invokes the same argv with
87
+ the flag stripped, so `--mode`, `--cwd`, and a `--` passthrough ride along.
88
+ Cannot combine with `--host`. Source: `apps/cli/src/lib/terminal/run-surface.ts`,
89
+ `apps/cli/src/commands/exec.ts`.
90
+
91
+ - **Terminal.app is a real launch backend now (`terminal`).** Registered last, so
92
+ it is the every-Mac floor without outranking a terminal the user chose to
93
+ install, and reported unavailable over SSH where `osascript` cannot reach the
94
+ GUI login. It has no scriptable split, so a split request opens a tab, and
95
+ `agents sessions resume --splits` now says so instead of quietly producing
96
+ tabs. `detectCurrentBackend` also recognizes `TERM_PROGRAM=Apple_Terminal`.
97
+ Source: `apps/cli/src/lib/terminal/backends/terminal-app.ts`.
98
+
99
+ - **`agents sessions resume` / `sessions focus` reach Terminal.app too.** Adding
100
+ it to the backend registry changes both: on a Mac with neither iTerm, Ghostty,
101
+ nor VSCodium installed they used to fall back to resuming in the current
102
+ process, and now open a Terminal.app tab; `resume`'s interactive picker gains a
103
+ Terminal row, and `--terminal-app` forces it (named apart from
104
+ `run --terminal`, which means something different). Source:
105
+ `apps/cli/src/commands/sessions-resume.ts`, `apps/cli/src/commands/focus.ts`.
106
+
107
+ - **New Task… in the menu bar.** A row above New Session that opens the
108
+ quick-dispatch bar — the same panel as `Cmd-Shift-O`, now reachable without the
109
+ chord (and without the Accessibility grant the chord needs). The status item
110
+ owns the one panel instance, so an interrupted capture is restored whichever
111
+ entry point you return through. Source:
112
+ `apps/cli/menubar/Sources/MenubarHelper/StatusItemController.swift`.
113
+
114
+ - **Activity, feed posts, and the sessions overview now speak defined project
115
+ names.** One resolver (`resolveProjectNameForCwd`, `lib/projects.ts`) backs all
116
+ three: a cwd inside a defined project (`~/.agents/projects/<name>.yaml`) reads
117
+ as the project's name — a multi-repo project is a single bucket in `agents
118
+ activity`, not one per repo — and anything else falls back to the
119
+ repository-level key, so nothing changes without definitions. Each peer
120
+ resolves its own cwds against its synced definitions before events cross the
121
+ wire. Source: `apps/cli/src/lib/projects.ts`, `apps/cli/src/commands/activity.ts`.
122
+
123
+ - **`agents activity --project <name>`** narrows the fleet stream to one project,
124
+ exact-matched on the resolved label — one project's PRs, plans, and worktrees
125
+ across every box without the rest of the fleet's noise. Source:
126
+ `apps/cli/src/lib/activity.ts` (`filterActivityByProject`).
127
+
128
+ - **`agents projects` — named multi-repo projects with a project progress rollup (beta).**
129
+ Define a project once in `~/.agents/projects/<name>.yaml` (name, home-relative
130
+ root/defaultPath, multiple repos with monorepo subpaths, described `contexts[]`
131
+ starting points, external `integrations[]`, Linear link) and `agents run --project
132
+ <name>` resolves the definition before the old `<root>/<slug>` convention — undefined
133
+ slugs behave exactly as before. The headline is `agents projects status`: instead of a
134
+ per-agent activity line, it renders one card per project — live agents by state, plan
135
+ completion, open **and** recently-merged PRs, tickets in flight, and the artifacts
136
+ agents produced — by rolling up signals already on disk (live agents matched to a project
137
+ by this machine's session cwd; the merged-PR count is repo-global via `gh`). `--window
138
+ <days>` and `--no-remote`
139
+ tune the PR/artifact lookup. Also `list` / `add` (infers root + origin slug) / `show` /
140
+ `edit` / `import --from-factory` (absorbs the Factory `projects.json` registry) / `rm`.
141
+ Enable with `agents beta enable projects`. Source: `apps/cli/src/lib/projects.ts`,
142
+ `apps/cli/src/lib/project-status.ts`, `apps/cli/src/commands/projects.ts`,
143
+ `apps/cli/src/lib/project-root.ts`.
144
+
145
+ - **The cross-fleet session sweep no longer hides sessions on manually-registered devices.** `agents sessions` fan-out (and therefore `--resolve`, cross-machine resume, and `--active`) picked peers with a strict `tailscale.online === true` test. A device registered with `address.via: "manual"` never gets a Tailscale peer entry at all, so its `online` stayed `undefined` and the sweep skipped it **permanently** — every session on that box was invisible and could not be resolved or resumed from any other machine. Peer selection is now `isDialableDevice`, a union of both liveness signals: a device with no Tailscale block is unknown-not-offline (the rule `ssh.ts` `renderDeviceTable` and Factory's `isDeviceOnline` already used, so the picker and the sweep finally agree on who exists), and a positive live SSH probe (`DeviceProfile.reachability`, RUSH-1965) additionally rescues a device whose snapshot says offline. A **failed** probe deliberately does not remove a peer — the probe runs on a short SSH budget and returns false negatives on a congested tailnet (observed calling the local machine unreachable), and letting that shrink the sweep would hide sessions on healthy boxes. Applied to both sweeps that share this shape. Source: `apps/cli/src/lib/devices/registry.ts` (`isDialableDevice`), `apps/cli/src/lib/session/remote-list.ts`, `apps/cli/src/lib/remote-agents-json.ts`.
146
+
147
+ ## 1.20.91
148
+
149
+ - **An agent can now say it is stuck: `agents feed post --blocked` (RUSH-2110).** The
150
+ feed carried benign progress but had no way to signal "I cannot proceed", so agents
151
+ hand-rolled it into the status text (`NEEDS MUQSIT: …`) and it reached nobody. A
152
+ blocked post writes `status.blocked` to the shared activity stream *and* opens an
153
+ answerable block in the ledger, so the ask stays open until someone resolves it
154
+ instead of scrolling away. It is a flag on the existing verb, not a new command —
155
+ one thing for an agent to learn, and one stream where most posts are benign and
156
+ some need a human. Blocked is a state, not a volume: it always broadcasts at
157
+ `important`, so passing `--level` too is a usage error rather than a silent
158
+ override. Pair it with `--option` for an answerable choice or `--default` for a
159
+ safe fallback policy may apply. Source: `apps/cli/src/commands/feed.ts`,
160
+ `apps/cli/src/lib/feed.ts`.
161
+ - **Feed blocks are actually delivered.** `publishBlock` wrote every "needs you"
162
+ record to the ledger and stopped there — `broadcastPostedEvent` ran only for
163
+ `feed post`, so a block was durable and invisible at the same time. Blocks now
164
+ reach the configured `feed.broadcast` sinks, carrying the ask and the literal
165
+ `agents focus <id>` command that unblocks it, and a block that reaches nobody
166
+ exits non-zero instead of looking like a success. Source:
167
+ `apps/cli/src/lib/feed-broadcast.ts`.
168
+ - **New `desktop` channel provider.** `agents send --channel desktop` (and
169
+ `notify.owner.channel: desktop`) posts a native notification through the branded
170
+ menu-bar helper. It is the only channel with no external dependency — no network,
171
+ no login, no vendor CLI — so it still reaches you at your Mac when a messaging
172
+ gateway is down. It reports real deliverability rather than always succeeding:
173
+ on Linux it probes for `notify-send` instead of trusting the platform name.
174
+ Source: `apps/cli/src/lib/channels/providers/desktop.ts`.
175
+
176
+ - **`agents perf` — disposable SQLite latency warehouse.** Indexed p50/p99
177
+ rollups for hooks, CLI commands, and `agent.run` timings without scanning the
178
+ audit JSONL. Warehouse lives at `~/.agents/.cache/perf/perf.db` (safe to wipe);
179
+ identity columns reuse sessions/events string shapes (`session_id`, `agent`,
180
+ `machine`, …) for soft cross-reference — no foreign keys. Hook shims spool
181
+ into the same DB; `agents hooks profile` reads it first. Source:
182
+ `apps/cli/src/lib/perf/db.ts`, `apps/cli/src/commands/perf.ts`.
183
+
184
+ - **A routine that misses its fire now runs late instead of being silently lost.** Fires
185
+ are in-process croner timers, and croner only ever schedules forward from "now" — so a
186
+ daemon that was down, asleep, or wedged when a routine came due dropped that fire
187
+ outright, and `loadAll()` rebuilt every timer looking only at the future. Detection
188
+ existed but ran **once, at daemon startup**, and only logged a warning plus a
189
+ notification; catching up was a manual `agents routines catchup`. Observed cost: zion's
190
+ daemon was down from 02:03Z to 08:23Z while the laptop slept, `weekly-fleet-retro` was
191
+ armed for exactly 04:00Z, never ran, and the restart logged `2 routine(s) overdue` and
192
+ did nothing. The daemon now re-scans every 5 minutes as well as at startup and runs each
193
+ missed routine via the same detached path `catchup` already used. Source:
194
+ `apps/cli/src/lib/catchup.ts`, `apps/cli/src/lib/daemon.ts`.
195
+ - **New `catchup:` routine field, and `agents routines add --no-catchup`.** Defaults to
196
+ true — a routine you scheduled is one you expect to have run. Set `catchup: false` for a
197
+ routine whose worth expires with its slot (a 9am brief is useless at 3pm); the miss is
198
+ still recorded, it just is not re-run. `agents routines list --json` reports the
199
+ effective value as `catchup`.
200
+ - **New `missed` run status.** A missed fire previously left no trace anywhere — no run
201
+ record, no log line in the routine's history — so `agents routines list` kept showing the
202
+ previous run's `completed` as though it were current, sometimes for weeks. A miss is now
203
+ written as a real run stamped at the moment the fire was due, so `agents routines runs
204
+ <name>` shows the gap, and the listing renders it distinctly from `failed` (a miss is an
205
+ infrastructure problem, not a task failure). That record is also what makes catch-up
206
+ idempotent: it advances the overdue comparison, so the same missed fire is never
207
+ reconsidered across ticks or a daemon restart storm, and its directory is created with a
208
+ non-recursive `mkdir` — an atomic claim, so if the daemon's timer and a manual
209
+ `agents routines catchup` overlap, only one of them runs the routine. Source: `apps/cli/src/lib/routines.ts` (`RunMeta`),
210
+ `apps/cli/src/commands/routines.ts`.
211
+ - **A routine is never caught up for a fire that predates it.** `detectOverdueJobs` walks back
212
+ a week for the most recent expected occurrence, and a routine with no runs is overdue by
213
+ definition — so before this, `agents routines add` on any daily or weekly schedule whose slot
214
+ had already passed made the routine instantly "overdue". That was cosmetic while catch-up was
215
+ a manual command; with the daemon now catching up automatically it would have run every newly
216
+ created routine once, within five minutes of creating it. Routines gain a `createdAt` stamp
217
+ (written once, like `actor`), and overdue detection floors the expected fire at it — falling
218
+ back to the routine file's mtime for routines written before the field existed. Observed on
219
+ the live fleet: `agents-cli-updates`, created Aug 1 and never run, was flagged overdue for a
220
+ Jul 27 fire. Source: `apps/cli/src/lib/overdue.ts` (`routineEffectiveStart`),
221
+ `apps/cli/src/lib/routines.ts` (`writeJob`).
222
+
223
+ - **`agents secrets list` can be filtered.** It had no filtering at all —
224
+ `--host` picks a machine and `--json` picks a format, but nothing selected over
225
+ the bundles themselves, so "which of these read with no Touch ID?", "which
226
+ still store a raw value inline?", "what have I not touched in three months?"
227
+ meant piping the table through `grep` or went unanswered. There is now an axis
228
+ per question: a `[query]` positional over name and description, `--policy`,
229
+ `--backend`, `--type`, `--kind`, `--held`/`--not-held`, `--expired`,
230
+ `--expiring [days]`, `--unused <duration>`, plus `--sort` and `-n/--limit`.
231
+ Every axis narrows independently, so they compose. Following the `agents
232
+ sessions` house style, an unknown value is a loud error naming the valid set
233
+ rather than an empty list, filters apply before `--json` so the payload is the
234
+ exact twin of the table, and they are forwarded over `--host` so a remote list
235
+ narrows the same way. `--held`/`--not-held` read live broker state and so
236
+ refuse to run off macOS instead of reporting every bundle as unheld. An empty
237
+ result names the filters that emptied it and the total it started from. Source:
238
+ `apps/cli/src/lib/secrets/list-filter.ts`, `apps/cli/src/commands/secrets.ts`.
239
+
240
+ - **The EXPIRING column no longer hides keys that have already expired.**
241
+ `countExpiringSoon` counted only keys due in the next 30 days — the guard is
242
+ `d >= 0` — so a bundle whose token died last month rendered `-`, identical to
243
+ one with no expiry at all. The only places a lapsed key surfaced were
244
+ `agents secrets view` and a hard abort at inject time, i.e. after it had already
245
+ broken a run. The column now counts lapsed and upcoming together and turns red
246
+ once anything has lapsed, and `secrets list --json` gains an `expired` count
247
+ alongside the existing `expiringSoon`. Source: `apps/cli/src/commands/secrets.ts`.
248
+
249
+ - **`agents secrets list` now states the hold window instead of the bare word
250
+ `hold`.** The `hold` tier is a duration — prompt once, then stay silent for
251
+ `secrets.agent.holdMs` (7 days by default) — but the POLICY column printed only
252
+ the tier name, so a reader could not tell it meant a window, let alone which
253
+ one; finding out meant running `agents secrets status`. The column now reads
254
+ `hold 7d`, and `hold 7d · held 6d` while the broker is actually caching the
255
+ bundle. It follows the configured window, so a 24-hour hold reads `hold 1d`.
256
+ `always` and `never` are unchanged — neither has a window, and annotating one
257
+ would repeat the mistake the `daily` rename fixed. Two adjacent bugs go with
258
+ it: `agents secrets view` printed "7d by default" as a string literal and so
259
+ misstated the window for anyone who had configured `holdMs`, and a stale broker
260
+ entry past its expiry rendered as `hold · held expired` because the column
261
+ tested the entry for presence rather than liveness. `secrets list --json` and
262
+ `secrets view --json` gain an additive `holdMs` field (null on `always`/`never`)
263
+ so a machine caller gets the window too. Source:
264
+ `apps/cli/src/commands/secrets.ts`.
265
+
266
+ - **Richer session previews: skills, hooks, links, artifacts, repos, todo status.** The `agents sessions` quick preview and full summary now show the skills a session invoked (with counts), the hooks that fired (Claude transcripts, with repeat counts and failures), a clickable Links section (Linear/Jira/GitHub/GitLab URLs harvested from the conversation), the documents the session produced (`.agents/artifacts|plans|reports` and other `*.md`/`*.html` creations), the repos it worked in (via `.git` walk-up), and an error tally in the picker. The full summary's Plan section now marks checklist items `[x]`/`[>]`/`[ ]` and renders the checklist alongside the ExitPlanMode text instead of hiding it. Changes/Dirs lines collapse `.agents/worktrees/<slug>` prefixes to `⧉ <slug>/…`, are width-capped, and no longer list shell junk (`2>&1`, `$VAR` paths), `node_modules`, or agents-cli internal archives. Source: `apps/cli/src/lib/session/highlights.ts`, `apps/cli/src/lib/session/parse.ts`, `apps/cli/src/lib/session/render.ts`, `apps/cli/src/commands/sessions-picker.ts`.
267
+
3
268
  ## 1.20.90
4
269
 
270
+ - **Bash commands are now parsed and classified for richer activity summaries.** The
271
+ `11-activity-log.py` hook tokenizes every Bash tool call and emits a structured
272
+ `bash.executed` activity record with `category`, `bashTool`, and `bashAction`.
273
+ High-signal commands also raise milestones: `video.rendered`/`video.converted`
274
+ for `ffmpeg`, `image.upscaled` for `realesrgan`/`waifu2x`/`swin2sr`, and
275
+ `metadata.edited` for `exiftool`/`id3v2`/`metaflac`/`vorbiscomment`. The session
276
+ renderer and digest use the shared `lib/session/bash-command.ts` classifier.
277
+ Source: `apps/cli/src/lib/session/bash-command.ts`,
278
+ `apps/cli/src/lib/activity.ts`, `apps/cli/src/lib/session/digest.ts`,
279
+ `apps/cli/src/lib/session/render.ts`.
280
+
5
281
  - **`agents sessions --active` now shows one row per agent, not one per directory.**
6
282
  A live tmux agent pane whose durable identity records were missing (the common case
7
283
  once meta/pid-registry entries age out) was dropped, then re-surfaced by the ps-scan
package/README.md CHANGED
@@ -288,7 +288,7 @@ Filters **stack** (they AND together), the active set shows in the header, and t
288
288
 
289
289
  Each live session resolves to `working`, `waiting_input` (with why -- a question, a plan review, or a permission prompt), or `idle`, alongside badges for the PR it opened, the worktree it sits in, and the ticket it's working. `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.
290
290
 
291
- 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, and the last test verdict -- the signals to reload a task in seconds.
291
+ 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.
292
292
 
293
293
  ### Resume anywhere — and stay resumed
294
294
 
package/dist/bin/agents CHANGED
Binary file
@@ -8,14 +8,80 @@
8
8
  * it tails the logs and collapses routine work to counts, surfacing milestones
9
9
  * individually and newest-first.
10
10
  *
11
- * Fleet-wide by opt-in: `--devices-all` (or `--host <box>`) fans the same
12
- * `activity --json` payload out across the fleet the way `agents feed` does,
13
- * merges every peer's stream host-tagged, and joins each item to live sessions
14
- * (project / ticket / execution host) so `--group-by project` shows, per
15
- * project, what each agent did, where, and for which ticket -- progress at a
16
- * glance. Local-only stays the default.
11
+ * Fleet-wide and project-grouped BY DEFAULT: the question this command answers
12
+ * is "what are my agents doing", and agents run on every box, so a local-only
13
+ * flat stream answered a narrower question than anyone asked. Each run fans the
14
+ * same `activity --json` payload out across the fleet the way `agents feed`
15
+ * does, merges every peer's stream host-tagged, joins each item to live sessions
16
+ * (project / ticket / execution host), and buckets it by project -- one level,
17
+ * no sub-grouping, with the machines named in each project's header.
18
+ *
19
+ * `--local` scopes back to this machine, `--host <box>` to named peers, and
20
+ * `--flat` (or `--group-by none`) restores the single newest-first stream.
17
21
  */
18
22
  import type { Command } from 'commander';
23
+ import { type ActivityGroupBy } from '../lib/activity.js';
19
24
  /** Recursion guard: a peer answering a fan-out never re-fans-out itself. */
20
25
  export declare const ACTIVITY_NO_FANOUT_ENV = "AGENTS_ACTIVITY_LOCAL";
26
+ interface ActivityOpts {
27
+ json?: boolean;
28
+ all?: boolean;
29
+ milestones?: boolean;
30
+ limit: number;
31
+ since?: number;
32
+ local?: boolean;
33
+ host?: string[];
34
+ device?: string[];
35
+ devicesAll?: boolean;
36
+ hostsAll?: boolean;
37
+ groupBy?: string;
38
+ flat?: boolean;
39
+ project?: string;
40
+ filter?: string;
41
+ }
42
+ /**
43
+ * Does this hook-registration error concern one of the activity-log hooks?
44
+ * `registerHooksToSettings` prefixes each error with the manifest hook name
45
+ * (`<name>: script not found`), so the entry names are the discriminator.
46
+ */
47
+ export declare function isActivityHookError(error: string): boolean;
48
+ /**
49
+ * Is this error attributable to a named manifest hook at all? Errors that name
50
+ * no hook — `Failed to parse settings.json`, `Failed to write
51
+ * agents-cli-hooks.ts: …` — are agent-level aborts, not per-hook noise, and
52
+ * must never be filtered out.
53
+ */
54
+ export declare function isManifestHookError(error: string, manifestNames: string[]): boolean;
55
+ /**
56
+ * One compact trailing note for peers that didn't answer the fan-out. Now that
57
+ * every run dials the fleet, an offline box is routine -- but never silent: the
58
+ * reader has to know the timeline is missing a machine, not that the machine
59
+ * was idle. Empty string when everything answered.
60
+ */
61
+ export declare function formatUnreachableNote(skipped: string[]): string;
62
+ /**
63
+ * Resolve `--group-by` / `--flat` into the grouping dimension, or `undefined`
64
+ * for a flat stream. Throws on an unknown value so the caller can exit 1 --
65
+ * a mistyped dimension must not silently fall back to the default.
66
+ */
67
+ export declare function resolveActivityGrouping(opts: Pick<ActivityOpts, 'groupBy' | 'flat'>): ActivityGroupBy | undefined;
68
+ /** Which machines an invocation reads from. Pure -- no SSH, no device registry. */
69
+ export interface ActivityScope {
70
+ /** Read this box's own activity logs. */
71
+ includeLocal: boolean;
72
+ /** Dial peers over SSH. */
73
+ wantRemote: boolean;
74
+ /** Peers to dial; `undefined` means "every reachable device". */
75
+ remoteHosts?: string[];
76
+ }
77
+ /**
78
+ * Decide the read scope. Fleet-wide is the DEFAULT -- agents run on every box,
79
+ * so "what are my agents doing" is a fleet question -- and three things narrow
80
+ * it: `--local`, an explicit `--host`/`--device` list, and the recursion guard
81
+ * a peer answering a fan-out carries (else every peer would re-fan the fleet).
82
+ * `--devices-all`/`--hosts-all` are kept as explicit no-ops for scripts that
83
+ * already pass them.
84
+ */
85
+ export declare function resolveActivityScope(opts: Pick<ActivityOpts, 'local' | 'host'>, self: string, noFanoutEnv?: boolean): ActivityScope;
21
86
  export declare function registerActivityCommand(program: Command): void;
87
+ export {};