@phnx-labs/agents-cli 1.20.87 → 1.20.89

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 (94) hide show
  1. package/CHANGELOG.md +323 -0
  2. package/README.md +12 -4
  3. package/dist/bin/agents +0 -0
  4. package/dist/commands/commands.js +7 -7
  5. package/dist/commands/doctor.d.ts +0 -19
  6. package/dist/commands/doctor.js +219 -305
  7. package/dist/commands/exec.js +7 -19
  8. package/dist/commands/factory.js +26 -2
  9. package/dist/commands/funnel.js +16 -1
  10. package/dist/commands/inspect.js +3 -5
  11. package/dist/commands/menubar.js +117 -34
  12. package/dist/commands/routines.js +25 -3
  13. package/dist/commands/secrets-rotate-passphrase.d.ts +17 -0
  14. package/dist/commands/secrets-rotate-passphrase.js +96 -0
  15. package/dist/commands/secrets.js +2 -0
  16. package/dist/commands/sessions.d.ts +7 -1
  17. package/dist/commands/sessions.js +40 -12
  18. package/dist/commands/ssh.js +3 -3
  19. package/dist/commands/usage.d.ts +3 -2
  20. package/dist/commands/usage.js +2 -9
  21. package/dist/commands/webhook.js +7 -2
  22. package/dist/lib/agents.d.ts +31 -1
  23. package/dist/lib/agents.js +55 -0
  24. package/dist/lib/command-skills.d.ts +10 -0
  25. package/dist/lib/command-skills.js +14 -0
  26. package/dist/lib/commands.js +28 -2
  27. package/dist/lib/daemon.d.ts +29 -0
  28. package/dist/lib/daemon.js +75 -6
  29. package/dist/lib/devices/doctor-findings.d.ts +167 -0
  30. package/dist/lib/devices/doctor-findings.js +893 -0
  31. package/dist/lib/devices/fleet-divergence.d.ts +22 -0
  32. package/dist/lib/devices/fleet-divergence.js +34 -10
  33. package/dist/lib/devices/fleet-inventory.d.ts +17 -6
  34. package/dist/lib/devices/fleet-inventory.js +56 -8
  35. package/dist/lib/events.d.ts +1 -1
  36. package/dist/lib/exec.d.ts +14 -3
  37. package/dist/lib/exec.js +41 -8
  38. package/dist/lib/factory/snapshot.d.ts +78 -0
  39. package/dist/lib/factory/snapshot.js +209 -0
  40. package/dist/lib/fs-atomic.d.ts +14 -1
  41. package/dist/lib/fs-atomic.js +35 -3
  42. package/dist/lib/funnel.d.ts +1 -0
  43. package/dist/lib/funnel.js +8 -0
  44. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  45. package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
  46. package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +2 -2
  47. package/dist/lib/menubar/install-menubar.d.ts +53 -2
  48. package/dist/lib/menubar/install-menubar.js +183 -28
  49. package/dist/lib/platform/process.d.ts +2 -0
  50. package/dist/lib/platform/process.js +5 -3
  51. package/dist/lib/project-resources.js +34 -20
  52. package/dist/lib/resources.d.ts +8 -0
  53. package/dist/lib/resources.js +34 -1
  54. package/dist/lib/routines-placement.d.ts +2 -1
  55. package/dist/lib/routines-placement.js +8 -4
  56. package/dist/lib/routines.d.ts +57 -1
  57. package/dist/lib/routines.js +74 -1
  58. package/dist/lib/runner.d.ts +16 -1
  59. package/dist/lib/runner.js +58 -16
  60. package/dist/lib/sandbox.d.ts +2 -0
  61. package/dist/lib/sandbox.js +38 -0
  62. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  63. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  64. package/dist/lib/secrets/bundles.js +9 -34
  65. package/dist/lib/secrets/filestore.d.ts +152 -34
  66. package/dist/lib/secrets/filestore.js +676 -123
  67. package/dist/lib/secrets/rc-hygiene.d.ts +0 -6
  68. package/dist/lib/secrets/rc-hygiene.js +0 -24
  69. package/dist/lib/session/active.d.ts +6 -6
  70. package/dist/lib/session/active.js +6 -6
  71. package/dist/lib/session/discover.d.ts +5 -0
  72. package/dist/lib/session/discover.js +137 -1
  73. package/dist/lib/session/parse.d.ts +2 -0
  74. package/dist/lib/session/parse.js +76 -37
  75. package/dist/lib/session/remote-active.d.ts +4 -1
  76. package/dist/lib/session/remote-active.js +8 -2
  77. package/dist/lib/session/sync/agents.js +0 -0
  78. package/dist/lib/session/types.d.ts +1 -1
  79. package/dist/lib/session/types.js +1 -1
  80. package/dist/lib/session/viewing-in.d.ts +31 -0
  81. package/dist/lib/session/viewing-in.js +47 -0
  82. package/dist/lib/staleness/detectors/commands.js +14 -5
  83. package/dist/lib/staleness/types.d.ts +2 -0
  84. package/dist/lib/staleness/writers/commands.js +13 -7
  85. package/dist/lib/state.d.ts +17 -0
  86. package/dist/lib/state.js +30 -2
  87. package/dist/lib/triggers/handlers.d.ts +95 -0
  88. package/dist/lib/triggers/handlers.js +384 -0
  89. package/dist/lib/triggers/webhook.d.ts +10 -2
  90. package/dist/lib/triggers/webhook.js +65 -11
  91. package/dist/lib/usage.d.ts +72 -1
  92. package/dist/lib/usage.js +21 -27
  93. package/dist/lib/versions.js +30 -13
  94. package/package.json +1 -1
