@phnx-labs/agents-cli 1.22.114 → 1.22.116

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 (243) hide show
  1. package/CHANGELOG.md +245 -0
  2. package/README.md +22 -102
  3. package/dist/browser.js +0 -0
  4. package/dist/cli/command-registry.js +0 -7
  5. package/dist/commands/accounts.d.ts +3 -77
  6. package/dist/commands/accounts.js +13 -366
  7. package/dist/commands/audit.js +1 -1
  8. package/dist/commands/auth.js +0 -2
  9. package/dist/commands/browser.d.ts +53 -0
  10. package/dist/commands/browser.js +210 -9
  11. package/dist/commands/doctor.d.ts +2 -3
  12. package/dist/commands/doctor.js +0 -11
  13. package/dist/commands/events.d.ts +1 -3
  14. package/dist/commands/events.js +4 -7
  15. package/dist/commands/exec.d.ts +0 -1
  16. package/dist/commands/exec.js +214 -148
  17. package/dist/commands/feed-watch.js +52 -8
  18. package/dist/commands/feed.js +65 -14
  19. package/dist/commands/focus.js +1 -1
  20. package/dist/commands/go.d.ts +0 -17
  21. package/dist/commands/go.js +2 -19
  22. package/dist/commands/logs.js +1 -1
  23. package/dist/commands/mcp.js +8 -83
  24. package/dist/commands/memory.js +4 -47
  25. package/dist/commands/message.js +4 -4
  26. package/dist/commands/plugins.js +1 -93
  27. package/dist/commands/repo.js +0 -44
  28. package/dist/commands/resume.js +4 -1
  29. package/dist/commands/secrets-passthrough.js +2 -2
  30. package/dist/commands/send.d.ts +4 -4
  31. package/dist/commands/send.js +6 -51
  32. package/dist/commands/sessions-backup-setup.js +1 -1
  33. package/dist/commands/sessions-picker.d.ts +11 -0
  34. package/dist/commands/sessions-picker.js +88 -7
  35. package/dist/commands/sessions-resume.js +0 -1
  36. package/dist/commands/sessions-share.d.ts +5 -7
  37. package/dist/commands/sessions-share.js +98 -49
  38. package/dist/commands/sessions.d.ts +21 -2
  39. package/dist/commands/sessions.js +158 -11
  40. package/dist/commands/setup-browser.js +18 -2
  41. package/dist/commands/setup-computer.js +20 -6
  42. package/dist/commands/setup-secrets.d.ts +2 -2
  43. package/dist/commands/setup-secrets.js +24 -4
  44. package/dist/commands/setup-term.d.ts +24 -0
  45. package/dist/commands/setup-term.js +70 -0
  46. package/dist/commands/setup-terminal.d.ts +3 -0
  47. package/dist/commands/setup-terminal.js +22 -0
  48. package/dist/commands/setup.d.ts +1 -1
  49. package/dist/commands/setup.js +29 -11
  50. package/dist/commands/skills.js +0 -8
  51. package/dist/commands/ssh.d.ts +6 -0
  52. package/dist/commands/ssh.js +93 -302
  53. package/dist/commands/sync.js +14 -5
  54. package/dist/commands/teams.js +1 -1
  55. package/dist/commands/traces.js +1 -1
  56. package/dist/lib/accounting/rotate.d.ts +63 -1
  57. package/dist/lib/accounting/rotate.js +56 -0
  58. package/dist/lib/accounts/add.d.ts +0 -5
  59. package/dist/lib/accounts/add.js +3 -9
  60. package/dist/lib/accounts/slots.js +32 -2
  61. package/dist/lib/answer-router.d.ts +11 -2
  62. package/dist/lib/answer-router.js +26 -2
  63. package/dist/lib/artifacts-client.d.ts +20 -0
  64. package/dist/lib/artifacts-client.js +46 -0
  65. package/dist/lib/auth-mint.d.ts +5 -4
  66. package/dist/lib/auth-mint.js +6 -5
  67. package/dist/lib/browser/drivers/arc.d.ts +1 -1
  68. package/dist/lib/browser/runtime-state.d.ts +55 -0
  69. package/dist/lib/browser/runtime-state.js +99 -18
  70. package/dist/lib/browser/service.d.ts +10 -0
  71. package/dist/lib/browser/service.js +229 -37
  72. package/dist/lib/browser/types.d.ts +18 -0
  73. package/dist/lib/cli-resources.js +3 -1
  74. package/dist/lib/cloud/dispatch.js +1 -1
  75. package/dist/lib/cloudflare/creds.d.ts +10 -0
  76. package/dist/lib/cloudflare/creds.js +46 -0
  77. package/dist/lib/cloudflare/provision.d.ts +35 -0
  78. package/dist/lib/cloudflare/provision.js +144 -0
  79. package/dist/lib/computer/sessions-list.d.ts +55 -0
  80. package/dist/lib/computer/sessions-list.js +168 -1
  81. package/dist/lib/config-keys.d.ts +1 -1
  82. package/dist/lib/config-keys.js +5 -0
  83. package/dist/lib/daemon/daemon.js +8 -1
  84. package/dist/lib/daemon/feed-stream-service.d.ts +23 -0
  85. package/dist/lib/daemon/feed-stream-service.js +40 -0
  86. package/dist/lib/daemon-services.d.ts +1 -1
  87. package/dist/lib/daemon-services.js +5 -0
  88. package/dist/lib/device-config.js +61 -0
  89. package/dist/lib/devices/connect.d.ts +49 -5
  90. package/dist/lib/devices/connect.js +169 -21
  91. package/dist/lib/devices/doctor-findings.js +2 -6
  92. package/dist/lib/feed/answer.d.ts +153 -4
  93. package/dist/lib/feed/answer.js +716 -105
  94. package/dist/lib/feed/envelope.d.ts +79 -0
  95. package/dist/lib/feed/envelope.js +23 -0
  96. package/dist/lib/feed/events.d.ts +6 -0
  97. package/dist/lib/feed/events.js +8 -0
  98. package/dist/lib/feed/feed.d.ts +61 -1
  99. package/dist/lib/feed/feed.js +226 -14
  100. package/dist/lib/feed/hub-server.d.ts +141 -0
  101. package/dist/lib/feed/hub-server.js +586 -0
  102. package/dist/lib/feed/hub.d.ts +95 -0
  103. package/dist/lib/feed/hub.js +255 -0
  104. package/dist/lib/feed/pr-status.d.ts +8 -0
  105. package/dist/lib/feed/pr-status.js +9 -1
  106. package/dist/lib/feed/tool-activity.d.ts +108 -0
  107. package/dist/lib/feed/tool-activity.js +313 -0
  108. package/dist/lib/feed/tools.d.ts +198 -0
  109. package/dist/lib/feed/tools.js +265 -0
  110. package/dist/lib/feed/watch.d.ts +50 -50
  111. package/dist/lib/feed/watch.js +147 -16
  112. package/dist/lib/feed-outcome.d.ts +1 -1
  113. package/dist/lib/feed-outcome.js +9 -2
  114. package/dist/lib/feed-policy.js +9 -3
  115. package/dist/lib/fleet/auth-sync.d.ts +2 -55
  116. package/dist/lib/fleet/auth-sync.js +2 -89
  117. package/dist/lib/format.d.ts +1 -1
  118. package/dist/lib/format.js +1 -1
  119. package/dist/lib/git.d.ts +0 -16
  120. package/dist/lib/git.js +0 -58
  121. package/dist/lib/harness-auth-capabilities.js +7 -2
  122. package/dist/lib/helper-versions.js +1 -1
  123. package/dist/lib/hosts/dispatch.d.ts +20 -1
  124. package/dist/lib/hosts/dispatch.js +52 -30
  125. package/dist/lib/hosts/remote-cmd.d.ts +72 -1
  126. package/dist/lib/hosts/remote-cmd.js +151 -10
  127. package/dist/lib/hosts/remote-cmd.test-fixture.d.ts +2 -0
  128. package/dist/lib/hosts/remote-cmd.test-fixture.js +22 -0
  129. package/dist/lib/mailbox.d.ts +12 -0
  130. package/dist/lib/mailbox.js +16 -2
  131. package/dist/lib/mcp.js +17 -11
  132. package/dist/lib/menubar/snapshot.d.ts +51 -0
  133. package/dist/lib/menubar/snapshot.js +42 -3
  134. package/dist/lib/open-url.js +2 -2
  135. package/dist/lib/probe.d.ts +4 -1
  136. package/dist/lib/probe.js +5 -2
  137. package/dist/lib/projects.d.ts +23 -0
  138. package/dist/lib/projects.js +78 -0
  139. package/dist/lib/pwsh.d.ts +33 -0
  140. package/dist/lib/pwsh.js +56 -0
  141. package/dist/lib/redact.d.ts +8 -0
  142. package/dist/lib/redact.js +11 -0
  143. package/dist/lib/refresh.d.ts +6 -2
  144. package/dist/lib/refresh.js +92 -72
  145. package/dist/lib/secrets-cli.d.ts +11 -0
  146. package/dist/lib/secrets-cli.js +30 -0
  147. package/dist/lib/secrets-client.js +3 -2
  148. package/dist/lib/session/active.d.ts +1 -0
  149. package/dist/lib/session/active.js +8 -0
  150. package/dist/lib/session/db.d.ts +67 -3
  151. package/dist/lib/session/db.js +381 -126
  152. package/dist/lib/session/detached.d.ts +7 -0
  153. package/dist/lib/session/detached.js +29 -0
  154. package/dist/lib/session/prompt.d.ts +23 -7
  155. package/dist/lib/session/prompt.js +46 -8
  156. package/dist/lib/session/remote/peer-stream.d.ts +24 -2
  157. package/dist/lib/session/remote/peer-stream.js +33 -6
  158. package/dist/lib/session/remote/remote-list.d.ts +20 -0
  159. package/dist/lib/session/remote/remote-list.js +22 -6
  160. package/dist/lib/session/remote/watch.d.ts +12 -0
  161. package/dist/lib/session/remote/watch.js +9 -0
  162. package/dist/lib/session/remote-preview-cache.d.ts +29 -0
  163. package/dist/lib/session/remote-preview-cache.js +373 -0
  164. package/dist/lib/session/sync/backend.d.ts +3 -3
  165. package/dist/lib/session/sync/backend.js +3 -3
  166. package/dist/lib/session/sync/provision.d.ts +1 -1
  167. package/dist/lib/session/sync/provision.js +2 -2
  168. package/dist/lib/session/tail.d.ts +50 -0
  169. package/dist/lib/session/tail.js +219 -0
  170. package/dist/lib/sessions-client.js +0 -3
  171. package/dist/lib/setup-tool-install.d.ts +3 -0
  172. package/dist/lib/setup-tool-install.js +27 -0
  173. package/dist/lib/setup-tool-status.d.ts +22 -0
  174. package/dist/lib/setup-tool-status.js +220 -0
  175. package/dist/lib/share-runtime.d.ts +11 -0
  176. package/dist/lib/share-runtime.js +63 -0
  177. package/dist/lib/signin-badge.d.ts +19 -4
  178. package/dist/lib/signin-badge.js +29 -11
  179. package/dist/lib/smart-launch.d.ts +1 -5
  180. package/dist/lib/smart-launch.js +3 -11
  181. package/dist/lib/ssh-exec.d.ts +44 -0
  182. package/dist/lib/ssh-exec.js +119 -0
  183. package/dist/lib/startup/command-registry.d.ts +6 -4
  184. package/dist/lib/startup/command-registry.js +10 -7
  185. package/dist/lib/state.js +2 -2
  186. package/dist/lib/storage/selection.d.ts +2 -2
  187. package/dist/lib/storage/selection.js +2 -2
  188. package/dist/lib/sync-umbrella.d.ts +5 -0
  189. package/dist/lib/sync-umbrella.js +18 -10
  190. package/dist/lib/term-driver.d.ts +24 -0
  191. package/dist/lib/term-driver.js +36 -0
  192. package/dist/lib/terminal/index.d.ts +1 -1
  193. package/dist/lib/terminal/index.js +1 -1
  194. package/dist/lib/terminal/inject.d.ts +38 -0
  195. package/dist/lib/terminal/inject.js +55 -9
  196. package/dist/lib/terminal/transport.d.ts +15 -5
  197. package/dist/lib/terminal/transport.js +61 -11
  198. package/dist/lib/traces/backend.d.ts +1 -2
  199. package/dist/lib/traces/backend.js +1 -2
  200. package/dist/lib/traces/provision.d.ts +1 -1
  201. package/dist/lib/traces/provision.js +2 -2
  202. package/dist/lib/types.d.ts +8 -6
  203. package/package.json +2 -3
  204. package/dist/commands/artifacts-setup.d.ts +0 -53
  205. package/dist/commands/artifacts-setup.js +0 -161
  206. package/dist/commands/artifacts.d.ts +0 -18
  207. package/dist/commands/artifacts.js +0 -58
  208. package/dist/commands/attach.d.ts +0 -12
  209. package/dist/commands/attach.js +0 -86
  210. package/dist/commands/auth-mint.d.ts +0 -12
  211. package/dist/commands/auth-mint.js +0 -108
  212. package/dist/commands/reconnect.d.ts +0 -46
  213. package/dist/commands/reconnect.js +0 -115
  214. package/dist/commands/share.d.ts +0 -293
  215. package/dist/commands/share.js +0 -1424
  216. package/dist/lib/fleet/remote-login.d.ts +0 -170
  217. package/dist/lib/fleet/remote-login.js +0 -568
  218. package/dist/lib/share/analytics.d.ts +0 -13
  219. package/dist/lib/share/analytics.js +0 -45
  220. package/dist/lib/share/backend.d.ts +0 -120
  221. package/dist/lib/share/backend.js +0 -176
  222. package/dist/lib/share/capture.d.ts +0 -31
  223. package/dist/lib/share/capture.js +0 -174
  224. package/dist/lib/share/config.d.ts +0 -72
  225. package/dist/lib/share/config.js +0 -211
  226. package/dist/lib/share/delete.d.ts +0 -123
  227. package/dist/lib/share/delete.js +0 -173
  228. package/dist/lib/share/html.d.ts +0 -20
  229. package/dist/lib/share/html.js +0 -88
  230. package/dist/lib/share/http-error.d.ts +0 -53
  231. package/dist/lib/share/http-error.js +0 -65
  232. package/dist/lib/share/og.d.ts +0 -26
  233. package/dist/lib/share/og.js +0 -84
  234. package/dist/lib/share/provision.d.ts +0 -127
  235. package/dist/lib/share/provision.js +0 -285
  236. package/dist/lib/share/publish.d.ts +0 -379
  237. package/dist/lib/share/publish.js +0 -818
  238. package/dist/lib/share/worker-template.d.ts +0 -27
  239. package/dist/lib/share/worker-template.js +0 -2424
  240. package/dist/lib/storage/index.d.ts +0 -14
  241. package/dist/lib/storage/index.js +0 -14
  242. package/dist/lib/storage/visibility.d.ts +0 -82
  243. package/dist/lib/storage/visibility.js +0 -99
