@phnx-labs/agents-cli 1.22.46 → 1.22.47

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 (167) hide show
  1. package/CHANGELOG.md +279 -0
  2. package/LICENSE +102 -182
  3. package/README.md +31 -18
  4. package/dist/cli/command-registry.d.ts +1 -1
  5. package/dist/cli/command-registry.js +4 -2
  6. package/dist/commands/accounts.js +56 -12
  7. package/dist/commands/auth.js +7 -5
  8. package/dist/commands/browser-sessions-picker.js +9 -7
  9. package/dist/commands/browser.js +266 -15
  10. package/dist/commands/config.js +26 -4
  11. package/dist/commands/cost.d.ts +1 -1
  12. package/dist/commands/detach.d.ts +13 -0
  13. package/dist/commands/detach.js +11 -8
  14. package/dist/commands/exec.js +55 -38
  15. package/dist/commands/feed-watch.d.ts +2 -0
  16. package/dist/commands/feed-watch.js +28 -0
  17. package/dist/commands/feed.js +27 -0
  18. package/dist/commands/feedback.js +3 -19
  19. package/dist/commands/insights.d.ts +1 -1
  20. package/dist/commands/insights.js +2 -2
  21. package/dist/commands/lease.js +3 -3
  22. package/dist/commands/routines.js +1 -1
  23. package/dist/commands/sessions-picker-factory.d.ts +2 -1
  24. package/dist/commands/sessions-picker-factory.js +1 -1
  25. package/dist/commands/sessions-stop.d.ts +24 -0
  26. package/dist/commands/sessions-stop.js +66 -0
  27. package/dist/commands/sessions-trace.d.ts +82 -0
  28. package/dist/commands/sessions-trace.js +387 -0
  29. package/dist/commands/sessions.js +4 -0
  30. package/dist/commands/ssh.d.ts +15 -0
  31. package/dist/commands/ssh.js +194 -16
  32. package/dist/commands/teams.js +34 -2
  33. package/dist/commands/view.d.ts +2 -0
  34. package/dist/commands/view.js +18 -31
  35. package/dist/commands/watchdog.js +9 -14
  36. package/dist/lib/account-capabilities.d.ts +4 -0
  37. package/dist/lib/account-capabilities.js +13 -9
  38. package/dist/lib/account-registry.d.ts +2 -0
  39. package/dist/lib/account-registry.js +30 -2
  40. package/dist/lib/accounting/rotate.d.ts +9 -0
  41. package/dist/lib/accounting/rotate.js +12 -2
  42. package/dist/lib/accounting/usage.d.ts +70 -3
  43. package/dist/lib/accounting/usage.js +235 -63
  44. package/dist/lib/agent-modes.js +29 -1
  45. package/dist/lib/agent-spec/agents.d.ts +4 -3
  46. package/dist/lib/agent-spec/agents.js +14 -6
  47. package/dist/lib/analytics/mix-commands.d.ts +1 -1
  48. package/dist/lib/analytics/mix-commands.js +2 -2
  49. package/dist/lib/auth-health.d.ts +13 -3
  50. package/dist/lib/auth-health.js +50 -8
  51. package/dist/lib/browser/devices.d.ts +19 -0
  52. package/dist/lib/browser/devices.js +23 -0
  53. package/dist/lib/browser/ipc.d.ts +1 -1
  54. package/dist/lib/browser/ipc.js +33 -7
  55. package/dist/lib/browser/profiles.d.ts +106 -1
  56. package/dist/lib/browser/profiles.js +300 -17
  57. package/dist/lib/browser/remote-control.d.ts +26 -2
  58. package/dist/lib/browser/remote-control.js +33 -3
  59. package/dist/lib/browser/runtime-state.d.ts +9 -0
  60. package/dist/lib/browser/runtime-state.js +24 -8
  61. package/dist/lib/browser/service.d.ts +37 -0
  62. package/dist/lib/browser/service.js +78 -20
  63. package/dist/lib/browser/sessions-list.d.ts +1 -3
  64. package/dist/lib/browser/sessions-list.js +3 -16
  65. package/dist/lib/browser/types.d.ts +12 -1
  66. package/dist/lib/codex-policy.d.ts +11 -1
  67. package/dist/lib/codex-policy.js +20 -5
  68. package/dist/lib/config-keys.d.ts +4 -3
  69. package/dist/lib/config-keys.js +17 -7
  70. package/dist/lib/daemon/runner.js +15 -2
  71. package/dist/lib/daemon-ticks.js +2 -2
  72. package/dist/lib/device-config.d.ts +25 -8
  73. package/dist/lib/device-config.js +90 -17
  74. package/dist/lib/devices/config-migration.d.ts +7 -0
  75. package/dist/lib/devices/config-migration.js +67 -3
  76. package/dist/lib/devices/health.d.ts +27 -2
  77. package/dist/lib/devices/health.js +39 -9
  78. package/dist/lib/devices/interactive-host.d.ts +15 -0
  79. package/dist/lib/devices/interactive-host.js +53 -0
  80. package/dist/lib/devices/registry.d.ts +61 -4
  81. package/dist/lib/devices/registry.js +94 -38
  82. package/dist/lib/devices/stats-cache.d.ts +6 -0
  83. package/dist/lib/devices/stats-cache.js +10 -2
  84. package/dist/lib/exec.d.ts +5 -3
  85. package/dist/lib/exec.js +32 -16
  86. package/dist/lib/feed/answer.d.ts +29 -0
  87. package/dist/lib/feed/answer.js +145 -0
  88. package/dist/lib/feed/attention.d.ts +83 -0
  89. package/dist/lib/feed/attention.js +0 -0
  90. package/dist/lib/feed/feed.d.ts +109 -0
  91. package/dist/lib/feed/feed.js +154 -3
  92. package/dist/lib/feed/pr-status.d.ts +14 -0
  93. package/dist/lib/feed/pr-status.js +47 -0
  94. package/dist/lib/feed/watch.d.ts +59 -0
  95. package/dist/lib/feed/watch.js +180 -0
  96. package/dist/lib/fleet/capture.js +6 -0
  97. package/dist/lib/fleet/remote-login.js +8 -3
  98. package/dist/lib/fleet/types.d.ts +17 -0
  99. package/dist/lib/harness/adapter.d.ts +11 -0
  100. package/dist/lib/harness/adapters/claude.js +38 -24
  101. package/dist/lib/harness/adapters/codex.js +2 -4
  102. package/dist/lib/hooks/cache.js +8 -0
  103. package/dist/lib/hooks/match.d.ts +3 -0
  104. package/dist/lib/hooks/match.js +25 -0
  105. package/dist/lib/hosts/passthrough.js +16 -0
  106. package/dist/lib/hosts/registry.js +7 -0
  107. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  108. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  109. package/dist/lib/menubar/install-menubar.d.ts +13 -0
  110. package/dist/lib/menubar/install-menubar.js +26 -2
  111. package/dist/lib/open-url.d.ts +60 -2
  112. package/dist/lib/open-url.js +167 -12
  113. package/dist/lib/refresh-coordinator.d.ts +1 -1
  114. package/dist/lib/refresh-coordinator.js +1 -1
  115. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  116. package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +2 -0
  117. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  118. package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
  119. package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +13 -1
  120. package/dist/lib/session/active.d.ts +67 -0
  121. package/dist/lib/session/active.js +69 -1
  122. package/dist/lib/session/db.js +4 -2
  123. package/dist/lib/session/discover.d.ts +2 -0
  124. package/dist/lib/session/discover.js +12 -6
  125. package/dist/lib/session/prompt.d.ts +35 -0
  126. package/dist/lib/session/prompt.js +56 -0
  127. package/dist/lib/session/remote/watch.d.ts +1 -1
  128. package/dist/lib/session/remote/watch.js +6 -1
  129. package/dist/lib/session/render.js +7 -3
  130. package/dist/lib/session/session-cache.js +5 -1
  131. package/dist/lib/session/trajectory-compare.d.ts +47 -0
  132. package/dist/lib/session/trajectory-compare.js +116 -0
  133. package/dist/lib/session/trajectory-html.d.ts +15 -0
  134. package/dist/lib/session/trajectory-html.js +750 -0
  135. package/dist/lib/session/trajectory-lineage.d.ts +92 -0
  136. package/dist/lib/session/trajectory-lineage.js +195 -0
  137. package/dist/lib/session/trajectory-text.d.ts +37 -0
  138. package/dist/lib/session/trajectory-text.js +277 -0
  139. package/dist/lib/session/trajectory.d.ts +102 -0
  140. package/dist/lib/session/trajectory.js +335 -0
  141. package/dist/lib/startup/command-registry.d.ts +3 -1
  142. package/dist/lib/startup/command-registry.js +5 -2
  143. package/dist/lib/state.d.ts +1 -1
  144. package/dist/lib/state.js +4 -2
  145. package/dist/lib/teams/agents.js +9 -0
  146. package/dist/lib/terminal/inject.d.ts +19 -0
  147. package/dist/lib/terminal/inject.js +19 -9
  148. package/dist/lib/tmux/session.d.ts +46 -13
  149. package/dist/lib/tmux/session.js +173 -27
  150. package/dist/lib/types.d.ts +16 -0
  151. package/dist/lib/usage-backoff.d.ts +2 -1
  152. package/dist/lib/usage-backoff.js +60 -19
  153. package/dist/lib/usage-refresh.d.ts +17 -3
  154. package/dist/lib/usage-refresh.js +57 -11
  155. package/dist/lib/watchdog/log.d.ts +1 -1
  156. package/dist/lib/watchdog/log.js +1 -1
  157. package/dist/lib/watchdog/runner.d.ts +36 -45
  158. package/dist/lib/watchdog/runner.js +150 -119
  159. package/dist/lib/watchdog/service.d.ts +0 -1
  160. package/dist/lib/watchdog/service.js +0 -1
  161. package/dist/lib/watchdog/watchdog-agent.d.ts +38 -0
  162. package/dist/lib/watchdog/watchdog-agent.js +59 -0
  163. package/dist/lib/watchdog/watchdog.d.ts +11 -2
  164. package/dist/lib/watchdog/watchdog.js +37 -104
  165. package/package.json +2 -2
  166. package/dist/commands/usage.d.ts +0 -27
  167. package/dist/commands/usage.js +0 -96