@@ -66,7 +66,35 @@ interface ClaudeOauthCredentials {
66
66
  rateLimitTier?: string | null;
67
67
  organizationUuid?: string | null;
68
68
  }
69
- /** Fetch usage info for a given agent, dispatching to the agent-specific implementation. */
69
+ /** The single registry of agent usage sources and their transport. */
70
+ declare const USAGE_SOURCES: {
71
+ readonly claude: {
72
+ readonly fetch: typeof getClaudeUsageInfo;
73
+ readonly network: true;
74
+ };
75
+ readonly codex: {
76
+ readonly fetch: typeof getCodexUsageInfo;
77
+ readonly network: false;
78
+ };
79
+ readonly kimi: {
80
+ readonly fetch: typeof getKimiUsageInfo;
81
+ readonly network: true;
82
+ };
83
+ readonly droid: {
84
+ readonly fetch: typeof getDroidUsageInfo;
85
+ readonly network: true;
86
+ };
87
+ readonly grok: {
88
+ readonly fetch: typeof getGrokUsageInfo;
89
+ readonly network: false;
90
+ };
91
+ readonly cursor: {
92
+ readonly fetch: typeof getCursorUsageInfo;
93
+ readonly network: true;
94
+ };
95
+ };
96
+ export declare const USAGE_SOURCE_AGENT_IDS: (keyof typeof USAGE_SOURCES)[];
97
+ /** Fetch usage info for a given agent through the canonical source registry. */
70
98
  export declare function getUsageInfo(agentId: AgentId, options?: UsageOptions): Promise<UsageInfo>;
71
99
  /** Derive a stable lookup key from account info for usage deduplication. */
72
100
  export declare function getUsageLookupKey(info?: Pick<AccountInfo, 'usageKey' | 'accountKey'> | null): string | null;