@@ -1,5 +1,5 @@
1
1
  import chalk from 'chalk';
2
- import { ensureFeedPublishHook, listAskStats, listBlocks, recordNotified, buildDeclaredBlock, publishBlock, } from '../lib/feed/feed.js';
2
+ import { ensureFeedPublishHook, listAskStats, listBlocks, recordNotified, buildDeclaredBlock, deriveBlockState, publishBlock, } from '../lib/feed/feed.js';
3
3
  import { ensureActivityLogHook, readRecentActivity, formatActivityLine, formatProgressUpdate, mergeActivityEvents, parseActivityPayload, } from '../lib/feed/activity.js';
4
4
  import { projectKeyFromCwd } from '../lib/project-key.js';
5
5
  import { postFeedStatus } from '../lib/feed-post.js';
@@ -16,7 +16,7 @@ import { gatherRemoteAgentsJson } from '../lib/remote-agents-json.js';
16
16
  import { loadPolicy, applyPolicyToBlock, isPhoneUrgent } from '../lib/feed-policy.js';
17
17
  import { notifyUrgentBlock } from '../lib/notify.js';
18
18
  import { registerFeedWatchCommand } from './feed-watch.js';
19
- import { claimAndRouteAttentionAnswer, forwardFeedAnswer } from '../lib/feed/answer.js';
19
+ import { AnswerError, answerOwnerIsLocal, checkAnswerDelivery, claimAndRouteAttentionAnswer, forwardFeedAnswer, parseAttentionKey, } from '../lib/feed/answer.js';
20
20
  import { gcMailbox } from '../lib/mailbox-gc.js';
