@phnx-labs/agents-cli 1.22.41 → 1.22.43

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 (253) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +10 -4
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.js +25 -7
  5. package/dist/cli/command-registry.d.ts +2 -3
  6. package/dist/cli/command-registry.js +4 -8
  7. package/dist/commands/accounts.d.ts +29 -0
  8. package/dist/commands/accounts.js +220 -29
  9. package/dist/commands/alias.d.ts +7 -4
  10. package/dist/commands/alias.js +34 -9
  11. package/dist/commands/auth.d.ts +9 -0
  12. package/dist/commands/auth.js +108 -0
  13. package/dist/commands/browser-sessions-picker.js +42 -62
  14. package/dist/commands/browser.js +30 -38
  15. package/dist/commands/computer-actions.d.ts +1 -1
  16. package/dist/commands/computer-actions.js +1 -1
  17. package/dist/commands/computer-sessions-picker.js +32 -55
  18. package/dist/commands/computer.d.ts +1 -1
  19. package/dist/commands/computer.js +22 -8
  20. package/dist/commands/daemon.js +1 -1
  21. package/dist/commands/doctor.d.ts +5 -3
  22. package/dist/commands/doctor.js +23 -8
  23. package/dist/commands/exec.js +3 -2
  24. package/dist/commands/feed.js +2 -31
  25. package/dist/commands/harness.js +3 -3
  26. package/dist/commands/hooks.js +1 -1
  27. package/dist/commands/import.js +1 -1
  28. package/dist/commands/insights.js +163 -85
  29. package/dist/commands/inspect.js +2 -2
  30. package/dist/commands/mine.js +1 -1
  31. package/dist/commands/monitors.js +1 -1
  32. package/dist/commands/org.d.ts +6 -0
  33. package/dist/commands/org.js +175 -0
  34. package/dist/commands/packages.js +1 -1
  35. package/dist/commands/profiles.js +2 -2
  36. package/dist/commands/prune.js +1 -1
  37. package/dist/commands/routines.js +44 -26
  38. package/dist/commands/run-account-picker.d.ts +19 -0
  39. package/dist/commands/run-account-picker.js +81 -0
  40. package/dist/commands/sessions-picker-factory.d.ts +40 -0
  41. package/dist/commands/sessions-picker-factory.js +67 -0
  42. package/dist/commands/sessions-picker.js +124 -122
  43. package/dist/commands/setup-browser.js +4 -4
  44. package/dist/commands/setup-mine.js +1 -1
  45. package/dist/commands/setup-preferences.js +2 -2
  46. package/dist/commands/setup.js +10 -4
  47. package/dist/commands/snapshot.d.ts +1 -1
  48. package/dist/commands/snapshot.js +4 -4
  49. package/dist/commands/status.d.ts +4 -2
  50. package/dist/commands/status.js +10 -7
  51. package/dist/commands/sync.d.ts +1 -0
  52. package/dist/commands/sync.js +30 -3
  53. package/dist/commands/versions.js +1 -1
  54. package/dist/commands/view.js +7 -1
  55. package/dist/commands/webhook.js +1 -1
  56. package/dist/lib/account-capabilities.d.ts +10 -0
  57. package/dist/lib/account-capabilities.js +34 -0
  58. package/dist/lib/accounting/rotate.d.ts +5 -3
  59. package/dist/lib/accounting/rotate.js +36 -7
  60. package/dist/lib/accounting/usage.d.ts +18 -4
  61. package/dist/lib/accounting/usage.js +138 -27
  62. package/dist/lib/agent-spec/agents.d.ts +584 -0
  63. package/dist/lib/agent-spec/agents.js +3127 -0
  64. package/dist/lib/agent-spec/provider.js +1 -1
  65. package/dist/lib/agents.d.ts +2 -584
  66. package/dist/lib/agents.js +2 -3127
  67. package/dist/lib/browser/drivers/local.d.ts +8 -2
  68. package/dist/lib/browser/drivers/local.js +8 -2
  69. package/dist/lib/browser/drivers/ssh.d.ts +8 -2
  70. package/dist/lib/browser/drivers/ssh.js +10 -4
  71. package/dist/lib/browser/hygiene.d.ts +1 -1
  72. package/dist/lib/browser/hygiene.js +5 -1
  73. package/dist/lib/browser/profiles.d.ts +74 -1
  74. package/dist/lib/browser/profiles.js +114 -5
  75. package/dist/lib/browser/runtime-state.d.ts +11 -5
  76. package/dist/lib/browser/runtime-state.js +13 -9
  77. package/dist/lib/browser/service.d.ts +68 -30
  78. package/dist/lib/browser/service.js +305 -194
  79. package/dist/lib/browser/types.d.ts +95 -3
  80. package/dist/lib/browser/types.js +51 -0
  81. package/dist/lib/catchup.js +1 -1
  82. package/dist/lib/cloud/rush.d.ts +0 -15
  83. package/dist/lib/cloud/rush.js +0 -35
  84. package/dist/lib/computer/actions.d.ts +1 -1
  85. package/dist/lib/computer/actions.js +1 -1
  86. package/dist/lib/{computer-rpc.js → computer/computer-rpc.js} +5 -5
  87. package/dist/lib/computer/dispatch.d.ts +1 -1
  88. package/dist/lib/computer/download.d.ts +1 -1
  89. package/dist/lib/computer/download.js +3 -3
  90. package/dist/lib/{ssh-tunnel.d.ts → computer/ssh-tunnel.d.ts} +1 -1
  91. package/dist/lib/{ssh-tunnel.js → computer/ssh-tunnel.js} +12 -12
  92. package/dist/lib/crabbox/runtimes.d.ts +6 -2
  93. package/dist/lib/crabbox/runtimes.js +21 -5
  94. package/dist/lib/daemon/daemon.js +87 -59
  95. package/dist/lib/{runner.d.ts → daemon/runner.d.ts} +28 -11
  96. package/dist/lib/{runner.js → daemon/runner.js} +143 -123
  97. package/dist/lib/devices/doctor-findings.d.ts +1 -1
  98. package/dist/lib/devices/doctor-findings.js +4 -4
  99. package/dist/lib/devices/fleet-inventory.js +1 -1
  100. package/dist/lib/devices/harness-inventory.js +1 -1
  101. package/dist/lib/devices/health-report.js +1 -1
  102. package/dist/lib/devices/registry.js +4 -22
  103. package/dist/lib/doctor-diff.d.ts +1 -1
  104. package/dist/lib/doctor-diff.js +1 -1
  105. package/dist/lib/drift-sync.d.ts +1 -1
  106. package/dist/lib/drift-sync.js +2 -2
  107. package/dist/lib/drift.d.ts +1 -1
  108. package/dist/lib/drift.js +1 -1
  109. package/dist/lib/entitlement.d.ts +31 -0
  110. package/dist/lib/entitlement.js +137 -0
  111. package/dist/lib/exec.js +52 -205
  112. package/dist/lib/feed/feed.js +2 -8
  113. package/dist/lib/format.d.ts +9 -0
  114. package/dist/lib/format.js +16 -0
  115. package/dist/lib/fs-atomic.d.ts +7 -0
  116. package/dist/lib/fs-atomic.js +9 -0
  117. package/dist/lib/github/pr-mergeable.d.ts +49 -0
  118. package/dist/lib/github/pr-mergeable.js +157 -0
  119. package/dist/lib/github/pr-verdict.d.ts +67 -0
  120. package/dist/lib/github/pr-verdict.js +72 -0
  121. package/dist/lib/harness/adapter.d.ts +161 -0
  122. package/dist/lib/harness/adapter.js +47 -0
  123. package/dist/lib/harness/adapters/claude.d.ts +2 -0
  124. package/dist/lib/harness/adapters/claude.js +110 -0
  125. package/dist/lib/harness/adapters/codex.d.ts +2 -0
  126. package/dist/lib/harness/adapters/codex.js +83 -0
  127. package/dist/lib/harness/adapters/copilot.d.ts +2 -0
  128. package/dist/lib/harness/adapters/copilot.js +23 -0
  129. package/dist/lib/harness/adapters/cursor.d.ts +2 -0
  130. package/dist/lib/harness/adapters/cursor.js +38 -0
  131. package/dist/lib/harness/adapters/droid.d.ts +2 -0
  132. package/dist/lib/harness/adapters/droid.js +17 -0
  133. package/dist/lib/harness/adapters/grok.d.ts +2 -0
  134. package/dist/lib/harness/adapters/grok.js +14 -0
  135. package/dist/lib/harness/adapters/kimi.d.ts +2 -0
  136. package/dist/lib/harness/adapters/kimi.js +49 -0
  137. package/dist/lib/harness/adapters/muse.d.ts +2 -0
  138. package/dist/lib/harness/adapters/muse.js +44 -0
  139. package/dist/lib/harness/adapters/opencode.d.ts +2 -0
  140. package/dist/lib/harness/adapters/opencode.js +14 -0
  141. package/dist/lib/harness/exec-config-version.d.ts +8 -0
  142. package/dist/lib/harness/exec-config-version.js +22 -0
  143. package/dist/lib/harness/index.d.ts +1 -0
  144. package/dist/lib/harness/index.js +34 -0
  145. package/dist/lib/{hooks.d.ts → hooks/install.d.ts} +1 -1
  146. package/dist/lib/{hooks.js → hooks/install.js} +11 -11
  147. package/dist/lib/hosts/passthrough.d.ts +10 -0
  148. package/dist/lib/hosts/passthrough.js +28 -6
  149. package/dist/lib/hosts/session-index.js +1 -1
  150. package/dist/lib/import.js +1 -1
  151. package/dist/lib/installations/index.d.ts +4 -4
  152. package/dist/lib/installations/index.js +3 -4
  153. package/dist/lib/installations/migrate.js +6 -6
  154. package/dist/lib/{shims.d.ts → installations/shims.d.ts} +2 -2
  155. package/dist/lib/{shims.js → installations/shims.js} +13 -115
  156. package/dist/lib/installations/store.d.ts +141 -3
  157. package/dist/lib/installations/store.js +475 -5
  158. package/dist/lib/installations/versions.d.ts +40 -125
  159. package/dist/lib/installations/versions.js +57 -462
  160. package/dist/lib/isolation-boundary-report.d.ts +1 -1
  161. package/dist/lib/isolation-boundary-report.js +1 -1
  162. package/dist/lib/mailbox-gc.js +2 -3
  163. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  164. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  165. package/dist/lib/menubar/install-menubar.js +19 -8
  166. package/dist/lib/monitors/config.d.ts +2 -2
  167. package/dist/lib/monitors/config.js +3 -2
  168. package/dist/lib/monitors/dispatch.d.ts +1 -1
  169. package/dist/lib/monitors/dispatch.js +2 -2
  170. package/dist/lib/monitors/state.d.ts +1 -1
  171. package/dist/lib/origin-machine.d.ts +18 -0
  172. package/dist/lib/origin-machine.js +34 -0
  173. package/dist/lib/perf/db.js +1 -1
  174. package/dist/lib/perf/spool.js +1 -1
  175. package/dist/lib/plugins/plugins.js +1 -1
  176. package/dist/lib/plugins/skills.js +1 -1
  177. package/dist/lib/prix-account.d.ts +158 -0
  178. package/dist/lib/prix-account.js +214 -0
  179. package/dist/lib/profiles.d.ts +7 -0
  180. package/dist/lib/profiles.js +26 -1
  181. package/dist/lib/project-key.js +2 -2
  182. package/dist/lib/project-launch.js +1 -1
  183. package/dist/lib/refresh.js +2 -2
  184. package/dist/lib/resource-inventory.d.ts +1 -1
  185. package/dist/lib/resource-inventory.js +1 -1
  186. package/dist/lib/rules/rules.js +1 -1
  187. package/dist/lib/sandbox.d.ts +24 -0
  188. package/dist/lib/sandbox.js +101 -0
  189. package/dist/lib/scheduling/routines.d.ts +18 -9
  190. package/dist/lib/scheduling/routines.js +17 -9
  191. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  192. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  193. package/dist/lib/secrets/agent.js +9 -1
  194. package/dist/lib/secrets/index.js +1 -1
  195. package/dist/lib/secrets/list-filter.js +1 -1
  196. package/dist/lib/self-heal/checks/hook-runtime.js +1 -1
  197. package/dist/lib/self-heal/checks/path.js +1 -1
  198. package/dist/lib/self-heal/checks/shadowing.js +1 -1
  199. package/dist/lib/self-heal/checks/shims.js +1 -1
  200. package/dist/lib/service-manifest.d.ts +20 -0
  201. package/dist/lib/service-manifest.js +34 -0
  202. package/dist/lib/session/cloud.js +1 -1
  203. package/dist/lib/session/db.js +1 -1
  204. package/dist/lib/session/discover.d.ts +39 -0
  205. package/dist/lib/session/discover.js +3 -3
  206. package/dist/lib/session/fork.js +1 -1
  207. package/dist/lib/session/live-metadata.js +1 -1
  208. package/dist/lib/session/origin-machine.d.ts +1 -18
  209. package/dist/lib/session/origin-machine.js +4 -34
  210. package/dist/lib/session/parse.js +24 -42
  211. package/dist/lib/session/recovery.js +1 -1
  212. package/dist/lib/session/relative-time.d.ts +1 -44
  213. package/dist/lib/session/relative-time.js +4 -120
  214. package/dist/lib/session/remote-list.js +1 -1
  215. package/dist/lib/session/remote.js +2 -2
  216. package/dist/lib/session/short-id.d.ts +1 -17
  217. package/dist/lib/session/short-id.js +4 -20
  218. package/dist/lib/session/width.d.ts +1 -29
  219. package/dist/lib/session/width.js +4 -101
  220. package/dist/lib/snapshot.d.ts +2 -2
  221. package/dist/lib/snapshot.js +1 -1
  222. package/dist/lib/staleness/prune.d.ts +1 -1
  223. package/dist/lib/staleness/prune.js +1 -1
  224. package/dist/lib/staleness/writers/hooks.js +1 -1
  225. package/dist/lib/startup/command-registry.d.ts +4 -1
  226. package/dist/lib/startup/command-registry.js +12 -5
  227. package/dist/lib/teams/agents.js +2 -19
  228. package/dist/lib/teams/parsers.js +20 -26
  229. package/dist/lib/teams/placement-probe.js +1 -1
  230. package/dist/lib/teams/registry.js +2 -21
  231. package/dist/lib/teams/scheduler.js +1 -1
  232. package/dist/lib/text/relative-time.d.ts +44 -0
  233. package/dist/lib/text/relative-time.js +120 -0
  234. package/dist/lib/text/short-id.d.ts +17 -0
  235. package/dist/lib/text/short-id.js +20 -0
  236. package/dist/lib/text/width.d.ts +29 -0
  237. package/dist/lib/text/width.js +101 -0
  238. package/dist/lib/triggers/handlers.d.ts +7 -0
  239. package/dist/lib/triggers/handlers.js +9 -1
  240. package/dist/lib/triggers/webhook.d.ts +1 -0
  241. package/dist/lib/triggers/webhook.js +3 -2
  242. package/dist/lib/uninstall.js +1 -1
  243. package/dist/lib/version.d.ts +9 -2
  244. package/dist/lib/version.js +11 -9
  245. package/dist/lib/view-types.d.ts +4 -0
  246. package/package.json +1 -1
  247. package/dist/commands/tickets.d.ts +0 -2
  248. package/dist/commands/tickets.js +0 -43
  249. package/dist/lib/observe-aliases.d.ts +0 -30
  250. package/dist/lib/observe-aliases.js +0 -38
  251. package/dist/lib/tickets/list.d.ts +0 -53
  252. package/dist/lib/tickets/list.js +0 -153
  253. /package/dist/lib/{computer-rpc.d.ts → computer/computer-rpc.d.ts} +0 -0
