@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,86 +0,0 @@
1
- import chalk from 'chalk';
2
- import { runOnPeer } from '../lib/session/remote-list.js';
3
- import { sessionRecoveryPeer } from '../lib/session/recovery.js';
4
- import { resolveSessionMetadataValue, resumeSessionInPlace } from './sessions.js';
5
- import { readDetachRecord, clearDetachRecord, isHeadlessAlive } from '../lib/session/detached.js';
6
- import { attachLocalLiveSelector } from '../lib/session/local-tmux-attach.js';
7
- export function registerAttachCommand(program) {
8
- // Deprecated: superseded by `agents sessions resume`, which detects the state
9
- // (live pane / headless / ended) instead of making the caller pick a verb.
10
- // Hidden from help; kept as a warned, functional alias for one release so old
11
- // muscle-memory and scripts don't break.
12
- program
13
- .command('attach', { hidden: true })
14
- .argument('<id>', 'Short or full id of the backgrounded/parked session to resume interactively')
15
- .description('Deprecated — use `agents sessions resume <id>` instead.')
16
- .action(async (id) => {
17
- console.warn(chalk.yellow('`agents sessions attach` is deprecated — use `agents sessions resume` instead:'));
18
- console.warn(chalk.gray(` agents sessions resume ${id}`));
19
- await attachAction(id);
20
- });
21
- }
22
- export async function attachAction(id) {
23
- // PHNX-3292: this deprecated spelling still gets the local-pane fast path —
24
- // a live tmux alias/short id on THIS box attaches with zero SSH, matching
25
- // `sessions resume`. `attach` takes no `--device`, so hosts is always empty.
26
- if (await attachLocalLiveSelector(id.trim(), [])) {
27
- return;
28
- }
29
- const outcome = await resolveSessionMetadataValue(id);
30
- if (outcome.kind === 'partial') {
31
- // RUSH-2492: an unreachable peer is a warning, not a hard failure. The
32
- // resolver already resolves an id found on the reachable fleet (SES-9a), so
33
- // reaching here means the session was not found on any device we COULD reach
34
- // — it may live on one of the unreachable peers, which we could not check.
35
- const offline = outcome.failedPeers;
36
- console.error(chalk.yellow(`Warning: ${offline.length} device(s) unreachable, not checked: ${offline.join(', ')}`));
37
- console.error(chalk.red(`No session matching "${id}" on any reachable device (${offline.length} unreachable, not checked).`));
38
- console.error(chalk.gray(' If it lives on an offline box, wake it (agents devices) or run there: agents ssh <device>'));
39
- process.exitCode = 1;
40
- return;
41
- }
42
- if (outcome.kind === 'not-found') {
43
- console.error(chalk.red(`No session matching "${id}".`));
44
- console.error(chalk.gray(' See your sessions: agents sessions'));
45
- process.exitCode = 1;
46
- return;
47
- }
48
- if (outcome.kind === 'ambiguous') {
49
- console.error(chalk.red(`"${id}" matches ${outcome.candidates.length} sessions. Pass the full session id.`));
50
- process.exitCode = 1;
51
- return;
52
- }
53
- const meta = outcome.session;
54
- // Route the WHOLE attach operation to the origin, not just its eventual
55
- // resume. The detach record and headless PID are device-local; clearing them
56
- // here would leave the real background continuation running beside a second
57
- // process on the owning machine.
58
- const peer = sessionRecoveryPeer(meta);
59
- if (peer) {
60
- const routed = await runOnPeer(attachRecoveryArgs(meta), peer, { tty: true, sessionId: meta.id });
61
- if (routed === 'no-target') {
62
- console.error(chalk.red(`Cannot attach ${meta.shortId}: origin device ${peer} is not a registered reachable peer.`));
63
- process.exitCode = 1;
64
- }
65
- return;
66
- }
67
- // If it's backgrounded, stop the headless continuation first so two processes
68
- // don't resume the same transcript at once.
69
- const rec = readDetachRecord(meta.id);
70
- if (rec) {
71
- if (isHeadlessAlive(rec)) {
72
- try {
73
- process.kill(rec.headlessPid, 'SIGTERM');
74
- }
75
- catch {
76
- /* already gone */
77
- }
78
- }
79
- clearDetachRecord(meta.id);
80
- }
81
- console.log(chalk.gray(`Attaching ${meta.agent} ${meta.id.slice(0, 8)} — resuming interactively…`));
82
- await resumeSessionInPlace(meta);
83
- }
84
- export function attachRecoveryArgs(session) {
85
- return ['sessions', 'attach', session.id];
86
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * Shared `mint` subcommand registered on both `agents auth` (the ticket
3
- * surface) and `agents accounts` (the credential noun). Hidden on both:
4
- * `agents accounts add <harness> [name]` / `agents accounts login <harness>#<name>`
5
- * is the taught path. Implementation lives in lib/auth-mint.ts so neither
6
- * command file owns the seed path.
7
- */
8
- import type { Command } from 'commander';
9
- import { type MintDriveHooks } from '../lib/auth-mint.js';
10
- export declare function registerMintCommand(parent: Command, testHooks?: MintDriveHooks, opts?: {
11
- hidden?: boolean;
12
- }): Command;
@@ -1,108 +0,0 @@
1
- /**
2
- * Shared `mint` subcommand registered on both `agents auth` (the ticket
3
- * surface) and `agents accounts` (the credential noun). Hidden on both:
4
- * `agents accounts add <harness> [name]` / `agents accounts login <harness>#<name>`
5
- * is the taught path. Implementation lives in lib/auth-mint.ts so neither
6
- * command file owns the seed path.
7
- */
8
- import chalk from 'chalk';
9
- import { setHelpSections } from '../lib/help.js';
10
- import { readStdinSync, runOrDie } from '../lib/format.js';
11
- import { isInteractiveTerminal } from './utils.js';
12
- import { getMintFlow, listMintableHarnesses, mintAndSeed, } from '../lib/auth-mint.js';
13
- const MINT_POINTER = 'agents accounts add <harness> [name] / agents accounts login <harness>#<name>';
14
- function collect(value, previous) {
15
- return [...previous, value];
16
- }
17
- function printResult(result, json) {
18
- if (json) {
19
- console.log(JSON.stringify({
20
- harness: result.harness,
21
- account: result.account,
22
- email: result.email,
23
- authBundleKey: result.authBundleKey,
24
- rotated: result.rotated,
25
- fleet: result.fleet,
26
- }, null, 2));
27
- return;
28
- }
29
- const verb = result.rotated ? 'Rotated' : 'Minted';
30
- console.log(chalk.green(`${verb} ${result.harness} setup-token for ${result.email} into account '${result.account}' and reserved auth bundle key ${result.authBundleKey}.`));
31
- console.log(chalk.gray('The token is never printed. Native OAuth was not copied.'));
32
- console.log(chalk.gray(`Run: agents run ${result.harness} --account ${result.account}`));
33
- if (result.fleet.length) {
34
- for (const row of result.fleet) {
35
- console.log(chalk.green(` synced ${row.device} (${row.message})`));
36
- }
37
- }
38
- }
39
- export function registerMintCommand(parent, testHooks, opts) {
40
- const hidden = opts?.hidden ?? true;
41
- const mint = parent
42
- .command('mint <harness>', { hidden })
43
- .description('Mint a long-lived setup-token and seed it as a named account')
44
- .option('--account <name-or-email>', 'Named account to create/rotate, or the account email')
45
- .option('--email <email>', 'Email that keys the reserved auth bundle when --account is a name')
46
- .option('--token-stdin', 'Seed an already-minted token from stdin (skip the PTY drive)')
47
- .option('--code <code>', 'Authorization code to paste into the setup-token prompt')
48
- .option('--no-open', 'Print the authorize URL instead of opening a browser')
49
- .option('--fleet', 'Sync the minted account and reserved auth bundle to every other registered device')
50
- .option('--device <name>', 'Sync to this device (repeatable)', collect, [])
51
- .option('--json', 'Machine-readable result (never includes the token)')
52
- .action((harness, o, command) => {
53
- const json = !!o.json || !!command.optsWithGlobals().json;
54
- return runOrDie(async () => {
55
- getMintFlow(harness);
56
- let token;
57
- if (o.tokenStdin) {
58
- token = readStdinSync();
59
- if (!token)
60
- throw new Error('No value received on stdin. Pass the setup-token on stdin with --token-stdin.');
61
- }
62
- else if (!isInteractiveTerminal() && !o.code) {
63
- throw new Error(`Minting ${harness} interactively needs a TTY (or --token-stdin / --code). Supported harnesses: ${listMintableHarnesses().join(', ')}.`);
64
- }
65
- const result = await mintAndSeed({
66
- harness,
67
- account: o.account,
68
- email: o.email,
69
- token,
70
- code: o.code,
71
- open: o.open,
72
- fleet: o.fleet,
73
- devices: o.device,
74
- json,
75
- hooks: {
76
- ...testHooks,
77
- ...(o.tokenStdin || o.code || !isInteractiveTerminal()
78
- ? {}
79
- : {
80
- readCode: async () => {
81
- const { input } = await import('@inquirer/prompts');
82
- return input({ message: 'Paste the authorization code from the browser' });
83
- },
84
- }),
85
- },
86
- });
87
- printResult(result, json);
88
- }, { json });
89
- });
90
- if (hidden) {
91
- mint.hook('preAction', () => {
92
- console.error(chalk.gray(`'agents ${parent.name()} mint' is a hidden alias; use \`${MINT_POINTER}\` — still works this release.`));
93
- });
94
- }
95
- setHelpSections(mint, {
96
- examples: `agents accounts add claude work
97
- agents accounts login claude#work
98
- agents accounts mint claude --token-stdin < token.txt
99
- agents accounts mint claude --code AUTHCODE --json
100
- agents accounts mint claude --fleet`,
101
- notes: `Hidden alias of the worker-credential step that \`agents accounts add <harness> [name]\` (mint during add) and \`agents accounts login <harness>#<name>\` (re-mint) now own. Claude is the only harness with an interactive long-lived setup-token (\`claude setup-token\`, ~1 year, shareable across machines). The command drives that flow in a PTY, opens the authorize URL, captures a well-formed sk-ant-oat01- token (refusing the #1767 TTY-banner capture), and seeds:
102
- 1. a named provider account (policy never) for \`agents run --account\` / \`agents accounts sync\`
103
- 2. the reserved FILE-BASED auth bundle keyed per email, which usage/probe reads
104
- Native rotating OAuth is never copied. Other harnesses fail loud: device-code login is \`agents fleet login\`; API keys are \`agents accounts add\`.
105
- Already have a token? \`--token-stdin\` skips the browser dance. \`agents auth mint\` and \`agents accounts mint\` are the same hidden command.`,
106
- });
107
- return mint;
108
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * `agents reconnect [session-id]` — get me back into an agent terminal whose ssh
3
- * link dropped.
4
- *
5
- * The auto-reconnect in lib/hosts/reconnect.ts already re-attaches a live remote
6
- * pane over its own bounded backoff on a transient blink. This is the MANUAL
7
- * recovery for after it gave up — a sustained outage, or a VS Code terminal tab
8
- * that closed with the dead ssh client. One verb that always tries hardest to put
9
- * you back into that agent: attach the live pane if it still exists, else resume
10
- * the session; live pane > resumed copy > a clear message about what was lost.
11
- *
12
- * It delegates to `focus`, which already does exactly attach-else-resume for a
13
- * resolved id ({@link focusAction} → `focusResolvedSession`), so there is no second
14
- * recovery path to keep in sync. What `reconnect` adds is the recovery framing and,
15
- * with no id, targeting the MOST RECENT session in this shell's directory — the one
16
- * that most likely just dropped — instead of opening the full fleet picker.
17
- */
18
- import type { Command } from 'commander';
19
- import type { SessionMeta } from '../lib/session/types.js';
20
- /**
21
- * The recency signal a no-id reconnect targets: last activity if the scan
22
- * computed one, else the creation time. A row with neither parseable sorts last.
23
- * Pure so target selection is unit-tested without the scanner.
24
- */
25
- export declare function sessionRecency(s: Pick<SessionMeta, 'lastActivity' | 'timestamp'>): number;
26
- /**
27
- * Pick the session to reconnect when the user gave no id: the most recently
28
- * active one in scope — the terminal that most likely just dropped. Pure; returns
29
- * undefined for an empty scope so the caller can print guidance.
30
- */
31
- export declare function pickMostRecentSession(sessions: SessionMeta[]): SessionMeta | undefined;
32
- /**
33
- * Resolve the no-id target: prefer the most recent session started from THIS
34
- * directory (the shell the user is reconnecting from), falling back to the most
35
- * recent session anywhere when the current directory has none. Best-effort — a
36
- * discovery failure yields undefined, never throws. Injectable `discover` keeps
37
- * the two-step scope preference testable without touching the real scanner.
38
- */
39
- export declare function resolveRecentTarget(cwd: string, discover?: (opts: {
40
- cwd?: string;
41
- all?: boolean;
42
- since?: string;
43
- limit?: number;
44
- }) => Promise<SessionMeta[]>): Promise<SessionMeta | undefined>;
45
- export declare function reconnectAction(id: string | undefined): Promise<void>;
46
- export declare function registerReconnectCommand(program: Command): void;
@@ -1,115 +0,0 @@
1
- /**
2
- * `agents reconnect [session-id]` — get me back into an agent terminal whose ssh
3
- * link dropped.
4
- *
5
- * The auto-reconnect in lib/hosts/reconnect.ts already re-attaches a live remote
6
- * pane over its own bounded backoff on a transient blink. This is the MANUAL
7
- * recovery for after it gave up — a sustained outage, or a VS Code terminal tab
8
- * that closed with the dead ssh client. One verb that always tries hardest to put
9
- * you back into that agent: attach the live pane if it still exists, else resume
10
- * the session; live pane > resumed copy > a clear message about what was lost.
11
- *
12
- * It delegates to `focus`, which already does exactly attach-else-resume for a
13
- * resolved id ({@link focusAction} → `focusResolvedSession`), so there is no second
14
- * recovery path to keep in sync. What `reconnect` adds is the recovery framing and,
15
- * with no id, targeting the MOST RECENT session in this shell's directory — the one
16
- * that most likely just dropped — instead of opening the full fleet picker.
17
- */
18
- import chalk from 'chalk';
19
- import { focusAction } from './focus.js';
20
- import { discoverSessions } from '../lib/session/discover.js';
21
- import { setHelpSections } from '../lib/help.js';
22
- /**
23
- * The recency signal a no-id reconnect targets: last activity if the scan
24
- * computed one, else the creation time. A row with neither parseable sorts last.
25
- * Pure so target selection is unit-tested without the scanner.
26
- */
27
- export function sessionRecency(s) {
28
- const t = Date.parse(s.lastActivity ?? s.timestamp ?? '');
29
- return Number.isFinite(t) ? t : Number.NEGATIVE_INFINITY;
30
- }
31
- /**
32
- * Pick the session to reconnect when the user gave no id: the most recently
33
- * active one in scope — the terminal that most likely just dropped. Pure; returns
34
- * undefined for an empty scope so the caller can print guidance.
35
- */
36
- export function pickMostRecentSession(sessions) {
37
- let best;
38
- for (const s of sessions) {
39
- if (!best || sessionRecency(s) > sessionRecency(best))
40
- best = s;
41
- }
42
- return best;
43
- }
44
- /**
45
- * Resolve the no-id target: prefer the most recent session started from THIS
46
- * directory (the shell the user is reconnecting from), falling back to the most
47
- * recent session anywhere when the current directory has none. Best-effort — a
48
- * discovery failure yields undefined, never throws. Injectable `discover` keeps
49
- * the two-step scope preference testable without touching the real scanner.
50
- */
51
- export async function resolveRecentTarget(cwd, discover = discoverSessions) {
52
- try {
53
- const here = await discover({ cwd, since: '7d', limit: 200 });
54
- const local = pickMostRecentSession(here);
55
- if (local)
56
- return local;
57
- const any = await discover({ all: true, since: '7d', limit: 200 });
58
- return pickMostRecentSession(any);
59
- }
60
- catch {
61
- return undefined;
62
- }
63
- }
64
- export async function reconnectAction(id) {
65
- if (id) {
66
- // focus already attaches a live pane or recovers a dropped one for a resolved
67
- // id — on the origin device for a remote session. Reconnect is that path with
68
- // a recovery-first name; no reason to duplicate the resolution/attach logic.
69
- await focusAction(id, {});
70
- return;
71
- }
72
- const recent = await resolveRecentTarget(process.cwd());
73
- if (!recent) {
74
- console.log(chalk.gray('No recent session to reconnect from here.'));
75
- console.log(chalk.gray(' reconnect a specific one: agents reconnect <session-id>'));
76
- console.log(chalk.gray(' or pick from the fleet: agents sessions'));
77
- return;
78
- }
79
- const where = recent.machine ? ` on ${recent.machine}` : '';
80
- console.log(chalk.gray(`Reconnecting ${recent.shortId}${where} (most recent here)…`));
81
- await focusAction(recent.id, {});
82
- }
83
- export function registerReconnectCommand(program) {
84
- // Deprecated: superseded by `agents sessions resume`, which does the same
85
- // attach-else-recover and additionally takes a tmux alias. Hidden + warned +
86
- // functional for one release. Bare `reconnect` targeted the most recent
87
- // session in this directory; that default now lives on `resume`'s picker.
88
- const cmd = program
89
- .command('reconnect', { hidden: true })
90
- .argument('[session-id]', 'Session id/prefix to reconnect (default: the most recent session started here)')
91
- .description('Deprecated — use `agents sessions resume` instead.')
92
- .action(async (id) => {
93
- console.warn(chalk.yellow('`agents reconnect` is deprecated — use `agents sessions resume` instead:'));
94
- console.warn(chalk.gray(` agents sessions resume${id ? ` ${id}` : ''}`));
95
- await reconnectAction(id);
96
- });
97
- setHelpSections(cmd, {
98
- examples: `
99
- # Reconnect the session that just dropped in this shell (most recent here)
100
- agents reconnect
101
-
102
- # Reconnect one specific agent terminal by id/prefix
103
- agents reconnect 74b13b0b
104
-
105
- # Same, spelled under the sessions group
106
- agents sessions reconnect 74b13b0b
107
- `,
108
- notes: `
109
- - Best-effort recovery: a living remote tmux pane is JOINED (a second client, no fork); a dropped one is RESUMED on its origin device (a copy if it was mid-run, a /continue if idle).
110
- - With no id, targets the most recent session started from this directory (the terminal that most likely just dropped), not the full fleet picker. Falls back to the most recent session anywhere when this directory has none.
111
- - This is the manual companion to the automatic reconnect that runs during a live 'agents run --device <box>' when the network blinks; use it after that gave up or the terminal tab closed.
112
- - Deprecated: use 'agents sessions resume' — it attaches a live pane, foregrounds a headless session, or recovers an ended one.
113
- `,
114
- });
115
- }
@@ -1,293 +0,0 @@
1
- import { type Command } from 'commander';
2
- import { type ShareConfig } from '../lib/share/config.js';
3
- import { type CloudflareRequester } from '../lib/share/provision.js';
4
- import { type PublishResult, type ShareVisibility } from '../lib/share/publish.js';
5
- import { deleteShare, type DeleteShareResult } from '../lib/share/delete.js';
6
- import type { PhoenixSession } from '../lib/identity/client.js';
7
- export declare function formatSharePublishResult(result: PublishResult, json?: boolean): string;
8
- /** Compare the configured endpoint's last-deployed template hash against the
9
- * hash of the CURRENT `worker-template.ts` render. A config with no recorded
10
- * hash (every endpoint provisioned before this field existed) is "unknown" —
11
- * never "current" or "outdated", since there is nothing to compare against. */
12
- export declare function shareTemplateStatus(cfg: ShareConfig): 'current' | 'outdated' | 'unknown';
13
- /** One published object as reported by the Worker's `?format=json` listing route. */
14
- interface ShareListItem {
15
- slug: string;
16
- url: string;
17
- /** Object size in bytes. */
18
- size: number;
19
- /** Stored content type, or null if the Worker had none recorded. */
20
- contentType: string | null;
21
- /** ISO timestamp the object was last written (R2 `uploaded`). */
22
- publishedAt: string;
23
- /** ISO auto-expire timestamp, or null for a permanent share. */
24
- expiresAt: string | null;
25
- /** Human display title (explicit `--label` or auto-derived), or null for a
26
- * share published before this field existed. */
27
- label: string | null;
28
- /** Harness/agent name that published this (`AGENTS_AGENT_NAME`), or null. */
29
- agent: string | null;
30
- /** Session id that published this, or null. */
31
- session: string | null;
32
- /** Hostname the publish ran from, or null. */
33
- host: string | null;
34
- /** git repo name at publish time, or null (published outside a git repo, or
35
- * before this field existed). */
36
- repo: string | null;
37
- /** Count of retained prior versions under this slug (see `share revisions`). */
38
- revisionCount: number;
39
- /** The visibility stamped at publish time: public | unlisted | me | org.
40
- * Missing on Workers that predate this field → treated as public. */
41
- visibility: ShareVisibility;
42
- /** Arbitrary `--meta key=value` entries attached at publish time (RUSH-2683)
43
- * — everything that isn't a reserved provenance/label key. `{}` when none
44
- * were set, or when the deployed Worker predates this field. */
45
- meta: Record<string, string>;
46
- }
47
- interface ShareListResult {
48
- /** The namespace listed. */
49
- user: string;
50
- count: number;
51
- objects: ShareListItem[];
52
- }
53
- /** DI seam for tests — override the real HTTP GET of the JSON listing route.
54
- * The optional `headers` carry the owner bearer for hidden-visibility listings. */
55
- type ListingFetchFn = (url: string, headers?: Record<string, string>) => Promise<{
56
- status: number;
57
- contentType: string;
58
- body: string;
59
- }>;
60
- interface ShareEditResult {
61
- ok: true;
62
- url: string;
63
- label: string | null;
64
- meta: Record<string, string>;
65
- /** The visibility the page now carries (present on Workers that support the
66
- * visibility edit; absent from an older deployed template). */
67
- visibility?: ShareVisibility;
68
- /** The visibility the page had before this edit, when the Worker reports it. */
69
- previousVisibility?: ShareVisibility;
70
- }
71
- export declare function runShareEdit(target: string, opts: {
72
- githubUser?: string;
73
- config?: ShareConfig;
74
- writeToken?: string;
75
- byo?: boolean;
76
- session?: PhoenixSession | null;
77
- label?: string | null;
78
- meta?: Record<string, string>;
79
- metaMode?: 'merge' | 'replace';
80
- removeMeta?: string[];
81
- /** Change the page's visibility in place (public | unlisted | me | org).
82
- * A metadata-only rewrite like label/meta — the body is untouched, so no
83
- * revision is created. me/org require a Phoenix session. `private` is
84
- * rejected here — token-gating needs a fresh viewer key only the publish
85
- * path mints (PHNX-3654). */
86
- visibility?: ShareVisibility;
87
- force?: boolean;
88
- fetchEdit?: typeof fetch;
89
- }): Promise<ShareEditResult>;
90
- /** Parse the Worker's listing JSON into a validated result, failing loud (with the
91
- * outdated-template hint) on any body that isn't the expected shape — an old Worker
92
- * serves the HTML gallery for a non-empty namespace, which must not be silently
93
- * accepted as "you have published nothing". */
94
- export declare function parseShareListing(user: string, body: string): ShareListResult;
95
- /** Fetch and parse the machine-readable listing of the caller's namespace from the
96
- * Worker's `?format=json` route. Fails loud when share was never configured, when
97
- * the deployed template is known-outdated (RUSH-2449 templateHash), or when the
98
- * live response proves the route is absent (404 or a non-JSON 200 = the old HTML
99
- * gallery) — never a silent empty/wrong result. Signed-in users hit the managed
100
- * endpoint; BYO still uses `readShareConfig()`. */
101
- export declare function runShareList(opts?: {
102
- githubUser?: string;
103
- config?: ShareConfig;
104
- writeToken?: string;
105
- byo?: boolean;
106
- /** DI seam — override `readSession()`. Named `phoenixSession` because
107
- * `session` is already the listing filter (session id). */
108
- phoenixSession?: PhoenixSession | null;
109
- fetchListing?: ListingFetchFn;
110
- /** Only shares published by this agent/harness (case-insensitive, exact). */
111
- agent?: string;
112
- /** Only shares published from this session id (exact). */
113
- session?: string;
114
- /** Only shares whose label contains this text (case-insensitive substring). */
115
- label?: string;
116
- /** Only shares matching every provided `--meta key=value` entry. */
117
- meta?: Record<string, string>;
118
- /** Visibility filter. `public` (default) lists only public gallery pages;
119
- * `unlisted`/`me`/`org` include that owner's hidden pages; `all` includes
120
- * every active page. Hidden scopes send the owner's bearer and `scope=mine`. */
121
- scope?: 'public' | 'unlisted' | 'private' | 'me' | 'org' | 'all';
122
- }): Promise<ShareListResult>;
123
- /** Client-side filtering over an already-fetched listing (RUSH-2683) — the
124
- * Worker has no query surface for this, so it narrows the fetched set instead
125
- * of a second round trip. `count` reflects the FILTERED set, matching what the
126
- * caller actually sees. */
127
- export declare function applyShareListFilters(result: ShareListResult, filters: {
128
- agent?: string;
129
- session?: string;
130
- label?: string;
131
- meta?: Record<string, string>;
132
- scope?: 'public' | 'unlisted' | 'private' | 'me' | 'org' | 'all';
133
- }): ShareListResult;
134
- export declare function formatShareList(result: ShareListResult, json?: boolean): string;
135
- /** One retained prior version of a slug, as reported by the Worker's
136
- * `?revisions=json` route. */
137
- interface ShareRevisionItem {
138
- /** R2 object key, `<user>/<slug>/rev-<ts>-<rand>`. */
139
- key: string;
140
- url: string;
141
- size: number;
142
- contentType: string | null;
143
- /** ISO timestamp this version was replaced (when the copy was made). */
144
- uploadedAt: string;
145
- expiresAt: string | null;
146
- label: string | null;
147
- agent: string | null;
148
- session: string | null;
149
- host: string | null;
150
- repo: string | null;
151
- /** Arbitrary `--meta key=value` entries attached at publish time (RUSH-2683)
152
- * — everything that isn't a reserved provenance/label key. `{}` when none
153
- * were set, or when the deployed Worker predates this field. */
154
- meta: Record<string, string>;
155
- }
156
- interface ShareRevisionsResult {
157
- /** The canonical `<user>/<slug>` key these are revisions of. */
158
- key: string;
159
- count: number;
160
- revisions: ShareRevisionItem[];
161
- }
162
- /** Parse the Worker's `?revisions=json` payload, failing loud (with the same
163
- * outdated-template hint as {@link parseShareListing}) on an unexpected shape. */
164
- export declare function parseShareRevisions(key: string, body: string): ShareRevisionsResult;
165
- /** Fetch and parse the retained prior versions of one published slug. `target`
166
- * accepts the same three forms as `agents artifacts unshare` (a full URL, `<user>/<slug>`,
167
- * or a bare slug resolved against the caller's own namespace) — reuses
168
- * {@link resolveDeleteTarget} rather than re-deriving the key. */
169
- export declare function runShareRevisions(target: string, opts?: {
170
- githubUser?: string;
171
- config?: ShareConfig;
172
- writeToken?: string;
173
- byo?: boolean;
174
- session?: PhoenixSession | null;
175
- fetchListing?: ListingFetchFn;
176
- }): Promise<ShareRevisionsResult>;
177
- /** The resolved page URL plus a signed-in-owner URL that carries a one-time
178
- * login ticket, so opening it activates the shared page's inline visibility
179
- * control (PHNX-3370). */
180
- interface ShareOpenResult {
181
- /** `<user>/<slug>` key of the target page. */
182
- key: string;
183
- /** The plain page URL (no ticket). */
184
- url: string;
185
- /** The page URL with `?phoenix_ticket=<t>` — open THIS to be the owner. */
186
- ownerUrl: string;
187
- }
188
- /** Mint a one-time login ticket for the signed-in owner and build the URL that
189
- * opens their own published page **as the owner**, so the inline visibility
190
- * control is live in the browser. Managed backend only — the control is gated on
191
- * the Phoenix identity, and BYO (WRITE_TOKEN) endpoints have no per-viewer login.
192
- * `target` accepts the same three forms as `visibility`/`unshare` (a full URL,
193
- * `<user>/<slug>`, or a bare slug in the caller's namespace). */
194
- export declare function runShareOpen(target: string, opts?: {
195
- githubUser?: string;
196
- config?: ShareConfig;
197
- session?: PhoenixSession | null;
198
- /** DI seam — override the ticket-mint POST. */
199
- fetchTicket?: (url: string, bearer: string) => Promise<{
200
- status: number;
201
- body: string;
202
- }>;
203
- }): Promise<ShareOpenResult>;
204
- export declare function formatShareRevisions(result: ShareRevisionsResult, json?: boolean): string;
205
- export declare function formatShareDeleteResult(result: DeleteShareResult, json?: boolean): string;
206
- interface ShareDeleteCliOpts {
207
- keepCover?: boolean;
208
- keepRevisions?: boolean;
209
- ifExists?: boolean;
210
- forUser?: string;
211
- deleteJson?: boolean;
212
- }
213
- /** Shared handler for `agents artifacts share delete <targets...>` and the
214
- * nested `agents artifacts unshare <targets...>` alias. Deletes each target independently and
215
- * continues past a failed one (rm-style), reporting all results and exiting
216
- * non-zero if any target failed to verify as gone.
217
- *
218
- * `deleteFn` is a DI seam for tests (defaults to the real `deleteShare`) — it is
219
- * never exposed as a CLI flag, only used to inject a fake config/checker/deleter
220
- * without touching the keychain or a live endpoint. */
221
- export declare function runShareDelete(targets: string[], opts: ShareDeleteCliOpts, deleteFn?: typeof deleteShare): Promise<void>;
222
- /**
223
- * Register the `share` subtree under its parent group — `agents artifacts share`
224
- * (see commands/artifacts.ts). `agents artifacts unshare` is the nested alias
225
- * registered via {@link registerUnshareCommand} on the artifacts group.
226
- * registration on the ROOT program, so it is {@link registerUnshareCommand}, not
227
- * part of this subtree.
228
- */
229
- export declare function registerShareCommands(artifactsCmd: Command): void;
230
- /**
231
- * Register `agents artifacts unshare <targets...>` as the nested alias of
232
- * `agents artifacts share delete`. Top-level `agents unshare` is retired.
233
- */
234
- export declare function registerUnshareCommand(artifactsCmd: Command): void;
235
- /** Provision a fresh R2 bucket + Worker on the user's Cloudflare and persist the
236
- * endpoint config + write token. Shared by both modes of `agents artifacts setup`
237
- * (the flag-driven provision and the interactive wizard). */
238
- export declare function runShareProvision(opts: {
239
- bundle: string;
240
- worker: string;
241
- bucket: string;
242
- account?: string;
243
- token?: string;
244
- domain?: string;
245
- analyticsToken?: string;
246
- request?: CloudflareRequester;
247
- /** Bind PHOENIX_ID_BASE even when the mapped hostname is not the managed domain. */
248
- managed?: boolean;
249
- }): Promise<void>;
250
- interface ShareUpdateResult {
251
- updated: boolean;
252
- templateHash: string;
253
- baseUrl: string;
254
- workerName: string;
255
- /** True when this was a `--check` run: nothing was deployed, the fields below
256
- * just report whether a deploy WOULD be needed. Used by the release train to
257
- * decide during preflight — before it verifies deploy creds — whether this
258
- * release even changes the Worker. */
259
- checked?: boolean;
260
- /** Whether the current `worker-template.ts` render differs from what the
261
- * endpoint last deployed (or `--force`/an endpoint with no recorded hash). */
262
- deployNeeded?: boolean;
263
- /** The template hash the endpoint last deployed, per local config. Undefined
264
- * on an endpoint provisioned before the hash field existed. */
265
- deployedHash?: string;
266
- }
267
- /** Re-deploy the Worker script on an ALREADY-provisioned endpoint to match the
268
- * current `worker-template.ts`. Reuses the existing account/worker/bucket and
269
- * write token from `readShareConfig()`/the `share` bundle — never creates a
270
- * bucket, touches routes/domains, or regenerates the token (see
271
- * `updateWorker` in `lib/share/provision.ts` for how the token — and, on a
272
- * managed endpoint, `PHOENIX_ID_BASE` — survives the re-upload). Idempotent:
273
- * no-ops the script upload when the deployed hash already matches unless
274
- * `force`; a managed endpoint still re-applies `PHOENIX_ID_BASE`. */
275
- export declare function runShareUpdate(opts?: {
276
- bundle?: string;
277
- account?: string;
278
- token?: string;
279
- force?: boolean;
280
- /** Report whether a deploy is needed and return without deploying. Needs no
281
- * Cloudflare credentials — change detection is a pure local render+hash. */
282
- check?: boolean;
283
- request?: CloudflareRequester;
284
- /** Bind PHOENIX_ID_BASE even when the configured hostname is not the managed domain. */
285
- managed?: boolean;
286
- }): Promise<ShareUpdateResult>;
287
- /** Join an existing share endpoint (no provisioning): prompt for the endpoint
288
- * details + write token and persist them. Shared by `agents artifacts share join`
289
- * and the `agents artifacts setup` wizard. */
290
- export declare function runShareJoin(baseUrl?: string, opts?: {
291
- token?: string;
292
- }): Promise<void>;
293
- export {};