@phnx-labs/agents-cli 1.22.78 → 1.22.80

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 (90) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +28 -1
  3. package/dist/bootstrap.js +40 -12
  4. package/dist/commands/accounts.d.ts +22 -0
  5. package/dist/commands/accounts.js +158 -35
  6. package/dist/commands/config.js +37 -0
  7. package/dist/commands/exec.js +21 -10
  8. package/dist/commands/update.js +169 -18
  9. package/dist/commands/versions.d.ts +11 -0
  10. package/dist/commands/versions.js +30 -4
  11. package/dist/commands/view.d.ts +69 -3
  12. package/dist/commands/view.js +235 -75
  13. package/dist/index.js +35 -2
  14. package/dist/lib/account-catalog.d.ts +97 -1
  15. package/dist/lib/account-catalog.js +134 -6
  16. package/dist/lib/account-registry.d.ts +43 -0
  17. package/dist/lib/account-registry.js +97 -2
  18. package/dist/lib/accounting/rotate.d.ts +2 -2
  19. package/dist/lib/accounting/rotate.js +5 -5
  20. package/dist/lib/accounts/auth-operation-lock.d.ts +9 -0
  21. package/dist/lib/accounts/auth-operation-lock.js +55 -0
  22. package/dist/lib/accounts/connect.d.ts +170 -0
  23. package/dist/lib/accounts/connect.js +383 -0
  24. package/dist/lib/capabilities.js +2 -0
  25. package/dist/lib/commands.js +2 -0
  26. package/dist/lib/config-keys.d.ts +11 -2
  27. package/dist/lib/config-keys.js +21 -1
  28. package/dist/lib/daemon/daemon.js +5 -0
  29. package/dist/lib/daemon/harness-update-service.d.ts +110 -0
  30. package/dist/lib/daemon/harness-update-service.js +216 -0
  31. package/dist/lib/daemon-services.d.ts +1 -1
  32. package/dist/lib/daemon-services.js +5 -0
  33. package/dist/lib/device-config.d.ts +0 -1
  34. package/dist/lib/device-config.js +50 -5
  35. package/dist/lib/exec.js +26 -2
  36. package/dist/lib/fs-atomic.d.ts +2 -0
  37. package/dist/lib/fs-atomic.js +2 -0
  38. package/dist/lib/hooks/install.js +7 -2
  39. package/dist/lib/installations/active-check.d.ts +48 -0
  40. package/dist/lib/installations/active-check.js +84 -0
  41. package/dist/lib/installations/index.d.ts +5 -1
  42. package/dist/lib/installations/index.js +4 -0
  43. package/dist/lib/installations/installation-lock.d.ts +6 -0
  44. package/dist/lib/installations/installation-lock.js +29 -0
  45. package/dist/lib/installations/launch-gate.d.ts +69 -0
  46. package/dist/lib/installations/launch-gate.js +133 -0
  47. package/dist/lib/installations/native-command.d.ts +5 -0
  48. package/dist/lib/installations/native-command.js +52 -0
  49. package/dist/lib/installations/shims.d.ts +8 -2
  50. package/dist/lib/installations/shims.js +105 -2
  51. package/dist/lib/installations/store.d.ts +5 -1
  52. package/dist/lib/installations/store.js +24 -3
  53. package/dist/lib/installations/strategies.js +55 -35
  54. package/dist/lib/installations/types.d.ts +17 -0
  55. package/dist/lib/installations/update-cancellation.d.ts +82 -0
  56. package/dist/lib/installations/update-cancellation.js +122 -0
  57. package/dist/lib/installations/update-policy.d.ts +69 -0
  58. package/dist/lib/installations/update-policy.js +114 -0
  59. package/dist/lib/installations/update-runtime.d.ts +118 -0
  60. package/dist/lib/installations/update-runtime.js +321 -0
  61. package/dist/lib/installations/update.d.ts +25 -0
  62. package/dist/lib/installations/update.js +141 -2
  63. package/dist/lib/installations/versions.d.ts +1 -0
  64. package/dist/lib/installations/versions.js +166 -131
  65. package/dist/lib/platform/process.d.ts +3 -1
  66. package/dist/lib/platform/process.js +2 -2
  67. package/dist/lib/staleness/detectors/commands.d.ts +1 -2
  68. package/dist/lib/staleness/detectors/hooks.d.ts +1 -2
  69. package/dist/lib/staleness/detectors/mcp.d.ts +1 -2
  70. package/dist/lib/staleness/detectors/permissions.d.ts +1 -2
  71. package/dist/lib/staleness/detectors/plugins.d.ts +1 -7
  72. package/dist/lib/staleness/detectors/rules.d.ts +1 -2
  73. package/dist/lib/staleness/detectors/skills.d.ts +1 -2
  74. package/dist/lib/staleness/detectors/subagents.d.ts +1 -7
  75. package/dist/lib/staleness/detectors/workflows.d.ts +1 -2
  76. package/dist/lib/staleness/writers/commands.d.ts +1 -2
  77. package/dist/lib/staleness/writers/hooks.d.ts +1 -2
  78. package/dist/lib/staleness/writers/mcp.d.ts +1 -2
  79. package/dist/lib/staleness/writers/permissions.d.ts +1 -12
  80. package/dist/lib/staleness/writers/plugins.d.ts +1 -6
  81. package/dist/lib/staleness/writers/rules.d.ts +1 -2
  82. package/dist/lib/staleness/writers/skills.d.ts +1 -2
  83. package/dist/lib/staleness/writers/subagents.d.ts +1 -2
  84. package/dist/lib/staleness/writers/workflows.d.ts +1 -8
  85. package/dist/lib/state.d.ts +3 -1
  86. package/dist/lib/state.js +38 -13
  87. package/dist/lib/types.d.ts +26 -1
  88. package/dist/lib/types.js +5 -0
  89. package/dist/lib/view-types.d.ts +6 -0
  90. package/package.json +1 -1