package/README.md CHANGED
@@ -54,7 +54,7 @@ agents setup status # readiness for browser, computer, fleet,
54
54
  agents run claude "explain this repo" # run any agent on your existing subscription
55
55
  ```
56
56
 
57
- `agents setup` is interactive and idempotent -- safe to re-run on any machine. Once core setup exists, it opens a status-aware menu for browser, computer, secrets, fleet, share, watchdog, and device preferences; each choice delegates to the same wizard available under `agents setup <capability>`. In CI or another non-TTY, bare setup prints the checklist without prompting. The `agi-cli.sh` one-liner installs this same canonical `@phnx-labs/agents-cli` package. Prefer bun? `bun install -g @phnx-labs/agents-cli` works too.
57
+ Everything here — and every other command in this README — is free and needs no account; the optional `agents auth login` exists only for [team spaces](#sign-in). `agents setup` is interactive and idempotent -- safe to re-run on any machine. Once core setup exists, it opens a status-aware menu for browser, computer, secrets, fleet, share, watchdog, and device preferences; each choice delegates to the same wizard available under `agents setup <capability>`. In CI or another non-TTY, bare setup prints the checklist without prompting. The `agi-cli.sh` one-liner installs this same canonical `@phnx-labs/agents-cli` package. Prefer bun? `bun install -g @phnx-labs/agents-cli` works too.
58
58
 
59
59
  Full path -- installing harnesses, logging in, smoke-testing `agents teams`, and setting up your own fleet: [`apps/cli/docs/QUICKSTART.md`](apps/cli/docs/QUICKSTART.md).
60
60
 
@@ -224,8 +224,8 @@ Supports plan (read-only), edit, auto, and skip modes, effort levels, JSON outpu
224
224
  Treat `skip` as a last-resort escape hatch. In direct-exec runs (without `--acp`),
225
225
  agi-cli forwards the harness's native no-prompt flag; it does not add another
226
226
  safety layer. Prefer `auto` where it adds a safer automatic policy (smart classifier
227
- on Claude/Copilot, native high-auto mode on Droid, or interactive Kimi), or `edit`
228
- everywhere else. For headless Kimi, `edit`, `auto`, and `skip` all use the same
227
+ on Claude/Copilot, never-prompt over a sandbox on Codex, native high-auto mode on
228
+ Droid, or interactive Kimi), or `edit` everywhere else. For headless Kimi, `edit`, `auto`, and `skip` all use the same
229
229
  already-auto-approved `-p` behavior, so prefer `edit` rather than signaling a blanket
230
230
  bypass. Harnesses without a native bypass flag reject direct-exec `skip`.
231
231
 
@@ -247,11 +247,13 @@ permission requests at the ACP protocol layer: it selects `allow_always` when of
247
247
  otherwise the first permission option offered by the server. The same last-resort
248
248
  warning applies.
249
249
 
250
- Codex has no native smart-classifier mode, so `agents run codex --mode auto` resolves
251
- to sandboxed `edit` and can still prompt. When `--mode` is omitted for Codex, the same
252
- safe writable mode is used: the workspace, `~/.agents`, and regenerable toolchain caches
253
- are writable; network access is enabled; and approvals are requested on demand. An
254
- explicit `--mode plan` keeps the filesystem read-only while leaving network access on.
250
+ Codex has three managed permission profiles rather than a smart classifier. `edit`
251
+ and `auto` share one sandbox the workspace, `~/.agents`, and regenerable toolchain
252
+ caches are writable, and network access is enabled and differ only in approvals:
253
+ `edit` requests them on demand, while `auto` never prompts, so a sandbox-denied
254
+ command fails and the agent works around it instead of stopping on a dialog nobody
255
+ is watching. When `--mode` is omitted for Codex, `edit` is used. An explicit
256
+ `--mode plan` keeps the filesystem read-only while leaving network access on.
255
257
  `agents run codex --mode skip` is different:
256
258
  it bypasses approvals **and** removes the sandbox. `full` remains an alias for `skip`,
257
259
  but new scripts should use the explicit `skip` name.
@@ -295,6 +297,11 @@ agents sessions render a1b2c3d4 -o session.md
295
297
  # Or publish it as a link in one step (unlisted + redacted by default)
296
298
  agents sessions share a1b2c3d4
297
299
 
300
+ # Visualize a session as a trajectory -- tool-call waterfall, timing, stalls, errors
301
+ agents trace a1b2c3d4 # opens the HTML (a person at a terminal)
302
+ agents trace a1b2c3d4 --text --errors-only # compact text an agent reads in-context
303
+ agents sessions trace a1b2c3d4 --json # the versioned sessions-trace envelope
304
+
298
305
  # Just the last 3 turns, user messages only
299
306
  agents sessions a1b2c3d4 --last 3 --include user
300
307
 
@@ -434,6 +441,8 @@ agents feed --flat # one row per agent (legacy)
434
441
  agents feed --device mac-mini # scope the view to one or more hosts
435
442
  agents feed --local # skip the SSH fan-out
436
443
  agents feed --json # blocks stamped with their outcome key
444
+ agents feed watch --json # versioned agents + attention + activity NDJSON
445
+ agents feed answer <key> --choice 0 # first answer wins; route over the recorded reply rail
437
446
  agents feed post --title "Halfway done" "CI green, watching merge" # title + body
438
447
  ```