@@ -151,6 +179,8 @@ export declare function deriveUsageStatusFromSnapshot(snapshot: UsageSnapshot |
151
179
  export declare function formatUsageStatusBadge(usageStatus: 'available' | 'rate_limited' | 'out_of_credits' | null | undefined): string;
152
180
  /** Format a multi-line usage section for detailed agent views. */
153
181
  export declare function formatUsageSection(usage: UsageInfo): string[];
182
+ /** Fetch Codex usage by scanning the most recent session files for rate-limit events. */
183
+ declare function getCodexUsageInfo(options?: UsageOptions): Promise<UsageInfo>;
154
184
  /**
155
185
  * The access token to use for a READ-ONLY Claude usage fetch, or null when the
156
186
  * stored token is within the refresh leeway.
@@ -167,6 +197,8 @@ export declare function formatUsageSection(usage: UsageInfo): string[];
167
197
  * Pure — unit-tested.
168
198
  */
169
199
  export declare function claudeUsageAccessTokenNoRefresh(oauth: Pick<ClaudeOauthCredentials, 'accessToken' | 'expiresAt'>): string | null;
200
+ /** Fetch Claude usage via the Anthropic OAuth usage API. */
201
+ declare function getClaudeUsageInfo(options?: UsageOptions): Promise<UsageInfo>;
170
202
  /** Raw quota bucket from the Kimi /usages response (numbers arrive as strings). */
171
203
  interface KimiUsageQuota {
172
204
  limit?: string | number | null;
@@ -192,6 +224,18 @@ export interface KimiUsagesResponse {
192
224
  } | null> | null;
193
225
  subType?: string | null;
194
226
  }
227
+ /**
228
+ * Fetch Kimi usage via the Kimi Code /usages API. Kimi's JWT has no email
229
+ * claim, so the account row can't show an address — but /usages returns quota
230
+ * windows and the membership tier, which is what we render.
231
+ *
232
+ * Deliberately NO token refresh: `agents view` is a read/inspect command and
233
+ * must not rotate the user's Kimi OAuth credential (rewriting the file,
234
+ * invalidating the old refresh token, racing a concurrently-running kimi CLI).
235
+ * The kimi CLI refreshes on its own launch; if the stored token is expired we
236
+ * skip the live fetch and let the SWR cache serve the last-seen snapshot.
237
+ */
238
+ declare function getKimiUsageInfo(options?: UsageOptions): Promise<UsageInfo>;
195
239
  /** Normalize the Kimi /usages payload into the common UsageWindow shape. */
196
240
  export declare function normalizeKimiWindows(data: KimiUsagesResponse): UsageWindow[];
197
241
  /** Derive a display plan label from Kimi's membership tier or subscription type. */
@@ -212,6 +256,22 @@ export interface DroidBillingLimitsResponse {
212
256
  } | null;
213
257
  } | null;
214
258
  }
259
+ /**
260
+ * Fetch Droid usage via Factory's billing limits API — the same endpoint the
261
+ * droid CLI polls for its token-limit banner. The WorkOS access token comes
262
+ * from the locally decrypted ~/.factory/auth.v2.file (the same credential
263
+ * account identity in agents.ts reads).
264
+ *
265
+ * Deliberately NO token refresh, for a sharper reason than Kimi's: WorkOS
266
+ * refresh tokens are single-use and rotate on every exchange, so refreshing
267
+ * here would race a concurrently running droid session and can permanently
268
+ * invalidate the user's login chain. Droid refreshes its own credential when
269
+ * it runs; if the stored token is expired we skip the live fetch and let the
270
+ * SWR cache serve the last-seen snapshot. This same single-use-rotation property
271
+ * is why `agents apply` refuses to propagate droid credentials across machines
272
+ * (see `isCredentialSafeToPropagate` in `../fleet/auth-sync.ts`).
273
+ */
274
+ declare function getDroidUsageInfo(options?: UsageOptions): Promise<UsageInfo>;
215
275
  /**
216
276
  * Live auth probes — the same authenticated GET the usage fetchers above do,
217
277
  * but surfacing the raw HTTP status instead of swallowing 401/expired to null.
@@ -296,6 +356,8 @@ export declare function writeClaudeUsageCache(usageKey: string, snapshot: UsageS
296
356
  * Returns true only when a valid access token can be obtained.
297
357
  */
298
358
  export declare function isClaudeAuthValid(home?: string): Promise<boolean>;
359
+ /** Parse the latest billing info from Grok's unified log. */
360
+ declare function getGrokUsageInfo(options?: UsageOptions): Promise<UsageInfo>;
299
361
  /** Per-model bucket in Cursor's /api/usage response. */