@@ -386,7 +386,7 @@ export function buildPreview(session) {
386
386
  const header = formatHeader(safe, events);
387
387
  const body = parseError
388
388
  ? ' ' + chalk.red(`Failed to parse session: ${parseError}`)
389
- : formatCompactPreview(digest, safe);
389
+ : formatCompactPreview(digest, safe, events);
390
390
  const output = [header, '', body].filter(Boolean).join('\n');
391
391
  previewCache.set(cacheKey, output);
392
392
  return output;
@@ -398,8 +398,6 @@ const DOT = chalk.gray(' · ');
398
398
  function formatHeader(session, events) {
399
399
  const model = extractModel(events) || session.model;
400
400
  const { createdAgo, lastActiveAgo, duration } = extractTiming(session, events);
401
- const totalMessages = session.messageCount ?? countMessages(events);
402
- const totalTokens = session.tokenCount;
403
401
  // Line 1: Agent v version · shortId · model · account
404
402
  const line1 = [];
405
403
  line1.push(chalk.gray(`${displayAgent(session.agent)}${session.version ? ` v${session.version}` : ''}`));
@@ -429,18 +427,6 @@ function formatHeader(session, events) {
429
427
  line2.push(chalk.gray('last active ') + chalk.white(lastActiveAgo + ' ago'));
430
428
  if (duration)
431
429
  line2.push(chalk.gray('lasted ') + chalk.white(duration));
432
- // Line 3: N msgs · T tokens · [label ·] uuid
433
- const line3 = [];
434
- if (totalMessages !== undefined) {
435
- line3.push(chalk.bold.white(String(totalMessages)) + chalk.gray(` msg${totalMessages === 1 ? '' : 's'}`));
436
- }
437
- if (totalTokens !== undefined) {
438
- line3.push(chalk.bold.white(formatTokens(totalTokens)) + chalk.gray(' tokens'));
439
- }
440
- if (session.filePath)
441
- line3.push(chalk.gray(linkPath(session.filePath, session.id)));
442
- else
443
- line3.push(chalk.gray(session.id));
444
430
  // Line 4: ticket + PR — clickable when a URL is resolvable (OSC 8 hyperlink),
445
431
  // plain text otherwise. Only rendered when the session carries either.
446
432
  const line4 = [];
@@ -467,7 +453,6 @@ function formatHeader(session, events) {
467
453
  ...titleLines,
468
454
  line1.join(DOT),
469
455
  line2.join(DOT),
470
- line3.join(DOT),
471
456
  ...(line4.length ? [line4.join(DOT)] : []),
472
457
  ].join('\n');
473
458
  }
@@ -512,24 +497,20 @@ export function formatTeamLineage(session) {
512
497
  }
513
498
  function formatMetaOnlyBody(session) {
514
499
  const lines = [];
500
+ const termWidth = process.stdout.columns || 80;
501
+ const valueWidth = termWidth - VERB_GUTTER - 5;
502
+ // Same verb-led rows as the digest body (RUSH-2757), from SessionMeta alone.
515
503
  if (session.topic) {
516
- lines.push(chalk.cyan('Prompt: ') + chalk.white(truncate(session.topic.trim(), (process.stdout.columns || 80) - 12)));
517
- }
518
- const teamLine = formatTeamLineage(session);
519
- if (teamLine) {
520
- lines.push(chalk.cyan('Team: ') + teamLine);
504
+ lines.push(verbLabel('Asked') + chalk.white(`"${truncate(session.topic.trim(), valueWidth)}"`));
521
505
  }
522
506
  const compact = formatTodoCompact(session.todos);
523
- if (compact) {
524
- lines.push(chalk.cyan('Todos: ') + chalk.white(compact));
507
+ const teamLine = formatTeamLineage(session);
508
+ const doing = [compact ? chalk.white(compact) : '', teamLine].filter(Boolean);
509
+ if (doing.length) {
510
+ lines.push(verbLabel('Doing') + doing.join(DOT));
525
511
  }
526
- const termWidth = process.stdout.columns || 80;
527
512
  for (const l of session.todos?.items?.length ? renderTodos(session.todos.items, termWidth) : []) {
528
- lines.push(l);
529
- }
530
- const dirs = session.recentDirectoriesTouched?.slice(0, DIRS_TOUCHED_MAX) ?? [];
531
- if (dirs.length) {
532
- lines.push(chalk.cyan('Dirs: ') + chalk.white(dirs.join(chalk.gray(' · '))));
513
+ lines.push(' ' + l);
533
514
  }
534
515
  // `plan` is the whole ExitPlanMode markdown, not a path — summarize it. The
535
516
  // pane is height-clamped anyway, so pasting the blob would just push every
@@ -537,10 +518,24 @@ function formatMetaOnlyBody(session) {
537
518
  const planLines = session.plan?.trim() ? session.plan.trim().split('\n') : [];
538
519
  if (planLines.length) {
539
520
  const head = truncate(planLines[0].replace(/^#+\s*/, ''), termWidth - 20);
540
- lines.push(chalk.cyan('Plan: ') + chalk.white(head) + chalk.gray(` · ${planLines.length} lines`));
521
+ lines.push(verbLabel('Made') + chalk.white(head) + chalk.gray(` · plan, ${planLines.length} lines`));
541
522
  }
542
- if (lines.length === 0)
543
- return '';
523
+ const cost = [];
524
+ if (session.messageCount !== undefined) {
525
+ cost.push(chalk.white(String(session.messageCount)) + chalk.gray(` msg${session.messageCount === 1 ? '' : 's'}`));
526
+ }
527
+ if (session.tokenCount !== undefined) {
528
+ cost.push(chalk.white(formatTokens(session.tokenCount)) + chalk.gray(' tokens'));
529
+ }
530
+ if (cost.length) {
531
+ lines.push(verbLabel('Cost') + cost.join(DOT));
532
+ }
533
+ const dirs = session.recentDirectoriesTouched?.slice(0, DIRS_TOUCHED_MAX) ?? [];
534
+ const details = [
535
+ session.filePath ? chalk.gray(linkPath(session.filePath, session.id.slice(0, 8))) : chalk.gray(session.id.slice(0, 8)),
536
+ ...dirs.map(d => chalk.gray(d)),
537
+ ];
538
+ lines.push(verbLabel('Details ▸') + joinWidthCapped(details, valueWidth));
544
539
  return lines.map(l => ' ' + l).join('\n');
545
540
  }
546
541
  function extractModel(events) {
@@ -720,45 +715,42 @@ export function buildSessionPreviewDigest(events, session) {
720
715
  test: detectTestResult(events),
721
716
  };
722
717
  }
723
- function formatCompactPreview(digest, session) {
718
+ // Verb-led row gutter (RUSH-2757): every row label pads to this width so the
719
+ // values align into one scannable column. 'Details ▸' is the widest label.
720
+ const VERB_GUTTER = 9;
721
+ function verbLabel(v) {
722
+ return chalk.cyan(v.padEnd(VERB_GUTTER)) + ' ';
723
+ }
724
+ function formatCompactPreview(digest, session, events) {
724
725
  const { firstUser, lastAssistant, filesRead, toolCalls, planFile, todos, subAgentCount, toolTags, changes: chg, dirs, repos, artifacts, skills, plugins, hooks, links, errorCount, firstError, toolHistogram: hist, test, } = digest;
725
726
  const lines = [];
726
727
  const termWidth = process.stdout.columns || 80;
727
- // Originating user prompt (first non-system user turn).
728
- if (firstUser) {
729
- const first = extractSessionTopic(firstUser) || cleanSessionPrompt(firstUser).split('\n').find(l => l.trim()) || '';
730
- if (first) {
731
- lines.push(chalk.cyan('Prompt: ') + chalk.white(truncate(first.trim(), termWidth - 12)));
732
- }
728
+ const valueWidth = termWidth - VERB_GUTTER - 5;
729
+ // Asked — the originating user prompt (first non-system user turn), quoted.
730
+ const asked = firstUser
731
+ ? (extractSessionTopic(firstUser) || cleanSessionPrompt(firstUser).split('\n').find(l => l.trim()) || '')
732
+ : (session.topic && !isSyntheticUserMessage(session.topic) ? session.topic : '');
733
+ if (asked.trim()) {
734
+ lines.push(verbLabel('Asked') + chalk.white(`"${truncate(asked.trim(), valueWidth)}"`));
733
735
  }
734
- else if (session.topic && !isSyntheticUserMessage(session.topic)) {
735
- lines.push(chalk.cyan('Prompt: ') + chalk.white(truncate(session.topic.trim(), termWidth - 12)));
736
- }
737
- // Compact checklist: ✓done/total · current step (RUSH-2045).
736
+ // Doing the work in motion: checklist progress (RUSH-2045), team lineage,
737
+ // sub-agent fan-out. The full checklist renders indented beneath.
738
738
  const compact = formatTodoCompact(todos);
739
- if (compact) {
740
- lines.push(chalk.cyan('Todos: ') + chalk.white(compact));
741
- }
742
- const todosRendered = todos?.items?.length ? renderTodos(todos.items, termWidth) : [];
743
- if (todosRendered.length > 0) {
744
- for (const l of todosRendered)
745
- lines.push(' ' + l);
746
- }
747
- // Recent activity = directories touched (not raw tool calls). Prefer a
748
- // parser-supplied dirsTouched when present; else derive from event paths.
749
- // Width-capped: a long Dirs line used to wrap and swamp the whole pane.
750
- if (dirs.length) {
751
- lines.push(chalk.cyan('Dirs: ') + joinWidthCapped(dirs, termWidth - 12));
752
- }
753
- // Repos worked in (basename of each `.git` root under the touched paths).
754
- if (repos.length) {
755
- lines.push(chalk.cyan('Repos: ') + chalk.white(repos.slice(0, 4).join(chalk.gray(' · '))));
756
- }
757
739
  const teamLine = formatTeamLineage(session);
758
- if (teamLine) {
759
- lines.push(chalk.cyan('Team: ') + teamLine);
740
+ const doing = [
741
+ compact ? chalk.white(compact) : '',
742
+ teamLine,
743
+ subAgentCount ? chalk.gray(`${subAgentCount} sub-agent${subAgentCount === 1 ? '' : 's'}`) : '',
744
+ ].filter(Boolean);
745
+ if (doing.length) {
746
+ lines.push(verbLabel('Doing') + doing.join(DOT));
760
747
  }
761
- const activity = [];
748
+ const todosRendered = todos?.items?.length ? renderTodos(todos.items, termWidth) : [];
749
+ for (const l of todosRendered)
750
+ lines.push(' ' + l);
751
+ // Made — what the session produced: file deltas, reads, artifacts (named +
752
+ // clickable), the plan file, and the PR when the session carries one.
753
+ const made = [];
762
754
  const changed = chg.created + chg.modified + chg.deleted;
763
755
  if (changed) {
764
756
  const parts = [
@@ -766,71 +758,61 @@ function formatCompactPreview(digest, session) {
766
758
  chg.modified ? chalk.yellow(`~${chg.modified}`) : '',
767
759
  chg.deleted ? chalk.red(`−${chg.deleted}`) : '',
768
760
  ].filter(Boolean).join(' ');
769
- activity.push(`${parts} ${chalk.gray('changed')}`);
761
+ made.push(`${parts} ${chalk.gray('changed')}`);
770
762
  }
771
763
  if (filesRead)
772
- activity.push(chalk.gray(`${filesRead} read`));
773
- if (toolCalls)
774
- activity.push(chalk.gray(`${toolCalls} tool${toolCalls === 1 ? '' : 's'}`));
775
- if (activity.length) {
776
- lines.push(chalk.cyan('Changes: ') + activity.join(chalk.gray(' · ')));
777
- }
778
- // Documents the session produced (`.agents/artifacts|plans|reports`, other
779
- // *.md/*.html creations) — the files a human browses later, named + clickable.
764
+ made.push(chalk.gray(`${filesRead} read`));
780
765
  if (artifacts.length) {
781
- const shown = artifacts.slice(0, 5).map(a => linkPath(a.path, a.basename));
782
- const more = artifacts.length > 5 ? chalk.gray(` · +${artifacts.length - 5} more`) : '';
783
- lines.push(chalk.cyan('Artifacts: ') + shown.join(chalk.gray(' · ')) + more);
784
- }
785
- // Skills invoked (plugin skills included — they ride the same Skill tool).
786
- if (skills.length) {
787
- const shown = skills.slice(0, 5).map(s => chalk.white(s.name) + (s.count > 1 ? chalk.gray(` ×${s.count}`) : ''));
788
- const more = skills.length > 5 ? chalk.gray(` · +${skills.length - 5} more`) : '';
789
- lines.push(chalk.cyan('Skills: ') + shown.join(chalk.gray(' · ')) + more);
766
+ const shown = artifacts.slice(0, 2).map(a => linkPath(a.path, a.basename));
767
+ const more = artifacts.length > 2 ? chalk.gray(` +${artifacts.length - 2}`) : '';
768
+ made.push(shown.join(chalk.gray(' · ')) + more);
790
769
  }
791
- if (plugins.length) {
792
- lines.push(chalk.cyan('Plugins: ') + chalk.white(plugins.slice(0, 5).join(chalk.gray(' · '))));
770
+ if (planFile) {
771
+ made.push(chalk.white(linkPath(planFile, planFile.split('/').pop() || planFile)));
793
772
  }
794
- // Hooks fired (Claude transcripts record firings; other harnesses don't).
795
- if (hooks.length) {
796
- const shown = hooks.slice(0, 4).map(h => chalk.white(h.name) + (h.count > 1 ? chalk.gray(` ×${h.count}`) : '') + (h.failed ? chalk.red(` (${h.failed} failed)`) : ''));
797
- const more = hooks.length > 4 ? chalk.gray(` · +${hooks.length - 4} more`) : '';
798
- lines.push(chalk.cyan('Hooks: ') + shown.join(chalk.gray(' · ')) + more);
773
+ if (session.prUrl) {
774
+ made.push(chalk.blue(linkUrl(session.prUrl, session.prNumber ? `PR#${session.prNumber}` : 'PR')));
799
775
  }
800
- // Links mentioned in the conversation — clickable (OSC 8), tracker-classified.
801
- if (links.length) {
802
- const shown = links.slice(0, 5).map(l => chalk.blue(linkUrl(l.url, l.label)));
803
- const more = links.length > 5 ? chalk.gray(` · +${links.length - 5} more`) : '';
804
- lines.push(chalk.cyan('Links: ') + shown.join(chalk.gray(' · ')) + more);
776
+ if (made.length) {
777
+ lines.push(verbLabel('Made') + made.join(DOT));
805
778
  }
806
- // Error tally, mirroring the full summary's Errors section in one line.
779
+ // Health — error tally + the last test/build verdict; absent when both clean.
780
+ const health = [];
807
781
  if (errorCount) {
808
- lines.push(chalk.cyan('Errors: ') + chalk.red(`${errorCount} failure${errorCount === 1 ? '' : 's'}`) + chalk.gray(` — first: ${firstError || 'unknown'}`));
809
- }
810
- const metadata = [
811
- ...toolTags,
812
- subAgentCount ? `${subAgentCount} sub-agent${subAgentCount === 1 ? '' : 's'}` : '',
813
- ].filter(Boolean);
814
- if (metadata.length) {
815
- lines.push(chalk.cyan('Meta: ') + chalk.gray(metadata.join(' · ')));
816
- }
817
- // Tool mix (top 4) — what kind of work this was.
818
- if (hist.length) {
819
- lines.push(chalk.cyan('Tools: ') + chalk.gray(hist.map(h => `${h.tool} ${h.count}`).join(' · ')));
782
+ health.push(chalk.red(`${errorCount} failure${errorCount === 1 ? '' : 's'}`) + chalk.gray(` — first: ${firstError || 'unknown'}`));
820
783
  }
821
- // Last test/build verdict.
822
784
  if (test?.ok) {
823
785
  const bits = [
824
786
  test.passed !== undefined ? chalk.green(`${test.passed} pass`) : '',
825
787
  test.failed ? chalk.red(`${test.failed} fail`) : '',
826
788
  ].filter(Boolean).join(chalk.gray(' · '));
827
789
  const mark = test.failed ? chalk.red('✗') : chalk.green('✓');
828
- lines.push(chalk.cyan('Tests: ') + `${mark} ${test.runner}${bits ? ' ' + bits : ''}`);
790
+ health.push(`${mark} ${test.runner}${bits ? ' ' + bits : ''}`);
829
791
  }
830
- if (planFile) {
831
- const basename = planFile.split('/').pop() || planFile;
832
- lines.push(chalk.cyan('Plan: ') + chalk.white(linkPath(planFile, basename)));
792
+ if (health.length) {
793
+ lines.push(verbLabel('Health') + health.join(DOT));
794
+ }
795
+ // Cost — volume: messages, tokens (moved here from the header's old line 3),
796
+ // and the top of the tool mix.
797
+ const totalMessages = session.messageCount ?? (events ? countMessages(events) : undefined);
798
+ const cost = [];
799
+ if (totalMessages !== undefined) {
800
+ cost.push(chalk.white(String(totalMessages)) + chalk.gray(` msg${totalMessages === 1 ? '' : 's'}`));
801
+ }
802
+ if (session.tokenCount !== undefined) {
803
+ cost.push(chalk.white(formatTokens(session.tokenCount)) + chalk.gray(' tokens'));
804
+ }
805
+ if (hist.length) {
806
+ cost.push(chalk.gray(hist.map(h => `${h.tool} ${h.count}`).join(' · ')));
833
807
  }
808
+ else if (toolCalls) {
809
+ cost.push(chalk.gray(`${toolCalls} tool${toolCalls === 1 ? '' : 's'}`));
810
+ }
811
+ if (cost.length) {
812
+ lines.push(verbLabel('Cost') + cost.join(DOT));
813
+ }
814
+ // Latest — the agent's last message, full and wrapped to the pane (the densest
815
+ // line in the preview; parts 1-2 of RUSH-2757 made it wrap instead of clip).
834
816
  if (lastAssistant) {
835
817
  const maxLines = todosRendered.length > 0 || compact ? LAST_RESPONSE_MAX_LINES_WITH_TODOS : LAST_RESPONSE_MAX_LINES;
836
818
  // Content sits at column 4 (outer body indent + the ' ' prefix below), so
@@ -838,14 +820,28 @@ function formatCompactPreview(digest, session) {
838
820
  const rendered = renderLastResponse(lastAssistant, maxLines, terminalWidth() - 4);
839
821
  if (rendered.length > 0) {
840
822
  lines.push('');
841
- lines.push(chalk.cyan('Last response:'));
823
+ lines.push(chalk.cyan('Latest'));
842
824
  for (const l of rendered)
843
825
  lines.push(' ' + l);
844
826
  }
845
827
  }
846
- if (lines.length === 0) {
847
- lines.push(chalk.gray('No activity recorded in this session.'));
848
- }
828
+ // Details the folded long tail: session id, skills, plugins, hooks, links,
829
+ // dirs, repos, capability tags. One width-capped line instead of seven labeled
830
+ // rows (a long tail used to wrap and swamp the whole pane); links stay
831
+ // clickable (OSC 8), hook failures stay red. Full lists go to the cap — it is
832
+ // the ONLY bounding, so its `… +N more` tail accounts for every hidden item
833
+ // (pre-slicing here made overflow vanish with no trace).
834
+ const details = [
835
+ session.filePath ? chalk.gray(linkPath(session.filePath, session.id.slice(0, 8))) : chalk.gray(session.id.slice(0, 8)),
836
+ ...skills.map(s => chalk.white(s.name) + (s.count > 1 ? chalk.gray(` ×${s.count}`) : '')),
837
+ ...plugins.map(p => chalk.white(p)),
838
+ ...hooks.map(h => chalk.white(h.name) + (h.failed ? chalk.red(` (${h.failed} failed)`) : '')),
839
+ ...links.map(l => chalk.blue(linkUrl(l.url, l.label))),
840
+ ...dirs.map(d => chalk.gray(d)),
841
+ ...repos.map(r => chalk.gray(r)),
842
+ ...toolTags.map(t => chalk.gray(t)),
843
+ ];
844
+ lines.push(verbLabel('Details ▸') + joinWidthCapped(details, valueWidth));
849
845
  return lines.map(l => ' ' + l).join('\n');
850
846
  }
851
847
  function classifySessionTool(tool, command) {
@@ -928,20 +924,26 @@ const SLUG_WORKTREE_RE = /--agents-worktrees-(.+)$/;
928
924
  * Join display tokens with ` · `, stopping before the line exceeds `maxWidth`
929
925
  * and appending `… +N more` for the rest. Keeps the Dirs line on one row.
930
926
  */
927
+ /**
928
+ * Join pre-styled items with ` · ` up to a visible width, then `… +N more`.
929
+ * Width is measured ANSI-aware (stringWidth), so colored / OSC 8-linked items
930
+ * are not miscounted; items arrive already styled and are not recolored.
931
+ */
931
932
  function joinWidthCapped(items, maxWidth) {
932
- const sep = ' · ';
933
933
  let out = '';
934
+ let width = 0;
934
935
  let shown = 0;
935
936
  for (const item of items) {
936
- const next = shown === 0 ? item : out + sep + item;
937
- if (shown > 0 && next.length > maxWidth)
937
+ const itemWidth = stringWidth(item);
938
+ const nextWidth = shown === 0 ? itemWidth : width + 3 + itemWidth;
939
+ if (shown > 0 && nextWidth > maxWidth)
938
940
  break;
939
- out = next;
941
+ out = shown === 0 ? item : out + DOT + item;
942
+ width = nextWidth;
940
943
  shown++;
941
944
  }
942
945
  const remaining = items.length - shown;
943
- const suffix = remaining > 0 ? ` … +${remaining} more` : '';
944
- return chalk.white(out) + (suffix ? chalk.gray(suffix) : '');
946
+ return out + (remaining > 0 ? chalk.gray(` … +${remaining} more`) : '');
945
947
  }
946
948
  /** Relativize a file path to its parent dir, short enough for one preview line. */
947
949
  export function relativizeDir(filePath, cwd) {
@@ -10,7 +10,7 @@
10
10
  import chalk from 'chalk';
11
11
  import { setConfigValue } from '../lib/device-config.js';
12
12
  import { findFirstInstalledBrowser, listInstalledBrowsers } from '../lib/browser/chrome.js';
13
- import { DEFAULT_BROWSER_PROFILE_NAME, createProfile, findFreeProfilePort, getConfiguredDefaultProfileName, getProfile, } from '../lib/browser/profiles.js';
13
+ import { DEFAULT_BROWSER_PROFILE_NAME, getAutoDetectedProfile, createProfile, findFreeProfilePort, getConfiguredDefaultProfileName, } from '../lib/browser/profiles.js';
14
14
  import { DEFAULT_VIEWPORT } from '../lib/browser/devices.js';
15
15
  import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
16
16
  import { defaultBrowserChoice } from './setup-preferences.js';
@@ -29,9 +29,9 @@ export async function runBrowserWizard() {
29
29
  console.error(chalk.red('No supported browser found.\n') + chalk.dim(INSTALL_HINT));
30
30
  return false;
31
31
  }
32
- const existing = await getProfile(DEFAULT_BROWSER_PROFILE_NAME);
32
+ const existing = await getAutoDetectedProfile();
33
33
  if (existing) {
34
- console.log(chalk.dim(`Browser profile "${DEFAULT_BROWSER_PROFILE_NAME}" already exists.`));
34
+ console.log(chalk.dim(`Browser profile "${existing.name}" already exists.`));
35
35
  return true;
36
36
  }
37
37
  const created = await createAutoDefault();
@@ -46,7 +46,7 @@ export async function runBrowserWizard() {
46
46
  }
47
47
  const { confirm, select } = await import('@inquirer/prompts');
48
48
  // If a default profile already exists, this is a reconfigure.
49
- const existing = await getProfile(DEFAULT_BROWSER_PROFILE_NAME);
49
+ const existing = await getAutoDetectedProfile();
50
50
  if (existing) {
51
51
  console.log(chalk.dim(`Browser profile "${existing.name}" already exists (${existing.browser}${existing.binary ? ` · ${existing.binary}` : ''}).`));
52
52
  const change = await confirm({ message: 'Re-create it (e.g. to pin a different browser)?', default: false });
@@ -11,7 +11,7 @@
11
11
  import chalk from 'chalk';
12
12
  import { initBrand, registerMineManageCommands } from './mine.js';
13
13
  import { validateBrandName, getBrandConfig } from '../lib/brand.js';
14
- import { isShimsInPath } from '../lib/shims.js';
14
+ import { isShimsInPath } from '../lib/installations/shims.js';
15
15
  import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
16
16
  /**
17
17
  * Optional/heavier top-level commands a brand commonly turns off. Kept short so
@@ -14,7 +14,7 @@
14
14
  */
15
15
  import chalk from 'chalk';
16
16
  import { listInstalledBrowsers } from '../lib/browser/chrome.js';
17
- import { DEFAULT_BROWSER_PROFILE_NAME, createProfile, findFreeProfilePort, getConfiguredDefaultProfileName, getProfile, } from '../lib/browser/profiles.js';
17
+ import { DEFAULT_BROWSER_PROFILE_NAME, getAutoDetectedProfile, createProfile, findFreeProfilePort, getConfiguredDefaultProfileName, } from '../lib/browser/profiles.js';
18
18
  import { DEFAULT_VIEWPORT } from '../lib/browser/devices.js';
19
19
  import { getConfigValue, setConfigValue } from '../lib/device-config.js';
20
20
  import { loadDevices } from '../lib/devices/registry.js';
@@ -88,7 +88,7 @@ export async function maybePickBrowserProfile() {
88
88
  return false;
89
89
  if (getConfiguredDefaultProfileName())
90
90
  return false;
91
- if (await getProfile(DEFAULT_BROWSER_PROFILE_NAME))
91
+ if (await getAutoDetectedProfile())
92
92
  return false;
93
93
  const installed = listInstalledBrowsers();
94
94
  if (installed.length === 0)
@@ -16,7 +16,7 @@ import { isGitRepo, cloneIntoExisting, pullRepo } from '../lib/git.js';
16
16
  import { isPromptCancelled, isInteractiveTerminal } from './utils.js';
17
17
  import { AGENTS, agentConfigDirName, getUnmanagedAgentInstalls, countSessionFiles, agentLabel } from '../lib/agents.js';
18
18
  import { setGlobalDefault } from '../lib/installations/versions.js';
19
- import { ensureShimCurrent, switchHomeFileSymlinks, isShimsInPath, addShimsToPath, getPathSetupInstructions, assertIsolationBoundary } from '../lib/shims.js';
19
+ import { ensureShimCurrent, switchHomeFileSymlinks, isShimsInPath, addShimsToPath, getPathSetupInstructions, assertIsolationBoundary } from '../lib/installations/shims.js';
20
20
  import { setHelpSections } from '../lib/help.js';
21
21
  import { registerSetupBrowserCommand, runBrowserWizard } from './setup-browser.js';
22
22
  import { registerSetupComputerCommand, runComputerWizard } from './setup-computer.js';
@@ -25,8 +25,9 @@ import { registerSetupMineCommand } from './setup-mine.js';
25
25
  import { registerSetupSecretsCommand } from './setup-secrets.js';
26
26
  import { registerSetupFleetCommand } from './setup-fleet.js';
27
27
  import { registerSetupWatchdogCommand, runWatchdogSetupWizard } from './setup-watchdog.js';
28
+ import { registerAliasCommand } from './alias.js';
28
29
  import { runPreferencesStep } from './setup-preferences.js';
29
- import { getConfiguredDefaultProfileName, getProfile, isProfileLaunchableHere, DEFAULT_BROWSER_PROFILE_NAME } from '../lib/browser/profiles.js';
30
+ import { getConfiguredDefaultProfileName, getProfile, getAutoDetectedProfile, isProfileLaunchableHere } from '../lib/browser/profiles.js';
30
31
  import { listInstalledBrowsers } from '../lib/browser/chrome.js';
31
32
  import { probeComputerTrust } from './computer.js';
32
33
  import { readShareConfig } from '../lib/share/config.js';
@@ -265,7 +266,9 @@ export async function ensureInitialized(program) {
265
266
  }
266
267
  export async function getSetupStatus() {
267
268
  const configuredBrowserProfile = getConfiguredDefaultProfileName();
268
- const browserProfile = await getProfile(configuredBrowserProfile ?? DEFAULT_BROWSER_PROFILE_NAME);
269
+ const browserProfile = configuredBrowserProfile
270
+ ? await getProfile(configuredBrowserProfile)
271
+ : await getAutoDetectedProfile();
269
272
  const browserReady = browserProfile !== null && isProfileLaunchableHere(browserProfile);
270
273
  const installedBrowsers = listInstalledBrowsers();
271
274
  const computerState = process.platform === 'darwin' ? (await probeComputerTrust() ? 'ready' : 'missing') : 'n/a';
@@ -360,7 +363,7 @@ export function registerSetupCommand(program) {
360
363
  .description('Set up agents-cli, or re-open the capability onboarding hub.')
361
364
  .option('-f, --force', 'Re-run setup even if ~/.agents/.system/ already exists (use with caution)')
362
365
  .option('--no-system-repo', 'Skip cloning the system repo (you must populate ~/.agents/.system/ yourself)');
363
- // Capability subcommands: `agents setup browser|computer|mine|secrets|fleet`.
366
+ // Capability subcommands: `agents setup browser|computer|mine|secrets|fleet|alias`.
364
367
  // Share/artifact publishing is set up by `agents artifacts setup` (RUSH-2580);
365
368
  // the hub below still offers it as a phase via runShareWizard.
366
369
  registerSetupBrowserCommand(setupCmd);
@@ -369,6 +372,7 @@ export function registerSetupCommand(program) {
369
372
  registerSetupSecretsCommand(setupCmd);
370
373
  registerSetupFleetCommand(setupCmd);
371
374
  registerSetupWatchdogCommand(setupCmd);
375
+ registerAliasCommand(setupCmd);
372
376
  setupCmd.command('status')
373
377
  .description('Show setup readiness for core, browser, computer, secrets, fleet, share, watchdog, and preferences.')
374
378
  .option('--json', 'print machine-readable JSON')
@@ -395,6 +399,7 @@ export function registerSetupCommand(program) {
395
399
  agents setup secrets
396
400
  agents setup fleet
397
401
  agents setup watchdog
402
+ agents setup alias add teams
398
403
  `,
399
404
  notes: `
400
405
  What it does:
@@ -410,6 +415,7 @@ export function registerSetupCommand(program) {
410
415
  agents setup secrets # choose secrets backend/policy defaults + import
411
416
  agents setup fleet # discover Tailscale devices + configure SSH access
412
417
  agents setup watchdog # choose which devices run the daemon watchdog pass
418
+ agents setup alias add teams # PATH shorthand: teams runs agents teams
413
419
 
414
420
  To install CLIs from agents.yaml and sync resources into version homes:
415
421
  agents sync --local -y
@@ -2,7 +2,7 @@
2
2
  * `agents devices snapshot` — one-process consumer snapshot for pollers.
3
3
  *
4
4
  * Replaces the N× `view --json` + `sessions --active --json` (+ optional feed)
5
- * fork storm with a single command. Does NOT replace `agents status`, which
5
+ * fork storm with a single command. Does NOT replace `agents sync status`, which
6
6
  * remains the UnifiedSyncStatus sync contract for menubar / Agency drift.
7
7
  *
8
8
  * JSON shape: {@link FleetSnapshot} in `lib/snapshot.ts` (version: 1).
@@ -2,7 +2,7 @@
2
2
  * `agents devices snapshot` — one-process consumer snapshot for pollers.
3
3
  *
4
4
  * Replaces the N× `view --json` + `sessions --active --json` (+ optional feed)
5
- * fork storm with a single command. Does NOT replace `agents status`, which
5
+ * fork storm with a single command. Does NOT replace `agents sync status`, which
6
6
  * remains the UnifiedSyncStatus sync contract for menubar / Agency drift.
7
7
  *
8
8
  * JSON shape: {@link FleetSnapshot} in `lib/snapshot.ts` (version: 1).
@@ -60,16 +60,16 @@ function renderHuman(snap) {
60
60
  console.log(` ${'Sync'.padEnd(12)} ${sys} · ${need} version${need === 1 ? '' : 's'} need sync`);
61
61
  }
62
62
  console.log(chalk.gray('\n Machine-readable: agents devices snapshot --json\n' +
63
- ' Sync-only (unchanged): agents status --json'));
63
+ ' Sync-only (unchanged): agents sync status --json'));
64
64
  }
65
65
  export function registerSnapshotCommand(devicesCmd) {
66
66
  const cmd = addHostOption(devicesCmd
67
67
  .command('snapshot')
68
- .description('One-process poll snapshot: install inventory + active sessions (optional feed/sync). Not the sync-status command — use `agents status` for drift.'))
68
+ .description('One-process poll snapshot: install inventory + active sessions (optional feed/sync). Not the sync-status command — use `agents sync status` for drift.'))
69
69
  .option('--json', 'Emit the machine-readable FleetSnapshot contract (version 1)')
70
70
  .option('--all-hosts', 'Include remote devices in the sessions gather (same fan-out as `sessions --active`; default is this machine only)')
71
71
  .option('--with-feed', 'Include open feed-block summary (needs-you count + compact rows)')
72
- .option('--with-sync', 'Include UnifiedSyncStatus (same engine as `agents status`; opt-in)')
72
+ .option('--with-sync', 'Include UnifiedSyncStatus (same engine as `agents sync status`; opt-in)')
73
73
  .option('--agent <name>', 'Restrict inventory to one agent (e.g. claude)');
74
74
  setHelpSections(cmd, {
75
75
  examples: `
@@ -1,6 +1,7 @@
1
1
  /**
2
- * `agents status` — the unified sync-status surface.
2
+ * `agents sync status` — the unified sync-status surface.
3
3
  *
4
+ * Nested under `sync` because this is sync drift, not a separate noun (RUSH-2864).
4
5
  * One command that answers "is my fleet in sync?" the same way every other
5
6
  * surface does, because it reads the same engine (computeSyncStatus). Human mode
6
7
  * renders the summary and, when a TTY finds drift, offers the interactive
@@ -9,4 +10,5 @@
9
10
  * prompts (the "kick it" path, safe in scripts).
10
11
  */
11
12
  import { Command } from 'commander';
12
- export declare function registerStatusCommand(program: Command): void;
13
+ /** Attach `status` under the `sync` group. The former top-level `agents status` is retired. */
14
+ export declare function registerStatusCommand(syncCmd: Command): void;
@@ -1,6 +1,7 @@
1
1
  /**
2
- * `agents status` — the unified sync-status surface.
2
+ * `agents sync status` — the unified sync-status surface.
3
3
  *
4
+ * Nested under `sync` because this is sync drift, not a separate noun (RUSH-2864).
4
5
  * One command that answers "is my fleet in sync?" the same way every other
5
6
  * surface does, because it reads the same engine (computeSyncStatus). Human mode
6
7
  * renders the summary and, when a TTY finds drift, offers the interactive
@@ -11,6 +12,7 @@
11
12
  import chalk from 'chalk';
12
13
  import { AGENTS } from '../lib/agents.js';
13
14
  import { setHelpSections } from '../lib/help.js';
15
+ import { addHostOption } from '../lib/hosts/option.js';
14
16
  import { computeSyncStatus } from '../lib/sync-status.js';
15
17
  import { promptDriftSync } from '../lib/drift-sync.js';
16
18
  import { resolveConfiguredModel } from '../lib/models.js';
@@ -29,23 +31,24 @@ function versionSummary(v) {
29
31
  }
30
32
  return chalk.green('in sync');
31
33
  }
32
- export function registerStatusCommand(program) {
33
- const cmd = program
34
+ /** Attach `status` under the `sync` group. The former top-level `agents status` is retired. */
35
+ export function registerStatusCommand(syncCmd) {
36
+ const cmd = addHostOption(syncCmd
34
37
  .command('status')
35
- .description('Unified sync status across the fleet — what is drifted, missing, or behind, with an option to sync it.')
38
+ .description('Unified sync status across the fleet — what is drifted, missing, or behind, with an option to sync it.'))
36
39
  .option('--json', 'Output the machine-readable UnifiedSyncStatus contract')
37
40
  .option('--yes', 'Reconcile everything detected (pull .system if behind + sync drifted/missing resources) without prompting')
38
41
  .option('--cwd <path>', 'Resolution cwd for project layer detection (default: process.cwd())');
39
42
  setHelpSections(cmd, {
40
43
  examples: `
41
44
  # Show what's out of sync; offer to fix it (interactive)
42
- agents status
45
+ agents sync status
43
46
 
44
47
  # Machine-readable status for the menu-bar / Agency
45
- agents status --json
48
+ agents sync status --json
46
49
 
47
50
  # Reconcile everything with no prompts (CI / scripts / the "kick it" path)
48
- agents status --yes
51
+ agents sync status --yes
49
52
  `,
50
53
  });
51
54
  cmd.action(async (opts, command) => {
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Forms:
5
5
  * agents sync # umbrella: fetch config repos -> reconcile all (secrets opt-in)
6
+ * agents sync status # report fleet drift (former top-level `agents status`)
6
7
  * agents sync --repos|--secrets # umbrella: fetch only those, then reconcile
7
8
  * agents sync --cloud # umbrella: fetch all, skip reconcile
8
9
  * agents sync --local # umbrella: reconcile all, no fetch