439
448
 
@@ -600,7 +609,7 @@ agents hosts check gpu-box # reachable? which agi-cli version?
600
609
 
601
610
  # Run there instead of locally
602
611
  agents run claude --device gpu-box "profile this build" # headless: follows live by default
603
- agents run claude --device gpu-box # no prompt → interactive TTY over SSH (tmux-backed)
612
+ agents run claude --device gpu-box # no prompt → direct interactive TTY over SSH
604
613
  agents accounts sync work --device gpu-box # portable provider account only; native OAuth stays local
605
614
  agents run claude --device auto "…" # affinity-pick host from 14d usage (harness stays claude)
606
615
  agents run claude --device auto "…" # same — auto is a host value, not a harness name
@@ -638,10 +647,12 @@ agents devices sync # ingest `tailscale status`
638
647
  agents devices ignore ipad # sync the dismissal via agents.yaml fleet.discovery
639
648
  agents repo push user # carry device decisions to the other machines
640
649
  agents repo pull user # pull and reconcile them into this machine's registry
641
- agents devices list # fleet + headroom: load, mem, idle/busy which box has room (cache-first)
650
+ agents devices list # spec (cores/RAM/disk) + load/mem/disk + headroom + role + description
642
651
  agents devices list --live # force a live probe of every device (alias of --refresh)