300
362
  interface CursorUsageModel {
301
363
  numRequests?: number | null;
@@ -319,4 +381,13 @@ export interface CursorUsageResponse {
319
381
  * bar to draw here and return no windows rather than a misleading empty gauge.
320
382
  */
321
383
  export declare function normalizeCursorUsage(data: CursorUsageResponse): UsageWindow[];
384
+ /**
385
+ * Fetch Cursor usage from the dashboard usage endpoint. Cursor authenticates the
386
+ * request with a `WorkosCursorSessionToken` cookie of the form
387
+ * `<oauth-subject>::<access-token>` (the same pair the web dashboard sends), not a
388
+ * bearer header. Free/legacy plans return a monthly request bar; usage-based plans
389
+ * have no request cap, so they return a live-but-window-less snapshot (the account
390
+ * row still renders, without a misleading empty gauge).
391
+ */
392
+ declare function getCursorUsageInfo(options?: UsageOptions): Promise<UsageInfo>;
322
393
  export {};
package/dist/lib/usage.js CHANGED
@@ -59,24 +59,23 @@ const COMPACT_BAR_LEN = 5;
59
59
  const USAGE_BAR_LEN = 10;
60
60
  const FULL = '\u2588';
61
61
  const EMPTY = '\u2591';
62
- /** Fetch usage info for a given agent, dispatching to the agent-specific implementation. */
62
+ /** The single registry of agent usage sources and their transport. */
63
+ const USAGE_SOURCES = {
64
+ claude: { fetch: getClaudeUsageInfo, network: true },
65
+ codex: { fetch: getCodexUsageInfo, network: false },
66
+ kimi: { fetch: getKimiUsageInfo, network: true },
67
+ droid: { fetch: getDroidUsageInfo, network: true },
68
+ grok: { fetch: getGrokUsageInfo, network: false },
69
+ cursor: { fetch: getCursorUsageInfo, network: true },
70
+ };
71
+ export const USAGE_SOURCE_AGENT_IDS = Object.keys(USAGE_SOURCES);
72
+ function getUsageSource(agentId) {
73
+ return USAGE_SOURCES[agentId];
74
+ }
75
+ /** Fetch usage info for a given agent through the canonical source registry. */
63
76
  export async function getUsageInfo(agentId, options) {
64
- switch (agentId) {
65
- case 'claude':
66
- return getClaudeUsageInfo(options);
67
- case 'codex':
68
- return getCodexUsageInfo(options);
69
- case 'kimi':
70
- return getKimiUsageInfo(options);
71
- case 'droid':
72
- return getDroidUsageInfo(options);
73
- case 'grok':
74
- return getGrokUsageInfo(options);
75
- case 'cursor':
76
- return getCursorUsageInfo(options);
77
- default:
78
- return { snapshot: null, error: null };
79
- }
77
+ const source = getUsageSource(agentId);
78
+ return source ? source.fetch(options) : { snapshot: null, error: null };
80
79
  }
81
80
  /** Derive a stable lookup key from account info for usage deduplication. */
82
81
  export function getUsageLookupKey(info) {
@@ -117,12 +116,7 @@ export function buildCanonicalUsageContext(inputs) {
117
116
  * versus simply not applicable (Antigravity, OpenCode).
118
117
  */
119
118
  export function agentReportsUsage(agentId) {
120
- return (agentId === 'claude' ||
121
- agentId === 'codex' ||
122
- agentId === 'kimi' ||
123
- agentId === 'droid' ||
124
- agentId === 'grok' ||
125
- agentId === 'cursor');
119
+ return getUsageSource(agentId) !== undefined;
126
120
  }
127
121
  /** Fetch usage info for all unique accounts in parallel, keyed by usage key. */
128
122
  export async function getUsageInfoByIdentity(inputs, opts) {
@@ -160,14 +154,14 @@ const inFlightRefreshes = new Map();
160
154
  export async function getUsageInfoForIdentity(input, opts) {
161
155
  const usageKey = getUsageLookupKey(input.info);
162
156
  const forceRefresh = opts?.forceRefresh === true;
163
- // Agents whose usage comes from a live network call (Claude, Kimi, Droid) go
157
+ // Agents whose registered usage source makes a live network call go
164
158
  // through the stale-while-revalidate cache below so `agents run`/`agents view`
165
159
  // stay off the network on the hot path. Everything else (Codex reads local
166
160
  // session logs) takes the legacy blocking path. The on-disk cache is shared and
167
161
  // keyed by usageKey, which is namespaced per agent (`claude:org=…`,
168
- // `kimi:user=…`, `droid:org=…`), so one cache file holds every account without
169
- // collision.
170
- const usesNetworkUsage = input.agentId === 'claude' || input.agentId === 'kimi' || input.agentId === 'droid';
162
+ // `kimi:user=…`, `droid:org=…`, `cursor:user=…`), so one cache file holds every
163
+ // account without collision.
164
+ const usesNetworkUsage = getUsageSource(input.agentId)?.network === true;
171
165
  if (!usesNetworkUsage || !usageKey) {
172
166
  return getUsageInfo(input.agentId, {
173
167
  home: input.home,
@@ -43,7 +43,7 @@ import { discoverPlugins, marketplaceSpecForName } from './plugins.js';
43
43
  import { loadManifest, saveManifest, buildManifest as buildSyncManifest, isStale } from './staleness/index.js';
44
44
  import { emit } from './events.js';
45
45
  import { safeJoin } from './paths.js';
46
- import { readSkillSourceCommandMarker, shouldInstallCommandAsSkill } from './command-skills.js';
46
+ import { readSkillSourceCommandMarker, shouldAlsoInstallCommandAsSkill, shouldInstallCommandAsSkill, } from './command-skills.js';
47
47
  import { getWriter, getDetector } from './staleness/registry.js';
48
48
  import { syncMemoryToVersionHome } from './memory.js';
49
49
  import { listPluginSkillNames, resolveCommandSource, resolveSkillSource } from './staleness/writers/sources.js';
@@ -2555,21 +2555,30 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
2555
2555
  };
2556
2556
  const trustedCommandNames = (names) => names.filter((name) => resolveCommandSource(name) !== null);
2557
2557
  // Sync commands — dispatch through WRITERS.commands. The writer dispatches
2558
- // between native (file copy / TOML conversion) and commands-as-skills
2559
- // (grok, Codex >= 0.117.0) based on `shouldInstallCommandAsSkill`. The
2560
- // previous COMMANDS_CAPABLE_AGENTS gate excluded grok even though it
2561
- // takes the commands-as-skills path — silently dropping every command.
2558
+ // between native (file copy / TOML conversion), commands-as-skills, and the
2559
+ // registry-driven dual-write path based on the command-skill predicates. The
2560
+ // previous COMMANDS_CAPABLE_AGENTS gate excluded skills-only targets such as
2561
+ // Kimi, silently dropping every converted command.
2562
2562
  const commandsWriter = getWriter('commands', agent);
2563
2563
  const commandsToSync = selection
2564
2564
  ? trustedCommandNames(resolveSelection(selection.commands, available.commands))
2565
2565
  : trustedCommandNames(available.commands); // No selection = sync all trusted commands, excluding project-only commands
2566
2566
  const commandsAsSkills = shouldInstallCommandAsSkill(agent, version);
2567
+ const commandsAlsoAsSkills = shouldAlsoInstallCommandAsSkill(agent, version);
2568
+ const commandsInstallAsSkills = commandsAsSkills || commandsAlsoAsSkills;
2569
+ let writtenCommands = [];
2567
2570
  if (commandsToSync.length > 0 && commandsWriter) {
2568
- const commandsTarget = path.join(agentDir, agentConfig.commandsSubdir);
2571
+ // Agents that replace native command files with skills (codex >= 0.117.0,
2572
+ // kimi) must have their legacy command dir removed, or files written by an
2573
+ // older version linger forever: the orphan sweep below is gated off for
2574
+ // them, and `agents prune` only sees their skills. Gated on
2575
+ // `commandsAsSkills`, never `commandsAlsoAsSkills` -- a dual-write agent's
2576
+ // native dir is a live product surface (Cursor IDE) and must not be wiped.
2569
2577
  if (commandsAsSkills && agentConfig.commandsSubdir) {
2570
- removePath(commandsTarget);
2578
+ removePath(path.join(agentDir, agentConfig.commandsSubdir));
2571
2579
  }
2572
2580
  const r = commandsWriter.write({ version, versionHome, selection: commandsToSync, cwd });
2581
+ writtenCommands = r.synced;
2573
2582
  result.commands = r.synced.length > 0;
2574
2583
  }
2575
2584
  // Orphan-sweep stale top-level command files from previous syncs under a
@@ -2584,13 +2593,19 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
2584
2593
  if (fs.existsSync(commandsTargetSweep)) {
2585
2594
  const ext = agentConfig.format === 'toml' ? '.toml' : '.md';
2586
2595
  const trustedCommands = new Set(commandsToSync);
2596
+ // A dual-write target's native directory also belongs to another product
2597
+ // surface (Cursor IDE). Delete only names the command writer recorded as
2598
+ // successfully emitted during the preceding full sync.
2599
+ const previouslyManagedCommands = commandsAlsoAsSkills
2600
+ ? new Set(loadManifest(agent, version)?.writtenCommands ?? [])
2601
+ : null;
2587
2602
  for (const entry of fs.readdirSync(commandsTargetSweep, { withFileTypes: true })) {
2588
2603
  if (!entry.isFile() || entry.name.startsWith('.'))
2589
2604
  continue;
2590
2605
  if (!entry.name.endsWith(ext))
2591
2606
  continue;
2592
2607
  const name = entry.name.slice(0, -ext.length);
2593
- if (!trustedCommands.has(name)) {
2608
+ if (!trustedCommands.has(name) && (!previouslyManagedCommands || previouslyManagedCommands.has(name))) {
2594
2609
  removePath(safeJoin(commandsTargetSweep, entry.name));
2595
2610
  }
2596
2611
  }
@@ -2612,7 +2627,7 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
2612
2627
  let skillsToSync = userPassedSelection
2613
2628
  ? selectedSkillsToSync
2614
2629
  : Array.from(new Set([...selectedSkillsToSync, ...pluginSkillsToSync]));
2615
- if (commandsAsSkills && commandsToSync.length > 0 && skillsToSync.length > 0) {
2630
+ if (commandsInstallAsSkills && commandsToSync.length > 0 && skillsToSync.length > 0) {
2616
2631
  const commandNames = new Set(commandsToSync);
2617
2632
  const skillRoots = [
2618
2633
  path.join(getUserAgentsDir(), 'skills'),
@@ -2639,13 +2654,13 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
2639
2654
  // dot-dirs to keep plugin-managed subtrees (.plugins/, .promptcuts) intact.
2640
2655
  const skillsTargetSweep = path.join(agentDir, 'skills');
2641
2656
  if (!userPassedSelection && fs.existsSync(skillsTargetSweep) && !fs.lstatSync(skillsTargetSweep).isSymbolicLink()) {
2642
- // Trust real skills AND command-skills: when commandsAsSkills, the
2657
+ // Trust real skills AND command-skills: when commandsInstallAsSkills, the
2643
2658
  // commands writer (above) materialized each command as a skill dir under
2644
2659
  // skills/. Those names are not in skillsToSync, so without this they'd be
2645
2660
  // swept as orphans — silently deleting every converted command (e.g.
2646
- // /recap on kimi/grok).
2661
+ // /recap on Kimi or newer Codex releases).
2647
2662
  const trustedSkills = new Set(skillsToSync);
2648
- if (commandsAsSkills)
2663
+ if (commandsInstallAsSkills)
2649
2664
  for (const cmd of commandsToSync)
2650
2665
  trustedSkills.add(cmd);
2651
2666
  for (const entry of fs.readdirSync(skillsTargetSweep, { withFileTypes: true })) {
@@ -2866,7 +2881,9 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
2866
2881
  // one-off override, so the resulting state matches what the manifest
2867
2882
  // records as the synced set.
2868
2883
  if (!userPassedSelection) {
2869
- saveManifest(agent, version, buildSyncManifest(agent, version, cwd));
2884
+ const manifest = buildSyncManifest(agent, version, cwd);
2885
+ manifest.writtenCommands = writtenCommands;
2886
+ saveManifest(agent, version, manifest);
2870
2887
  }
2871
2888
  return result;
2872
2889
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phnx-labs/agents-cli",
3
- "version": "1.20.87",
3
+ "version": "1.20.89",
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",