21
21
  import { isValidMailboxId } from '../lib/mailbox.js';
22
22
  import { getActiveSessions } from '../lib/session/active.js';
@@ -171,7 +171,10 @@ function renderBlock(b, localHost, indent = '') {
171
171
  const cost = b.costOfDelay ? chalk.gray(`cost:${b.costOfDelay}`) : '';
172
172
  const rank = b.delayRank ? chalk.gray(`rank:${Math.round(b.delayRank.score)}`) : '';
173
173
  // Shared fleet-comms glyphs: ▲ open ask, ✓ answered (see comms-render GLYPH).
174
- const marker = b.answer
174
+ // A PENDING claim carries an answer record while the block is still open, so
175
+ // the delivered glyph is driven by the canonical state, not by `b.answer`
176
+ // being set — a claimed-but-undelivered ask must keep reading as needs-you.
177
+ const marker = deriveBlockState(b) !== 'open'
175
178
  ? chalk.green(GLYPH.delivered)
176
179
  : b.kind === 'control'
177
180
  ? chalk.red('!')
@@ -197,7 +200,9 @@ function renderBlock(b, localHost, indent = '') {
197
200
  if (b.answer) {
198
201
  const verified = b.answer.verified ? chalk.green(GLYPH.delivered) : chalk.yellow('?');
199
202
  const who = b.answer.answeredFrom + (b.answer.answeredBy ? ` (${b.answer.answeredBy})` : '');
200
- console.log(`${indent} ${chalk.green('answered')} by ${who} ${verified}`);
203
+ const pending = deriveBlockState(b) === 'open';
204
+ const label = pending ? chalk.yellow('claimed (delivery unconfirmed)') : chalk.green('answered');
205
+ console.log(`${indent} ${label} by ${who} ${verified}`);
201
206
  }
202
207
  if (b.parkedAt) {
203
208
  console.log(`${indent} ${chalk.red('hard-parked')} ${relTime(b.parkedAt)}`);
@@ -314,6 +319,23 @@ export async function loadSessionMetasForFeedEnrichment(load) {
314
319
  throw err;
315
320
  }
316
321
  }
322
+ /**
323
+ * One human line per answer outcome. The three states the operator has to tell
324
+ * apart are a real receipt, a hand-off no rail can confirm, and a refusal —
325
+ * never collapsed into a single "Delivered" (PHNX-3999).
326
+ */
327
+ function renderAnswerResult(result) {
328
+ switch (result.status) {
329
+ case 'failed':
330
+ return `Not delivered: ${result.reason ?? 'unknown failure'} — answering again is safe.`;
331
+ case 'unknown':
332
+ return `Delivery unconfirmed: ${result.reason ?? 'no rail reported a receipt.'} Run \`agents feed answer ${result.attentionKey} --check\` rather than resending.`;
333
+ case 'already_answered':
334
+ return `Already answered — ${result.receipt?.status ?? 'claimed'}${result.receipt ? ` as ${result.receipt.msgId}` : ''} at ${result.receipt?.at ?? result.attempt}.`;
335
+ default:
336
+ return `Delivered ${result.receipt?.msgId} (${result.receipt?.status}).`;
337
+ }
338
+ }
317
339
  export function registerFeedCommand(program) {
318
340
  const feed = program
319
341
  .command('feed')
@@ -334,23 +356,52 @@ export function registerFeedCommand(program) {
334
356
  .option('--choice <choice-id>', 'Stable choice id from the attention item')
335
357
  .option('--text <answer>', 'Free-text answer')
336
358
  .option('--as <operator>', 'Verified operator id for high-consequence answers')
359
+ .option('--check', 'Read-only: report this item\'s delivery state without claiming, routing or resending')
360
+ .option('--attempt <at>', 'With --check: the attempt timestamp being checked, so a newer one is reported as such')
337
361
  .option('--json', 'Emit the delivery result as JSON')
338
362
  .action(async (attentionKey, opts, invoked) => {
363
+ const wantsJson = Boolean(opts.json || invoked.parent?.opts()?.json);
339
364
  try {
340
- const ownerHost = attentionKey.slice(0, attentionKey.indexOf('/'));
341
- const result = ownerHost && ownerHost !== machineId()
342
- ? await forwardFeedAnswer({ host: ownerHost, attentionKey, choiceId: opts.choice, text: opts.text, operatorId: opts.as })
343
- : await claimAndRouteAttentionAnswer({
344
- attentionKey, choiceId: opts.choice, text: opts.text,
345
- operator: { id: opts.as, verified: Boolean(opts.as), label: opts.as },
346
- });
347
- if (opts.json || invoked.parent?.opts()?.json)
365
+ // The key's own host decides the rail; `answerOwnerIsLocal` normalizes
366
+ // both sides so a `.local` suffix is not read as a different machine.
367
+ const { host: ownerHost } = parseAttentionKey(attentionKey);
368
+ const local = answerOwnerIsLocal(ownerHost);
369
+ if (opts.check && (opts.choice != null || opts.text != null)) {
370
+ throw new AnswerError('--check is read-only; it takes no --choice or --text.', 'empty_answer');
371
+ }
372
+ if (opts.attempt != null && !opts.check) {
373
+ throw new AnswerError('--attempt only applies to --check.', 'empty_answer');
374
+ }
375
+ const result = opts.check
376
+ ? (local
377
+ ? checkAnswerDelivery(attentionKey, undefined, opts.attempt)
378
+ : await forwardFeedAnswer({ host: ownerHost, attentionKey, check: true, attempt: opts.attempt, operatorId: opts.as }))
379
+ : local
380
+ ? await claimAndRouteAttentionAnswer({
381
+ attentionKey, choiceId: opts.choice, text: opts.text,
382
+ operator: { id: opts.as, verified: Boolean(opts.as), label: opts.as },
383
+ })
384
+ : await forwardFeedAnswer({ host: ownerHost, attentionKey, choiceId: opts.choice, text: opts.text, operatorId: opts.as });
385
+ if (wantsJson)
348
386
  console.log(JSON.stringify(result));
349
387
  else
350
- console.log(result.status === 'delivered' ? `Delivered ${result.receipt.msgId}.` : `Already answered (${result.receipt.at}).`);
388
+ console.log(renderAnswerResult(result));
351
389
  }
352
390
  catch (error) {
353
- invoked.error(`error: ${error instanceof Error ? error.message : String(error)}`);
391
+ // A failure is a first-class outcome for the operator UI, not a parse
392
+ // error: `--json` still gets a result object it can branch on, with a
393
+ // non-zero exit so a scripted caller sees the failure too.
394
+ const message = error instanceof Error ? error.message : String(error);
395
+ if (wantsJson) {
396
+ const failure = {
397
+ status: 'failed', delivery: 'failed', resolved: false, reason: message,
398
+ code: error instanceof AnswerError ? error.code : 'rail_failed', attentionKey,
399
+ };
400
+ console.log(JSON.stringify(failure));
401
+ process.exitCode = 1;
402
+ return;
403
+ }
404
+ invoked.error(`error: ${message}`);
354
405
  }
355
406
  });
356
407
  feed
@@ -136,7 +136,7 @@ export function registerFocusCommand(program) {
136
136
  # Resolve latest on yosemite-s0, then pick from that version's sessions
137
137
  agents sessions focus claude@latest --device yosemite-s0
138
138
 
139
- # Attach only — refuse if nothing is joinable (old sessions go)
139
+ # Attach only — refuse if nothing is joinable
140
140
  agents sessions focus a1b2c3d4 --attach-only
141
141
 
142
142
  # Pick from live sessions on this machine only
@@ -1,23 +1,6 @@
1
- /**
2
- * `agents sessions go [id]` — DEPRECATED alias for `agents sessions focus --attach-only`.
3
- *
4
- * `go` was "attach or refuse" (never fork/resume). `focus --attach-only` is exactly
5
- * that behavior, so `go` now prints a deprecation notice and delegates to `focusAction`.
6
- *
7
- * This file still owns the shared reach engine that `focus` imports:
8
- * - `gatherLiveTargets` / `pickLiveTarget` / `buildLivePool` — live-session discovery + picker
9
- * - `jumpTo` — the side-effecting jump: attach the already-running terminal
10
- * local tmux -> attach (switch-client when already inside tmux)
11
- * local Ghostty -> focus its tab (Cmd+<n> via System Events; tab # from ghostty-tabs)
12
- * remote tmux -> ssh -tt + tmux attach (pane->session resolved on the remote)
13
- * otherwise -> hand off to the `UnreachableFallback` (attach-only refuses; focus resumes)
14
- * - `refuseFallback` — the attach-only fallback (remote -> login shell; local -> refuse)
15
- */
16
- import type { Command } from 'commander';
17
1
  import { type ActiveSession } from '../lib/session/active.js';
18
2
  import type { SessionMeta } from '../lib/session/types.js';
19
3
  import { type LiveStatusFilter } from './sessions.js';
20
- export declare function registerGoCommand(program: Command): void;
21
4
  /**
22
5
  * Scope a live-session pool by device and live status. Pure so the `focus`
23
6
  * device/status filters are unit-testable without touching the sweep. `hosts`
@@ -1,10 +1,6 @@
1
1
  /**
2
- * `agents sessions go [id]` — DEPRECATED alias for `agents sessions focus --attach-only`.
3
- *
4
- * `go` was "attach or refuse" (never fork/resume). `focus --attach-only` is exactly
5
- * that behavior, so `go` now prints a deprecation notice and delegates to `focusAction`.
6
- *
7
- * This file still owns the shared reach engine that `focus` imports:
2
+ * The shared live-session reach engine that `sessions focus` / `resume --attach-only`
3
+ * import ("attach or refuse", never fork/resume):
8
4
  * - `gatherLiveTargets` / `pickLiveTarget` / `buildLivePool` — live-session discovery + picker
9
5
  * - `jumpTo` — the side-effecting jump: attach the already-running terminal
10
6
  * local tmux -> attach (switch-client when already inside tmux)
@@ -26,7 +22,6 @@ import { dedupeByMachineSession, mergeLocalFirst, pickSessionInteractive, matche
26
22
  import { buildPreview } from './sessions-picker.js';
27
23
  import { multiItemPicker } from '../lib/picker.js';
28
24
  import { isPromptCancelled } from './utils.js';
29
- import { focusAction } from './focus.js';
30
25
  import { machineId } from '../lib/session/sync/config.js';
31
26
  import { attachTmux, runTmux } from '../lib/tmux/binary.js';
32
27
  import { ensureSessionHookRepaired, paneExitStatus, teardownIfAgentExited } from '../lib/tmux/session.js';
@@ -36,18 +31,6 @@ import { connectionEndedNotice } from '../lib/hosts/reconnect.js';
36
31
  import { enumerateGhosttyTabs, assignGhosttyTabs } from '../lib/session/ghostty-tabs.js';
37
32
  import { addressabilityRecoveryHint } from '../lib/terminal/resolve.js';
38
33
  const execFileAsync = promisify(execFile);
39
- export function registerGoCommand(program) {
40
- program
41
- .command('go', { hidden: true })
42
- .argument('[id]', 'Short/full session id to jump to; omit for an interactive picker')
43
- .option('--local', 'Only this machine (skip the cross-host sweep)')
44
- .description('Deprecated — use `agents sessions resume --attach-only` instead.')
45
- .action(async (id, opts) => {
46
- console.warn(chalk.yellow('`agents sessions go` is deprecated — use `agents sessions resume --attach-only` instead:'));
47
- console.warn(chalk.gray(` agents sessions resume ${id ?? '<id>'} --attach-only`));
48
- await focusAction(id, { local: opts.local, attachOnly: true });
49
- });
50
- }
51
34
  /**
52
35
  * Scope a live-session pool by device and live status. Pure so the `focus`
53
36
  * device/status filters are unit-testable without touching the sweep. `hosts`
@@ -263,7 +263,7 @@ export function registerLogsCommand(program) {
263
263
  .action((id, opts) => runLogs(id, opts));
264
264
  addEventsReadOptions(logsCmd
265
265
  .command('audit')
266
- .description('Alias for `agents events --audit`'), false)
266
+ .description('Alias for `agents events audit`'))
267
267
  .addHelpText('after', `
268
268
  Examples:
269
269
  agents logs audit Recent activity across everything
@@ -5,14 +5,14 @@ import ora from 'ora';
5
5
  import { checkbox } from '@inquirer/prompts';
6
6
  import { capableAgents, isCapable } from '../lib/capabilities.js';
7
7
  import { emit } from '../lib/feed/events.js';
8
- import { AGENTS, getAllCliStates, resolveAgentName, formatAgentError, registerMcpToTargets, unregisterMcpFromTargets, listInstalledMcpsWithScope, parseMcpConfig, getMcpConfigPathForHome, agentLabel, } from '../lib/agents.js';
8
+ import { AGENTS, getAllCliStates, resolveAgentName, formatAgentError, unregisterMcpFromTargets, listInstalledMcpsWithScope, parseMcpConfig, getMcpConfigPathForHome, agentLabel, } from '../lib/agents.js';
9
9
  import { readManifest, writeManifest, createDefaultManifest } from '../lib/manifest.js';
10
10
  import { listMcpServerConfigs, discoverMcpConfigsFromRepo, installMcpConfigCentrally, isProjectMcpTrusted, trustProjectMcp, untrustProjectMcp, getMcpTrustStorePath, } from '../lib/mcp.js';
11
11
  import { cloneRepo } from '../lib/git.js';
12
12
  import { getMcpDir, getProjectAgentsDir } from '../lib/state.js';
13
- import { getEffectiveHome, getGlobalDefault, listInstalledVersions, getVersionHomePath, resolveInstalledAgentTargets, resolveConfiguredAgentTargets, syncResourcesToVersion, } from '../lib/installations/versions.js';
13
+ import { getEffectiveHome, getGlobalDefault, listInstalledVersions, getVersionHomePath, resolveInstalledAgentTargets, syncResourcesToVersion, } from '../lib/installations/versions.js';
14
14
  import { getUserAgentsDir } from '../lib/state.js';
15
- import { isPromptCancelled, isInteractiveTerminal, requireInteractiveSelection, promptRemovalTargets, parseCommaSeparatedList, ensureAgentVersionsInstalled, resolveAgentTargetsAutoInstalling, resolveInstalledAgentTargetsAutoInstalling, VersionNotInstalledError, resolveListFilterOrExit, } from './utils.js';
15
+ import { isPromptCancelled, isInteractiveTerminal, requireInteractiveSelection, promptRemovalTargets, parseCommaSeparatedList, ensureAgentVersionsInstalled, resolveAgentTargetsAutoInstalling, VersionNotInstalledError, resolveListFilterOrExit, } from './utils.js';
16
16
  import { showResourceList, buildTargetsSection, } from './resource-view.js';
17
17
  /**
18
18
  * Parse a comma-separated --agents string into validated agent IDs and
@@ -137,12 +137,12 @@ Examples:
137
137
  agents mcp add my-api https://api.example.com --transport http --agents claude
138
138
 
139
139
  # Apply servers from manifest to specific agents
140
- agents mcp register --agents codex@0.116.0
140
+ agents sync --mcp codex@0.116.0
141
141
 
142
142
  When to use:
143
143
  - After install: 'agents mcp add <server>' to connect a new service
144
- - Version upgrade: 'agents mcp register' to sync servers to the new version
145
- - Team setup: commit mcp config to .agents and run 'agents mcp register'
144
+ - Version upgrade: 'agents sync --mcp' to sync servers to the new version
145
+ - Team setup: commit mcp config to .agents and run 'agents sync --mcp'
146
146
  `);
147
147
  withAliases(mcpCmd
148
148
  .command('list [agent]'), 'list')
@@ -220,7 +220,7 @@ When to use:
220
220
  });
221
221
  mcpCmd
222
222
  .command('add <name> [command_or_url...]')
223
- .description('Add an MCP server to the manifest (run "agents mcp register" afterward to apply)')
223
+ .description('Add an MCP server to the manifest (run "agents sync --mcp" afterward to apply)')
224
224
  .option('-a, --agents <list>', 'Targets: claude, codex@0.116.0', capableAgents('mcp').join(','))
225
225
  .option('-s, --scope <scope>', 'user (global) or project (repo-specific)', 'user')
226
226
  .option('-t, --transport <type>', 'stdio (default) or http', 'stdio')
@@ -336,7 +336,7 @@ Examples:
336
336
  writeManifest(localPath, manifest);
337
337
  emit('mcp.add', { module: 'mcp', server: name });
338
338
  console.log(chalk.green(`Added MCP server '${name}' to manifest`));
339
- console.log(chalk.gray('Run: agents mcp register to apply'));
339
+ console.log(chalk.gray('Run: agents sync --mcp to apply'));
340
340
  });
341
341
  withAliases(mcpCmd
342
342
  .command('remove [name]'), 'remove')
@@ -565,81 +565,6 @@ Examples:
565
565
  }
566
566
  console.log();
567
567
  });
568
- // Deprecated: superseded by `agents sync --mcp`. Kept as a warned, functional
569
- // alias so old muscle-memory and scripts don't break.
570
- mcpCmd
571
- .command('register [name]', { hidden: true })
572
- .description('Deprecated — use `agents sync --mcp` instead.')
573
- .option('-a, --agents <list>', 'Override manifest targets: claude, codex@0.116.0')
574
- .option('-y, --yes', 'Auto-install any missing agent versions without prompting')
575
- .addHelpText('after', `
576
- Examples:
577
- # Register all servers from manifest
578
- agents mcp register
579
-
580
- # Register a specific server
581
- agents mcp register notion
582
-
583
- # Register to specific agents (overrides manifest config)
584
- agents mcp register --agents codex@0.116.0
585
- `)
586
- .action(async (name, options) => {
587
- console.warn(chalk.yellow('`agents mcp register` is deprecated — use `agents sync --mcp` instead:'));
588
- console.warn(chalk.gray(' all servers: agents sync --mcp'));
589
- console.warn(chalk.gray(' specific server: agents sync --mcp <name>'));
590
- const localPath = getUserAgentsDir();
591
- const manifest = readManifest(localPath);
592
- if (!manifest?.mcp) {
593
- console.log(chalk.yellow('No MCP servers in manifest'));
594
- return;
595
- }
596
- const entries = name
597
- ? (() => {
598
- const config = manifest.mcp?.[name];
599
- return config ? [[name, config]] : [];
600
- })()
601
- : Object.entries(manifest.mcp);
602
- if (entries.length === 0) {
603
- console.log(chalk.yellow(`MCP server '${name}' not found in manifest`));
604
- return;
605
- }
606
- for (const [mcpName, config] of entries) {
607
- const transport = config.transport || 'stdio';
608
- const commandOrUrl = transport === 'http' ? config.url : config.command;
609
- if (!commandOrUrl) {
610
- console.log(`\n ${chalk.cyan(mcpName)}: ${chalk.yellow(`missing ${transport === 'http' ? 'url' : 'command'}`)}`);
611
- continue;
612
- }
613
- console.log(`\n ${chalk.cyan(mcpName)}:`);
614
- let targets;
615
- if (options.agents) {
616
- const resolved = await resolveInstalledAgentTargetsAutoInstalling(options.agents, capableAgents('mcp'), { yes: options.yes });
617
- if (!resolved) {
618
- console.log(chalk.gray(' Cancelled.'));
619
- continue;
620
- }
621
- targets = resolved;
622
- }
623
- else {
624
- targets = resolveConfiguredAgentTargets(config.agents, config.agentVersions, capableAgents('mcp'));
625
- }
626
- const results = await registerMcpToTargets(targets, mcpName, commandOrUrl, config.scope || 'user', transport, { headers: config.headers });
627
- const applied = results.filter(r => r.success).length;
628
- for (const result of results) {
629
- if (result.success) {
630
- console.log(` ${chalk.green('+')} ${formatTargetLabel(result.agentId, result.version)}`);
631
- }
632
- else if (result.error?.startsWith('skipped:')) {
633
- console.log(` ${chalk.yellow('-')} ${formatTargetLabel(result.agentId, result.version)}: ${result.error}`);
634
- }
635
- else {
636
- console.log(` ${chalk.red('x')} ${formatTargetLabel(result.agentId, result.version)}: ${result.error}`);
637
- }
638
- }
639
- if (applied > 0)
640
- emit('mcp.register', { module: 'mcp', server: mcpName, applied });
641
- }
642
- });
643
568
  }
644
569
  async function installMcpsFromRepoSource(source, options) {
645
570
  const spinner = ora('Cloning repository...').start();
@@ -7,9 +7,9 @@
7
7
  import { withAliases } from '../lib/verbs.js';
8
8
  import chalk from 'chalk';
9
9
  import * as fs from 'fs';
10
- import { listMemoryFacts, addMemoryFact, removeMemoryFact, readMemoryFact, ensureUserMemoryDir, getUserMemoryDir, syncMemoryToVersionHome, } from '../lib/memory.js';
10
+ import { listMemoryFacts, addMemoryFact, removeMemoryFact, readMemoryFact, getUserMemoryDir, syncMemoryToVersionHome, } from '../lib/memory.js';
11
11
  import { capableAgents } from '../lib/capabilities.js';
12
- import { resolveAgentName, formatAgentError, agentLabel, ALL_AGENT_IDS } from '../lib/agents.js';
12
+ import { ALL_AGENT_IDS } from '../lib/agents.js';
13
13
  import { listInstalledVersions, getVersionHomePath, } from '../lib/installations/versions.js';
14
14
  import { supports } from '../lib/capabilities.js';
15
15
  import { setHelpSections } from '../lib/help.js';
@@ -33,7 +33,7 @@ export function registerMemoryCommands(program) {
33
33
  agents memory remove preferred-editor
34
34
 
35
35
  # Fan out to all capable installed agent versions
36
- agents memory sync
36
+ agents sync --memory
37
37
  `,
38
38
  notes: `
39
39
  Memory is the knowledge store (learned facts), distinct from rules
@@ -84,7 +84,7 @@ export function registerMemoryCommands(program) {
84
84
  }
85
85
  }
86
86
  else {
87
- console.log(chalk.gray(' Run: agents memory sync (or agents sync) to fan out'));
87
+ console.log(chalk.gray(' Run: agents sync --memory to fan out'));
88
88
  }
89
89
  });
90
90
  withAliases(memoryCmd
@@ -111,49 +111,6 @@ export function registerMemoryCommands(program) {
111
111
  console.log(chalk.dim(`# ${fact.name} [${fact.layer}] ${fact.path}`));
112
112
  console.log(fs.readFileSync(fact.path, 'utf-8'));
113
113
  });
114
- // Deprecated: superseded by `agents sync --memory`. Kept as a warned, functional
115
- // alias so old muscle-memory and scripts don't break.
116
- memoryCmd
117
- .command('sync [agent]', { hidden: true })
118
- .description('Deprecated — use `agents sync --memory` instead.')
119
- .option('-a, --agent <agent>', 'Limit to one agent (or agent@version)')
120
- .action(async (agentArg, options) => {
121
- console.warn(chalk.yellow('`agents memory sync` is deprecated — use `agents sync --memory` instead:'));
122
- console.warn(chalk.gray(' all agents: agents sync --memory'));
123
- console.warn(chalk.gray(' one agent: agents sync --memory <agent>'));
124
- ensureUserMemoryDir();
125
- const input = agentArg || options.agent;
126
- if (input) {
127
- const parts = input.split('@');
128
- const resolved = resolveAgentName(parts[0]);
129
- if (!resolved) {
130
- console.error(chalk.red(formatAgentError(parts[0], capableAgents('memory'))));
131
- process.exit(1);
132
- }
133
- const agent = resolved;
134
- const versions = parts[1]
135
- ? [parts[1]]
136
- : listInstalledVersions(agent);
137
- if (versions.length === 0) {
138
- console.log(chalk.yellow(`No installed versions of ${agentLabel(agent)}`));
139
- return;
140
- }
141
- for (const version of versions) {
142
- const home = getVersionHomePath(agent, version);
143
- const facts = syncMemoryToVersionHome(agent, home, process.cwd());
144
- console.log(chalk.green(`Synced ${facts.length} fact(s) → ${agent}@${version}`));
145
- }
146
- return;
147
- }
148
- const results = syncAllMemory(process.cwd());
149
- if (results.length === 0) {
150
- console.log(chalk.gray('No memory-capable agent versions installed.'));
151
- return;
152
- }
153
- for (const r of results) {
154
- console.log(chalk.green(`Synced ${r.facts.length} fact(s) → ${r.agent}@${r.version}`));
155
- }
156
- });
157
114
  }
158
115
  function syncAllMemory(cwd) {
159
116
  const out = [];
@@ -153,17 +153,17 @@ async function deliverViaHostReroute(route, text, opts) {
153
153
  * injected input a running agent consumes, never a notification a human reads.
154
154
  * Mirrors SHARED_NOTES in commands/send.ts so an agent reading either --help
155
155
  * sees the same three-plane map and doesn't reach for `message` when it means
156
- * `send`/`notify`.
156
+ * `send`.
157
157
  */
158
158
  const CONTROL_PLANE_NOTES = `
159
159
  Planes (do not mix them up):
160
160
  message / sessions inject - CONTROL a running agent (mailbox answer, terminal keystroke, or resume by runtime)
161
- send / notify - DELIVER a message to a human recipient over a channel provider
162
- feed post - RECORD progress / milestones (optional broadcast may call send/notify)
161
+ send - DELIVER a message to a human recipient over a channel provider
162
+ feed post - RECORD progress / milestones (optional broadcast may call send)
163
163
 
164
164
  <text> here is consumed BY THE TARGET AGENT (an answer, a keystroke, or the
165
165
  argument to a resume) -- it is not a notification a person reads on their
166
- phone. To reach the operator instead, use \`agents send\` / \`agents notify\`
166
+ phone. To reach the operator instead, use \`agents send --to owner\`
167
167
  (or a feed.broadcast \`channel:\` sink).
168
168
  `;
169
169
  export function registerMessageCommand(program) {
@@ -48,7 +48,7 @@ Examples:
48
48
  agents plugins view rush-toolkit
49
49
 
50
50
  # Sync a plugin to specific agents
51
- agents plugins sync rush-toolkit claude
51
+ agents sync --plugin rush-toolkit claude
52
52
 
53
53
  # Remove a plugin from all agents and delete its source
54
54
  agents plugins remove rush-toolkit
@@ -283,98 +283,6 @@ Examples:
283
283
  }
284
284
  console.log();
285
285
  });
286
- // Deprecated: superseded by `agents sync --plugin <name>`. Kept as a warned,
287
- // functional alias so old muscle-memory and scripts don't break.
288
- pluginsCmd
289
- .command('sync <name> [agent]', { hidden: true })
290
- .description('Deprecated — use `agents sync --plugin <name>` instead.')
291
- .option('--allow-exec-surfaces', 'Enable the plugin even when it ships hooks/, .mcp.json, bin/, scripts/, settings.json, or permissions/')
292
- .addHelpText('after', `
293
- Examples:
294
- # Sync a plugin to every installed version of an agent
295
- agents plugins sync rush-toolkit claude
296
-
297
- # Sync to one specific version (parity with 'agents sync')
298
- agents plugins sync rush-toolkit claude@2.1.142
299
-
300
- # Sync to all supported agents (every installed version of each)
301
- agents plugins sync rush-toolkit
302
-
303
- # Re-affirm consent for a hooks-bearing plugin
304
- agents plugins sync hivemind claude --allow-exec-surfaces
305
- `)
306
- .action(async (name, agentArg, options) => {
307
- console.warn(chalk.yellow('`agents plugins sync` is deprecated — use `agents sync --plugin` instead:'));
308
- console.warn(chalk.gray(` agents sync --plugin ${name}`));
309
- const plugin = getPlugin(name);
310
- if (!plugin) {
311
- console.log(chalk.red(`Plugin '${name}' not found`));
312
- process.exit(1);
313
- }
314
- // Accept the same "agent@version" form as `agents sync`. Splitting here
315
- // also means an unknown spec is reported cleanly rather than crashing
316
- // isCapable() with a bare "claude@2.1.168".
317
- let versionArg;
318
- let agentName = agentArg;
319
- if (agentArg && agentArg.includes('@')) {
320
- const at = agentArg.lastIndexOf('@');
321
- agentName = agentArg.slice(0, at);
322
- versionArg = agentArg.slice(at + 1);
323
- }
324
- // Determine target agents
325
- let targetAgents;
326
- if (agentName) {
327
- const agentId = agentName;
328
- if (!isCapable(agentId, 'plugins')) {
329
- console.log(chalk.red(`Agent '${agentName}' does not support plugins`));
330
- process.exit(1);
331
- }
332
- if (!pluginSupportsAgent(plugin, agentId)) {
333
- console.log(chalk.red(`Plugin '${name}' does not support ${agentLabel(agentId)}`));
334
- process.exit(1);
335
- }
336
- targetAgents = [agentId];
337
- }
338
- else {
339
- if (versionArg) {
340
- console.log(chalk.red(`A version (@${versionArg}) requires naming the agent, e.g. claude@${versionArg}`));
341
- process.exit(1);
342
- }
343
- targetAgents = capableAgents('plugins').filter(a => pluginSupportsAgent(plugin, a));
344
- }
345
- const allowExec = options.allowExecSurfaces === true;
346
- for (const agentId of targetAgents) {
347
- const versions = listInstalledVersions(agentId);
348
- if (versions.length === 0)
349
- continue;
350
- // Default to EVERY installed version. The previous behaviour synced only
351
- // the global default, which silently skipped non-default versions used
352
- // by balanced rotation -- so a rotated version would lack the plugin's
353
- // slash commands. An explicit agent@version narrows back to one.
354
- let targetVersions;
355
- if (versionArg) {
356
- if (!versions.includes(versionArg)) {
357
- console.log(chalk.red(`${agentLabel(agentId)} has no installed version ${versionArg} (installed: ${versions.join(', ')})`));
358
- process.exit(1);
359
- }
360
- targetVersions = [versionArg];
361
- }
362
- else {
363
- targetVersions = versions;
364
- }
365
- for (const version of targetVersions) {
366
- const didSync = allowExec
367
- ? syncPluginToVersion(plugin, agentId, getVersionHomePath(agentId, version), { allowExecSurfaces: true, version }).success
368
- : syncResourcesToVersion(agentId, version, { plugins: [name] }).plugins.length > 0;
369
- if (didSync) {
370
- console.log(chalk.green(`Synced ${name} to ${agentLabel(agentId)}@${version}${allowExec ? ' (exec surfaces enabled)' : ''}`));
371
- }
372
- else {
373
- console.log(chalk.gray(`${name} already synced to ${agentLabel(agentId)}@${version}`));
374
- }
375
- }
376
- }
377
- });
378
286
  // agents plugins remove [name]
379
287
  withAliases(pluginsCmd
380
288
  .command('remove [name]'), 'remove')
@@ -31,8 +31,6 @@ function resolveRepoPath(target) {
31
31
  import { applyExtraAliasToVersions, ensureAgentsDir, getExtraRepoDir, getSystemAgentsDir, getUserAgentsDir, readMeta, resolveExtraRepoDir, updateMeta, } from '../lib/state.js';
32
32
  import { parseSource, pullRepo, commitAndPush, isGitRepo, isSystemRepoOrigin, adoptRepo, adoptUserRepoIfNeeded, recordUserRepoRemote, resolveUserRepoRemoteUrl, getRemoteUrl, sameGitRemote, displayHomePath, syncRepoGit, } from '../lib/git.js';
33
33
  import { DEFAULT_SYSTEM_REPO } from '../lib/types.js';
34
- import { ALL_AGENT_IDS, isAgentName, resolveAgentName } from '../lib/agents.js';
35
- import { refresh } from '../lib/refresh.js';
36
34
  import { capableAgents } from '../lib/capabilities.js';
37
35
  import { getGlobalDefault, getVersionHomePath, listInstalledVersions } from '../lib/installations/versions.js';
38
36
  import { syncAllMarketplaces } from '../lib/plugins/plugin-marketplace.js';
@@ -1230,48 +1228,6 @@ Examples:
1230
1228
  }
1231
1229
  }
1232
1230
  });