643
- agents devices list --full # add per-device cores and free/total RAM
652
+ agents devices list --full # add per-device free/total RAM detail
644
653
  agents devices list --no-stats # instant: names/addresses only, skip the probe
654
+ agents devices describe mac-mini "signing + notarize box" # one-line purpose, synced + shown in the list
655
+ agents devices ignored # dismissed nodes — when, and which machine dismissed them
645
656
  agents devices config zion interactive.host zion # the device agents show YOU artifacts on (★ in the list)
646
657
  agents devices config mac-mini agents.max-concurrent 4 # per-device settings (tracked devices/<name>/agents.yaml)
647
658
  agents devices config mac-mini scheduler.enabled off # bare `devices config <name>` opens a settings menu (TTY)
@@ -814,7 +825,7 @@ tools:
814
825
  ---
815
826
  ```
816
827
 
817
- Workflows that need to write — post PR comments, edit files, send Slack — should run with `--mode edit`, or `--mode auto` on Claude Code and GitHub Copilot. Reserve `--mode skip` (legacy alias: `full`) for last-resort bypasses. `agents run` defaults to `--mode plan` for other harnesses; Codex defaults to its safe writable profile. An explicit Codex `--mode plan` is read-only with network access.
828
+ Workflows that need to write — post PR comments, edit files, send Slack — should run with `--mode edit`, or `--mode auto` on Claude Code, GitHub Copilot, and Codex. Reserve `--mode skip` (legacy alias: `full`) for last-resort bypasses. `agents run` defaults to `--mode plan` for other harnesses; Codex defaults to its safe writable profile. An explicit Codex `--mode plan` is read-only with network access.
818
829
 
819
830
  Resolution is project > user > system: a `<repo>/.agents/workflows/<name>/` overrides a same-named workflow in `~/.agents/workflows/`. Commit project workflows with your repo so teammates get the same pipeline.
820
831
 
@@ -898,7 +909,7 @@ agents setup mine remove jack --purge
898
909
 
899
910
  Under the hood, `init` drops a pure pass-through shim in `~/.agents/.cache/shims/<name>` (already on `PATH`) that sets `AGENTS_BRAND` and forwards every argument to the same binary — nothing is copied or forked. The brand's config lives in `~/.agents/agents.yaml` (`brands.<name>`), so it rides `agents repo push/pull` across your fleet. Disabling a command hides it **only** under that brand; plain `agents` / `ag` keep every command. Curated skills/plugins/MCP ride a per-brand [resource profile](apps/cli/docs/profiles.md). Full reference: [Make it yours](apps/cli/docs/mine.md).
900
911
 
901
- > Personal use is free and Apache-2.0. Redistributing a branded build commercially will require a license in a future release.
912
+ > Branded builds are free for personal and commercial use alike. New versions ship under FSL-1.1-Apache-2.0: every user and company may use, modify, and redistribute; only offering agents-cli itself as a competing commercial product or service is barred, and each version automatically becomes Apache-2.0 two years after release.
902
913
 
903
914
  ---
904
915
 
@@ -1005,7 +1016,7 @@ agents browser profiles create cloud \
1005
1016
 
1006
1017
  ## Sign in
1007
1018
 
1008
- `agents auth` signs this machine in to **Phoenix ID** the Phoenix Labs account layer that spaces and plan tiers hang off. Sign-in is Google-only and runs a device-code flow: the CLI shows a code, your browser confirms it, and the CLI picks the session up.
1019
+ Signing in is **optional**. Every local feature — `agents run`, sessions, teams, fleet dispatch, secrets, browser, computer — works with no account. The one thing an account unlocks is **team spaces**, the hosted surface under `agents auth space`. `agents auth` signs this machine in to **Phoenix ID**, the Phoenix Labs account layer behind team spaces. Sign-in is Google-only and runs a device-code flow: the CLI shows a code, your browser confirms it, and the CLI picks the session up.
1009
1020
 
1010
1021
  ```bash
