@phnx-labs/agents-cli 1.20.27 → 1.20.28

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 (83) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/dist/commands/doctor.js +57 -4
  3. package/dist/commands/exec.d.ts +1 -1
  4. package/dist/commands/exec.js +177 -6
  5. package/dist/commands/hosts.d.ts +11 -0
  6. package/dist/commands/hosts.js +229 -0
  7. package/dist/commands/repo.d.ts +29 -0
  8. package/dist/commands/repo.js +174 -38
  9. package/dist/commands/secrets.d.ts +2 -7
  10. package/dist/commands/secrets.js +15 -23
  11. package/dist/commands/sessions.d.ts +2 -0
  12. package/dist/commands/sessions.js +7 -24
  13. package/dist/commands/sync.d.ts +2 -0
  14. package/dist/commands/sync.js +22 -5
  15. package/dist/commands/view.js +27 -11
  16. package/dist/index.js +2 -1
  17. package/dist/lib/agents.d.ts +1 -0
  18. package/dist/lib/agents.js +44 -4
  19. package/dist/lib/browser/drivers/ssh.d.ts +47 -2
  20. package/dist/lib/browser/drivers/ssh.js +113 -24
  21. package/dist/lib/browser/profiles.js +28 -1
  22. package/dist/lib/browser/runtime-state.js +28 -8
  23. package/dist/lib/browser/types.d.ts +10 -1
  24. package/dist/lib/cli-resources.js +10 -1
  25. package/dist/lib/doctor-diff.d.ts +12 -0
  26. package/dist/lib/doctor-diff.js +89 -2
  27. package/dist/lib/exec.d.ts +27 -0
  28. package/dist/lib/exec.js +62 -19
  29. package/dist/lib/hooks.d.ts +17 -0
  30. package/dist/lib/hooks.js +127 -3
  31. package/dist/lib/hosts/dispatch.d.ts +26 -0
  32. package/dist/lib/hosts/dispatch.js +71 -0
  33. package/dist/lib/hosts/progress.d.ts +21 -0
  34. package/dist/lib/hosts/progress.js +49 -0
  35. package/dist/lib/hosts/providers/local.d.ts +17 -0
  36. package/dist/lib/hosts/providers/local.js +81 -0
  37. package/dist/lib/hosts/ready.d.ts +37 -0
  38. package/dist/lib/hosts/ready.js +88 -0
  39. package/dist/lib/hosts/registry.d.ts +22 -0
  40. package/dist/lib/hosts/registry.js +65 -0
  41. package/dist/lib/hosts/ssh-config.d.ts +37 -0
  42. package/dist/lib/hosts/ssh-config.js +157 -0
  43. package/dist/lib/hosts/tasks.d.ts +32 -0
  44. package/dist/lib/hosts/tasks.js +58 -0
  45. package/dist/lib/hosts/types.d.ts +51 -0
  46. package/dist/lib/hosts/types.js +21 -0
  47. package/dist/lib/loop.d.ts +9 -0
  48. package/dist/lib/loop.js +13 -1
  49. package/dist/lib/mcp.js +12 -3
  50. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  51. package/dist/lib/migrate.js +9 -5
  52. package/dist/lib/platform/exec.d.ts +10 -0
  53. package/dist/lib/platform/exec.js +17 -0
  54. package/dist/lib/platform/index.d.ts +1 -0
  55. package/dist/lib/platform/index.js +1 -0
  56. package/dist/lib/platform/links.d.ts +15 -0
  57. package/dist/lib/platform/links.js +42 -0
  58. package/dist/lib/platform/paths.d.ts +18 -0
  59. package/dist/lib/platform/paths.js +22 -0
  60. package/dist/lib/platform/posixpath.d.ts +28 -0
  61. package/dist/lib/platform/posixpath.js +153 -0
  62. package/dist/lib/plugins.d.ts +10 -0
  63. package/dist/lib/plugins.js +1 -1
  64. package/dist/lib/project-launch.js +6 -3
  65. package/dist/lib/sandbox.js +5 -2
  66. package/dist/lib/self-update.js +7 -2
  67. package/dist/lib/session/db.d.ts +23 -0
  68. package/dist/lib/session/db.js +76 -1
  69. package/dist/lib/session/discover.d.ts +26 -0
  70. package/dist/lib/session/discover.js +75 -4
  71. package/dist/lib/session/relative-time.d.ts +7 -0
  72. package/dist/lib/session/relative-time.js +28 -0
  73. package/dist/lib/session/remote.d.ts +31 -3
  74. package/dist/lib/session/remote.js +121 -14
  75. package/dist/lib/ssh-exec.d.ts +45 -0
  76. package/dist/lib/ssh-exec.js +61 -0
  77. package/dist/lib/startup/command-registry.d.ts +1 -0
  78. package/dist/lib/startup/command-registry.js +2 -0
  79. package/dist/lib/types.d.ts +21 -0
  80. package/dist/lib/versions.d.ts +6 -2
  81. package/dist/lib/versions.js +8 -4
  82. package/package.json +1 -1
  83. package/scripts/postinstall.js +62 -0
@@ -45,6 +45,7 @@ export const loadPty = async () => (await import('../../commands/pty.js')).regis
45
45
  export const loadTmux = async () => (await import('../../commands/tmux.js')).registerTmuxCommands;
46
46
  export const loadBrowser = async () => (await import('../../commands/browser.js')).registerBrowserCommand;
47
47
  export const loadComputer = async () => (await import('../../commands/computer.js')).registerComputerCommand;
48
+ export const loadHosts = async () => (await import('../../commands/hosts.js')).registerHostsCommand;
48
49
  export const loadPull = async () => (await import('../../commands/pull.js')).registerPullCommand;
49
50
  export const loadPush = async () => (await import('../../commands/push.js')).registerPushCommand;
50
51
  export const loadRepo = async () => (await import('../../commands/repo.js')).registerRepoCommands;
@@ -126,6 +127,7 @@ export const COMMAND_LOADERS = {
126
127
  tmux: [loadTmux],
127
128
  browser: [loadBrowser],
128
129
  computer: [loadComputer],
130
+ hosts: [loadHosts],
129
131
  pull: [loadPull],
130
132
  push: [loadPush],
131
133
  repo: [loadRepo],
@@ -612,6 +612,27 @@ export interface Meta {
612
612
  * lives separately in ~/.agents/.cache/browser/<profile>/.
613
613
  */
614
614
  browser?: Record<string, BrowserProfileConfig>;
615
+ /**
616
+ * Agent-host registry keyed by host name (`agents hosts`). Portable user
617
+ * config synced with `agents repo push/pull`. For `ssh-config` hosts this is
618
+ * just an overlay (caps/os) — the connection details stay in ~/.ssh/config and
619
+ * are never copied. `inline` hosts carry their own address/user.
620
+ */
621
+ hosts?: Record<string, HostEntry>;
622
+ }
623
+ /** Persisted agent-host entry in agents.yaml (overlay or inline). */
624
+ export interface HostEntry {
625
+ /** `ssh-config`: reach via the bare name (ssh resolves). `inline`: use address/user below. */
626
+ source: 'ssh-config' | 'inline';
627
+ /** SSH-reachable target — inline hosts only (ssh-config hosts omit it). */
628
+ address?: string;
629
+ /** SSH user — inline hosts only. */
630
+ user?: string;
631
+ /** Captured at enroll probe. */
632
+ os?: string;
633
+ /** Free-form capability tags for routing (e.g. ['gpu']). */
634
+ caps?: string[];
635
+ addedAt?: string;
615
636
  }
616
637
  /** Browser profile definition stored in agents.yaml. */
617
638
  export interface BrowserProfileConfig {
@@ -241,12 +241,16 @@ export declare function resolveVersion(agent: AgentId, projectPath?: string): st
241
241
  /**
242
242
  * Normalize a user-supplied @version token across CLI subcommands.
243
243
  *
244
- * undefined / "" / "default" -> undefined (caller falls back to project pin or global default)
244
+ * undefined / "" / "default" / "pinned" -> undefined (caller falls back to project pin or global default)
245
+ * "any" -> undefined (caller imposes no version constraint — e.g. resume across any version)
245
246
  * "latest" -> highest installed version (process.exit if none installed)
246
247
  * "oldest" -> lowest installed version (process.exit if none installed)
247
248
  * "x.y.z" (installed) -> "x.y.z"
248
249
  * "x.y.z" (not installed) -> process.exit with installed-list hint
249
250
  *
251
+ * `pinned` is a synonym for `default`: both name the project pin / global
252
+ * default, which the caller resolves.
253
+ *
250
254
  * Use this anywhere the user can type `agents <cmd> claude@<token>` to keep the
251
255
  * vocabulary consistent. Subcommands with different semantics for `latest`
252
256
  * (install/remove/use, where `latest` means npm-latest) keep their existing
@@ -255,7 +259,7 @@ export declare function resolveVersion(agent: AgentId, projectPath?: string): st
255
259
  export declare function resolveVersionAlias(agent: AgentId, raw: string | undefined | null): string | undefined;
256
260
  /**
257
261
  * Loose variant of resolveVersionAlias for record-filter contexts (sessions,
258
- * team history). Same `default`/`latest`/`oldest` semantics, but explicit
262
+ * team history). Same `default`/`pinned`/`latest`/`oldest` semantics, but explicit
259
263
  * versions pass through unchanged so historical records of uninstalled versions
260
264
  * remain queryable.
261
265
  */
@@ -1363,19 +1363,23 @@ export function resolveVersion(agent, projectPath) {
1363
1363
  /**
1364
1364
  * Normalize a user-supplied @version token across CLI subcommands.
1365
1365
  *
1366
- * undefined / "" / "default" -> undefined (caller falls back to project pin or global default)
1366
+ * undefined / "" / "default" / "pinned" -> undefined (caller falls back to project pin or global default)
1367
+ * "any" -> undefined (caller imposes no version constraint — e.g. resume across any version)
1367
1368
  * "latest" -> highest installed version (process.exit if none installed)
1368
1369
  * "oldest" -> lowest installed version (process.exit if none installed)
1369
1370
  * "x.y.z" (installed) -> "x.y.z"
1370
1371
  * "x.y.z" (not installed) -> process.exit with installed-list hint
1371
1372
  *
1373
+ * `pinned` is a synonym for `default`: both name the project pin / global
1374
+ * default, which the caller resolves.
1375
+ *
1372
1376
  * Use this anywhere the user can type `agents <cmd> claude@<token>` to keep the
1373
1377
  * vocabulary consistent. Subcommands with different semantics for `latest`
1374
1378
  * (install/remove/use, where `latest` means npm-latest) keep their existing
1375
1379
  * parsing.
1376
1380
  */
1377
1381
  export function resolveVersionAlias(agent, raw) {
1378
- if (!raw || raw === 'default')
1382
+ if (!raw || raw === 'default' || raw === 'pinned' || raw === 'any')
1379
1383
  return undefined;
1380
1384
  if (raw === 'latest' || raw === 'oldest') {
1381
1385
  const installed = listInstalledVersions(agent);
@@ -1399,12 +1403,12 @@ export function resolveVersionAlias(agent, raw) {
1399
1403
  }
1400
1404
  /**
1401
1405
  * Loose variant of resolveVersionAlias for record-filter contexts (sessions,
1402
- * team history). Same `default`/`latest`/`oldest` semantics, but explicit
1406
+ * team history). Same `default`/`pinned`/`latest`/`oldest` semantics, but explicit
1403
1407
  * versions pass through unchanged so historical records of uninstalled versions
1404
1408
  * remain queryable.
1405
1409
  */
1406
1410
  export function resolveVersionAliasLoose(agent, raw) {
1407
- if (!raw || raw === 'default')
1411
+ if (!raw || raw === 'default' || raw === 'pinned' || raw === 'any')
1408
1412
  return undefined;
1409
1413
  if (raw === 'latest' || raw === 'oldest') {
1410
1414
  const installed = listInstalledVersions(agent);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phnx-labs/agents-cli",
3
- "version": "1.20.27",
3
+ "version": "1.20.28",
4
4
  "description": "One CLI for all your AI coding agents - versions, config, cloud dispatch, sessions, and teams (now with first-class Grok Build CLI support)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -239,6 +239,10 @@ To enable version-aware shims, add this to your shell config:
239
239
  console.log(` Installed shorthands: ${written.join(', ')}`);
240
240
  }
241
241
 
242
+ if (process.platform !== 'win32') {
243
+ await ensureAgentsResolvablePosix();
244
+ }
245
+
242
246
  await healLongRunningProcesses();
243
247
 
244
248
  const version = getVersion();
@@ -252,6 +256,64 @@ To enable version-aware shims, add this to your shell config:
252
256
  }
253
257
  }
254
258
 
259
+ /**
260
+ * Make the `agents` command resolvable in a *login* shell on POSIX.
261
+ *
262
+ * `agents`/`ag` reach PATH only through npm's bin symlink in the npm global-bin
263
+ * dir. Under nvm (and other per-user node prefixes) that dir is missing from a
264
+ * non-interactive login shell's PATH, so `bash -lc 'agents …'` fails with
265
+ * command-not-found — which breaks `agents secrets export --host` (it runs
266
+ * `bash -lc 'agents secrets import …'` on the remote) and the routines daemon
267
+ * (src/lib/daemon.ts falls back to bare `agents`). This is the POSIX symmetric
268
+ * counterpart of the Windows branch in main() that registers npm's global-bin
269
+ * dir on the user PATH.
270
+ *
271
+ * Self-heal, not a prompt: it fires ONLY when `agents` is otherwise
272
+ * unresolvable — the genuinely-broken state — so it acts decisively, exactly
273
+ * like the Windows PATH registration. The symlink never clobbers a dev build
274
+ * (scripts/install.sh) or any real file. Skipped in CI (ephemeral homes) and
275
+ * when AGENTS_NO_HEAL=1.
276
+ */
277
+ async function ensureAgentsResolvablePosix() {
278
+ if (process.env.CI || process.env.AGENTS_NO_HEAL === '1') return;
279
+ try {
280
+ const { localBinDir, ensureLocalBinSymlink, loginShellResolves, dirOnLoginPath } =
281
+ await import('../dist/lib/platform/posixpath.js');
282
+
283
+ // macOS/homebrew, system-node Linux, and dev-build users already resolve it.
284
+ if (loginShellResolves('agents')) return;
285
+
286
+ const binDir = localBinDir();
287
+ const results = ['agents', 'ag'].map((name) => ensureLocalBinSymlink(name, AGENTS_BIN, binDir));
288
+ if (!results.some((r) => r.created)) return; // nothing we could safely link
289
+
290
+ if (dirOnLoginPath(binDir)) {
291
+ console.log(`\n Linked 'agents' into ${binDir} (already on the login PATH) so 'bash -lc agents' resolves.`);
292
+ return;
293
+ }
294
+
295
+ // ~/.local/bin isn't on the *bash* login PATH yet. The consumers run
296
+ // `bash -lc`, so add it to the file a bash login shell reads (~/.bash_profile
297
+ // when present, else ~/.profile) — not the interactive $SHELL rc, which for a
298
+ // zsh user (.zshrc) bash would never source.
299
+ const bashRc = fs.existsSync(path.join(HOME, '.bash_profile'))
300
+ ? path.join(HOME, '.bash_profile')
301
+ : path.join(HOME, '.profile');
302
+ const marker = '# agents-cli: ensure ~/.local/bin on PATH (so the agents command resolves)';
303
+ let already = false;
304
+ try {
305
+ already = fs.existsSync(bashRc) && fs.readFileSync(bashRc, 'utf-8').includes(marker);
306
+ } catch { /* unreadable rc — fall through and append */ }
307
+ if (!already) {
308
+ fs.appendFileSync(bashRc, `\n${marker}\nexport PATH="${binDir}:$PATH"\n`);
309
+ }
310
+ console.log(`\n Linked 'agents' into ${binDir} and added it to PATH in ${path.basename(bashRc)}.`);
311
+ console.log(` Restart your shell (or run: source ~/${path.basename(bashRc)}) to pick it up.`);
312
+ } catch {
313
+ /* best-effort: a failure here must never break the install */
314
+ }
315
+ }
316
+
255
317
  /**
256
318
  * Self-heal long-running processes onto the just-installed code (macOS).
257
319
  *