1233
- // Deprecated: superseded by `agents sync`. `agents sync --local` runs the same
1234
- // reconcile stage (sync-umbrella.ts calls this exact `refresh()`), and `agents
1235
- // sync <agent>` targets one agent — with the added reach `refresh` lacks
1236
- // (all installed versions, no silent skip when there is no global default).
1237
- // Hidden from help; kept as a warned, functional alias so old muscle-memory and
1238
- // scripts don't break. Migrate callers to `agents sync`.
1239
- repoCmd
1240
- .command('refresh [agent]', { hidden: true })
1241
- .description('Deprecated — use `agents sync` instead.')
1242
- .option('-y, --yes', 'Auto-sync everything without prompting')
1243
- .option('--skip-clis', 'Skip CLI version install/upgrade from agents.yaml')
1244
- .action(async (arg, options) => {
1245
- console.warn(chalk.yellow('`agents repo refresh` is deprecated — use `agents sync` instead:'));
1246
- console.warn(chalk.gray(' all agents: agents sync --local'));
1247
- console.warn(chalk.gray(' one agent: agents sync <agent>'));
1248
- let agentFilter;
1249
- if (arg) {
1250
- if (!isAgentName(arg)) {
1251
- console.log(chalk.red(`Unknown agent "${arg}".`));
1252
- console.log(chalk.gray(`Available: ${ALL_AGENT_IDS.join(', ')}`));
1253
- process.exitCode = 1;
1254
- return;
1255
- }
1256
- agentFilter = resolveAgentName(arg);
1257
- }
1258
- try {
1259
- await refresh({
1260
- agentFilter,
1261
- skipPrompts: options.yes,
1262
- skipClis: options.skipClis,
1263
- });
1264
- console.log(chalk.green('\nRefresh complete'));
1265
- }
1266
- catch (err) {
1267
- if (isPromptCancelled(err)) {
1268
- console.log(chalk.yellow('\nCancelled'));
1269
- return;
1270
- }
1271
- console.error(chalk.red(err.message));
1272
- process.exit(1);
1273
- }
1274
- });
1275
1231
  const statusCmd = repoCmd
1276
1232
  .command('status [alias]', { hidden: true })
1277
1233
  .description('Alias of `list` (kept for muscle memory). Add --devices-all to report across the fleet.')
@@ -8,6 +8,7 @@ import chalk from 'chalk';
8
8
  import { resolveSessionMetadataValue } from './sessions.js';
9
9
  import { sessionOwnerDevice, consumeResumePinned, RESUME_PINNED_ENV } from '../lib/session/resume-owner.js';
10
10
  import { machineId } from '../lib/machine-id.js';
11
+ import { takeOverDetachedSession } from '../lib/session/detached.js';
11
12
  const RESUME_SOURCE_ENV = 'AGENTS_RESUME_SOURCE_JSON';
12
13
  /** Inspect local archived context after the owner hop fails. Recovery still
13
14
  * requires readable content and explicit replay consent before starting a run. */
@@ -161,7 +162,9 @@ export async function runStrictResume(sessionId, prompt, options) {
161
162
  }
162
163
  return;
163
164
  }
164
- process.exitCode = await delegateLocalResume(pinnedHere ? resumeLocalFallbackSource(outcome.session) : outcome.session, prompt, options);
165
+ const localSession = pinnedHere ? resumeLocalFallbackSource(outcome.session) : outcome.session;
166
+ await takeOverDetachedSession(localSession.id);
167
+ process.exitCode = await delegateLocalResume(localSession, prompt, options);
165
168
  }
166
169
  /**
167
170
  * Spawn the delegated local `agents run --resume` for a session this box owns