package/dist/lib/state.js CHANGED
@@ -1325,12 +1325,23 @@ export function writeMetaUnlocked(meta) {
1325
1325
  ? deviceAccounts.native : undefined;
1326
1326
  const accountsBindings = deviceAccounts?.bindings && Object.keys(deviceAccounts.bindings).length > 0
1327
1327
  ? deviceAccounts.bindings : undefined;
1328
- if (accountsNative || accountsBindings) {
1328
+ // This box's account⇄home map (PHNX-3940) is device-scoped, so it round-trips
1329
+ // through the device doc alongside native/bindings, never the synced central file.
1330
+ const accountsHomes = deviceAccounts?.homes && Object.keys(deviceAccounts.homes).length > 0
1331
+ ? deviceAccounts.homes : undefined;
1332
+ // In-flight connect attempts (PHNX-3940), device-scoped like homes.
1333
+ const accountsPending = deviceAccounts?.pendingConnects && Object.keys(deviceAccounts.pendingConnects).length > 0
1334
+ ? deviceAccounts.pendingConnects : undefined;
1335
+ if (accountsNative || accountsBindings || accountsHomes || accountsPending) {
1329
1336
  const da = {};
1330
1337
  if (accountsNative)
1331
1338
  da.native = accountsNative;
1332
1339
  if (accountsBindings)
1333
1340
  da.bindings = accountsBindings;
1341
+ if (accountsHomes)
1342
+ da.homes = accountsHomes;
1343
+ if (accountsPending)
1344
+ da.pendingConnects = accountsPending;
1334
1345
  doc.accounts = da;
1335
1346
  }
1336
1347
  else if (writesDeviceAccounts)
@@ -1470,10 +1481,18 @@ function overlayMachineLocal(meta) {
1470
1481
  if (acc.bindings !== undefined && !isMap(acc.bindings)) {
1471
1482
  throw new Error(`Device config corrupted at ${devicePath}: accounts.bindings must be a map.`);
1472
1483
  }
1484
+ if (acc.homes !== undefined && !isMap(acc.homes)) {
1485
+ throw new Error(`Device config corrupted at ${devicePath}: accounts.homes must be a map.`);
1486
+ }
1487
+ if (acc.pendingConnects !== undefined && !isMap(acc.pendingConnects)) {
1488
+ throw new Error(`Device config corrupted at ${devicePath}: accounts.pendingConnects must be a map.`);
1489
+ }
1473
1490
  const native = acc.native;
1474
1491
  const bindings = acc.bindings;
1475
- if (native || bindings)
1476
- meta.deviceAccounts = { ...(native ? { native } : {}), ...(bindings ? { bindings } : {}) };
1492
+ const homes = acc.homes;
1493
+ const pendingConnects = acc.pendingConnects;
1494
+ if (native || bindings || homes || pendingConnects)
1495
+ meta.deviceAccounts = { ...(native ? { native } : {}), ...(bindings ? { bindings } : {}), ...(homes ? { homes } : {}), ...(pendingConnects ? { pendingConnects } : {}) };
1477
1496
  }
1478
1497
  if (Object.prototype.hasOwnProperty.call(dm, 'routines')) {
1479
1498
  if (!Array.isArray(dm.routines) || dm.routines.some((name) => typeof name !== 'string')) {
@@ -1533,12 +1552,16 @@ function migrateSystemMetaToUser() {
1533
1552
  * mtime check below catches it on the next read (assuming the mtime advanced).
1534
1553
  * - The cache stores the merged system+user meta; both files' mtimes contribute.
1535
1554
  */
1536
- export function readMeta() {
1537
- ensureAgentsDir();
1555
+ export function readMeta(options = {}) {
1556
+ const migrate = options.migrate !== false;
1557
+ if (migrate)
1558
+ ensureAgentsDir();
1559
+ // A preview must not suppress a later real migration by populating its cache.
1560
+ const remember = (meta) => migrate ? rememberMeta(meta) : meta;
1538
1561
  // Fast path: serve from cache when both source files are byte-identical to
1539
1562
  // what we last parsed. Reduces N readMeta calls per CLI invocation to ~2 stat
1540
1563
  // syscalls plus an in-memory object spread.
1541
- if (metaCache) {
1564
+ if (migrate && metaCache) {
1542
1565
  if (currentMetaStamp() === metaCache.stamp) {
1543
1566
  return metaCache.meta;
1544
1567
  }
@@ -1575,12 +1598,14 @@ export function readMeta() {
1575
1598
  // non-heartbeated lock. This one-shot legacy migration needs no synchronous
1576
1599
  // commit: it self-heals on the daemon's next publish tick or the next real
1577
1600
  // CLI central write.
1578
- withMetaLock(() => writeMetaUnlocked(meta));
1579
- try {
1580
- fs.unlinkSync(oldMetaFile);
1601
+ if (migrate) {
1602
+ withMetaLock(() => writeMetaUnlocked(meta));
1603
+ try {
1604
+ fs.unlinkSync(oldMetaFile);
1605
+ }
1606
+ catch { /* non-critical */ }
1581
1607
  }
1582
- catch { /* non-critical */ }
1583
- return rememberMeta(meta);
1608
+ return remember(meta);
1584
1609
  }
1585
1610
  catch {
1586
1611
  /* meta.yaml migration failed */
@@ -1621,11 +1646,11 @@ export function readMeta() {
1621
1646
  };
1622
1647
  }
1623
1648
  overlayMachineLocal(meta);
1624
- return rememberMeta(meta);
1649
+ return remember(meta);
1625
1650
  }
1626
1651
  const meta = createDefaultMeta();
1627
1652
  overlayMachineLocal(meta);
1628
- return rememberMeta(meta);
1653
+ return remember(meta);
1629
1654
  }
1630
1655
  /** Serialize and write agents.yaml to the user repo, invalidating the in-memory cache. */
1631
1656
  export function writeMeta(meta) {
@@ -8,7 +8,9 @@
8
8
  import type { CloudProviderId } from './cloud/types.js';
9
9
  import type { FeedBroadcastConfig } from './feed-broadcast.js';
10
10
  /** Unique identifier for a current or legacy AI coding agent. */
11
- export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'copilot' | 'amp' | 'goose' | 'antigravity' | 'grok' | 'kimi' | 'droid' | 'hermes' | 'muse' | 'warp';
11
+ export declare const AGENT_IDS: readonly ["claude", "codex", "gemini", "cursor", "opencode", "openclaw", "copilot", "amp", "goose", "antigravity", "grok", "kimi", "droid", "hermes", "muse", "warp"];
12
+ export type AgentId = typeof AGENT_IDS[number];
13
+ export declare function isAgentId(value: string): value is AgentId;
12
14
  /** How `agents run <agent>` chooses an installed version when none is pinned. */
13
15
  export type RunStrategy = 'pinned' | 'available' | 'balanced';
14
16
  export type RunEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'auto';
@@ -861,6 +863,29 @@ export interface Meta {
861
863
  scope: 'version' | 'device';
862
864
  }>;
863
865
  bindings?: Record<string, string>;
866
+ /**
867
+ * THIS box's account⇄home map (PHNX-3940): stable account id → the local
868
+ * installation label whose isolated home hosts that account's native login,
869
+ * as created by `agents accounts connect`. It is DEVICE-scoped on purpose —
870
+ * one account materializes a different home per host, and the label a box
871
+ * minted must never be assumed to exist on another box — so it lives in the
872
+ * device doc, never the fleet-synced central `accounts.native` identity row.
873
+ * A reconnect reads this to reuse the exact home even when its credential has
874
+ * expired (so local signed-in discovery can no longer find it).
875
+ */
876
+ homes?: Record<string, string>;
877
+ /**
878
+ * THIS box's IN-FLIGHT `agents accounts connect` attempts (PHNX-3940):
879
+ * `${agent}:${name}` (lowercased) → the opaque slot minted for that attempt,
880
+ * BEFORE its login completed. It exists so a failed/cancelled named connect
881
+ * retries into the SAME fresh home instead of orphaning a new one each time,
882
+ * WITHOUT a deterministic name→slot function (which would recompute an
883
+ * already-taken slot after a rename and overwrite another account's login —
884
+ * the security flaw this replaces). It is cleared the moment the account is
885
+ * registered, so a live pending slot is by definition not yet an account's
886
+ * home. Device-scoped for the same reason as {@link homes}.
887
+ */
888
+ pendingConnects?: Record<string, string>;
864
889
  };
865
890
  agents?: Partial<Record<AgentId, string>>;
866
891
  /**
package/dist/lib/types.js CHANGED
@@ -5,6 +5,11 @@
5
5
  * configuration schemas, resource tracking, registry types, and permission
6
6
  * formats for each supported agent.
7
7
  */
8
+ /** Unique identifier for a current or legacy AI coding agent. */
9
+ export const AGENT_IDS = ['claude', 'codex', 'gemini', 'cursor', 'opencode', 'openclaw', 'copilot', 'amp', 'goose', 'antigravity', 'grok', 'kimi', 'droid', 'hermes', 'muse', 'warp'];
10
+ export function isAgentId(value) {
11
+ return AGENT_IDS.includes(value);
12
+ }
8
13
  /**
9
14
  * Reserved `<agent>` keyword for `agents run auto` — full-auto dispatch:
10
15
  * host (14d launch affinity) → harness (best-account headroom, weighted) →
@@ -2,9 +2,13 @@ import type { ConfiguredModelSource } from './models.js';
2
2
  import type { ProfileSummary } from './profiles.js';
3
3
  import type { AgentId } from './types.js';
4
4
  import type { AuthVerdict } from './auth-health.js';
5
+ import type { NativeAccountCatalogRow } from './account-catalog.js';
5
6
  export type SyncState = 'synced' | 'new' | 'modified' | 'deleted';
6
7
  export interface ViewJsonVersion {
8
+ /** Stable installation label; retained for existing machine consumers. */
7
9
  version: string;
10
+ /** Actual vendor release, independent of the stable installation label. */
11
+ releaseVersion?: string;
8
12
  isDefault: boolean;
9
13
  isolated: boolean;
10
14
  isIsolatedDefault: boolean;
@@ -65,6 +69,8 @@ export interface ViewJsonVersion {
65
69
  export interface ViewJsonAgent {
66
70
  agent: AgentId;
67
71
  versions: ViewJsonVersion[];
72
+ /** Account-first projection, additive so older consumers keep working. */
73
+ accounts?: NativeAccountCatalogRow[];
68
74
  harnesses: ProfileSummary[];
69
75
  }
70
76
  export type ResourceSection = 'commands' | 'skills' | 'mcp' | 'memory' | 'hooks' | 'workflows' | 'plugins';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phnx-labs/agents-cli",
3
- "version": "1.22.78",
3
+ "version": "1.22.80",
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",