@phnx-labs/agents-cli 1.20.77 → 1.20.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +589 -0
- package/README.md +27 -25
- package/dist/bin/agents +0 -0
- package/dist/commands/activity.d.ts +9 -0
- package/dist/commands/activity.js +153 -24
- package/dist/commands/apply.js +11 -4
- package/dist/commands/cli.js +1 -1
- package/dist/commands/commands.d.ts +1 -1
- package/dist/commands/commands.js +7 -6
- package/dist/commands/defaults.js +3 -11
- package/dist/commands/doctor.d.ts +74 -0
- package/dist/commands/doctor.js +718 -40
- package/dist/commands/events.js +1 -1
- package/dist/commands/exec.js +53 -8
- package/dist/commands/feed.d.ts +4 -0
- package/dist/commands/feed.js +87 -11
- package/dist/commands/harness.js +2 -2
- package/dist/commands/hooks.js +1 -1
- package/dist/commands/import.js +8 -4
- package/dist/commands/logs.js +6 -0
- package/dist/commands/models.js +1 -1
- package/dist/commands/packages.js +6 -6
- package/dist/commands/permissions.js +1 -1
- package/dist/commands/profiles.js +1 -1
- package/dist/commands/pull.d.ts +1 -1
- package/dist/commands/pull.js +4 -4
- package/dist/commands/repo.d.ts +78 -0
- package/dist/commands/repo.js +195 -11
- package/dist/commands/routines.js +16 -4
- package/dist/commands/rules.js +13 -12
- package/dist/commands/secrets.d.ts +3 -1
- package/dist/commands/secrets.js +108 -34
- package/dist/commands/sessions-browser.d.ts +45 -3
- package/dist/commands/sessions-browser.js +118 -12
- package/dist/commands/sessions-export.d.ts +3 -0
- package/dist/commands/sessions-export.js +13 -10
- package/dist/commands/sessions-inject.d.ts +7 -4
- package/dist/commands/sessions-inject.js +18 -18
- package/dist/commands/sessions-picker.d.ts +15 -1
- package/dist/commands/sessions-picker.js +90 -7
- package/dist/commands/sessions-resume.d.ts +16 -0
- package/dist/commands/sessions-resume.js +14 -13
- package/dist/commands/sessions.d.ts +126 -1
- package/dist/commands/sessions.js +365 -42
- package/dist/commands/set.d.ts +15 -0
- package/dist/commands/set.js +79 -0
- package/dist/commands/setup-fleet.d.ts +21 -0
- package/dist/commands/setup-fleet.js +201 -0
- package/dist/commands/setup-secrets.d.ts +20 -0
- package/dist/commands/setup-secrets.js +223 -0
- package/dist/commands/setup.js +17 -3
- package/dist/commands/skills.js +1 -1
- package/dist/commands/ssh.js +9 -1
- package/dist/commands/sync.js +7 -2
- package/dist/commands/teams-picker.js +0 -1
- package/dist/commands/teams.d.ts +33 -1
- package/dist/commands/teams.js +208 -44
- package/dist/commands/versions.js +10 -5
- package/dist/commands/view.d.ts +1 -0
- package/dist/commands/view.js +11 -0
- package/dist/index.js +8 -13
- package/dist/lib/acp/harnesses.js +0 -7
- package/dist/lib/activity.d.ts +156 -0
- package/dist/lib/activity.js +282 -0
- package/dist/lib/agents.d.ts +9 -23
- package/dist/lib/agents.js +72 -100
- package/dist/lib/auto-pull.d.ts +16 -8
- package/dist/lib/auto-pull.js +23 -28
- package/dist/lib/browser/service.js +3 -0
- package/dist/lib/browser/types.d.ts +7 -0
- package/dist/lib/capabilities.js +6 -2
- package/dist/lib/crabbox/lease.js +2 -2
- package/dist/lib/crabbox/setup-copy.d.ts +4 -4
- package/dist/lib/crabbox/setup-copy.js +4 -4
- package/dist/lib/daemon.d.ts +26 -40
- package/dist/lib/daemon.js +63 -123
- package/dist/lib/devices/fleet-divergence.d.ts +101 -0
- package/dist/lib/devices/fleet-divergence.js +188 -0
- package/dist/lib/devices/fleet-inventory.d.ts +19 -0
- package/dist/lib/devices/fleet-inventory.js +57 -0
- package/dist/lib/devices/fleet.d.ts +1 -1
- package/dist/lib/devices/fleet.js +1 -1
- package/dist/lib/devices/health-report.d.ts +10 -2
- package/dist/lib/devices/health-report.js +32 -1
- package/dist/lib/doctor-diff.d.ts +20 -0
- package/dist/lib/doctor-diff.js +6 -1
- package/dist/lib/drift.d.ts +31 -11
- package/dist/lib/drift.js +58 -7
- package/dist/lib/events.d.ts +8 -1
- package/dist/lib/events.js +10 -1
- package/dist/lib/exec.js +35 -8
- package/dist/lib/feed-post.d.ts +28 -1
- package/dist/lib/feed-post.js +110 -2
- package/dist/lib/fleet/apply.js +8 -1
- package/dist/lib/fleet/auth-sync.d.ts +18 -1
- package/dist/lib/fleet/auth-sync.js +25 -11
- package/dist/lib/fleet/remote-login.js +5 -0
- package/dist/lib/git.d.ts +27 -14
- package/dist/lib/git.js +138 -43
- package/dist/lib/hooks.d.ts +42 -0
- package/dist/lib/hooks.js +137 -93
- package/dist/lib/hosts/dispatch.d.ts +28 -1
- package/dist/lib/hosts/dispatch.js +33 -5
- package/dist/lib/hosts/option.js +2 -2
- package/dist/lib/hosts/passthrough.d.ts +22 -1
- package/dist/lib/hosts/passthrough.js +238 -13
- package/dist/lib/hosts/remote-cmd.js +2 -0
- package/dist/lib/hosts/run-target.d.ts +2 -0
- package/dist/lib/hosts/run-target.js +1 -0
- package/dist/lib/hq/floor.d.ts +1 -1
- package/dist/lib/hq/floor.js +6 -1
- package/dist/lib/mcp.js +3 -71
- package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +2 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +15 -2
- package/dist/lib/menubar/notify-desktop.d.ts +15 -0
- package/dist/lib/menubar/notify-desktop.js +41 -5
- package/dist/lib/merged-resources.d.ts +11 -0
- package/dist/{commands/resources.js → lib/merged-resources.js} +11 -19
- package/dist/lib/permissions.d.ts +0 -32
- package/dist/lib/permissions.js +4 -157
- package/dist/lib/picker.js +1 -1
- package/dist/lib/platform/process.d.ts +16 -5
- package/dist/lib/platform/process.js +54 -0
- package/dist/lib/plugins.d.ts +0 -8
- package/dist/lib/plugins.js +4 -110
- package/dist/lib/project-resources.js +4 -1
- package/dist/lib/refresh.d.ts +5 -3
- package/dist/lib/refresh.js +7 -5
- package/dist/lib/resources/commands.js +4 -1
- package/dist/lib/resources/mcp.js +0 -4
- package/dist/lib/resources/permissions.d.ts +1 -1
- package/dist/lib/resources/permissions.js +1 -5
- package/dist/lib/resources/rules.js +4 -1
- package/dist/lib/resources/skills.js +4 -1
- package/dist/lib/resources/subagents.js +4 -0
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/routines.d.ts +20 -0
- package/dist/lib/routines.js +6 -0
- package/dist/lib/run-defaults.d.ts +1 -0
- package/dist/lib/run-defaults.js +9 -0
- package/dist/lib/runner.d.ts +0 -12
- package/dist/lib/runner.js +71 -29
- package/dist/lib/sandbox.js +0 -16
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +2 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +13 -1
- package/dist/lib/secrets/agent.d.ts +18 -0
- package/dist/lib/secrets/agent.js +131 -17
- package/dist/lib/secrets/audit.d.ts +46 -0
- package/dist/lib/secrets/audit.js +56 -0
- package/dist/lib/secrets/bundles.d.ts +12 -9
- package/dist/lib/secrets/bundles.js +47 -31
- package/dist/lib/secrets/index.d.ts +2 -1
- package/dist/lib/secrets/index.js +8 -2
- package/dist/lib/secrets/remote.d.ts +75 -2
- package/dist/lib/secrets/remote.js +139 -5
- package/dist/lib/secrets/scope.d.ts +26 -0
- package/dist/lib/secrets/scope.js +29 -0
- package/dist/lib/secrets/session-store.d.ts +10 -0
- package/dist/lib/secrets/session-store.js +64 -11
- package/dist/lib/secrets/sync.js +3 -3
- package/dist/lib/session/active.d.ts +117 -26
- package/dist/lib/session/active.js +199 -53
- package/dist/lib/session/actor-sidecar.d.ts +23 -0
- package/dist/lib/session/actor-sidecar.js +101 -0
- package/dist/lib/session/db.d.ts +41 -1
- package/dist/lib/session/db.js +173 -8
- package/dist/lib/session/digest.js +126 -21
- package/dist/lib/session/discover.d.ts +19 -2
- package/dist/lib/session/discover.js +32 -11
- package/dist/lib/session/hook-sessions.d.ts +9 -0
- package/dist/lib/session/hook-sessions.js +57 -8
- package/dist/lib/session/origin-machine.d.ts +18 -0
- package/dist/lib/session/origin-machine.js +34 -0
- package/dist/lib/session/pid-registry.d.ts +13 -0
- package/dist/lib/session/render.d.ts +2 -0
- package/dist/lib/session/render.js +1 -1
- package/dist/lib/session/state.d.ts +1 -0
- package/dist/lib/session/state.js +1 -1
- package/dist/lib/session/sync/config.js +2 -2
- package/dist/lib/session/types.d.ts +16 -0
- package/dist/lib/smart-launch.d.ts +86 -0
- package/dist/lib/smart-launch.js +172 -0
- package/dist/lib/staleness/detectors/commands.js +2 -2
- package/dist/lib/staleness/detectors/permissions.js +1 -45
- package/dist/lib/staleness/writers/commands.js +4 -5
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/startup/command-registry.d.ts +1 -2
- package/dist/lib/startup/command-registry.js +2 -4
- package/dist/lib/subagents-registry.js +5 -12
- package/dist/lib/subagents.d.ts +0 -10
- package/dist/lib/subagents.js +0 -12
- package/dist/lib/teams/agents.d.ts +0 -2
- package/dist/lib/teams/agents.js +10 -27
- package/dist/lib/teams/index.d.ts +1 -1
- package/dist/lib/teams/index.js +1 -1
- package/dist/lib/types.d.ts +17 -9
- package/dist/lib/usage.d.ts +28 -5
- package/dist/lib/usage.js +271 -8
- package/dist/lib/versions.js +7 -1
- package/dist/lib/watchdog/watchdog.d.ts +1 -1
- package/dist/lib/watchdog/watchdog.js +25 -13
- package/package.json +1 -2
- package/dist/commands/check.d.ts +0 -15
- package/dist/commands/check.js +0 -180
- package/dist/commands/resources.d.ts +0 -5
- package/dist/lib/secrets/account-token.d.ts +0 -20
- package/dist/lib/secrets/account-token.js +0 -64
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,594 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.20.82
|
|
4
|
+
|
|
5
|
+
- **Codex hook sync no longer leaves startup warnings after upgrades.** The Codex
|
|
6
|
+
hook registrar now prunes hook commands from sibling Codex version homes before
|
|
7
|
+
writing `hooks.json`, so removed versions such as `0.142.0` cannot leave dead
|
|
8
|
+
PreToolUse/Stop handlers that exit `127`. It also writes `SessionEnd` hook
|
|
9
|
+
timeouts at Codex's 3-second limit instead of emitting `timeout: 5` and making
|
|
10
|
+
Codex warn that it is clamping the value on every startup. Source:
|
|
11
|
+
`apps/cli/src/lib/hooks.ts`.
|
|
12
|
+
|
|
13
|
+
- **`agents secrets export`/`list`/`view` now accept `--device`/`--devices` as
|
|
14
|
+
aliases for `--host`/`--hosts`, and a keychain-backed `export --host` push is
|
|
15
|
+
verified.** `--device mac-mini` used to fail with "unknown option" on the secrets
|
|
16
|
+
commands even though the rest of the fleet vocabulary (`agents activity`,
|
|
17
|
+
`agents run --device`) accepts it; it now resolves identically to `--host`. And a
|
|
18
|
+
default keychain-backend push to a macOS host over headless SSH — the sign host a
|
|
19
|
+
Linux-driven release offloads `apple.com` provisioning to — used to land the bundle
|
|
20
|
+
metadata but no readable secret items (the remote login keychain is locked over
|
|
21
|
+
SSH), then fail every later read with the confusing `Bundle 'X' key 'Y': stored
|
|
22
|
+
item '...' not found`. The push now reads the bundle back the way a headless release
|
|
23
|
+
will and **fails loudly** when the keys didn't persist, naming the locked-login-keychain
|
|
24
|
+
cause and steering to `--remote-backend file` (headless-readable) or unlocking the
|
|
25
|
+
remote keychain. This unblocks headless Linux-driven releases. Source:
|
|
26
|
+
`apps/cli/src/commands/secrets.ts`, `apps/cli/src/lib/secrets/remote.ts`.
|
|
27
|
+
|
|
28
|
+
- **`agents sessions resume` shows session previews immediately and opens one tab
|
|
29
|
+
per session by default (RUSH-2023).** The multi-select picker now starts its
|
|
30
|
+
preview pane open whenever the caller supplies preview content; `tab` still
|
|
31
|
+
toggles it. Batch resume now uses full-width tabs across terminal backends,
|
|
32
|
+
with side-by-side two-per-tab packing available explicitly via `--splits`.
|
|
33
|
+
Source: `apps/cli/src/lib/picker.ts`,
|
|
34
|
+
`apps/cli/src/commands/sessions-resume.ts`.
|
|
35
|
+
|
|
36
|
+
- **`agents sessions --active` now distinguishes dead and abandoned sessions
|
|
37
|
+
(RUSH-2066).** The active-session engine computes lifecycle from PID liveness and
|
|
38
|
+
transcript mtime: a dead process reports `closed`, a transcript stale for
|
|
39
|
+
`ABANDONED_STALE_MS` reports `abandoned`, and a live opaque harness still reports
|
|
40
|
+
`running` as its honest floor. The default list, grouped active tallies, and
|
|
41
|
+
`agents hq floor` render `closed` / `abandoned` distinctly, and Factory maps
|
|
42
|
+
`closed` to done and `abandoned` to failed so dead work no longer appears idle.
|
|
43
|
+
Source:
|
|
44
|
+
`apps/cli/src/lib/session/active.ts`, `apps/cli/src/commands/sessions.ts`,
|
|
45
|
+
`apps/factory/src/core/remoteSessions.ts`.
|
|
46
|
+
|
|
47
|
+
- **`agents view` now surfaces the Cursor account and its usage.** Cursor was
|
|
48
|
+
absent from the account view; it now shows the signed-in account (email/authId
|
|
49
|
+
from `~/.cursor/cli-config.json`, token from `~/.config/cursor/auth.json`) and,
|
|
50
|
+
for request-capped (free/legacy) plans, a monthly request bar (`M`) from
|
|
51
|
+
`cursor.com/api/usage`. Usage-based plans have no request cap, so they render the
|
|
52
|
+
account row without a bar. Source: `apps/cli/src/lib/usage.ts`,
|
|
53
|
+
`apps/cli/src/lib/agents.ts`.
|
|
54
|
+
|
|
55
|
+
- **The routines daemon now anchors its working directory to `$HOME` on startup,
|
|
56
|
+
so a deleted launch directory no longer crashes every scheduled routine.** The
|
|
57
|
+
daemon is long-lived and inherited whatever cwd it was launched from — commonly a
|
|
58
|
+
git worktree under `.agents/worktrees/`. When that directory was later removed
|
|
59
|
+
(`git worktree remove`, `rm -rf`), the daemon kept the deleted inode as its cwd
|
|
60
|
+
(a process cannot chdir out of a deleted directory on its own), and every job it
|
|
61
|
+
spawned inherited the dead cwd — `spawnJobAttempt` and command runs pass no
|
|
62
|
+
explicit `cwd`. Bun then failed `getcwd()` at startup and *every* routine died at
|
|
63
|
+
0 seconds with `ENOENT: Bun could not find a file` (or `The current working
|
|
64
|
+
directory was deleted`) before the agent ran — a fleet-wide routine outage from a
|
|
65
|
+
single removed worktree. `runDaemon` now re-anchors to the home directory once at
|
|
66
|
+
startup (`anchorDaemonCwd`), making the scheduler immune regardless of how it was
|
|
67
|
+
launched. Source: `apps/cli/src/lib/daemon.ts` (`anchorDaemonCwd`, `runDaemon`).
|
|
68
|
+
|
|
69
|
+
- **`agents repo refresh` is deprecated in favor of `agents sync`.** The command is
|
|
70
|
+
now hidden from help and prints a deprecation notice on use, pointing at the
|
|
71
|
+
replacement: `agents sync --local` (reconcile all installed agents, no git) or
|
|
72
|
+
`agents sync <agent>` (one agent). It still runs for now so existing scripts and
|
|
73
|
+
muscle memory don't break — `refresh` was a partial variant of `sync` (it only
|
|
74
|
+
ever materialized the single global-default version, and silently no-op'd for an
|
|
75
|
+
agent with installed versions but no global default), whereas `sync` covers
|
|
76
|
+
every installed version. Internal callers (crabbox bootstrap, the `agents pull`
|
|
77
|
+
redirect, `agents setup` help) now use `agents sync --local`. The underlying
|
|
78
|
+
`refresh()` function stays — it is the reconcile stage behind `agents sync`.
|
|
79
|
+
Source: `apps/cli/src/commands/repo.ts`, `apps/cli/src/lib/crabbox/`.
|
|
80
|
+
|
|
81
|
+
- **`agents view` now shows Grok usage limits.** Grok's network usage endpoints
|
|
82
|
+
404, so usage is parsed from the local `~/.grok/logs/unified.jsonl` log instead —
|
|
83
|
+
the latest billing-period config and subscription tier render as a `W` window,
|
|
84
|
+
matching the other agents' live-usage display. Source: `apps/cli/src/lib/usage.ts`.
|
|
85
|
+
|
|
86
|
+
- **`agents run --host` now starts in the same project you launched it from, not the remote `$HOME`.** A host run with neither `--cwd` nor `--remote-cwd` sent no `cd` at all, so the remote agent opened in the home directory with no project context — every launch from a repo (including every Factory "Pick Host" tab) began with a manual `cd`. The dispatch now derives a working directory from the local cwd when the caller named none: a cwd under the local home is re-rooted onto the *remote* home (`~/src/x` → the host's `$HOME/src/x`), which is the normal fleet layout where the same checkout sits at the same home-relative path on every box. Because a derived directory is a best-effort mirror rather than something the user asked for, a host that lacks that checkout falls back to its home instead of failing the run; an explicit `--cwd`/`--remote-cwd` is never mirrored, so a directory you named that does not exist still fails loudly. A cwd outside the local home is not mirrored — a path like `/opt/thing` says nothing about the target's filesystem. Source: `apps/cli/src/lib/hosts/dispatch.ts` (`deriveMirroredCwd`, `remoteCdPrefix`), `apps/cli/src/commands/exec.ts`.
|
|
87
|
+
|
|
88
|
+
- **The Cmd+Shift+O quick-dispatch bar is now Plan / Run, and never runs an agent
|
|
89
|
+
in your home directory.** The two spotlight modes were renamed from File
|
|
90
|
+
Ticket / Fix to **Plan** (investigate → file a Linear ticket) and **Run**
|
|
91
|
+
(headless `agents run`). A new repo dropdown is populated from your recent
|
|
92
|
+
session working directories with `$HOME` dropped, and the pick is passed as
|
|
93
|
+
`--cwd` to both modes, so an agent is always scoped to a real repo instead of
|
|
94
|
+
the too-broad home dir; the last-picked repo is remembered. Run now always uses
|
|
95
|
+
`--strategy balanced` (auto load-balance across signed-in versions with
|
|
96
|
+
headroom, skipping rate-limited), and `--name` is seeded from a slug of your
|
|
97
|
+
task text instead of an opaque `quick-<timestamp>`. Source:
|
|
98
|
+
`apps/cli/menubar/Sources/MenubarHelper/PromptPanel.swift`,
|
|
99
|
+
`apps/cli/menubar/Sources/MenubarHelper/AgentsCLI.swift`.
|
|
100
|
+
|
|
101
|
+
- **The keychain Touch ID prompt now names the session that triggered the read
|
|
102
|
+
(RUSH-1971).** When a bundle read pops Touch ID, the operation prompt already
|
|
103
|
+
named the requesting agent, bundle, and reason; it now also carries the
|
|
104
|
+
triggering session's 8-char short-id — e.g. *"Claude is requesting to unlock the
|
|
105
|
+
'prod' bundle (session e0a1b2c3) for 7 days …"* — so an unexpected prompt is
|
|
106
|
+
attributable when an interactive agent, headless workers, and `secrets exec`
|
|
107
|
+
deploys all run at once. The short-id is derived from the `AGENT_SESSION_ID` the
|
|
108
|
+
exec env already exports; no keychain-helper re-sign is required (the enriched
|
|
109
|
+
string flows through the existing `AGENTS_KEYCHAIN_PROMPT` env). Source:
|
|
110
|
+
`apps/cli/src/lib/secrets/index.ts`, `apps/cli/src/lib/secrets/bundles.ts`.
|
|
111
|
+
|
|
112
|
+
- **`agents teams list` renders from cached team metadata instead of full status
|
|
113
|
+
probes (RUSH-1996).** The list and picker rows now read the team registry plus
|
|
114
|
+
teammate `meta.json` snapshots, so listing teams no longer blocks on remote log
|
|
115
|
+
pulls or unreachable hosts. Full teammate status is still loaded when a user picks
|
|
116
|
+
a team or runs `agents teams status <team>`. Source:
|
|
117
|
+
`apps/cli/src/commands/teams.ts`, `apps/cli/src/commands/teams.test.ts`,
|
|
118
|
+
`apps/cli/docs/teams.md`.
|
|
119
|
+
|
|
120
|
+
- **`agents setup secrets` now guides first-run secrets onboarding (RUSH-1999).**
|
|
121
|
+
The setup command registers a new `secrets` capability wizard that chooses a
|
|
122
|
+
default storage backend (`keychain`, encrypted `file`, or synced `vault`), sets
|
|
123
|
+
the existing default prompt policy (`daily`/`always`, with `never` gated for
|
|
124
|
+
explicit automation use), persists `secrets.backend` so future `agents
|
|
125
|
+
secrets create/import` commands use the selected backend when no backend flag is
|
|
126
|
+
passed, optionally delegates imports to `agents secrets import`, and writes
|
|
127
|
+
setup preferences under `~/.agents/.history/setup`. Source:
|
|
128
|
+
`apps/cli/src/commands/setup-secrets.ts`, `apps/cli/src/commands/secrets.ts`,
|
|
129
|
+
`apps/cli/src/commands/setup.ts`.
|
|
130
|
+
|
|
131
|
+
- **`agents setup fleet` now guides Tailscale device onboarding (RUSH-2000).**
|
|
132
|
+
The setup command registers a new `fleet` capability wizard that verifies
|
|
133
|
+
Tailscale, syncs discovered devices through the existing `agents devices sync`
|
|
134
|
+
path, applies SSH auth with `agents devices set`, optionally writes the
|
|
135
|
+
managed SSH config include, tests connectivity with `agents ssh <device>
|
|
136
|
+
uname`, and can run `agents fleet update` after registration. Source:
|
|
137
|
+
`apps/cli/src/commands/setup-fleet.ts`, `apps/cli/src/commands/setup.ts`.
|
|
138
|
+
|
|
139
|
+
- **`agents feed post` carries artifacts and a project chip, and progress posts
|
|
140
|
+
render rich (RUSH-2013 / RUSH-2014).** `feed post` gains `--attach <path-or-url…>`
|
|
141
|
+
(repeatable): a local file is copied under
|
|
142
|
+
`~/.agents/.history/attachments/<session>/<update>/` so the link survives a
|
|
143
|
+
worktree delete, and a URL is kept as a link — each classified to an
|
|
144
|
+
image/audio/video/file/link kind by extension. Every post is now stamped with its
|
|
145
|
+
project (basename of cwd, worktree-aware) on the activity event itself, so the
|
|
146
|
+
chip shows without a live-session join. A `status.posted` event renders as a
|
|
147
|
+
multi-line update — `agent · session · host · project` chips, the message, an
|
|
148
|
+
attachment row with per-kind glyphs, and a `↳ ag focus/sessions` hint — wherever
|
|
149
|
+
it appears (`feed post` echo, the feed activity lane, `agents feed --filter
|
|
150
|
+
updates`, and `agents activity`).
|
|
151
|
+
- **`agents feed --filter needs|updates|all` (RUSH-2015).** `needs` (default) is the
|
|
152
|
+
open-blocks inbox as before; `updates` shows only deliberate progress posts over
|
|
153
|
+
the local activity timeline (no block pipeline, no remote fan-out); `all` renders
|
|
154
|
+
the blocks then appends the updates view. `--json` under `--filter updates` emits
|
|
155
|
+
the raw `status.posted` events. Source:
|
|
156
|
+
`apps/cli/src/lib/activity.ts`, `apps/cli/src/lib/feed-post.ts`,
|
|
157
|
+
`apps/cli/src/commands/feed.ts`, `apps/cli/src/commands/activity.ts`.
|
|
158
|
+
|
|
159
|
+
- **Fix: actor attribution now actually reaches `agents sessions` and `--active`
|
|
160
|
+
for real runs (RUSH-2018/2019).** Two bugs, found by driving a real `agents run`
|
|
161
|
+
end-to-end: (1) the session index's `actor`/`initiated_by` were kept out of the
|
|
162
|
+
upsert `ON CONFLICT` entirely, so any row indexed *before* its actor sidecar
|
|
163
|
+
landed (an older scanner, or a scan racing the spawn-time write) was locked to
|
|
164
|
+
`NULL` forever — now `COALESCE(existing, incoming)` backfills a null while still
|
|
165
|
+
never clobbering a stored owner; (2) the live `--active` **owner** read only the
|
|
166
|
+
per-pid registry entry, which the SessionStart hook rewrites without an actor, so
|
|
167
|
+
real runs showed no owner — `--active` now falls back to the durable per-session
|
|
168
|
+
actor sidecar. Verified with a real `agents run`: the actor reaches `sessions.db`
|
|
169
|
+
and the `--active` owner resolves. Source: `apps/cli/src/lib/session/db.ts`,
|
|
170
|
+
`apps/cli/src/lib/session/active.ts` (`resolveOwner`).
|
|
171
|
+
|
|
172
|
+
- **Session lists expose the model and richer navigation metadata (RUSH-1981,
|
|
173
|
+
RUSH-1991, RUSH-1992, RUSH-1994).** Static flat rows add a compact model column
|
|
174
|
+
only when the result set has model data, with width sized to that set so an
|
|
175
|
+
80-column terminal does not wrap. Local CWD and ticket/PR cells are clickable
|
|
176
|
+
in supporting terminals, previews identify browser/computer use and sub-agent
|
|
177
|
+
counts, and `agents sessions --active --json` adds an always-present `prLink`
|
|
178
|
+
key. Existing session indexes migrate to schema v20 and rescan transcripts to
|
|
179
|
+
backfill model data.
|
|
180
|
+
|
|
181
|
+
## 1.20.81
|
|
182
|
+
|
|
183
|
+
- **Generic `--device all` / `--host all` fleet fan-out for every fleet-aware
|
|
184
|
+
command (RUSH-1969).** The passthrough now treats `all` as a sentinel value on
|
|
185
|
+
`--host`, `--device`, `--hosts`, and `--devices`. For any routable command
|
|
186
|
+
(`view`, `output`, `sync`, `doctor`, `list`, …) it runs `agents <cmd> --json`
|
|
187
|
+
on every registered device concurrently, then renders an OS-grouped roster
|
|
188
|
+
(`●` installed, `○` offline/skipped, `▸ … ← this machine`). Offline and
|
|
189
|
+
no-address devices render as rows instead of hanging the whole run. Add
|
|
190
|
+
`--json` to get a device-keyed object. Commands that already own `--all-hosts`
|
|
191
|
+
(`output`) keep their existing behavior. Source:
|
|
192
|
+
`apps/cli/src/lib/hosts/passthrough.ts`, `apps/cli/src/lib/hosts/option.ts`.
|
|
193
|
+
|
|
194
|
+
- **`agents apply` no longer propagates single-use rotating refresh tokens
|
|
195
|
+
(RUSH-1958).** Droid (WorkOS) credentials use a refresh token that rotates
|
|
196
|
+
server-side on every exchange; copying one credential file across N boxes
|
|
197
|
+
caused the first refresh on any box to invalidate every other holder, collapsing
|
|
198
|
+
the fleet to a single working login. `agents apply` now excludes droid — and any
|
|
199
|
+
future harness added to the shared `SINGLE_USE_ROTATING_REFRESH_AGENTS` set in
|
|
200
|
+
`src/lib/fleet/auth-sync.ts` — from credential propagation. The plan surfaces
|
|
201
|
+
these as `manual login needed (single-use rotating refresh token)` with the
|
|
202
|
+
device name, routing the user to log in on the target box itself. Source:
|
|
203
|
+
`src/lib/fleet/auth-sync.ts`, `src/lib/fleet/apply.ts`,
|
|
204
|
+
`src/commands/apply.ts`.
|
|
205
|
+
|
|
206
|
+
- **Non-Claude remote/tmux agent sessions now surface with their real id
|
|
207
|
+
(RUSH-2007).** `agents sessions --active` and the `agents sessions focus` picker
|
|
208
|
+
dropped every non-Claude tmux session (codex/gemini/kimi/grok/…) that lacked a
|
|
209
|
+
launch-minted id, so a live `agents run --device <host> <agent>` was invisible and
|
|
210
|
+
un-refocusable after an SSH drop. `listTmuxAgentSessions` now backfills the id from
|
|
211
|
+
the **deployed** SessionStart hook's own per-pid record at
|
|
212
|
+
`~/.agents/.cache/state/sessions/<pid>.json` — the CLI previously only read the
|
|
213
|
+
un-deployed session-tracker path (`terminals/sessions/`, empty on the fleet). A
|
|
214
|
+
targeted per-pid read (never a scan of that graveyard dir), freshness-guarded by
|
|
215
|
+
the launch's known start so a reused-pid record can't cross sessions. Source:
|
|
216
|
+
`apps/cli/src/lib/session/hook-sessions.ts`, `apps/cli/src/lib/session/active.ts`.
|
|
217
|
+
|
|
218
|
+
- **Releases publish the CI-tested tree, not a drifted merge.** On a busy default
|
|
219
|
+
branch, unrelated PRs merging during a release PR's CI window made the
|
|
220
|
+
squash-merge tree diverge from what CI actually tested, so `release.sh` refused
|
|
221
|
+
to publish (`merged tree != built tree`) and the release stalled — every attempt
|
|
222
|
+
merged a version bump it could never tag. The publish now tags the exact release
|
|
223
|
+
commit the full matrix went green on (the PR head), letting the intervening
|
|
224
|
+
commits ride the next release; the merge commit is still tagged when its tree
|
|
225
|
+
matches (no drift). The `wait_for_ci_green` gate is unchanged, so the published
|
|
226
|
+
tarball is always a tree the full matrix validated. The tree-comparison decision
|
|
227
|
+
is extracted into `scripts/select-publish-commit.sh` and unit-tested against a
|
|
228
|
+
real git repo. Source: `apps/cli/scripts/release.sh`,
|
|
229
|
+
`apps/cli/scripts/select-publish-commit.sh`.
|
|
230
|
+
|
|
231
|
+
- **Consolidate the observability + inspection commands into one role each; remove
|
|
232
|
+
`check` and `resources` (RUSH-1234).** Two overlapping command clusters had grown
|
|
233
|
+
ambiguous. `agents check` (the CI drift gate) is folded into `agents doctor --check`
|
|
234
|
+
— same drift engine, now with a scriptable exit code. `--check --quiet`,
|
|
235
|
+
`--check --json` (backward-compatible payload: every field the old `check --json`
|
|
236
|
+
emitted, plus additive `unwiredHookVersions`/`sourceBehind`), and `--check --devices`
|
|
237
|
+
all carry over; the standalone `check` command is removed. `agents resources` (the merged first-wins cross-layer
|
|
238
|
+
resource table) is folded into `agents view --merged`; the standalone `resources`
|
|
239
|
+
command is removed. The observability surfaces (`events`, `feed`, `activity`,
|
|
240
|
+
`output`, `sessions`) now have a documented one-role-each taxonomy — `events` is the
|
|
241
|
+
raw unified audit stream, `feed` the cross-agent decisions/status inbox, `activity`
|
|
242
|
+
the human milestone timeline, `output` productivity accounting, `sessions` the live
|
|
243
|
+
roster + transcripts. Running the removed `agents check` / `agents resources` now
|
|
244
|
+
reports `error: unknown command`. Source:
|
|
245
|
+
`apps/cli/src/commands/doctor.ts`, `apps/cli/src/commands/view.ts`,
|
|
246
|
+
`apps/cli/src/lib/merged-resources.ts`, `apps/cli/src/lib/startup/command-registry.ts`,
|
|
247
|
+
`apps/cli/docs/06-observability.md`.
|
|
248
|
+
|
|
249
|
+
- **`agents sessions --active` shows who launched each run (RUSH-2018).** New
|
|
250
|
+
**owner** column on the active-sessions table (and an `owner` field in
|
|
251
|
+
`--active --json`), sourced from the resolved actor stamped at spawn into the
|
|
252
|
+
per-pid registry and onto each teammate record. Displays the actor's short id
|
|
253
|
+
(an email's local-part) and stays honest — an unresolved local run shows `-`,
|
|
254
|
+
never a guessed box owner. The session index (`sessions.db`) also gains
|
|
255
|
+
write-once `actor` / `initiated_by` columns, kept out of the upsert
|
|
256
|
+
`ON CONFLICT` set so a content rescan never clobbers the original owner.
|
|
257
|
+
Source: `apps/cli/src/lib/session/pid-registry.ts`,
|
|
258
|
+
`apps/cli/src/lib/session/active.ts`, `apps/cli/src/commands/sessions.ts`
|
|
259
|
+
(`ownerLabel`), `apps/cli/src/lib/session/db.ts`, `apps/cli/src/lib/exec.ts`.
|
|
260
|
+
|
|
261
|
+
- **`agents sessions` attributes historical sessions to a person, and teams carry
|
|
262
|
+
spawn lineage (RUSH-2019).** Each run now writes a durable `sessionId -> actor`
|
|
263
|
+
sidecar at spawn (`~/.agents/.history/by-session/`, unlike the pruned pid
|
|
264
|
+
registry), and the session scanner joins it while indexing — so the write-once
|
|
265
|
+
`actor` / `initiated_by` columns added in RUSH-2018 populate automatically and the
|
|
266
|
+
durable `agents sessions` listing (not just `--active`) shows who launched each
|
|
267
|
+
session. Teammate spawns inherit the orchestrator's frozen actor and now record a
|
|
268
|
+
`parent_session_id` (the orchestrator's own `AGENTS_SESSION_ID`), so a team traces
|
|
269
|
+
back to the one human who started it and the spawn chain is walkable. Source:
|
|
270
|
+
`apps/cli/src/lib/session/actor-sidecar.ts`, `apps/cli/src/lib/exec.ts`,
|
|
271
|
+
`apps/cli/src/lib/session/db.ts`, `apps/cli/src/lib/teams/agents.ts`.
|
|
272
|
+
|
|
273
|
+
- **Actor provenance reaches events, routines, and browser tasks (RUSH-2020).**
|
|
274
|
+
Completes the actor layer's coverage beyond sessions: every emitted **event** now
|
|
275
|
+
records `actor` + `kind` through the audit origin (so `agents events` stats carry
|
|
276
|
+
a `byActor` breakdown in `agents logs stats`); a **routine** stamps its creator's
|
|
277
|
+
actor id at creation and seeds it into each fired run's env (`AGENTS_ACTOR`), so an
|
|
278
|
+
unattended cron's session and events attribute to the person who scheduled it
|
|
279
|
+
instead of `UNRESOLVED@<host>` — its run records gain `actor` (creator) and
|
|
280
|
+
`triggeredBy` (who kicked off that run); a **browser task** records the `owner` who
|
|
281
|
+
launched it, on the live task and in history. Source:
|
|
282
|
+
`apps/cli/src/lib/events.ts`, `apps/cli/src/lib/runner.ts`,
|
|
283
|
+
`apps/cli/src/lib/routines.ts`, `apps/cli/src/lib/browser/{types,service}.ts`.
|
|
284
|
+
|
|
285
|
+
- **`agents sessions` now shows an accurate working / waiting / idle status for
|
|
286
|
+
every harness, and shows it as text in the default list — not just a glyph.** Two
|
|
287
|
+
gaps are closed. (1) A live non-Claude/Codex agent (grok, droid, gemini, rush,
|
|
288
|
+
kimi, hermes, opencode, antigravity) used to fall through to a blanket `unknown`
|
|
289
|
+
because `findSessionFileForKind` / `computeLiveSignals` only resolved and parsed
|
|
290
|
+
Claude and Codex transcripts — a running Codex or grok session displayed
|
|
291
|
+
`unknown`. Every tracked harness whose transcript is locatable + parseable is now
|
|
292
|
+
wired into the same state engine: `findSessionFileForKind` resolves each kind's
|
|
293
|
+
transcript through the session index (`latestSessionFileForCwd`), and
|
|
294
|
+
`computeLiveSignals` parses it with that harness's own parser and runs it through
|
|
295
|
+
the same `inferSessionState`, so it gets a real `working` / `waiting_input` /
|
|
296
|
+
`idle` the principled way Claude/Codex do. For a genuinely opaque kind (cursor) or
|
|
297
|
+
an unreadable transcript, `resolveFallbackStatus` now reports `running` for any
|
|
298
|
+
live process — **a running agent never displays `unknown`** (that state is reserved
|
|
299
|
+
for the sole un-answerable case: a dead process whose transcript vanished
|
|
300
|
+
mid-read), and a live process is never downgraded to a fabricated `idle`. (2) The
|
|
301
|
+
default `agents sessions` list (flat, tree, and the project overview) showed only a
|
|
302
|
+
colored glyph for live rows; it now also prints the status **word** —
|
|
303
|
+
`working` / `waiting` / `idle` — next to the glyph, the same three states the
|
|
304
|
+
`--active` column shows, with `waiting` the unmistakable "needs you" case. The
|
|
305
|
+
single-session preview (`agents sessions <id> --preview`) leads with the same live
|
|
306
|
+
status line, flagging `← needs you` when the agent is waiting on a question,
|
|
307
|
+
permission, or plan review. Source: `apps/cli/src/lib/session/active.ts`
|
|
308
|
+
(`findSessionFileForKind`, `computeLiveSignals`, `resolveFallbackStatus`),
|
|
309
|
+
`apps/cli/src/commands/sessions.ts` (`liveStatusWord`, `flatSessionRow`,
|
|
310
|
+
`treeSessionRow`, `renderSessionPreview`).
|
|
311
|
+
|
|
312
|
+
- **`agents sessions inject` now addresses VSCodium / Cursor / VS Code and iTerm sessions, not just tmux.** It resolves targets through the same canonical resolver the watchdog uses (`resolveInjectTargetForSession`), so the manual unblock path and the watchdog agree on which sessions are reachable — and a failed resolve now surfaces the precise reason (host/rail) instead of a misleading "not running under tmux". Source: `apps/cli/src/commands/sessions-inject.ts`.
|
|
313
|
+
- **Watchdog brain focuses on driving idle agents to completion, with context-aware, tool-pointing nudges.** The decider prompt now reads the stalled agent's goal first, restates the conclusion it already reached, names the concrete next step (including a tool it forgot it has — `agents computer` / `agents browser` / `agents ssh <mac> "agents computer …"`), splits do-it-yourself from ask-the-human, and treats `idle` as its territory while leaving `waiting` prompts to the user's feed. Design + normative spec: `apps/cli/docs/watchdog.md`, `apps/cli/docs/specifications.md#watchdog`. Source: `apps/cli/src/lib/watchdog/watchdog.ts`.
|
|
314
|
+
|
|
315
|
+
## 1.20.80
|
|
316
|
+
|
|
317
|
+
- **`agents activity` goes fleet-wide, grouped, and session-enriched.** The activity
|
|
318
|
+
lane was a flat, local-only, newest-first list; it now shows progress-so-far across
|
|
319
|
+
the whole fleet — who did what, where, on which project, for which ticket. New flags:
|
|
320
|
+
`--devices-all` (alias `--hosts-all`) fans the same `activity --json` payload out to
|
|
321
|
+
every reachable device (feed-style, via `gatherRemoteAgentsJson`) and merges each
|
|
322
|
+
peer's stream host-tagged; `-H/--host` / `--device` scope to specific boxes; `--local`
|
|
323
|
+
forces local-only (still the default). `--group-by project|device|agent` buckets the
|
|
324
|
+
stream (e.g. per project, what each agent did and for which ticket) and `--filter
|
|
325
|
+
<text>` narrows by project/device/agent/event/ticket. Each item is enriched by JOINING
|
|
326
|
+
to live sessions — the resolved project (repo/worktree slug from cwd), the execution
|
|
327
|
+
host (`provenance.host`), and the Linear ticket (`ActiveSession.ticket`) — never by
|
|
328
|
+
re-parsing transcripts. Milestone tiering (`--milestones`) and the default collapse are
|
|
329
|
+
unchanged, and `--json` stays a mergeable per-host payload (now carrying the enriched
|
|
330
|
+
fields). Source: `apps/cli/src/commands/activity.ts`, `apps/cli/src/lib/activity.ts`
|
|
331
|
+
(`enrichActivityEvents`, `mergeActivityEvents`, `parseActivityPayload`, `groupActivity`,
|
|
332
|
+
`filterActivityEvents`, `projectFromCwd`).
|
|
333
|
+
|
|
334
|
+
- **Add `agents set` — a short front door for per-version run defaults.** `agents set claude@2.1.220 --model opus-5` pins the default model (and/or `--mode`) that `agents run` uses for that agent version. It reads and writes the same store as `agents defaults run set` (`agents.yaml` -> `run.defaults`), so the two stay consistent. Bare `agents set` lists every default; `agents set <selector>` shows one. Source: `apps/cli/src/commands/set.ts`.
|
|
335
|
+
|
|
336
|
+
- **`agents doctor` now reads as a triaged health report, not neutral status.**
|
|
337
|
+
The verdict was terse status text ("Verdict: 1 divergent, source ~/.agents 16
|
|
338
|
+
commits behind…") a user had to decode. It is now a severity-ranked health block
|
|
339
|
+
that leads with what is unhealthy, why it matters, and the exact fix — one row
|
|
340
|
+
per finding, tagged with a restrained terminal glyph (`✓` `✗` `⚠` and a subtle
|
|
341
|
+
info dot, colored via chalk to match the man-page voice):
|
|
342
|
+
```
|
|
343
|
+
Claude@2.1.220
|
|
344
|
+
✗ unhealthy — 3 issues (1 critical · 2 warnings)
|
|
345
|
+
|
|
346
|
+
✗ critical ask-user-question-guard — on disk but not wired into settings.json; the hook never fires
|
|
347
|
+
→ agents sync claude@2.1.220 --yes
|
|
348
|
+
⚠ warning ~/.agents — 16 commits behind origin/main; you're running stale config
|
|
349
|
+
→ agents repo pull user
|
|
350
|
+
⚠ warning 11-activity-log — differs from source
|
|
351
|
+
→ agents doctor claude@2.1.220 --fix
|
|
352
|
+
|
|
353
|
+
heal what's auto-fixable: agents doctor claude@2.1.220 --fix
|
|
354
|
+
```
|
|
355
|
+
A clean install collapses to one green line —
|
|
356
|
+
`✓ healthy — 34 resources reconciled · hooks wired · sources current`. Each
|
|
357
|
+
finding carries an agent-agnostic **severity**: **critical** (silent breakage —
|
|
358
|
+
an unwired hook, a missing/unparseable `settings.json`, a MISSING resource),
|
|
359
|
+
**warning** (stale/drift — a source layer behind origin, a DIVERGENT resource, a
|
|
360
|
+
stale/never-synced version), or **info** (an orphan/EXTRA resource →
|
|
361
|
+
`agents prune cleanup`). Both surfaces get the same treatment: the target report
|
|
362
|
+
`agents doctor <agent>@<version>` and the bare `agents doctor` overview, which
|
|
363
|
+
now opens with a `Health` banner aggregated across every installed version. The
|
|
364
|
+
existing per-resource detail rows are kept — the health block layers on top of
|
|
365
|
+
them as the verdict. `--json` gains a `verdict` field (target mode) and a
|
|
366
|
+
`health` field (overview), each carrying `severity`/`category`/`subject`/
|
|
367
|
+
`impact`/`fix` per issue; the existing `summary`/`kinds`/`hookWiring`/
|
|
368
|
+
`sourceBehind`/`sync`/`orphans` fields are unchanged. Source:
|
|
369
|
+
`apps/cli/src/commands/doctor.ts` (`computeVerdict`, `computeOverviewHealth`,
|
|
370
|
+
`healthBlockLines`, `renderHealthBlock`, `verdictIsAutoFixable`).
|
|
371
|
+
|
|
372
|
+
- **The daemon's `MenubarHelper --notify` one-shots can no longer pile up in the
|
|
373
|
+
menu bar.** Each routine notification (start/finish/overdue/heal) spawned a
|
|
374
|
+
fresh, detached, unsupervised `MenubarHelper --notify` process; on a stalled
|
|
375
|
+
delivery — a locked screen or a WindowServer/XPC hiccup — the helper's runloop
|
|
376
|
+
spin never reached its deadline and the process hung indefinitely, so duplicate
|
|
377
|
+
"Agents" instances accumulated. The one-shot is now bounded by two independent
|
|
378
|
+
watchdogs: `runOneShot` arms a background-thread force-exit at 3s (off the main
|
|
379
|
+
queue, so a wedged main thread can't starve it — unlike the 0.6s runloop
|
|
380
|
+
deadline it backs up), and the Node spawner (`spawnDetachedQuiet`) SIGKILLs the
|
|
381
|
+
child at 4s if it never self-exits. A notifier that posts normally (the common
|
|
382
|
+
sub-second path) is untouched; only a genuinely hung one is killed. Source:
|
|
383
|
+
`apps/cli/menubar/Sources/MenubarHelper/PromptPanel.swift` (`Notifier.runOneShot`),
|
|
384
|
+
`apps/cli/src/lib/menubar/notify-desktop.ts` (`spawnDetachedQuiet`,
|
|
385
|
+
`NOTIFY_TIMEOUT_MS`).
|
|
386
|
+
|
|
387
|
+
- **Removed the dead `commitOwnDeviceMeta` auto-commit from the pull path.** It
|
|
388
|
+
committed this machine's `devices/<host>/agents.yaml` pin snapshot to the user
|
|
389
|
+
repo's `main` on nearly every `pullRepo`, without pushing — so `main` diverged
|
|
390
|
+
N-ahead per machine and wedged `agents sync` across the fleet. Now that
|
|
391
|
+
per-device pins are gitignored (they are local runtime state — written by
|
|
392
|
+
`writeMetaUnlocked`, read on-disk by pinned-strategy resolution and the shim),
|
|
393
|
+
the function only ever no-ops, so it and its sole `pullRepo` call are deleted
|
|
394
|
+
along with their tests. `--strategy balanced` never read pins; the only behavior
|
|
395
|
+
removed is the never-reached auto-commit. Source: `apps/cli/src/lib/git.ts`
|
|
396
|
+
(`pullRepo`), `apps/cli/src/lib/git.test.ts`.
|
|
397
|
+
|
|
398
|
+
- **Remove Forge and hard-deprecate Gemini (RUSH-2060).** ForgeCode is no longer
|
|
399
|
+
an `AgentId`, install target, resource-sync target, subagent target, MCP target,
|
|
400
|
+
or permissions target. Gemini remains a legacy id so existing sessions/config can
|
|
401
|
+
still be read, but it is no longer a managed harness: `agents add gemini`,
|
|
402
|
+
`agents import gemini`, and `agents sync gemini` now fail and point users to
|
|
403
|
+
Antigravity. Gemini is also excluded from capability-driven resource writers,
|
|
404
|
+
staleness detectors, import choices, teams choices, model choices, fleet auth
|
|
405
|
+
sync, and plugin/MCP/permissions/subagent sync. Source:
|
|
406
|
+
`apps/cli/src/lib/agents.ts`, `apps/cli/src/lib/types.ts`,
|
|
407
|
+
`apps/cli/src/lib/capabilities.ts`, `apps/cli/src/commands/{versions,import,sync}.ts`,
|
|
408
|
+
and the resource writers under `apps/cli/src/lib/`.
|
|
409
|
+
(RUSH-2060)
|
|
410
|
+
|
|
411
|
+
- **Every agent secret access and unlock is now captured in the raw event stream and the audit log.** After the recent relaxation that lets agents read and unlock bundles more freely, `agents events --module secrets` now surfaces two typed, value-free events for the complete access picture. `secrets.get` records every path that resolves a secret VALUE out of a bundle (`run --secrets`, `secrets exec`/`export`, `view --reveal`, raw `get <item>`, `sync push`, remote `bundle@host`), and a new `secrets.unlocked` records the deliberate `agents secrets unlock` grant into the broker/durable session — the longer-lived grant a per-read event does not capture, carrying its TTL and the harness scope it was granted to (`*` = global). Every record is tagged with the resolving `agent` scope and lands at audit level in the append-only `~/.agents/events.jsonl` audit trail, but is non-milestone so it does not clutter `agents activity` / `agents feed`. The resolved value is never written — only bundle name, key NAMES, and counts. All value-read/unlock audits now funnel through one canonical `emitSecretAudit` helper (`apps/cli/src/lib/secrets/audit.ts`), wired into `lib/secrets/bundles.ts`, `commands/secrets.ts` (reveal / raw get / unlock), `lib/secrets/sync.ts`, and `lib/secrets/remote.ts`; the new event type is registered in `lib/events.ts`. Source: `apps/cli/src/lib/secrets/audit.ts`, `apps/cli/src/lib/events.ts`, `apps/cli/src/commands/secrets.ts`.
|
|
412
|
+
|
|
413
|
+
## 1.20.79
|
|
414
|
+
|
|
415
|
+
- **A daemon bounce no longer orphans the secrets broker.** Installing agents-cli ran `stopDaemon()`, which sent SIGTERM, scheduled its hard-kill escalation on a `setTimeout`, and cleared the daemon pid file immediately — without waiting for the process to actually exit. In a short-lived process like the npm postinstall the timer never fired at all, and the cleared pid file made `isDaemonRunning()` report false, so `startDaemon()` launched a second daemon alongside the live one. Its hosted broker then found the socket in use, missed one 700ms ping against the busy owner, unlinked the live socket and rebound — leaving the first broker running with every unlocked bundle in RAM that no client could reach. On a machine with two installs (nvm + homebrew) this reproduced on every upgrade: `lsof` showed two processes on one socket path at two different kernel socket addresses. `stopDaemon` now waits for the process to actually stop serving before clearing the pid file (and escalates to a tree-kill only if it does not), and `bindBrokerSocket` probes an in-use socket several times and refuses to reclaim it while a live process still owns the broker pid file, surfacing a clear error instead of silently starting a second broker. A zombie counts as exited — it holds no socket — so a daemon that is the caller's own child is not hard-killed after it has already gone. The socket owner is recorded in a dedicated `agent.owner` file rather than the standalone service's `agent.pid` single-instance claim, so the signal is present for the daemon-hosted broker (the primary configuration) without making a losing standalone service exit into a launchd restart loop; `ensureAgentRunning`'s one-off fallback and `teardownStaleBroker` also wait for a broker to stop serving before unlinking its socket and ownership record, instead of destroying the evidence the check depends on. Source: `apps/cli/src/lib/platform/process.ts` (`waitForExit`, `hasExited`), `apps/cli/src/lib/daemon.ts` (`stopDaemon`), `apps/cli/src/lib/secrets/agent.ts` (`ownerPath`, `brokerPidAlive`, `releaseBrokerPid`, `bindBrokerSocket`, `ensureAgentRunning`, `teardownStaleBroker`).
|
|
416
|
+
|
|
417
|
+
- **`agents doctor` now checks hook WIRING, not just hook files — and treats a
|
|
418
|
+
stale source layer as unhealthy.** Two blind spots let a version home read
|
|
419
|
+
"healthy" while its hooks were dead. (1) Doctor only compared hook FILES against
|
|
420
|
+
source, never that `settings.json` actually references each hook in the right
|
|
421
|
+
event array — so a hook whose script was byte-identical to source but never
|
|
422
|
+
wired into `PreToolUse`/`Stop`/… reported `ok` and silently never fired
|
|
423
|
+
(reproduced on `yosemite-s1`: `Claude@2.1.207` printed `hooks 32 items 32 ok`
|
|
424
|
+
while its `settings.json` PreToolUse array omitted `ask-user-question-guard.sh`).
|
|
425
|
+
Doctor now inspects the version's native `settings.json` (Claude-family: claude,
|
|
426
|
+
droid), verifying each hook per `(event, matcher)` group, and reports a
|
|
427
|
+
present-but-not-wired hook as `UNWIRED <hook> event=<event> matcher=<matcher>`,
|
|
428
|
+
counted against the verdict; a missing/unparseable `settings.json` is surfaced
|
|
429
|
+
too. `--fix` re-wires via the same `registerHooksToSettings` path `agents sync`
|
|
430
|
+
uses. (2) A source layer behind `origin/main` means the home is reconciled
|
|
431
|
+
against stale truth, yet the "N commits behind" fact was a buried preamble while
|
|
432
|
+
the verdict still said healthy — it now flips the per-version verdict to unhealthy
|
|
433
|
+
with the `agents repo pull` remediation. Both checks run in every mode, not just
|
|
434
|
+
`agents doctor <agent>@<version>`: bare `agents doctor` (overview) and the CI gate
|
|
435
|
+
`agents check` now flag a present-but-unwired hook and a behind-origin source
|
|
436
|
+
layer, and `agents check` exits non-zero on them. Source:
|
|
437
|
+
`apps/cli/src/lib/hooks.ts` (`checkVersionHookWiring`), `apps/cli/src/lib/drift.ts`
|
|
438
|
+
(`checkSyncStatus`/`computeSourceBehind`/`computeDrift`),
|
|
439
|
+
`apps/cli/src/lib/doctor-diff.ts`, `apps/cli/src/commands/doctor.ts`
|
|
440
|
+
(`computeVerdict`), `apps/cli/src/commands/check.ts`, `apps/cli/src/lib/git.ts`
|
|
441
|
+
(`commitsBehindUpstream`).
|
|
442
|
+
|
|
443
|
+
- **`agents repo pull` reconciles a diverged repo instead of wedging on it.** It ran
|
|
444
|
+
`git merge --ff-only`, which refuses *any* divergence — conflict or not — so a
|
|
445
|
+
single local commit permanently blocked every later pull with nothing actually in
|
|
446
|
+
conflict. Since `pullRepo` itself auto-commits the machine's own
|
|
447
|
+
`devices/<host>/agents.yaml` before pulling, every device eventually created that
|
|
448
|
+
commit and stopped receiving updates: on one fleet, nine machines sat 9 commits
|
|
449
|
+
behind and merged rule changes never reached any of them. It now rebases, which is
|
|
450
|
+
what its own documentation has always described. Per-device paths are disjoint, so
|
|
451
|
+
they replay cleanly. A genuine conflict aborts the rebase and rolls the checkout
|
|
452
|
+
back untouched, so a failed pull can never leave the repo detached, mid-rebase, or
|
|
453
|
+
with conflict markers in live config; a rebase already in progress is reported as
|
|
454
|
+
itself rather than as a dirty tree.
|
|
455
|
+
- **`agents repo pull` / `push` exit non-zero when a repo fails.** Both printed a
|
|
456
|
+
failure line and returned 0, so `agents fleet run "agents repo pull user"` reported
|
|
457
|
+
`11 ok` across a fleet that pulled nothing. Any automation gating on the exit code
|
|
458
|
+
read a total no-op as success. Matches `agents sync <repo>`, which already did this.
|
|
459
|
+
|
|
460
|
+
- **`agents repo status` reports across the fleet.** New `--devices-all` (alias
|
|
461
|
+
`--hosts-all`) fans `repo status`/`repo list` out to every reachable device and
|
|
462
|
+
renders one aggregated table (device · repo · sync · changes); `--devices <who>`
|
|
463
|
+
(alias `--hosts`) takes `all` or a comma-separated device list. Unreachable peers
|
|
464
|
+
are skipped with a clear marker, never failing the command, and a single
|
|
465
|
+
`--device`/`--host` still streams that one box as before. Source:
|
|
466
|
+
`apps/cli/src/commands/repo.ts`.
|
|
467
|
+
|
|
468
|
+
- **Routines now always authenticate as the machine they run on, never on an inherited Claude token.** The daemon was already forbidden from *injecting* a Claude OAuth token into a routine, but nothing stopped it *inheriting* one: `buildExecEnv` spreads the ambient `process.env`, and `sanitizeProcessEnv` only strips loader/interpreter variables, never credentials. So on any box whose daemon environment happened to carry `CLAUDE_CODE_OAUTH_TOKEN` — a provisioned fleet machine, a shell that exported it — every routine spawn silently ran on that one shared, rotating token instead of the host's own login. That is the fleet-wide-logout path the no-token design exists to prevent, reached by inheritance rather than injection: when the server rotates a refresh token, every other holder drops to "run /login". No CI runner has a token to inherit, so the existing test passed everywhere and the leak only appeared on a real machine (it surfaced on the release VM, halting a release). `buildRoutineSpawnEnv` now drops the variable, and the routine still authenticates exactly as before — `CLAUDE_CONFIG_DIR` is pinned to that box's per-account version home, so a routine uses whatever agent login is set up there and needs no token of its own. Source: `apps/cli/src/lib/runner.ts` (`buildRoutineSpawnEnv`).
|
|
469
|
+
|
|
470
|
+
- **The `daily` secrets policy is now called `hold`, because it was never daily.** The default prompt policy holds a bundle for `secrets.agent.holdMs` — 7 days out of the box — yet it was named `daily`, so `agents secrets policy --help` read as "you will be asked once a day" while the code comment beside it said "one Touch ID per ~7d". Both the CLI help and `docs/secrets.md` had resorted to apologising for it in prose ("Name is historical", "Despite the name, it is not tied to one calendar day"), which is a name stating something false, not a name that is merely unclear. It is not one day, not one session, and not any fixed period — it is the configured hold window, so it is now named for that. **`daily` and the wire token `session` remain accepted everywhere** (`agents secrets policy <bundle> daily`, `secrets.policy: daily` in agents.yaml, and the `tier: session` key already written into every bundle on every synced machine), so no config or stored bundle changes behaviour on upgrade. **One machine-readable surface does change**: `agents secrets list --json` and `agents secrets view --json` now report `"policy": "hold"` where a default-tier bundle previously reported `"daily"`. Anything matching on that string needs updating — the CLI keeps accepting `daily` as input, but it no longer emits it, because a JSON field that reports a name the CLI itself has retired is a worse trap than a one-line change. The help text now also states what the tier actually depends on: the hold is a property of the running broker plus the durable session, not of the stored keychain item, so a broker that is down degrades `hold` to prompt-every-read; only `never` is prompt-free independently of the broker. Source: `apps/cli/src/lib/secrets/bundles.ts` (`SecretsPolicy`, `parsePolicy`, `secretsDefaultPolicy`), `apps/cli/src/commands/secrets.ts` (`parsePolicyOpt`, `policy` command help), `apps/cli/src/lib/secrets/index.ts` (legacy token mapping for the signed helper), `apps/cli/docs/secrets.md`.
|
|
471
|
+
|
|
472
|
+
- **Claude usage/probe reads can authenticate with a file-based setup-token
|
|
473
|
+
instead of the login keychain — no Touch ID.** On macOS, reading a Claude
|
|
474
|
+
account's usage went through Claude Code's ACL-bound
|
|
475
|
+
`Claude Code-credentials-<hash>` keychain item (`loadClaudeOauth` →
|
|
476
|
+
`/usr/bin/security`), popping a Touch ID sheet on every cold read — per account,
|
|
477
|
+
roughly every 8h, and again on the routines daemon's 3-minute auth-health probe
|
|
478
|
+
(`probeLocalFleetAuth`), so `ag view` and the background warm both prompted.
|
|
479
|
+
`loadClaudeOauth` now first resolves a per-account `claude setup-token` from the
|
|
480
|
+
reserved **file-based** `auth` secrets bundle (keyed by account email as
|
|
481
|
+
`CLAUDE_CODE_OAUTH_TOKEN_<slug>`); when present, the usage endpoint is
|
|
482
|
+
authenticated with that long-lived, non-rotating token and the keychain is never
|
|
483
|
+
touched — killing the prompt. This applies only to the read-only usage/probe
|
|
484
|
+
callers (`accessTokenCache`); the full-credential run/export path (which needs the
|
|
485
|
+
refresh token) is unchanged, and an account with no provisioned setup-token still
|
|
486
|
+
falls through to the keychain for now. Keyed strictly per-account (never a bare
|
|
487
|
+
shared key) so one account's token can't be misapplied to another. Source:
|
|
488
|
+
`apps/cli/src/lib/usage.ts`; design: `docs/design/credential-management.md`.
|
|
489
|
+
|
|
490
|
+
## 1.20.78
|
|
491
|
+
|
|
492
|
+
- **`agents sessions <uuid>` now resolves a remote session exactly, across the
|
|
493
|
+
fleet.** A full session id absent from the local disk used to fall back to an
|
|
494
|
+
FTS content search — and because a UUID appears verbatim in other sessions'
|
|
495
|
+
transcripts (a watchdog `/continue <uuid>` reference), that surfaced a list of
|
|
496
|
+
unrelated "matches" instead of the one session, which actually lived on another
|
|
497
|
+
machine. A UUID is now treated as an identifier: on a local miss the CLI fans
|
|
498
|
+
the id lookup out to the online fleet (the existing `gatherRemoteList` SSH
|
|
499
|
+
sweep), and when exactly one machine holds it, renders that session's summary
|
|
500
|
+
from the owning peer via `runOnPeer` (instead of `Session transcript not
|
|
501
|
+
available`). Same id on more than one box surfaces a machine-labeled conflict to
|
|
502
|
+
disambiguate with `--device <host>`; a UUID found nowhere prints a clear "no
|
|
503
|
+
session on this machine" message. There is **no** fuzzy/content fallback for a
|
|
504
|
+
UUID anywhere — the peer's `--json` answer id-resolves too, so a content
|
|
505
|
+
mentioner can never masquerade as the session. `--local` still restricts the
|
|
506
|
+
lookup to the local machine, and a peer already answering a parent's sweep
|
|
507
|
+
(`AGENTS_SESSIONS_LOCAL=1`) never re-fans-out. Source:
|
|
508
|
+
`resolveSessionAcrossFleet` / `fleetHitsById` / `shouldFanOutForId` in
|
|
509
|
+
`apps/cli/src/commands/sessions.ts` (wired into `renderOneSession`), and the
|
|
510
|
+
id-only `--json` resolution at the sessions listing seam. (RUSH-2024)
|
|
511
|
+
|
|
512
|
+
- **`agents doctor --devices` now detects cross-device harness divergence (RUSH-2027).** The umbrella fleet diagnostic compares each registered device's installed harness inventory — resources (commands, skills, hooks, rules, mcp, permissions, subagents, plugins, promptcuts, workflows), per-agent installed versions, and `.agents`/`.system` config-repo state (branch, HEAD, dirty) — against the local machine as the baseline, and flags anything present on one box but missing on another. A plugin like `swarm` installed on `zion` but absent on `yosemite-s0` now surfaces as a clear warning (`yosemite-s0 is missing plugin 'swarm' (present on zion)`) instead of only being discovered at runtime as `Unknown command: /swarm:run`. Agent-version gaps (`yosemite-s0 is missing claude@2.1.220`) and diverged config repos are reported too. Read-only by default — it never installs or syncs; `--json` carries a stable `fleet` divergence block for the VS Code extension to consume. `agents fleet status` gained the same per-device divergence warning in its rollup. Every device's top-level `doctor --json` now emits a `fleet` inventory field so the comparison needs no extra probe. Source: `apps/cli/src/lib/devices/fleet-divergence.ts` (comparator), `apps/cli/src/lib/devices/fleet-inventory.ts` (`collectLocalFleetInventory`), `apps/cli/src/commands/doctor.ts` (`runDevicesDoctor`, `renderFleetDivergence`, `--json` `fleet` field), `apps/cli/src/lib/devices/health-report.ts` (`buildFleetHealthReport` divergence warning), `apps/cli/src/lib/git.ts` (`readRepoState`).
|
|
513
|
+
|
|
514
|
+
- **`agents doctor` now shows repo-behind notices; they no longer appear on stderr during normal commands (RUSH-2048).** `printPendingUpdateNotices()` — which wrote "agents-cli: ~/.agents/ is N commits behind origin/main" to stderr on every CLI invocation — is replaced by `readRepoBehindMarkers()`, which returns the same data without printing. `agents doctor` reads these markers and renders a "Repo updates" section showing which repos are behind and the `agents repo pull <alias>` fix command. `agents doctor --json` emits a `repos` array so menubar helpers and other consumers can read the same data. Markers persist on disk until the next background fetch overwrites them, so the notice stays visible until the user acts. Source: `apps/cli/src/lib/auto-pull.ts`, `apps/cli/src/commands/doctor.ts`, `apps/cli/src/index.ts`.
|
|
515
|
+
|
|
516
|
+
- **Session affinity data + host affinity resolver (RUSH-2049).** Sessions index
|
|
517
|
+
persists `machine` (schema v18) so affinity can `GROUP BY machine`.
|
|
518
|
+
`queryAffinityRollup` returns launch counts by device (and harness/joint for
|
|
519
|
+
analytics). Host affinity sampling lives in `smart-launch.ts` as
|
|
520
|
+
`resolveDeviceAffinity` / `applyDeviceAutoToOptions` (weight ∝ launches^α;
|
|
521
|
+
online hosts with no history still explore at weight 1). Account pick stays
|
|
522
|
+
the existing balanced strategy (live session/week rate-limit windows).
|
|
523
|
+
**User-facing host pick shipped as `--device auto` / `--host auto` in
|
|
524
|
+
RUSH-2059** (not a public `--smart` flag and not harness auto-pick). Source:
|
|
525
|
+
`apps/cli/src/lib/session/db.ts`, `origin-machine.ts`, `smart-launch.ts`.
|
|
526
|
+
|
|
527
|
+
- **`agents sessions --all` now widens every non-status filter, not just the
|
|
528
|
+
directory (RUSH-2055).** `--all` used to only drop the current-project scope; it
|
|
529
|
+
now also drops the 30-day window cap, so one flag means "all values for every
|
|
530
|
+
non-status filter" — all directories AND all time. `--active` still composes as a
|
|
531
|
+
status filter, and `-a` / `--device` / `--since` still narrow their own axis (an
|
|
532
|
+
explicit `--since` overrides the all-time default). Applies to both the bare
|
|
533
|
+
listing and `--active`. Source: `apps/cli/src/commands/sessions-browser.ts`.
|
|
534
|
+
|
|
535
|
+
- **Device affinity is `--device auto` (not `--smart` / harness `auto`) (RUSH-2059).**
|
|
536
|
+
Host pick from 14d usage affinity is a special value on the existing host flags:
|
|
537
|
+
`agents run claude --device auto` or `--host auto`. The harness is always the
|
|
538
|
+
agent you type — never auto-selected. Deprecated hidden `--smart` maps to
|
|
539
|
+
`--device auto` for one release. Extension New Agent unpinned launches use
|
|
540
|
+
`--device auto`. Banner: `device=auto → <host> (affinity …) · accounts=balanced`.
|
|
541
|
+
Source: `apps/cli/src/commands/exec.ts`, `smart-launch.ts`,
|
|
542
|
+
`apps/factory/src/core/agents.ts`.
|
|
543
|
+
|
|
544
|
+
- **`agents sessions --active` no longer hides most of your running sessions.** On a TTY, `--active` opens the interactive browser, and the browser resolved "running" two ways that both dropped live sessions: its live scan called the local-only `getActiveSessions()` instead of the fleet sweep the static view uses, and it treated running as an *intersection* with the transcript index (`pool.filter(r => live.has(r.id))`) rather than a source of rows. Together they meant every session on another machine was invisible, as was any local one the index didn't already carry — a fleet with 32 live sessions across 7 machines showed 4. The browser now shares one gather with the static view (`gatherActiveSessions`) and folds live sessions the index lacks in as their own rows, keyed by session id, cloud task id, or `machine:pid` so two id-less sessions never collapse into one. Picking a row that has no session id yet reports where the process is instead of trying to open a transcript that doesn't exist. Source: `apps/cli/src/commands/sessions.ts` (`gatherActiveSessions`, `isIdlessLiveRow`), `apps/cli/src/commands/sessions-browser.ts` (`liveRowKey`, `indexLiveRows`, `liveSessionToMeta`, `mergeLiveIntoPool`).
|
|
545
|
+
- **The session browser now shows which program each running session is in.** A new host column names the terminal or editor hosting the session — `codium`, `ghostty`, `tmux`, or `tmux→ghostty` when a tmux session is being watched through another app (a bare `tmux` means it is running detached) — so a session in the list can actually be found. The column is live-only and appears just in the running view, since transcript metadata carries no host. The id column also truncates now, so a row named by a 7-digit pid can no longer shunt every later column out of alignment. Source: `apps/cli/src/commands/sessions.ts` (`liveHostLabel`, `formatPickerLabel`, `PickerColumns.showHost`).
|
|
546
|
+
|
|
547
|
+
- **The routines daemon holds no Claude credential and injects no token.** A
|
|
548
|
+
scheduled or daemon-fired Claude run now authenticates exactly like an
|
|
549
|
+
interactive `agents run claude` on the same machine: through the rotation-pinned
|
|
550
|
+
account's own `CLAUDE_CONFIG_DIR` login (`.credentials.json`), which Claude Code
|
|
551
|
+
refreshes per-device. The daemon previously read a token from the `claude`
|
|
552
|
+
secrets bundle and injected it into every routine spawn — first as one ambient
|
|
553
|
+
`CLAUDE_CODE_OAUTH_TOKEN` (RUSH-1759), then also as per-account
|
|
554
|
+
`CLAUDE_CODE_OAUTH_TOKEN_<account>` setup-tokens — which shadowed each account's
|
|
555
|
+
own on-disk login and made the daemon a second, competing credential store. Both
|
|
556
|
+
paths are removed, along with the sandbox `ENV_ALLOWLIST` entry that forwarded
|
|
557
|
+
them; a sandboxed routine now strips `CLAUDE_CODE_OAUTH_TOKEN` from its
|
|
558
|
+
environment and falls through to the per-account login. A box whose interactive
|
|
559
|
+
login has expired is skipped up front by the auth-health preflight with a
|
|
560
|
+
`re-login required` hint instead of running on an injected fallback — log in once
|
|
561
|
+
on that box (`agents run claude`) to restore it; no daemon restart is needed. This
|
|
562
|
+
keeps the daemon out of the credential entirely, which is what avoids the
|
|
563
|
+
fleet-wide rotation logout (a shared/injected token was the cause, not the fix).
|
|
564
|
+
Removed: `readDaemonClaudeOAuthToken` / `readDaemonClaudeBundleEnv` /
|
|
565
|
+
`buildDetachedDaemonEnv` (`daemon.ts`), `resolveAccountSetupToken` and
|
|
566
|
+
`apps/cli/src/lib/secrets/account-token.ts`, `claudeHomeHasOwnCredential`
|
|
567
|
+
(`agents.ts`). Source: `apps/cli/src/lib/daemon.ts`, `runner.ts`, `sandbox.ts`,
|
|
568
|
+
`agents.ts`.
|
|
569
|
+
|
|
570
|
+
- **`agents sessions` no longer over-counts test results from arbitrary stdout.** The catch-up digest scraped any `\d+ pass`-shaped substring anywhere in a command's output, so a `442 passwords generated` log, a `git status: 442 files` line, or a `442 passes/sec` benchmark was reported as `Tests ✓ tests 442 pass`. It also treated any command merely containing a runner token as a test run, so npm-script sub-targets like `bun test:setup`, `npm run test:watch`, or `pnpm test:ci` were counted. Test-run classification now matches only real invocations (`bun/npm/yarn/pnpm test` bare, `vitest`, `jest`, `mocha`, `pytest`, `go test`, `cargo test`, `tsc`) and rejects `:sub-target` scripts, and pass/fail counts are read only from each runner's authoritative summary construct — vitest's ` Tests N passed` / ` Tests N failed | M passed` row, jest's `Tests:` line, pytest's `=== N passed[, M failed] in Xs ===` rule, bun's ` N pass`/` N fail` block closed by `Ran N tests`, and mocha's ` N passing`/` N failing`. A verdict is reported only when a real summary matched, so an ambiguous blob now shows nothing instead of a fabricated pass count. Source: `apps/cli/src/lib/session/digest.ts` (`TEST_RUNNERS` classification with `(?![:\w-])` guard, new `parseSummaryLine`, `parseTestOutput`); consumed by `apps/cli/src/lib/session/render.ts` (`renderTestsLine`) and `apps/cli/src/commands/sessions-picker.ts`.
|
|
571
|
+
|
|
572
|
+
- **Readable `Dirs:` line in `agents sessions`.** The session preview's touched-directories line no longer renders raw Claude project-slugs (`-home-me--agents-…`) or nested worktree paths. Paths under a git worktree collapse to `⧉ <slug>/<remainder>`; a Claude project-slug is matched in slug space (its cwd/`.`-encoding is lossy, so it is never decoded to a fake path) — a slug worktree shows `⧉ <name>` and a slug pointing at the session's own cwd (internal projects-storage scratch) is dropped; real paths still relativize against the session cwd and home (`~`). Source: `apps/cli/src/commands/sessions-picker.ts`.
|
|
573
|
+
|
|
574
|
+
- **`release.sh` is now a zero-config, self-routing release — runnable from any fleet box with an empty environment.** No routing/secret environment variables: `SIGN_HOST`, `SECRET_HOST`, `SIGN_HOST_REPO`, `FORCE_REMOTE_SIGN`, the `PREFERRED_SIGN_HOSTS` list, the `zion` fallback, and the `agents devices` fleet discovery are all gone. The release has three self-selected homes: git/gh orchestration on the invoking box, the Linux test suite on a **dynamic crabbox** (`scripts/sandbox.sh` selects an available Hetzner VM for the repo's `.crabbox.yaml` profile or warms one — never a hardcoded instance), and build + sign + notarize + `npm publish` + computer-helper on the **`mac-mini` home base** (the one hardcoded name, `RELEASE_HOME_BASE`). The script detects its own host (`scutil --get LocalHostName` / `hostname -s`) and runs the privileged phase on the home base — locally if already there, else over ssh — always by checking out the `v<version>` tag into a throwaway worktree and running **that worktree's** `release.sh --home-base-phase`, so the publishing script is the one carried by the release tag, never the home base's stale on-disk checkout; the worktree is removed on exit on success or failure. The npm token is resolved on the home base and never borrowed to the trigger box. A new shared `scripts/headless-sign-context.sh` factors the headless keychain-unlock + `AGENTS_SECRETS_PASSPHRASE` preamble (no Touch ID) used by both the on-home-base publish and `remote-sign-mac.sh`. A phase tracker (`[n/N]`, N=6 for a normal release, 4 for a catch-up publish) labels each phase with the box it runs on and a ✓/✗ result; a crabbox test failure prints the failing tests + the captured log path and halts before any PR/publish. Idempotency/catch-up/tree-verification guards are preserved. Source: `apps/cli/scripts/release.sh`, `apps/cli/scripts/remote-sign-mac.sh`, `apps/cli/scripts/headless-sign-context.sh`.
|
|
575
|
+
|
|
576
|
+
- **`agents secrets unlock` now grants globally, so one Touch ID actually covers everything.** An unlock was silently scoped to the ambient `AGENTS_AGENT_NAME`: typed in a plain shell it was stored under a literal `cli` harness, while a read from inside an agent looked under *its* harness (`claude`, `codex`, …). The two never met, so a valid 7-day grant was invisible to every agent for its whole life — `agents secrets exec <bundle>` reported "not unlocked in the secrets agent" while the bundle sat unexpired in the store, and each miss cost another Touch ID or blocked a headless run outright. An unlock with no `--for` is now a global grant that every harness and a plain shell can read; `--for <agent>` still narrows it to one harness, and readers resolve own-harness → global so a narrow grant wins where it applies. The broker's in-memory store and the durable session store share one scope chain, so behavior is identical before and after a daemon restart. Grants already written under the old `cli` scope migrate to global on the next broker start — an unlock you already paid Touch ID for keeps working across the upgrade instead of going unreadable. Source: `apps/cli/src/lib/secrets/scope.ts` (`GLOBAL_HARNESS`, `bundleScopeChain`), `apps/cli/src/lib/secrets/agent.ts` (`get` handler), `apps/cli/src/lib/secrets/session-store.ts` (`resolveSession`, `cli`→global migration), `apps/cli/src/lib/secrets/bundles.ts` (`readAndResolveBundleEnv`), `apps/cli/src/commands/secrets.ts` (`unlock --for`).
|
|
577
|
+
|
|
578
|
+
- **`agents sessions export <id>` now resolves a short id the same way `sessions
|
|
579
|
+
<id>` does — by id only, never fuzzy content.** The id-only fix landed for the
|
|
580
|
+
`sessions` view but `sessions export` still gated its index lookup on
|
|
581
|
+
`isCompleteSessionId`, so a bare hex short-id like `d3470b57` absent from the
|
|
582
|
+
discovered pool skipped the index and fell through to the text query — bundling
|
|
583
|
+
every transcript that merely MENTIONED the id into the export. The one canonical
|
|
584
|
+
id-shaped test, `looksLikeSessionId`, now lives beside `isCompleteSessionId` in
|
|
585
|
+
`lib/session/discover.ts` and is shared: `sessions export` resolves any id-shaped
|
|
586
|
+
selector through the index (exact -> prefix -> `findSessionsById`) and reports
|
|
587
|
+
"No session with id …" on a miss instead of shipping the mentioner. Source:
|
|
588
|
+
`apps/cli/src/lib/session/discover.ts`, `apps/cli/src/commands/sessions-export.ts`.
|
|
589
|
+
|
|
590
|
+
- **Resolve a Claude transcript across every version home, not just the live `~/.claude`.** A session launched under an earlier agent version keeps its transcript under that version's home; resolving only the `~/.claude` symlink (which repoints to the newest installed version) meant that installing a new version silently hid every still-running older-version session — no `sessionFile`, so `agents sessions` rendered it `unknown` and the watchdog skipped it as "no activity timestamp". `findClaudeSessionFile` now searches all version-home project roots via `getAgentSessionDirs`, newest mtime winning. Source: `apps/cli/src/lib/session/active.ts`.
|
|
591
|
+
|
|
3
592
|
## 1.20.77
|
|
4
593
|
|
|
5
594
|
- **Interactive `agents run --host` now tracks the real session for every agent,
|