1011
1022
  agents auth login # shows a code, opens a Phoenix-branded page
@@ -1314,7 +1325,7 @@ Two repos with the same shape, different roles:
1314
1325
 
1315
1326
  See [docs/concepts.md](apps/cli/docs/concepts.md) for the full mental model: DotAgents repos, resource kinds, and how resolution works end-to-end.
1316
1327
 
1317
- Other useful commands: `agents doctor` checks CLI availability and resource sync drift, `agents usage` shows available quota/rate-limit data for installed agents, `agents config budget` shows cross-vendor spend caps and current spend-to-cap (and enforces pre-flight estimates + a hard-cap kill-switch on every run — see [docs/observability.md](apps/cli/docs/observability.md#budget-guardrails-agents-budget)), `agents import` adopts an existing unmanaged install, `agents trash` lists and restores soft-deleted version directories, and `agents subagents` installs reusable subagent definitions for parent-agent workflows.
1328
+ Other useful commands: `agents doctor` checks CLI availability and resource sync drift, `agents view` shows per-account quota/rate-limit data for installed agents, `agents config budget` shows cross-vendor spend caps and current spend-to-cap (and enforces pre-flight estimates + a hard-cap kill-switch on every run — see [docs/observability.md](apps/cli/docs/observability.md#budget-guardrails-agents-budget)), `agents import` adopts an existing unmanaged install, `agents trash` lists and restores soft-deleted version directories, and `agents subagents` installs reusable subagent definitions for parent-agent workflows.
1318
1329
 
1319
1330
  ---
1320
1331
 
@@ -1499,7 +1510,7 @@ Claude Code, Codex CLI, Antigravity, Grok Build, and others each have their own
1499
1510
 
1500
1511
  ### Is it free?
1501
1512
 
1502
- Yes. This developer tool is entirely free because we believe developers should have the best tools — fast and robust — so they can create the best products for their users.
1513
+ Yes — every feature, with no account and no signup. `agents run`, sessions, teams, fleet dispatch, secrets, browser, and computer automation all work the moment you install. The optional `agents auth login` exists only to unlock hosted team spaces (`agents auth space`); there are no paid tiers. This developer tool is entirely free because we believe developers should have the best tools — fast and robust — so they can create the best products for their users.
1503
1514
 
1504
1515
  ### Is this like `nvm` / `mise` / `asdf` for AI agents?
1505
1516
 
@@ -1533,7 +1544,9 @@ macOS and Linux. Windows via WSL works but isn't first-class yet.
1533
1544
 
1534
1545
  **macOS-only features:** Keychain-based secrets (`agents secrets`, `agents accounts add`) require macOS. Default iCloud sync for bundles requires macOS + iCloud Keychain enabled; use `--no-icloud-sync` for device-local bundles. On Linux, use environment variables or `.env` files for API keys. Native Linux credential store support is planned.
1535
1546
 
1536
- Interactive tmux-backed runs require tmux 3.2 or newer.
1547
+ Interactive runs spawn directly by default. Enable `tmux.enabled` on a device to
1548
+ give each run an addressable pane for `agents message`, injection, and `agents
1549
+ focus`; tmux-backed runs require tmux 3.2 or newer.
1537
1550
 
1538
1551
  ### Do I need Node.js?
1539
1552
 
@@ -1592,4 +1605,4 @@ Commands in [`apps/cli/src/commands/`](apps/cli/src/commands/), libraries in [`a
1592
1605
 
1593
1606
  ## License
1594
1607
 
1595
- Apache-2.0 -- see [LICENSE](./LICENSE).
1608
+ FSL-1.1-Apache-2.0 -- see [LICENSE](./LICENSE). Free for every user and company to use, modify, and redistribute; the only barred use is offering agents-cli itself as a competing commercial product or service. Each version automatically becomes Apache-2.0 two years after its release.
@@ -63,8 +63,8 @@ export declare const loadMenubar: ModuleLoader;
63
63
  export declare const loadSync: ModuleLoader;
64
64
  export declare const loadRefreshRules: ModuleLoader;
65
65
  export declare const loadFactory: ModuleLoader;
66
- export declare const loadUsage: ModuleLoader;
67
66
  export declare const loadInsights: ModuleLoader;
67
+ export declare const loadTrace: ModuleLoader;
68
68
  export declare const loadPerf: ModuleLoader;
69
69
  export declare const loadPty: ModuleLoader;
70
70
  export declare const loadTmux: ModuleLoader;
@@ -65,8 +65,8 @@ export const loadMenubar = async () => (await import('../commands/menubar.js')).
65
65
  export const loadSync = async () => (await import('../commands/sync.js')).registerSyncCommand;
66
66
  export const loadRefreshRules = async () => (await import('../commands/refresh-rules.js')).registerRefreshRulesCommand;
67
67
  export const loadFactory = async () => (await import('../commands/factory.js')).registerFactoryCommands;
68
- export const loadUsage = async () => (await import('../commands/usage.js')).registerUsageCommand;
69
68
  export const loadInsights = async () => (await import('../commands/insights.js')).registerInsightsCommand;
69
+ export const loadTrace = async () => (await import('../commands/sessions-trace.js')).registerTraceCommand;
70
70
  export const loadPerf = async () => (await import('../commands/perf.js')).registerPerfCommand;
71
71
  export const loadPty = async () => (await import('../commands/pty.js')).registerPtyCommands;
72
72
  export const loadTmux = async () => (await import('../commands/tmux.js')).registerTmuxCommands;
@@ -172,8 +172,10 @@ export const COMMAND_LOADERS = {
172
172
  sync: [loadSync],
173
173
  'refresh-rules': [loadRefreshRules],
174
174
  factory: [loadFactory],
175
- usage: [loadUsage],
176
175
  insights: [loadInsights],
176
+ // `agents trace` is a top-level alias of `agents sessions trace` (precedent:
177
+ // `agents insights` aliases `agents sessions insights`). One implementation.
178
+ trace: [loadTrace],
177
179
  perf: [loadPerf],
178
180
  pty: [loadPty],
179
181
  tmux: [loadTmux],
@@ -3,7 +3,7 @@ import { password } from '@inquirer/prompts';
3
3
  import { setHelpSections } from '../lib/help.js';
4
4
  import { readMeta, updateMeta } from '../lib/state.js';
5
5
  import { ALL_AGENT_IDS, getAccountInfo, resolveAgentName } from '../lib/agents.js';
6
- import { getVersionHomePath, listInstalledVersions } from '../lib/installations/versions.js';
6
+ import { getGlobalDefault, getVersionHomePath, listInstalledVersions } from '../lib/installations/versions.js';
7
7
  import { assertNativeAccountNameable, nativeAccountCapability, nativeIdentityKey } from '../lib/account-capabilities.js';
8
8
  import { collectRunCandidates } from '../lib/accounting/rotate.js';
9
9
  import { isInteractiveTerminal } from './utils.js';
@@ -16,7 +16,10 @@ import { runDevicesAccounts } from './ssh.js';
16
16
  import { discoverNativeAccounts } from '../lib/account-catalog.js';
17
17
  import { readAndResolveBundleEnv } from '../lib/secrets/bundles.js';
18
18
  import { getAccountProvider, listAccountProviders } from '../lib/account-provider-registry.js';
19
- import { accountBindings, addAccount, addNativeAccount, bindAccount, findAccount, findUnifiedAccount, inspectAccount, listNativeAccounts, readAccountRegistry, removeAccount, renameAccount, setAccountSecret, unbindAccount } from '../lib/account-registry.js';
19
+ import { accountBindings, addAccount, addNativeAccount, bindAccount, findAccount, findUnifiedAccount, inspectAccount, labelNativeAccount, listNativeAccounts, readAccountRegistry, removeAccount, renameAccount, setAccountSecret, unbindAccount } from '../lib/account-registry.js';
20
+ function cleanCommandError(command, err) {
21
+ command.error(err instanceof Error ? err.message : String(err), { exitCode: 1, code: 'accounts.error' });
22
+ }
20
23
  function parseInstallation(raw) {
21
24
  const at = raw.lastIndexOf('@');
22
25
  if (at < 1 || at === raw.length - 1)
@@ -273,12 +276,43 @@ export function registerAccountsCommand(program) {
273
276
  });
274
277
  accounts.command('name <source> <name>')
275
278
  .description('Name a signed-in native installation without copying its OAuth credentials')
276
- .action(async (source, name) => {
277
- const identity = await nativeIdentityFromSource(source);
278
- const account = addNativeAccount(name, identity.agent, identity.identityKey, identity.identityLabel, identity.scope);
279
- console.log(chalk.green(`Named ${source} as ${account.name}.`));
280
- if (account.scope === 'device')
281
- console.log(chalk.gray(`${identity.agent} authentication is device-scoped; attach '${account.name}' to '${identity.agent}', not an individual version.`));
279
+ .action(async (source, name, _o, command) => {
280
+ try {
281
+ const identity = await nativeIdentityFromSource(source);
282
+ const account = addNativeAccount(name, identity.agent, identity.identityKey, identity.identityLabel, identity.scope);
283
+ console.log(chalk.green(`Named ${source} as ${account.name}.`));
284
+ if (account.scope === 'device')
285
+ console.log(chalk.gray(`${identity.agent} authentication is device-scoped; attach '${account.name}' to '${identity.agent}', not an individual version.`));
286
+ }
287
+ catch (err) {
288
+ cleanCommandError(command, err);
289
+ }
290
+ });
291
+ accounts.command('label <harness> [label]')
292
+ .description('Label a native login independently of its installed harness version')
293
+ .option('--account <email-or-id>', 'Native identity to label when the harness has multiple logins')
294
+ .action(async (harness, label, o, command) => {
295
+ try {
296
+ const agent = parseHarness(harness);
297
+ assertNativeAccountNameable(agent);
298
+ const candidates = (await collectRunCandidates(agent)).filter(candidate => candidate.signedIn);
299
+ const needle = o.account?.toLowerCase();
300
+ const selected = needle
301
+ ? candidates.find(candidate => candidate.email?.toLowerCase() === needle || candidate.accountKey?.toLowerCase() === needle)
302
+ : candidates.find(candidate => candidate.version === getGlobalDefault(agent)) ?? (candidates.length === 1 ? candidates[0] : undefined);
303
+ if (!selected)
304
+ throw new Error(needle
305
+ ? `Unknown ${agent} account '${o.account}'.`
306
+ : `Multiple ${agent} accounts are connected; pass --account <email|id>.`);
307
+ const identityKey = selected.accountKey ?? selected.email?.toLowerCase();
308
+ if (!identityKey)
309
+ throw new Error(`${agent} account '${selected.version}' has no stable identity.`);
310
+ const account = labelNativeAccount(agent, identityKey, selected.email ?? undefined, label, nativeAccountCapability(agent).scope);
311
+ console.log(chalk.green(`Labeled ${agent} account ${selected.email ?? identityKey} as '${account.name}'.`));
312
+ }
313
+ catch (err) {
314
+ cleanCommandError(command, err);
315
+ }
282
316
  });
283
317
  accounts.command('attach <account> <target>')
284
318
  .description('Attach a named account to a native installation or custom harness')
@@ -329,15 +363,25 @@ export function registerAccountsCommand(program) {
329
363
  accounts.command('remove <name>').description('Remove an account and its device-local credential').action((name) => removeAccount(name));
330
364
  accounts.command('set-default <agent> <name>')
331
365
  .description('Use this account for a harness when --account is omitted')
332
- .action((agentRaw, name) => {
333
- const { agent, account } = setDefaultAccount(agentRaw, name);
334
- console.log(chalk.green(`${agent} now uses account '${account.name}' unless --account overrides it.`));
366
+ .action((agentRaw, name, _o, command) => {
367
+ try {
368
+ const { agent, account } = setDefaultAccount(agentRaw, name);
369
+ console.log(chalk.green(`${agent} now uses account '${account.name}' unless --account overrides it.`));
370
+ }
371
+ catch (err) {
372
+ cleanCommandError(command, err);
373
+ }
335
374
  });
336
375
  const switchCmd = accounts.command('switch <harness> [account]')
337
376
  .description('Pick the default account for a harness')
338
377
  .option('--json', 'Machine-readable account list or the resulting default')
339
378
  .action(async (harness, account, o, command) => {
340
- await runAccountsSwitch(harness, account, { json: !!(o.json || command.optsWithGlobals().json) });
379
+ try {
380
+ await runAccountsSwitch(harness, account, { json: !!(o.json || command.optsWithGlobals().json) });
381
+ }
382
+ catch (err) {
383
+ cleanCommandError(command, err);
384
+ }
341
385
  });
342
386
  accounts.command('clear-default <agent>')
343
387
  .description('Return a harness to native login or balanced account selection')
@@ -3,9 +3,10 @@ import { PhoenixApiError, clearSession, createSpace, createSpaceInvite, fetchWho
3
3
  import { setHelpSections } from '../lib/help.js';
4
4
  import { runOrDie } from '../lib/format.js';
5
5
  /**
6
- * `agents auth` — sign in to Phoenix ID, the account layer behind teams and
7
- * plan tiers. Everything here goes through `lib/identity`; this file builds no
8
- * URLs and reads no credential files of its own.
6
+ * `agents auth` — sign in to Phoenix ID, the account layer behind team spaces.
7
+ * Signing in is optional: every local feature works with no account. Everything
8
+ * here goes through `lib/identity`; this file builds no URLs and reads no
9
+ * credential files of its own.
9
10
  */
10
11
  function sleep(ms) {
11
12
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -90,14 +91,15 @@ async function requireSpace(ref) {
90
91
  export function registerAuthCommand(program) {
91
92
  const auth = program
92
93
  .command('auth')
93
- .description('Sign in to Phoenix ID — the account layer behind spaces and plan tiers');
94
+ .description('Sign in to Phoenix ID — the account layer behind team spaces');
94
95
  setHelpSections(auth, {
95
96
  examples: `agents auth login # device-code sign-in via your browser
96
97
  agents auth whoami # who this machine is signed in as
97
98
  agents auth space create "Design Team" # start a space
98
99
  agents auth space invite ada@example.com # add a teammate
99
100
  agents auth logout # clear this machine only`,
100
- notes: `Sign-in is Google-only and opens a Phoenix-branded page; the CLI never sees a password.
101
+ notes: `Signing in is optional every local feature works with no account; team spaces are what it unlocks.
102
+ Sign-in is Google-only and opens a Phoenix-branded page; the CLI never sees a password.
101
103
  The session lives in this machine's agents state dir, so logging out here signs out nothing else.
102
104
  Point at a different backend with PHOENIX_ID_BASE (defaults to the production service).`,
103
105
  });
@@ -10,12 +10,13 @@
10
10
  * second renderer. Interactive routing and the browse loop live in
11
11
  * `sessions-picker-factory.ts` (shared with the computer twin).
12
12
  */
13
+ import { showFile } from '../lib/open-url.js';
13
14
  import chalk from 'chalk';
14
15
  import { itemPicker } from '../lib/picker.js';
15
16
  import { isPromptCancelled } from './utils.js';
16
17
  import { buildPreview } from './sessions-picker.js';
17
18
  import { createSessionsPickerCommand } from './sessions-picker-factory.js';
18
- import { runBrowserSessions, buildBrowserSessionRows, matchesBrowserSessionRow, openArtifact, formatBytes, } from '../lib/browser/sessions-list.js';
19
+ import { runBrowserSessions, buildBrowserSessionRows, matchesBrowserSessionRow, formatBytes, } from '../lib/browser/sessions-list.js';
19
20
  import { formatRelativeTime } from '../lib/session/relative-time.js';
20
21
  const KIND_LABEL = {
21
22
  screenshot: 'shots',
@@ -89,11 +90,12 @@ function formatArtifactLabel(a) {
89
90
  const age = formatRelativeTime(new Date(a.mtimeMs).toISOString());
90
91
  return `${age.padEnd(11)} ${a.name.padEnd(34)} ${formatBytes(a.bytes).padStart(8)}`;
91
92
  }
92
- /** Open one artifact in the OS default app, printing its path (matches the
93
- * non-interactive `--open` behavior) and any open failure. */
94
- function openAndReport(a) {
93
+ /** Open one artifact, printing its path (matches the non-interactive `--open`
94
+ * behavior) and any open failure. Routes through the same viewer seam as
95
+ * `--open`, so the interactive and non-interactive halves cannot diverge. */
96
+ async function openAndReport(a) {
95
97
  console.log(a.path);
96
- if (!openArtifact(a.path))
98
+ if ((await showFile(a.path)).via === 'none')
97
99
  console.error(`Could not open ${a.path}`);
98
100
  }
99
101
  /** Second-level picker over one row's captures, newest first. Enter opens the
@@ -136,12 +138,12 @@ const browserSessionsPicker = createSessionsPickerCommand({
136
138
  return;
137
139
  }
138
140
  if (row.artifacts.length === 1) {
139
- openAndReport(row.artifacts[0]);
141
+ await openAndReport(row.artifacts[0]);
140
142
  return;
141
143
  }
142
144
  const artifact = await pickArtifact(row);
143
145
  if (artifact)
144
- openAndReport(artifact);
146
+ await openAndReport(artifact);
145
147
  },
146
148
  });
147
149
  /** True when the interactive picker should open instead of the printed table: