@phnx-labs/agents-cli 1.22.42 → 1.22.44

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 (256) hide show
  1. package/CHANGELOG.md +149 -0
  2. package/README.md +15 -13
  3. package/dist/bootstrap.js +33 -13
  4. package/dist/cli/command-registry.d.ts +0 -8
  5. package/dist/cli/command-registry.js +1 -25
  6. package/dist/commands/alias.d.ts +7 -4
  7. package/dist/commands/alias.js +33 -8
  8. package/dist/commands/apply.d.ts +7 -10
  9. package/dist/commands/apply.js +15 -35
  10. package/dist/commands/artifacts.js +4 -5
  11. package/dist/commands/audit.d.ts +6 -6
  12. package/dist/commands/audit.js +12 -12
  13. package/dist/commands/auth.js +14 -6
  14. package/dist/commands/beta.d.ts +7 -1
  15. package/dist/commands/beta.js +16 -9
  16. package/dist/commands/commands.js +1 -1
  17. package/dist/commands/computer.js +20 -6
  18. package/dist/commands/daemon.js +1 -1
  19. package/dist/commands/doctor.d.ts +4 -2
  20. package/dist/commands/doctor.js +21 -9
  21. package/dist/commands/events.d.ts +2 -2
  22. package/dist/commands/events.js +6 -5
  23. package/dist/commands/exec.d.ts +1 -1
  24. package/dist/commands/exec.js +11 -6
  25. package/dist/commands/factory.d.ts +1 -1
  26. package/dist/commands/feed.js +1 -30
  27. package/dist/commands/fleet-capture.d.ts +1 -1
  28. package/dist/commands/fleet-capture.js +4 -5
  29. package/dist/commands/harness.js +4 -52
  30. package/dist/commands/hooks.js +1 -1
  31. package/dist/commands/insights.d.ts +1 -1
  32. package/dist/commands/insights.js +3 -2
  33. package/dist/commands/menubar.js +58 -1
  34. package/dist/commands/monitors.js +1 -1
  35. package/dist/commands/org.d.ts +5 -0
  36. package/dist/commands/org.js +83 -29
  37. package/dist/commands/output.js +2 -2
  38. package/dist/commands/profiles.js +2 -2
  39. package/dist/commands/prune.js +5 -4
  40. package/dist/commands/routines.js +43 -25
  41. package/dist/commands/routines.test-fixture.d.ts +86 -0
  42. package/dist/commands/routines.test-fixture.js +345 -0
  43. package/dist/commands/sessions-picker.js +124 -122
  44. package/dist/commands/sessions.test-fixture.d.ts +24 -0
  45. package/dist/commands/sessions.test-fixture.js +224 -0
  46. package/dist/commands/setup.js +9 -1
  47. package/dist/commands/share.d.ts +9 -10
  48. package/dist/commands/share.js +68 -50
  49. package/dist/commands/skills.js +1 -1
  50. package/dist/commands/snapshot.d.ts +1 -1
  51. package/dist/commands/snapshot.js +4 -4
  52. package/dist/commands/ssh.js +15 -62
  53. package/dist/commands/status.d.ts +4 -2
  54. package/dist/commands/status.js +10 -7
  55. package/dist/commands/subagents.js +1 -1
  56. package/dist/commands/sync.d.ts +1 -0
  57. package/dist/commands/sync.js +29 -2
  58. package/dist/commands/view.js +11 -2
  59. package/dist/commands/webhook.js +1 -1
  60. package/dist/lib/accounting/rotate.d.ts +5 -3
  61. package/dist/lib/accounting/rotate.js +36 -7
  62. package/dist/lib/accounting/usage.d.ts +18 -4
  63. package/dist/lib/accounting/usage.js +138 -27
  64. package/dist/lib/agent-spec/agents.d.ts +7 -7
  65. package/dist/lib/agent-spec/agents.js +15 -15
  66. package/dist/lib/analytics/mix-commands.d.ts +6 -28
  67. package/dist/lib/analytics/mix-commands.js +14 -40
  68. package/dist/lib/audit/log.d.ts +2 -2
  69. package/dist/lib/audit/log.js +2 -2
  70. package/dist/lib/beta.js +1 -1
  71. package/dist/lib/browser/domain-skills.d.ts +26 -6
  72. package/dist/lib/browser/domain-skills.js +81 -43
  73. package/dist/lib/cloud/rush.d.ts +0 -15
  74. package/dist/lib/cloud/rush.js +0 -35
  75. package/dist/lib/crabbox/runtimes.d.ts +6 -2
  76. package/dist/lib/crabbox/runtimes.js +21 -5
  77. package/dist/lib/daemon/daemon.js +97 -58
  78. package/dist/lib/daemon/daemon.test-fixture.d.ts +24 -0
  79. package/dist/lib/daemon/daemon.test-fixture.js +71 -0
  80. package/dist/lib/daemon/runner.d.ts +18 -1
  81. package/dist/lib/daemon/runner.js +105 -11
  82. package/dist/lib/daemon-ticks.d.ts +38 -1
  83. package/dist/lib/daemon-ticks.js +52 -5
  84. package/dist/lib/device-config.js +1 -2
  85. package/dist/lib/devices/discovery-policy.d.ts +3 -3
  86. package/dist/lib/devices/discovery-policy.js +3 -3
  87. package/dist/lib/devices/doctor-findings.js +1 -1
  88. package/dist/lib/devices/fleet.d.ts +4 -8
  89. package/dist/lib/devices/fleet.js +3 -15
  90. package/dist/lib/devices/health-report.js +4 -4
  91. package/dist/lib/devices/pool.d.ts +0 -6
  92. package/dist/lib/devices/pool.js +0 -6
  93. package/dist/lib/devices/registry.d.ts +0 -15
  94. package/dist/lib/devices/registry.js +0 -9
  95. package/dist/lib/devices/stats-cache.d.ts +12 -0
  96. package/dist/lib/devices/stats-cache.js +24 -5
  97. package/dist/lib/drift-sync.d.ts +1 -1
  98. package/dist/lib/drift-sync.js +2 -2
  99. package/dist/lib/drift.d.ts +1 -1
  100. package/dist/lib/exec.js +13 -3
  101. package/dist/lib/fleet/capture.d.ts +1 -1
  102. package/dist/lib/fleet/manifest.js +1 -1
  103. package/dist/lib/fleet/remote-login.d.ts +2 -2
  104. package/dist/lib/fleet/remote-login.js +3 -4
  105. package/dist/lib/format.d.ts +9 -0
  106. package/dist/lib/format.js +16 -0
  107. package/dist/lib/github/pr-mergeable.d.ts +49 -0
  108. package/dist/lib/github/pr-mergeable.js +157 -0
  109. package/dist/lib/github/pr-verdict.d.ts +67 -0
  110. package/dist/lib/github/pr-verdict.js +72 -0
  111. package/dist/lib/harness/adapter.d.ts +6 -5
  112. package/dist/lib/hosts/dispatch.d.ts +2 -0
  113. package/dist/lib/hosts/dispatch.js +8 -1
  114. package/dist/lib/hosts/passthrough.d.ts +10 -0
  115. package/dist/lib/hosts/passthrough.js +28 -7
  116. package/dist/lib/hosts/providers/devices.js +1 -13
  117. package/dist/lib/hosts/ready.d.ts +12 -3
  118. package/dist/lib/hosts/ready.js +27 -12
  119. package/dist/lib/hosts/registry.d.ts +4 -5
  120. package/dist/lib/hosts/registry.js +3 -7
  121. package/dist/lib/hosts/session-index.js +1 -1
  122. package/dist/lib/installations/shims.js +1 -1
  123. package/dist/lib/installations/versions.d.ts +40 -0
  124. package/dist/lib/installations/versions.js +78 -4
  125. package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +1 -5
  126. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  127. package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +2 -15
  128. package/dist/lib/menubar/install-menubar.d.ts +109 -0
  129. package/dist/lib/menubar/install-menubar.js +218 -12
  130. package/dist/lib/monitors/config.d.ts +2 -2
  131. package/dist/lib/monitors/config.js +3 -2
  132. package/dist/lib/origin-machine.d.ts +18 -0
  133. package/dist/lib/origin-machine.js +34 -0
  134. package/dist/lib/perf/db.js +1 -1
  135. package/dist/lib/perf/spool.js +1 -1
  136. package/dist/lib/prix-account.d.ts +2 -1
  137. package/dist/lib/prix-account.js +2 -1
  138. package/dist/lib/profiles.d.ts +7 -0
  139. package/dist/lib/profiles.js +26 -1
  140. package/dist/lib/remote-agents-json.js +1 -7
  141. package/dist/lib/routines-placement.d.ts +1 -1
  142. package/dist/lib/routines-placement.js +1 -1
  143. package/dist/lib/sandbox.d.ts +24 -0
  144. package/dist/lib/sandbox.js +101 -0
  145. package/dist/lib/scheduling/routines.d.ts +18 -9
  146. package/dist/lib/scheduling/routines.js +16 -8
  147. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  148. package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -2
  149. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  150. package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +1 -13
  151. package/dist/lib/secrets/agent.js +9 -1
  152. package/dist/lib/secrets/index.js +1 -1
  153. package/dist/lib/secrets/list-filter.js +1 -1
  154. package/dist/lib/service-manifest.d.ts +20 -0
  155. package/dist/lib/service-manifest.js +34 -0
  156. package/dist/lib/session/active.d.ts +4 -16
  157. package/dist/lib/session/active.js +2 -6
  158. package/dist/lib/session/cloud.js +1 -1
  159. package/dist/lib/session/db.d.ts +13 -98
  160. package/dist/lib/session/db.js +5 -12
  161. package/dist/lib/session/discover.d.ts +5 -81
  162. package/dist/lib/session/discover.js +5 -5
  163. package/dist/lib/session/fork.js +1 -1
  164. package/dist/lib/session/live-metadata.js +1 -1
  165. package/dist/lib/session/origin-machine.d.ts +1 -18
  166. package/dist/lib/session/origin-machine.js +4 -34
  167. package/dist/lib/session/relative-time.d.ts +1 -44
  168. package/dist/lib/session/relative-time.js +4 -120
  169. package/dist/lib/session/remote/remote-bundle.d.ts +12 -0
  170. package/dist/lib/session/remote/remote-bundle.js +61 -0
  171. package/dist/lib/session/remote/remote-list.d.ts +148 -0
  172. package/dist/lib/session/remote/remote-list.js +607 -0
  173. package/dist/lib/session/remote/remote.d.ts +132 -0
  174. package/dist/lib/session/remote/remote.js +314 -0
  175. package/dist/lib/session/remote/watch.d.ts +101 -0
  176. package/dist/lib/session/remote/watch.js +241 -0
  177. package/dist/lib/session/remote-bundle.d.ts +1 -12
  178. package/dist/lib/session/remote-bundle.js +3 -61
  179. package/dist/lib/session/remote-list.d.ts +1 -148
  180. package/dist/lib/session/remote-list.js +3 -607
  181. package/dist/lib/session/remote.d.ts +1 -132
  182. package/dist/lib/session/remote.js +3 -314
  183. package/dist/lib/session/short-id.d.ts +1 -17
  184. package/dist/lib/session/short-id.js +4 -20
  185. package/dist/lib/session/watch.d.ts +1 -101
  186. package/dist/lib/session/watch.js +3 -242
  187. package/dist/lib/session/width.d.ts +1 -29
  188. package/dist/lib/session/width.js +4 -101
  189. package/dist/lib/share/config.d.ts +12 -2
  190. package/dist/lib/share/config.js +47 -11
  191. package/dist/lib/share/delete.js +1 -1
  192. package/dist/lib/share/publish.js +1 -1
  193. package/dist/lib/share/worker-template.js +2 -2
  194. package/dist/lib/smart-launch.d.ts +4 -4
  195. package/dist/lib/smart-launch.js +8 -18
  196. package/dist/lib/snapshot.d.ts +2 -2
  197. package/dist/lib/snapshot.js +1 -1
  198. package/dist/lib/staleness/index.d.ts +3 -1
  199. package/dist/lib/staleness/index.js +21 -1
  200. package/dist/lib/staleness/types.d.ts +11 -0
  201. package/dist/lib/staleness/writers/commands.js +13 -4
  202. package/dist/lib/staleness/writers/hooks.js +3 -1
  203. package/dist/lib/staleness/writers/mcp.d.ts +0 -7
  204. package/dist/lib/staleness/writers/mcp.js +16 -1
  205. package/dist/lib/staleness/writers/rules.js +1 -1
  206. package/dist/lib/staleness/writers/skills.js +3 -1
  207. package/dist/lib/staleness/writers/subagents.d.ts +0 -9
  208. package/dist/lib/staleness/writers/subagents.js +18 -1
  209. package/dist/lib/staleness/writers/types.d.ts +10 -0
  210. package/dist/lib/startup/command-registry.d.ts +10 -1
  211. package/dist/lib/startup/command-registry.js +26 -7
  212. package/dist/lib/startup/root-command.d.ts +18 -1
  213. package/dist/lib/startup/root-command.js +18 -1
  214. package/dist/lib/state.js +7 -0
  215. package/dist/lib/teams/placement-probe.js +28 -13
  216. package/dist/lib/teams/scheduler.d.ts +3 -1
  217. package/dist/lib/teams/scheduler.js +1 -1
  218. package/dist/lib/text/relative-time.d.ts +44 -0
  219. package/dist/lib/text/relative-time.js +120 -0
  220. package/dist/lib/text/short-id.d.ts +17 -0
  221. package/dist/lib/text/short-id.js +20 -0
  222. package/dist/lib/text/width.d.ts +29 -0
  223. package/dist/lib/text/width.js +101 -0
  224. package/dist/lib/triggers/handlers.d.ts +7 -0
  225. package/dist/lib/triggers/handlers.js +8 -0
  226. package/dist/lib/triggers/webhook.d.ts +1 -0
  227. package/dist/lib/triggers/webhook.js +2 -1
  228. package/dist/lib/types.d.ts +1 -1
  229. package/dist/lib/view-types.d.ts +7 -0
  230. package/package.json +2 -3
  231. package/dist/bin/agents +0 -0
  232. package/dist/commands/serve.d.ts +0 -10
  233. package/dist/commands/serve.js +0 -68
  234. package/dist/commands/tickets.d.ts +0 -2
  235. package/dist/commands/tickets.js +0 -43
  236. package/dist/commands/trends.d.ts +0 -10
  237. package/dist/commands/trends.js +0 -12
  238. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  239. package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
  240. package/dist/lib/observe-aliases.d.ts +0 -30
  241. package/dist/lib/observe-aliases.js +0 -38
  242. package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
  243. package/dist/lib/serve/control.d.ts +0 -95
  244. package/dist/lib/serve/control.js +0 -260
  245. package/dist/lib/serve/data.d.ts +0 -81
  246. package/dist/lib/serve/data.js +0 -91
  247. package/dist/lib/serve/page.d.ts +0 -7
  248. package/dist/lib/serve/page.js +0 -140
  249. package/dist/lib/serve/server.d.ts +0 -80
  250. package/dist/lib/serve/server.js +0 -145
  251. package/dist/lib/serve/stream.d.ts +0 -43
  252. package/dist/lib/serve/stream.js +0 -116
  253. package/dist/lib/serve/token.d.ts +0 -35
  254. package/dist/lib/serve/token.js +0 -85
  255. package/dist/lib/tickets/list.d.ts +0 -53
  256. package/dist/lib/tickets/list.js +0 -153
@@ -1,25 +1,22 @@
1
1
  /**
2
- * `agents apply` (alias `ag apply`) — reconcile the whole fleet to a declared
3
- * profile in one command: install agents-cli + agents and sync config. Native
2
+ * `agents fleet apply` / `agents devices apply` — reconcile the whole fleet
3
+ * to a declared profile: install agents-cli + agents and sync config. Native
4
4
  * harness logins remain device-local; portable provider credentials move only
5
5
  * through explicit `agents accounts sync`.
6
6
  *
7
7
  * The manifest is the `fleet:` block of any `-f` file (default `agents.yaml`).
8
+ * Top-level `agents apply` is retired (RUSH-2981).
8
9
  */
9
10
  import { Command } from 'commander';
10
11
  /** padEnd on the visible width, ignoring chalk color codes. Exported for tests. */
11
12
  export declare function stripPad(s: string, width: number): string;
12
13
  /**
13
- * Attach the reconcile options + action to a command node. Shared by the
14
- * top-level `agents apply` and its `agents fleet apply` alias so the two can
15
- * never drift — identical flags, identical engine.
14
+ * Attach the reconcile options + action to a command node.
16
15
  */
17
16
  export declare function configureApplyCommand(cmd: Command): Command;
18
- export declare function registerApplyCommand(program: Command): void;
19
17
  /**
20
- * Surface `agents apply` under the fleet command tree as `agents fleet apply`
21
- * (and `agents devices apply`). Same reconcile engine as the top-level command
22
- * a discoverability alias for users who reach for `fleet` as the verb. Kept in
23
- * lockstep via {@link configureApplyCommand}.
18
+ * Canonical surface: `agents fleet apply` / `agents devices apply`.
19
+ * Top-level `agents apply` is retired (RUSH-2981) not a noun, already nested
20
+ * here. Same reconcile engine, kept in lockstep via {@link configureApplyCommand}.
24
21
  */
25
22
  export declare function registerFleetApplyAlias(devicesCmd: Command): void;
@@ -1,10 +1,11 @@
1
1
  /**
2
- * `agents apply` (alias `ag apply`) — reconcile the whole fleet to a declared
3
- * profile in one command: install agents-cli + agents and sync config. Native
2
+ * `agents fleet apply` / `agents devices apply` — reconcile the whole fleet
3
+ * to a declared profile: install agents-cli + agents and sync config. Native
4
4
  * harness logins remain device-local; portable provider credentials move only
5
5
  * through explicit `agents accounts sync`.
6
6
  *
7
7
  * The manifest is the `fleet:` block of any `-f` file (default `agents.yaml`).
8
+ * Top-level `agents apply` is retired (RUSH-2981).
8
9
  */
9
10
  import * as fs from 'fs';
10
11
  import * as path from 'path';
@@ -12,7 +13,7 @@ import { fileURLToPath } from 'url';
12
13
  import chalk from 'chalk';
13
14
  import { setHelpSections } from '../lib/help.js';
14
15
  import { machineId } from '../lib/session/sync/config.js';
15
- import { loadDevices, isControlDevice } from '../lib/devices/registry.js';
16
+ import { loadDevices } from '../lib/devices/registry.js';
16
17
  import { isHostPinned, managedKnownHostsPath } from '../lib/devices/known-hosts.js';
17
18
  import { ensureDevicesRegistered } from '../lib/devices/sync.js';
18
19
  import { readFleetFile, resolveDesired } from '../lib/fleet/manifest.js';
@@ -163,10 +164,7 @@ async function runApply(opts) {
163
164
  }
164
165
  }
165
166
  const registry = await loadDevices();
166
- // Control devices (a cockpit) never run agents — exclude them from the
167
- // reconcile set entirely so `agents apply` doesn't try to install/sync/login
168
- // onto a paired phone.
169
- const all = Object.values(registry).filter((d) => !isControlDevice(d));
167
+ const all = Object.values(registry);
170
168
  const online = all.filter((d) => d.tailscale?.online === true).map((d) => d.name);
171
169
  const registered = all.map((d) => d.name);
172
170
  // Unresolved names are skipped (surfaced above), never fatal — a manifest
@@ -290,9 +288,7 @@ function reportResults(results) {
290
288
  console.log(chalk.green('Fleet reconciled.'));
291
289
  }
292
290
  /**
293
- * Attach the reconcile options + action to a command node. Shared by the
294
- * top-level `agents apply` and its `agents fleet apply` alias so the two can
295
- * never drift — identical flags, identical engine.
291
+ * Attach the reconcile options + action to a command node.
296
292
  */
297
293
  export function configureApplyCommand(cmd) {
298
294
  return cmd
@@ -317,32 +313,10 @@ export function configureApplyCommand(cmd) {
317
313
  }
318
314
  });
319
315
  }
320
- export function registerApplyCommand(program) {
321
- const applyCmd = configureApplyCommand(program.command('apply'));
322
- setHelpSections(applyCmd, {
323
- examples: `
324
- # Preview what would change across the fleet
325
- agents apply --plan -f agents.yaml
326
-
327
- # Bring every device to the profile (installs + config sync; native login stays local)
328
- ag apply -f agents.yaml
329
-
330
- # One device only
331
- agents apply --device yosemite-s1 -y
332
-
333
- # Replicate every claude version on this machine onto a fresh box
334
- agents apply --agent claude@all --device yosemite-s0 -y
335
-
336
- # Install a specific pinned version on one device
337
- agents apply --agent claude@2.1.207 --device yosemite-s0
338
- `,
339
- });
340
- }
341
316
  /**
342
- * Surface `agents apply` under the fleet command tree as `agents fleet apply`
343
- * (and `agents devices apply`). Same reconcile engine as the top-level command
344
- * a discoverability alias for users who reach for `fleet` as the verb. Kept in
345
- * lockstep via {@link configureApplyCommand}.
317
+ * Canonical surface: `agents fleet apply` / `agents devices apply`.
318
+ * Top-level `agents apply` is retired (RUSH-2981) not a noun, already nested
319
+ * here. Same reconcile engine, kept in lockstep via {@link configureApplyCommand}.
346
320
  */
347
321
  export function registerFleetApplyAlias(devicesCmd) {
348
322
  const sub = configureApplyCommand(devicesCmd.command('apply'));
@@ -353,6 +327,12 @@ export function registerFleetApplyAlias(devicesCmd) {
353
327
 
354
328
  # Reconcile every device to the profile
355
329
  agents fleet apply -y
330
+
331
+ # One device only
332
+ agents fleet apply --device yosemite-s1 -y
333
+
334
+ # Replicate every claude version on this machine onto a fresh box
335
+ agents fleet apply --agent claude@all --device yosemite-s0 -y
356
336
  `,
357
337
  });
358
338
  }
@@ -34,7 +34,7 @@ export function registerArtifactsCommands(program) {
34
34
 
35
35
  # What's live in your namespace, and taking one down
36
36
  agents artifacts share list
37
- agents unshare my-plan-a1b2
37
+ agents artifacts unshare my-plan-a1b2
38
38
 
39
39
  # Endpoint health, and pushing a new Worker template to it
40
40
  agents artifacts share status
@@ -47,12 +47,11 @@ export function registerArtifactsCommands(program) {
47
47
  --account/--token/--domain/--analytics-token, or run non-interactively, and it
48
48
  provisions directly with what you named.
49
49
 
50
- agents unshare <targets...> stays a top-level alias of
51
- agents artifacts share delete.
50
+ agents artifacts unshare <targets...> is the nested alias of
51
+ agents artifacts share delete. Top-level \`agents unshare\` is gone.
52
52
 
53
53
  Full reference: apps/cli/docs/share.md.
54
54
  `,
55
55
  });
56
- // Top-level, deliberately: see registerUnshareCommand in commands/share.ts.
57
- registerUnshareCommand(program);
56
+ registerUnshareCommand(artifactsCmd);
58
57
  }
@@ -1,14 +1,14 @@
1
1
  /**
2
- * `agents audit` — thin alias of `agents events --include runs`.
2
+ * `agents events audit` — thin alias of `agents events --include runs`.
3
3
  *
4
4
  * New run-dispatch outcomes land in the unified event stream as `run.dispatched`
5
5
  * (see lib/audit/log.ts::recordDispatchedRun). This command does not own a
6
6
  * separate store or query path — it only sets the default family filter.
7
7
  *
8
- * agents audit ≡ agents events --include runs
9
- * agents audit list ≡ same
10
- * agents audit verify walks the legacy hash-chain file if present
11
- * (pre-unification history only)
8
+ * agents events audit ≡ agents events --include runs
9
+ * agents events audit list ≡ same
10
+ * agents events audit verify walks the legacy hash-chain file if present
11
+ * (pre-unification history only)
12
12
  */
13
13
  import type { Command } from 'commander';
14
- export declare function registerAuditCommands(program: Command): void;
14
+ export declare function registerAuditCommands(events: Command): void;
@@ -1,28 +1,28 @@
1
1
  /**
2
- * `agents audit` — thin alias of `agents events --include runs`.
2
+ * `agents events audit` — thin alias of `agents events --include runs`.
3
3
  *
4
4
  * New run-dispatch outcomes land in the unified event stream as `run.dispatched`
5
5
  * (see lib/audit/log.ts::recordDispatchedRun). This command does not own a
6
6
  * separate store or query path — it only sets the default family filter.
7
7
  *
8
- * agents audit ≡ agents events --include runs
9
- * agents audit list ≡ same
10
- * agents audit verify walks the legacy hash-chain file if present
11
- * (pre-unification history only)
8
+ * agents events audit ≡ agents events --include runs
9
+ * agents events audit list ≡ same
10
+ * agents events audit verify walks the legacy hash-chain file if present
11
+ * (pre-unification history only)
12
12
  */
13
13
  import chalk from 'chalk';
14
14
  import { verifyAuditChain, readAuditLog, getAuditLogPath, } from '../lib/audit/log.js';
15
15
  import { addEventsReadOptions, runEventsCommand } from './events.js';
16
- export function registerAuditCommands(program) {
17
- const audit = addEventsReadOptions(program
16
+ export function registerAuditCommands(events) {
17
+ const audit = addEventsReadOptions(events
18
18
  .command('audit')
19
19
  .description('Alias of `agents events --include runs` — dispatched-run outcomes'), false)
20
20
  .addHelpText('after', `
21
21
  Examples:
22
- agents audit Same as: agents events --include runs
23
- agents audit --since 7d --json
24
- agents audit list Muscle-memory alias of bare audit
25
- agents audit verify Legacy hash-chain file only (if present)
22
+ agents events audit Same as: agents events --include runs
23
+ agents events audit --since 7d --json
24
+ agents events audit list Muscle-memory alias of bare audit
25
+ agents events audit verify Legacy hash-chain file only (if present)
26
26
  `)
27
27
  .action((_options, command) => {
28
28
  const opts = command.optsWithGlobals();
@@ -33,7 +33,7 @@ Examples:
33
33
  });
34
34
  audit
35
35
  .command('list')
36
- .description('Alias of `agents audit` / `agents events --include runs`')
36
+ .description('Alias of `agents events audit` / `agents events --include runs`')
37
37
  .action((_options, command) => {
38
38
  const parent = command.parent;
39
39
  const opts = {
@@ -1,6 +1,8 @@
1
1
  import chalk from 'chalk';
2
2
  import { setHelpSections } from '../lib/help.js';
3
+ import { runOrDie } from '../lib/format.js';
3
4
  import { clearPrixSession, fetchWhoAmI, pollDeviceToken, PrixApiError, readPrixSession, resolvePrixToken, startDeviceAuthorization, writePrixSession, } from '../lib/prix-account.js';
5
+ import { registerAuthSpaceCommand } from './org.js';
4
6
  function sleep(ms) {
5
7
  return new Promise(resolve => setTimeout(resolve, ms));
6
8
  }
@@ -89,16 +91,22 @@ function runAuthLogout() {
89
91
  }
90
92
  }
91
93
  export function registerAuthCommand(program) {
92
- const auth = program.command('auth').description('Sign in to your Rush account (shared by `agents org` and paid tiers)');
93
- auth.command('login').description('Sign in via the device-code flow').action(async () => runAuthLogin());
94
+ const auth = program.command('auth').description('Sign in to your Prix account (spaces, paid tiers)');
95
+ auth.command('login').description('Sign in via the device-code flow').action(() => runOrDie(() => runAuthLogin()));
94
96
  auth.command('whoami').description('Show the signed-in account').option('--json', 'Machine-readable output')
95
- .action((o, command) => runAuthWhoami(!!(o.json || command.optsWithGlobals().json)));
96
- auth.command('logout').description('Clear the local `agents auth login` session').action(() => runAuthLogout());
97
+ .action((o, command) => {
98
+ const json = !!(o.json || command.optsWithGlobals().json);
99
+ return runOrDie(() => runAuthWhoami(json), { json });
100
+ });
101
+ auth.command('logout').description('Clear the local `agents auth login` session').action(() => runOrDie(() => runAuthLogout()));
102
+ registerAuthSpaceCommand(auth);
97
103
  setHelpSections(auth, {
98
104
  examples: `agents auth login
99
105
  agents auth whoami
100
106
  agents auth whoami --json
101
- agents auth logout`,
102
- notes: "`agents auth login` writes its own session, separate from \`rush login\`'s \`~/.rush/user.yaml\` — \`agents auth logout\` never signs you out of \`rush\`. If you're already signed in via \`rush login\`, \`agents auth whoami\`/\`agents org\` use that session automatically; no separate login is required.",
107
+ agents auth logout
108
+ agents auth space create acme-team
109
+ agents auth space invite dev@example.com --role admin`,
110
+ notes: "`agents auth login` writes its own session, separate from \`rush login\`'s \`~/.rush/user.yaml\` — \`agents auth logout\` never signs you out of \`rush\`. If you're already signed in via \`rush login\`, \`agents auth whoami\`/\`agents auth space\` use that session automatically; no separate login is required. \`agents org\` is a deprecated alias of \`agents auth space\`.",
103
111
  });
104
112
  }
@@ -1,2 +1,8 @@
1
+ /**
2
+ * `agents setup beta` — enable or disable preview features like factory.
3
+ * Nested under setup because opting into a preview is machine configuration,
4
+ * not its own noun (RUSH-2981).
5
+ */
1
6
  import type { Command } from 'commander';
2
- export declare function registerBetaCommands(program: Command): void;
7
+ /** Register `agents setup beta` under the parent `setup` command. */
8
+ export declare function registerBetaCommands(setupCmd: Command): void;
@@ -1,5 +1,6 @@
1
1
  import chalk from 'chalk';
2
2
  import { ALL_BETA_FEATURES, getBetaConfigLocation, getEnabledBetaFeatures, setBetaEnabled, } from '../lib/beta.js';
3
+ import { setHelpSections } from '../lib/help.js';
3
4
  const BETA_DESCRIPTIONS = {
4
5
  factory: 'Cloud-based agent dispatch via Rush Factory',
5
6
  };
@@ -20,16 +21,22 @@ function parseFeatures(values) {
20
21
  }
21
22
  return values.filter((v) => valid.has(v));
22
23
  }
23
- export function registerBetaCommands(program) {
24
- const beta = program
24
+ /** Register `agents setup beta` under the parent `setup` command. */
25
+ export function registerBetaCommands(setupCmd) {
26
+ const beta = setupCmd
25
27
  .command('beta')
26
- .description('Enable or disable preview features like factory.')
27
- .addHelpText('after', `
28
- Examples:
29
- agents beta list
30
- agents beta enable factory
31
- agents beta disable factory
32
- `);
28
+ .description('Enable or disable preview features like factory.');
29
+ setHelpSections(beta, {
30
+ examples: `
31
+ agents setup beta list
32
+ agents setup beta enable factory
33
+ agents setup beta disable factory
34
+ `,
35
+ notes: `
36
+ Writes the enabled set to ~/.agents/agents.yaml (beta.enabled). Top-level
37
+ \`agents beta\` is gone — use this group.
38
+ `,
39
+ });
33
40
  beta
34
41
  .command('list')
35
42
  .description('Show available beta features and whether they are enabled.')
@@ -392,7 +392,7 @@ Examples:
392
392
  }
393
393
  else {
394
394
  console.log(chalk.green(`\nRemoved ${removed} command(s) from version homes.`));
395
- console.log(chalk.gray('Central source unchanged. Commands will re-sync on next agent launch.'));
395
+ console.log(chalk.gray("Central source unchanged. Restore any target with 'agents sync <agent>@<version> --yes'."));
396
396
  }
397
397
  });
398
398
  // `commands prune` moved to the top-level `agents prune cleanup` command.
@@ -14,7 +14,7 @@ import { makeClaudeResponder, resolveApiKey, DEFAULT_CLAUDE_MODEL, DEFAULT_CLAUD
14
14
  import { TASK_PREVIEW_MAX_CHARS } from '../lib/computer/sessions-list.js';
15
15
  import { runComputerSessionsCommand } from './computer-sessions-picker.js';
16
16
  import { truncate } from '../lib/feed/events.js';
17
- import { namespacedServiceLabel, serviceManifestHomeEnv } from '../lib/service-manifest.js';
17
+ import { namespacedServiceLabel, serviceManifestHomeEnv, serviceManagerRegistrationAllowed } from '../lib/service-manifest.js';
18
18
  // Help groups — mirror `agents browser` so the mental model carries over.
19
19
  const COMPUTER_HELP_GROUPS = [
20
20
  { title: 'Installation', names: ['setup'] },
@@ -564,6 +564,10 @@ export async function activateComputerHelperMacLocal() {
564
564
  const uid = process.getuid?.();
565
565
  if (typeof uid !== 'number')
566
566
  throw new Error('cannot resolve uid');
567
+ const reg = serviceManagerRegistrationAllowed();
568
+ if (!reg.allowed) {
569
+ throw new Error(reg.reason);
570
+ }
567
571
  const domain = `gui/${uid}`;
568
572
  // Render the policy file BEFORE bootstrap so the daemon reads a fresh allow
569
573
  // list at startup (fail-safe: missing/unparseable → everything denied).
@@ -843,11 +847,21 @@ function registerStopCommand(program) {
843
847
  process.exit(1);
844
848
  }
845
849
  const domain = `gui/${uid}`;
846
- try {
847
- execFileSync('/bin/launchctl', ['bootout', domain, plistPath], { stdio: 'pipe' });
848
- }
849
- catch {
850
- // already gone — fine
850
+ // Same invariant as the start path: a redirected-HOME process must never
851
+ // talk to the real launchd (RUSH-2968). Stop has a local fallback the
852
+ // plist/socket cleanup below — so skip the bootout with the reason
853
+ // rather than throwing like start does.
854
+ const reg = serviceManagerRegistrationAllowed();
855
+ if (!reg.allowed) {
856
+ console.warn(`skipping launchctl bootout: ${reg.reason}`);
857
+ }
858
+ else {
859
+ try {
860
+ execFileSync('/bin/launchctl', ['bootout', domain, plistPath], { stdio: 'pipe' });
861
+ }
862
+ catch {
863
+ // already gone — fine
864
+ }
851
865
  }
852
866
  // launchd unlinks the socket when the daemon exits; helper also has an
853
867
  // atexit unlink. Best-effort cleanup if either path didn't fire.
@@ -761,7 +761,7 @@ function runWebhooksList(json) {
761
761
  const port = hostedReceiverPort(r);
762
762
  const funnel = r.funnel ? chalk.cyan(` public :${r.funnel.publicPort}`) : chalk.gray(' localhost only');
763
763
  console.log(` 127.0.0.1:${String(port).padEnd(6)} ${chalk.gray(`bundle ${r.bundle}`)}${funnel}`);
764
- console.log(chalk.gray(` endpoints: /hooks/github, /hooks/linear · ${r.rateLimit ?? DEFAULT_WEBHOOK_RATE_LIMIT}/min per source`));
764
+ console.log(chalk.gray(` endpoints: /hooks/github, /hooks/linear, /hooks/slack · ${r.rateLimit ?? DEFAULT_WEBHOOK_RATE_LIMIT}/min per source`));
765
765
  }
766
766
  console.log(chalk.gray(`\nConfig: ${getDaemonWebhooksConfigPath()}`));
767
767
  console.log(chalk.gray('Changes take effect on the next daemon restart.'));
@@ -78,9 +78,11 @@ export type IssueSeverity = 'critical' | 'warning' | 'info';
78
78
  *
79
79
  * Severity model (agent-agnostic — applies to every agent doctor inspects):
80
80
  * - critical (silent breakage): an unwired hook, a missing/unparseable
81
- * settings.json, a MISSING resource.
81
+ * settings.json, a MISSING hook or plugin.
82
82
  * - warning (stale / drift): a source layer behind origin, a DIVERGENT resource,
83
- * a stale / never-synced version.
83
+ * a stale / never-synced version, a MISSING resource of any other kind
84
+ * (see `missingResourceSeverity`, which reads this split from
85
+ * `FINDING_SEVERITY` — RUSH-2947).
84
86
  * - info (orphan): an EXTRA resource → `agents prune cleanup`.
85
87
  */
86
88
  export interface VerdictIssue {
@@ -2,7 +2,7 @@ import { IsolationBoundaryError } from '../lib/installations/shims.js';
2
2
  import { explainIsolationBoundary } from '../lib/isolation-boundary-report.js';
3
3
  import { addHostOption } from '../lib/hosts/option.js';
4
4
  import { buildRemoteAgentsInvocation } from '../lib/hosts/remote-cmd.js';
5
- import { loadDevices, isControlDevice } from '../lib/devices/registry.js';
5
+ import { loadDevices } from '../lib/devices/registry.js';
6
6
  import { fanOutDevices, planFleetTargets, remoteFleetTargets } from '../lib/devices/fleet.js';
7
7
  import { enterDoctorOverviewGate, invalidateDoctorOverviewCache, writeDoctorOverviewCache } from '../lib/devices/doctor-overview-cache.js';
8
8
  import { fleetDialTarget } from '../lib/devices/connect.js';
@@ -183,9 +183,6 @@ async function resolveFleetTargets(opts) {
183
183
  // Normalize names so zion/ZION/zion.local all match machineId() and we never
184
184
  // self-SSH the local box during fleet probes (RUSH-2114).
185
185
  .filter((d) => normalizeHost(d.name) !== localName)
186
- // Control devices (a cockpit) never run agents — skip them in the fleet
187
- // fan-out (an explicit --device <name> still resolves above).
188
- .filter((d) => !isControlDevice(d))
189
186
  .map((d) => ({
190
187
  name: d.name,
191
188
  sshTarget: d.name,
@@ -669,6 +666,19 @@ const AUTO_FIXABLE_CATEGORIES = new Set([
669
666
  export function verdictIsAutoFixable(v) {
670
667
  return v.issues.some((i) => AUTO_FIXABLE_CATEGORIES.has(i.category));
671
668
  }
669
+ /**
670
+ * Missing-resource severity for one `DoctorKind`, read from `FINDING_SEVERITY`
671
+ * (the fleet-mode rubric) so target mode agrees with it kind by kind instead of
672
+ * re-hardcoding its own. Hooks and plugins map to their dedicated critical
673
+ * finding kinds; every other kind maps to the generic 'missing-resource' warning.
674
+ */
675
+ function missingResourceSeverity(kind) {
676
+ if (kind === 'hooks')
677
+ return FINDING_SEVERITY['missing-hook'];
678
+ if (kind === 'plugins')
679
+ return FINDING_SEVERITY['missing-plugin'];
680
+ return FINDING_SEVERITY['missing-resource'];
681
+ }
672
682
  /**
673
683
  * Fold a version report's divergences into a triaged verdict — one severity-tagged
674
684
  * finding per unwired hook, missing/divergent/extra resource, and behind-origin
@@ -718,16 +728,18 @@ export function computeVerdict(report) {
718
728
  });
719
729
  }
720
730
  }
721
- // ── critical: missing resources (declared in sources, absent from home) ──
731
+ // ── missing resources (declared in sources, absent from home) — severity
732
+ // follows FINDING_SEVERITY: hooks/plugins are critical, everything else warns ──
722
733
  for (const kind of DOCTOR_ALL_KINDS) {
723
734
  for (const r of report.kinds[kind]) {
724
735
  if (r.status !== 'missing')
725
736
  continue;
737
+ const severity = missingResourceSeverity(kind);
726
738
  issues.push({
727
- severity: 'critical', category: 'missing', subject: r.name,
739
+ severity, category: 'missing', subject: r.name,
728
740
  impact: `declared in sources but absent from the version home (${kind})`,
729
741
  fix: fixCmd,
730
- text: `${r.name} missing`, color: 'red',
742
+ text: `${r.name} missing`, color: severity === 'critical' ? 'red' : 'yellow',
731
743
  });
732
744
  }
733
745
  }
@@ -1739,10 +1751,10 @@ export function registerDoctorCommand(program) {
1739
1751
  console.log(line);
1740
1752
  }
1741
1753
  // Point at the interactive reconcile when anything is out of sync — each
1742
- // finding carries its own fix, but `agents status` is the one place that
1754
+ // finding carries its own fix, but `agents sync status` is the one place that
1743
1755
  // reviews and applies them together (opt-in, never auto-fires here).
1744
1756
  if (syncRows.some((r) => r.status !== 'fresh' || (r.unwiredHooks ?? 0) > 0) || repoBehindMarkers.some((m) => m.behind > 0)) {
1745
- console.log(chalk.gray('\nRun `agents status` to review and sync what has drifted.'));
1757
+ console.log(chalk.gray('\nRun `agents sync status` to review and sync what has drifted.'));
1746
1758
  }
1747
1759
  // A routine runs on exactly one device. Each of these named several and
1748
1760
  // used to fire once per device — duplicate agent runs on every schedule.
@@ -7,7 +7,7 @@
7
7
  * (per-session activity: plans, PRs, worktrees, sub-agents, artifacts). Run-dispatch
8
8
  * outcomes land here as `run.dispatched` (readable via `--include runs`).
9
9
  *
10
- * `agents audit` and `agents logs` are thin aliases of this command.
10
+ * `agents events audit` and `agents logs` are thin aliases of this command.
11
11
  *
12
12
  * Filter with sessions-style `--include` / `--exclude` families (ops, activity,
13
13
  * commands, runs, security) plus field filters (`--module`, `--event`, …).
@@ -49,7 +49,7 @@ export interface EventsOptions {
49
49
  }
50
50
  /** Add the one canonical event-reader option surface to a command or alias. */
51
51
  export declare function addEventsReadOptions(command: Command, includeAuditFlag?: boolean): Command;
52
- /** Canonical reader used by `agents events`, `agents audit`, and `agents logs`. */
52
+ /** Canonical reader used by `agents events`, `agents events audit`, and `agents logs`. */
53
53
  export declare function runEventsCommand(options: EventsOptions, forceAudit?: boolean): Promise<void>;
54
54
  /** Shared by `events stats` and the `logs stats` alias. */
55
55
  export declare function runEventsStats(opts: {
@@ -7,7 +7,7 @@
7
7
  * (per-session activity: plans, PRs, worktrees, sub-agents, artifacts). Run-dispatch
8
8
  * outcomes land here as `run.dispatched` (readable via `--include runs`).
9
9
  *
10
- * `agents audit` and `agents logs` are thin aliases of this command.
10
+ * `agents events audit` and `agents logs` are thin aliases of this command.
11
11
  *
12
12
  * Filter with sessions-style `--include` / `--exclude` families (ops, activity,
13
13
  * commands, runs, security) plus field filters (`--module`, `--event`, …).
@@ -19,6 +19,7 @@ import { readUnifiedEvents } from '../lib/event-stream.js';
19
19
  import { parseFamilyList, EVENT_FAMILIES } from '../lib/event-families.js';
20
20
  import { ingestBatch } from '../lib/events-ingest.js';
21
21
  import { setHelpSections } from '../lib/help.js';
22
+ import { registerAuditCommands } from './audit.js';
22
23
  /**
23
24
  * Resolve `--limit` into a record cap. `0` means "no cap" — without it there is
24
25
  * no way to read the whole stream, and any aggregation (group-by failure, count
@@ -215,7 +216,7 @@ export function addEventsReadOptions(command, includeAuditFlag = true) {
215
216
  }
216
217
  return command;
217
218
  }
218
- /** Canonical reader used by `agents events`, `agents audit`, and `agents logs`. */
219
+ /** Canonical reader used by `agents events`, `agents events audit`, and `agents logs`. */
219
220
  export async function runEventsCommand(options, forceAudit = false) {
220
221
  if (options.follow) {
221
222
  await followLog();
@@ -356,9 +357,8 @@ Examples:
356
357
  agents events -f Live tail (operational)
357
358
  agents events stats
358
359
  agents events rotate --days 7
359
-
360
- agents audit Alias of: events --include runs
361
- agents logs Alias of: events`)
360
+ agents events audit Alias of: events --include runs
361
+ agents logs Run log viewer (also aliases events audit/stats/rotate)`)
362
362
  .action((_options, command) => runEventsCommand(command.optsWithGlobals()));
363
363
  // `events` both reads (its own action, above) and writes (this subcommand) —
364
364
  // the same shape as `feed` / `feed post`.
@@ -375,6 +375,7 @@ Examples:
375
375
  .option('--days <n>', 'Retention period in days (default 7)', '7')
376
376
  .option('--max-mb <n>', 'Total event storage ceiling in MiB (default 50)', '50')
377
377
  .action((opts) => runEventsRotate(opts));
378
+ registerAuditCommands(events);
378
379
  }
379
380
  /** Shared by `events rotate` and the `logs rotate` alias. */
380
381
  export function runEventsRotate(opts) {
@@ -15,7 +15,6 @@ export interface RunAccountPickerRequest {
15
15
  }
16
16
  /** Distinguish a terminal account-picker marker from an explicit @version pin. */
17
17
  export declare function parseRunAccountPickerRequest(agentSpec: string): RunAccountPickerRequest;
18
- /** Return every option whose routing semantics conflict with a local account choice. */
19
18
  /**
20
19
  * The `--device` alias family — the flags that mean "dispatch this run to another
21
20
  * machine over SSH". `--device` is canonical; `--on`/`--computer` are hidden
@@ -30,6 +29,7 @@ export declare function hostTargetGiven(options: {
30
29
  on?: string;
31
30
  computer?: string;
32
31
  }): string[];
32
+ /** Return every option whose selection semantics conflict with an account choice. */
33
33
  export declare function runAccountPickerConflicts(options: {
34
34
  resume?: string | boolean;
35
35
  strategy?: string;
@@ -36,7 +36,6 @@ export function parseRunAccountPickerRequest(agentSpec) {
36
36
  valid: !requested || (!!normalizedAgentSpec && !normalizedAgentSpec.includes('@')),
37
37
  };
38
38
  }
39
- /** Return every option whose routing semantics conflict with a local account choice. */
40
39
  /**
41
40
  * The `--device` alias family — the flags that mean "dispatch this run to another
42
41
  * machine over SSH". `--device` is canonical; `--on`/`--computer` are hidden
@@ -48,6 +47,7 @@ export function parseRunAccountPickerRequest(agentSpec) {
48
47
  export function hostTargetGiven(options) {
49
48
  return [options.host, options.device, options.on, options.computer].filter((v) => !!v);
50
49
  }
50
+ /** Return every option whose selection semantics conflict with an account choice. */
51
51
  export function runAccountPickerConflicts(options) {
52
52
  const conflicts = [];
53
53
  if (options.resume !== undefined)
@@ -60,8 +60,6 @@ export function runAccountPickerConflicts(options) {
60
60
  conflicts.push('--lease');
61
61
  if (options.box)
62
62
  conflicts.push('--box');
63
- if (hostTargetGiven(options).length)
64
- conflicts.push('--device');
65
63
  return conflicts;
66
64
  }
67
65
  /** Type guard that narrows a string to a known AgentId. */
@@ -845,7 +843,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
845
843
  const conflicts = runAccountPickerConflicts(options);
846
844
  if (conflicts.length > 0) {
847
845
  console.error(chalk.red(`Account selection with ${agentSpec} cannot be combined with ${conflicts.join(', ')}. ` +
848
- 'Pick the account locally, or use an explicit agent@version target.'));
846
+ 'Remove the conflicting selector, or use an explicit agent@version target.'));
849
847
  process.exit(1);
850
848
  }
851
849
  }
@@ -1450,6 +1448,11 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
1450
1448
  process.exit(1);
1451
1449
  }
1452
1450
  const interactiveHost = options.interactive === true || (prompt === undefined && options.headless !== true);
1451
+ if (accountPickerRequested && !interactiveHost) {
1452
+ console.error(chalk.red(`Account selection with ${agentSpec} requires an interactive host run. ` +
1453
+ `Use agents run ${runAgent}@ --device ${host.name} --interactive.`));
1454
+ process.exit(1);
1455
+ }
1453
1456
  if (interactiveHost) {
1454
1457
  // Interactive host run: forward the local TTY over SSH and let the
1455
1458
  // remote agent start its normal interactive UI (tmux on the host).
@@ -1496,6 +1499,7 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
1496
1499
  const exitCode = await runInteractiveOnHost(host, {
1497
1500
  agent: runAgent,
1498
1501
  version: resumeId ? undefined : runVersion,
1502
+ accountPicker: accountPickerRequested,
1499
1503
  strategy: resumeId ? undefined : runStrategy,
1500
1504
  account: resumeId ? undefined : options.account,
1501
1505
  fallback: options.fallback,
@@ -3015,8 +3019,9 @@ agents run auto --device yosemite-s0 "fix the flaky test" # pin the device
3015
3019
  let exitCode;
3016
3020
  let ranAgent = agent;
3017
3021
  let ranVersion = defaultVersion;
3018
- if (fallback.length > 0) {
3019
- // fallback requires a prompt enforced above, narrow the type here.
3022
+ if (fallback.length > 0 || (rotationResult !== null && prompt !== undefined && !options.interactive)) {
3023
+ // Fallback and balanced runs need captured output so a clean-exit
3024
+ // session-limit refusal can update account availability.
3020
3025
  // The sink reports which chain entry actually executed (may differ from
3021
3026
  // the primary after a rate-limit handoff) so the audit record is honest.
3022
3027
  const sink = {};
@@ -2,7 +2,7 @@
2
2
  * Software Factory CLI — submits Linear issues to a remote orchestrator.
3
3
  *
4
4
  * Requires FACTORY_FLOOR_URL pointing at a Factory-compatible endpoint.
5
- * Beta-gated; enable with `agents beta enable factory`.
5
+ * Beta-gated; enable with `agents setup beta enable factory`.
6
6
  */
7
7
  import type { Command } from 'commander';
8
8
  export declare function registerFactoryCommands(program: Command): void;