@phnx-labs/agents-cli 1.20.33 → 1.20.35
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.
- package/CHANGELOG.md +29 -0
- package/README.md +32 -2
- package/dist/commands/computer-actions.d.ts +15 -0
- package/dist/commands/computer-actions.js +120 -22
- package/dist/commands/computer.d.ts +23 -0
- package/dist/commands/computer.js +45 -3
- package/dist/commands/cost.js +17 -12
- package/dist/commands/doctor.d.ts +11 -0
- package/dist/commands/doctor.js +108 -14
- package/dist/commands/events.d.ts +16 -0
- package/dist/commands/events.js +173 -0
- package/dist/commands/exec.js +6 -1
- package/dist/commands/hosts.js +28 -24
- package/dist/commands/import.js +1 -1
- package/dist/commands/inspect.d.ts +2 -0
- package/dist/commands/inspect.js +54 -7
- package/dist/commands/logs.d.ts +17 -0
- package/dist/commands/logs.js +139 -0
- package/dist/commands/models.d.ts +3 -0
- package/dist/commands/models.js +27 -8
- package/dist/commands/permissions.js +9 -2
- package/dist/commands/repo.d.ts +34 -0
- package/dist/commands/repo.js +243 -65
- package/dist/commands/resource-view.d.ts +20 -0
- package/dist/commands/resource-view.js +90 -28
- package/dist/commands/rules.js +1 -1
- package/dist/commands/secrets-migrate.js +23 -11
- package/dist/commands/secrets.d.ts +20 -0
- package/dist/commands/secrets.js +93 -17
- package/dist/commands/sessions-resume.d.ts +2 -0
- package/dist/commands/sessions-resume.js +209 -0
- package/dist/commands/sessions-tail.d.ts +10 -0
- package/dist/commands/sessions-tail.js +11 -0
- package/dist/commands/sessions.d.ts +73 -1
- package/dist/commands/sessions.js +273 -53
- package/dist/commands/status.d.ts +12 -0
- package/dist/commands/status.js +81 -0
- package/dist/commands/teams.js +70 -6
- package/dist/commands/versions.js +2 -1
- package/dist/commands/view.d.ts +42 -0
- package/dist/commands/view.js +213 -83
- package/dist/commands/wallet.d.ts +6 -0
- package/dist/commands/wallet.js +22 -5
- package/dist/index.js +61 -32
- package/dist/lib/acp/harnesses.d.ts +1 -1
- package/dist/lib/acp/harnesses.js +2 -2
- package/dist/lib/agents.d.ts +12 -0
- package/dist/lib/agents.js +145 -41
- package/dist/lib/browser/cdp.js +5 -1
- package/dist/lib/browser/chrome.js +20 -0
- package/dist/lib/browser/drivers/ssh.d.ts +27 -0
- package/dist/lib/browser/drivers/ssh.js +94 -19
- package/dist/lib/browser/ipc.d.ts +3 -0
- package/dist/lib/browser/ipc.js +13 -9
- package/dist/lib/browser/service.js +71 -15
- package/dist/lib/daemon.d.ts +35 -0
- package/dist/lib/daemon.js +33 -5
- package/dist/lib/devices/connect.d.ts +3 -2
- package/dist/lib/devices/connect.js +5 -3
- package/dist/lib/doctor-diff.js +29 -2
- package/dist/lib/drift-sync.d.ts +43 -0
- package/dist/lib/drift-sync.js +179 -0
- package/dist/lib/events.d.ts +9 -2
- package/dist/lib/events.js +70 -11
- package/dist/lib/exec.d.ts +15 -0
- package/dist/lib/exec.js +43 -11
- package/dist/lib/hooks.js +8 -2
- package/dist/lib/hosts/dispatch.js +6 -7
- package/dist/lib/hosts/logs.d.ts +16 -0
- package/dist/lib/hosts/logs.js +45 -0
- package/dist/lib/hosts/progress.d.ts +66 -0
- package/dist/lib/hosts/progress.js +125 -17
- package/dist/lib/hosts/ready.d.ts +23 -2
- package/dist/lib/hosts/ready.js +35 -13
- package/dist/lib/hosts/reconcile.d.ts +53 -0
- package/dist/lib/hosts/reconcile.js +81 -0
- package/dist/lib/hosts/tasks.d.ts +8 -0
- package/dist/lib/hosts/tasks.js +14 -0
- package/dist/lib/permissions.d.ts +4 -0
- package/dist/lib/permissions.js +35 -0
- package/dist/lib/picker.d.ts +24 -0
- package/dist/lib/picker.js +124 -0
- package/dist/lib/platform/winpath.d.ts +31 -2
- package/dist/lib/platform/winpath.js +133 -24
- package/dist/lib/plugin-marketplace.d.ts +30 -0
- package/dist/lib/plugin-marketplace.js +215 -2
- package/dist/lib/plugins.d.ts +5 -0
- package/dist/lib/plugins.js +45 -4
- package/dist/lib/pwsh.d.ts +11 -0
- package/dist/lib/pwsh.js +13 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/agent.d.ts +42 -1
- package/dist/lib/secrets/agent.js +89 -11
- package/dist/lib/secrets/bundles.js +40 -9
- package/dist/lib/secrets/filestore.js +31 -1
- package/dist/lib/secrets/index.d.ts +33 -1
- package/dist/lib/secrets/index.js +90 -9
- package/dist/lib/secrets/windows.d.ts +74 -0
- package/dist/lib/secrets/windows.js +440 -0
- package/dist/lib/session/active.d.ts +7 -0
- package/dist/lib/session/active.js +11 -3
- package/dist/lib/session/discover.js +94 -0
- package/dist/lib/session/parse.d.ts +6 -0
- package/dist/lib/session/parse.js +283 -2
- package/dist/lib/session/pid-registry.d.ts +21 -0
- package/dist/lib/session/pid-registry.js +80 -0
- package/dist/lib/session/remote-active.d.ts +26 -0
- package/dist/lib/session/remote-active.js +141 -0
- package/dist/lib/session/remote.js +2 -6
- package/dist/lib/session/render.js +1 -1
- package/dist/lib/session/sync/config.d.ts +8 -0
- package/dist/lib/session/sync/config.js +11 -2
- package/dist/lib/session/types.d.ts +1 -1
- package/dist/lib/session/types.js +1 -1
- package/dist/lib/shims.d.ts +30 -2
- package/dist/lib/shims.js +107 -50
- package/dist/lib/ssh-exec.d.ts +26 -3
- package/dist/lib/ssh-exec.js +45 -3
- package/dist/lib/ssh-tunnel.d.ts +24 -5
- package/dist/lib/ssh-tunnel.js +60 -62
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/startup/command-registry.d.ts +3 -0
- package/dist/lib/startup/command-registry.js +6 -0
- package/dist/lib/sync-status.d.ts +102 -0
- package/dist/lib/sync-status.js +135 -0
- package/dist/lib/teams/agents.d.ts +24 -0
- package/dist/lib/teams/agents.js +30 -1
- package/dist/lib/teams/registry.js +25 -9
- package/dist/lib/terminal/backends/ghostty.d.ts +6 -0
- package/dist/lib/terminal/backends/ghostty.js +69 -0
- package/dist/lib/terminal/backends/index.d.ts +18 -0
- package/dist/lib/terminal/backends/index.js +29 -0
- package/dist/lib/terminal/backends/iterm.d.ts +6 -0
- package/dist/lib/terminal/backends/iterm.js +62 -0
- package/dist/lib/terminal/backends/tmux.d.ts +14 -0
- package/dist/lib/terminal/backends/tmux.js +23 -0
- package/dist/lib/terminal/engine.d.ts +39 -0
- package/dist/lib/terminal/engine.js +54 -0
- package/dist/lib/terminal/index.d.ts +14 -0
- package/dist/lib/terminal/index.js +5 -0
- package/dist/lib/terminal/policy.d.ts +11 -0
- package/dist/lib/terminal/policy.js +11 -0
- package/dist/lib/terminal/quote.d.ts +11 -0
- package/dist/lib/terminal/quote.js +13 -0
- package/dist/lib/terminal/shell.d.ts +6 -0
- package/dist/lib/terminal/shell.js +23 -0
- package/dist/lib/terminal/transport.d.ts +15 -0
- package/dist/lib/terminal/transport.js +40 -0
- package/dist/lib/terminal/types.d.ts +59 -0
- package/dist/lib/terminal/types.js +13 -0
- package/dist/lib/types.d.ts +27 -1
- package/dist/lib/usage.d.ts +30 -0
- package/dist/lib/usage.js +159 -2
- package/dist/lib/versions.d.ts +7 -3
- package/dist/lib/versions.js +10 -5
- package/dist/lib/whats-new.d.ts +9 -0
- package/dist/lib/whats-new.js +35 -0
- package/package.json +1 -1
package/dist/lib/usage.js
CHANGED
|
@@ -33,6 +33,7 @@ const CLAUDE_SCOPES = [
|
|
|
33
33
|
const CLAUDE_KEYCHAIN_SERVICE = 'Claude Code-credentials';
|
|
34
34
|
const getClaudeUsageCachePath = () => path.join(getCacheDir(), 'claude-usage.json');
|
|
35
35
|
const CACHED_CLAUDE_USAGE_SOURCE_LABEL = 'last seen live account data';
|
|
36
|
+
const KIMI_USAGES_URL = 'https://api.kimi.com/coding/v1/usages';
|
|
36
37
|
const COMPACT_BAR_LEN = 5;
|
|
37
38
|
const USAGE_BAR_LEN = 10;
|
|
38
39
|
const FULL = '\u2588';
|
|
@@ -44,6 +45,8 @@ export async function getUsageInfo(agentId, options) {
|
|
|
44
45
|
return getClaudeUsageInfo(options);
|
|
45
46
|
case 'codex':
|
|
46
47
|
return getCodexUsageInfo(options);
|
|
48
|
+
case 'kimi':
|
|
49
|
+
return getKimiUsageInfo(options);
|
|
47
50
|
default:
|
|
48
51
|
return { snapshot: null, error: null };
|
|
49
52
|
}
|
|
@@ -114,8 +117,14 @@ const inFlightRefreshes = new Map();
|
|
|
114
117
|
*/
|
|
115
118
|
export async function getUsageInfoForIdentity(input) {
|
|
116
119
|
const usageKey = getUsageLookupKey(input.info);
|
|
117
|
-
//
|
|
118
|
-
|
|
120
|
+
// Agents whose usage comes from a live network call (Claude, Kimi) go through
|
|
121
|
+
// the stale-while-revalidate cache below so `agents run`/`agents view` stay off
|
|
122
|
+
// the network on the hot path. Everything else (Codex reads local session
|
|
123
|
+
// logs) takes the legacy blocking path. The on-disk cache is shared and keyed
|
|
124
|
+
// by usageKey, which is namespaced per agent (`claude:org=…`, `kimi:user=…`),
|
|
125
|
+
// so one cache file holds every account without collision.
|
|
126
|
+
const usesNetworkUsage = input.agentId === 'claude' || input.agentId === 'kimi';
|
|
127
|
+
if (!usesNetworkUsage || !usageKey) {
|
|
119
128
|
return getUsageInfo(input.agentId, {
|
|
120
129
|
home: input.home,
|
|
121
130
|
cliVersion: input.cliVersion,
|
|
@@ -356,6 +365,152 @@ async function getClaudeUsageInfo(options) {
|
|
|
356
365
|
return { snapshot: null, error: 'Usage data unavailable right now.' };
|
|
357
366
|
}
|
|
358
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* Resolve Kimi's OAuth credential file. Sign-in is account-global but each
|
|
370
|
+
* installed version has an isolated home; the file physically lives only in the
|
|
371
|
+
* home the user logged in under. Check the per-version home first, then the
|
|
372
|
+
* active location under the real HOME — mirrors resolveAccountCredentialPath in
|
|
373
|
+
* agents.ts so every version reflects the true account state.
|
|
374
|
+
*/
|
|
375
|
+
function resolveKimiCredentialPath(home) {
|
|
376
|
+
const rel = ['.kimi-code', 'credentials', 'kimi-code.json'];
|
|
377
|
+
const perVersion = path.join(home || os.homedir(), ...rel);
|
|
378
|
+
try {
|
|
379
|
+
if (fs.existsSync(perVersion))
|
|
380
|
+
return perVersion;
|
|
381
|
+
}
|
|
382
|
+
catch { /* unreadable */ }
|
|
383
|
+
const active = path.join(process.env.AGENTS_REAL_HOME || os.homedir(), ...rel);
|
|
384
|
+
if (active !== perVersion) {
|
|
385
|
+
try {
|
|
386
|
+
if (fs.existsSync(active))
|
|
387
|
+
return active;
|
|
388
|
+
}
|
|
389
|
+
catch { /* unreadable */ }
|
|
390
|
+
}
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Fetch Kimi usage via the Kimi Code /usages API. Kimi's JWT has no email
|
|
395
|
+
* claim, so the account row can't show an address — but /usages returns quota
|
|
396
|
+
* windows and the membership tier, which is what we render.
|
|
397
|
+
*
|
|
398
|
+
* Deliberately NO token refresh: `agents view` is a read/inspect command and
|
|
399
|
+
* must not rotate the user's Kimi OAuth credential (rewriting the file,
|
|
400
|
+
* invalidating the old refresh token, racing a concurrently-running kimi CLI).
|
|
401
|
+
* The kimi CLI refreshes on its own launch; if the stored token is expired we
|
|
402
|
+
* skip the live fetch and let the SWR cache serve the last-seen snapshot.
|
|
403
|
+
*/
|
|
404
|
+
async function getKimiUsageInfo(options) {
|
|
405
|
+
try {
|
|
406
|
+
const credPath = resolveKimiCredentialPath(options?.home);
|
|
407
|
+
if (!credPath)
|
|
408
|
+
return { snapshot: null, error: null };
|
|
409
|
+
const cred = JSON.parse(fs.readFileSync(credPath, 'utf-8'));
|
|
410
|
+
const accessToken = cred?.access_token;
|
|
411
|
+
if (typeof accessToken !== 'string' || !accessToken) {
|
|
412
|
+
return { snapshot: null, error: null };
|
|
413
|
+
}
|
|
414
|
+
const expiresAt = typeof cred?.expires_at === 'number' ? cred.expires_at : null;
|
|
415
|
+
if (expiresAt !== null && Date.now() / 1000 >= expiresAt) {
|
|
416
|
+
return { snapshot: null, error: null };
|
|
417
|
+
}
|
|
418
|
+
const response = await fetch(KIMI_USAGES_URL, {
|
|
419
|
+
method: 'GET',
|
|
420
|
+
headers: {
|
|
421
|
+
Authorization: `Bearer ${accessToken}`,
|
|
422
|
+
Accept: 'application/json',
|
|
423
|
+
},
|
|
424
|
+
signal: AbortSignal.timeout(5000),
|
|
425
|
+
});
|
|
426
|
+
// 401/403/404 => expired token or no Kimi For Coding subscription; render
|
|
427
|
+
// nothing rather than a misleading empty bar.
|
|
428
|
+
if (!response.ok) {
|
|
429
|
+
return { snapshot: null, error: null };
|
|
430
|
+
}
|
|
431
|
+
const data = await response.json();
|
|
432
|
+
const windows = normalizeKimiWindows(data);
|
|
433
|
+
if (windows.length === 0) {
|
|
434
|
+
return { snapshot: null, error: null };
|
|
435
|
+
}
|
|
436
|
+
return {
|
|
437
|
+
snapshot: {
|
|
438
|
+
source: 'live',
|
|
439
|
+
sourceLabel: 'live account data',
|
|
440
|
+
capturedAt: new Date(),
|
|
441
|
+
windows,
|
|
442
|
+
plan: formatKimiPlan(data),
|
|
443
|
+
},
|
|
444
|
+
error: null,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
catch {
|
|
448
|
+
return { snapshot: null, error: null };
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/** Normalize the Kimi /usages payload into the common UsageWindow shape. */
|
|
452
|
+
export function normalizeKimiWindows(data) {
|
|
453
|
+
const windows = [];
|
|
454
|
+
// Per-window rate limit (e.g. a 300-minute bucket) -> "session".
|
|
455
|
+
const shortLimit = Array.isArray(data.limits)
|
|
456
|
+
? data.limits.find((entry) => entry?.detail)
|
|
457
|
+
: null;
|
|
458
|
+
const session = normalizeKimiWindow(shortLimit?.detail, 'session', 'Current session', 'S', kimiWindowMinutes(shortLimit?.window));
|
|
459
|
+
if (session)
|
|
460
|
+
windows.push(session);
|
|
461
|
+
// Rolling account quota -> "week".
|
|
462
|
+
const period = normalizeKimiWindow(data.usage, 'week', 'Current period', 'W', null);
|
|
463
|
+
if (period)
|
|
464
|
+
windows.push(period);
|
|
465
|
+
return windows;
|
|
466
|
+
}
|
|
467
|
+
/** Normalize a single Kimi quota bucket (used/limit strings) into a UsageWindow. */
|
|
468
|
+
function normalizeKimiWindow(quota, key, label, shortLabel, windowMinutes) {
|
|
469
|
+
const limit = kimiNumber(quota?.limit);
|
|
470
|
+
const used = kimiNumber(quota?.used);
|
|
471
|
+
if (limit === null || used === null || limit <= 0)
|
|
472
|
+
return null;
|
|
473
|
+
const usedPercent = normalizePercent((used / limit) * 100);
|
|
474
|
+
if (usedPercent === null)
|
|
475
|
+
return null;
|
|
476
|
+
return {
|
|
477
|
+
key,
|
|
478
|
+
label,
|
|
479
|
+
shortLabel,
|
|
480
|
+
usedPercent,
|
|
481
|
+
resetsAt: parseDateValue(quota?.resetTime),
|
|
482
|
+
windowMinutes: windowMinutes ?? inferWindowMinutes(key),
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
/** Parse a numeric field that Kimi serializes as a string (e.g. "100"). */
|
|
486
|
+
function kimiNumber(value) {
|
|
487
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
488
|
+
return value;
|
|
489
|
+
if (typeof value === 'string' && value.trim() !== '' && !Number.isNaN(Number(value))) {
|
|
490
|
+
return Number(value);
|
|
491
|
+
}
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
/** Convert a Kimi limit window (duration + timeUnit enum) to minutes. */
|
|
495
|
+
function kimiWindowMinutes(window) {
|
|
496
|
+
const duration = typeof window?.duration === 'number' ? window.duration : null;
|
|
497
|
+
if (duration === null || duration <= 0)
|
|
498
|
+
return null;
|
|
499
|
+
switch (window?.timeUnit) {
|
|
500
|
+
case 'TIME_UNIT_HOUR': return duration * 60;
|
|
501
|
+
case 'TIME_UNIT_SECOND': return duration / 60;
|
|
502
|
+
default: return duration; // TIME_UNIT_MINUTE or unknown -> minutes
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
/** Derive a display plan label from Kimi's membership tier or subscription type. */
|
|
506
|
+
export function formatKimiPlan(data) {
|
|
507
|
+
const level = data.user?.membership?.level;
|
|
508
|
+
const raw = (typeof level === 'string' && level) || (typeof data.subType === 'string' && data.subType) || '';
|
|
509
|
+
const tail = raw.split('_').pop() || ''; // LEVEL_INTERMEDIATE -> INTERMEDIATE
|
|
510
|
+
if (!tail)
|
|
511
|
+
return null;
|
|
512
|
+
return tail.charAt(0).toUpperCase() + tail.slice(1).toLowerCase();
|
|
513
|
+
}
|
|
359
514
|
/** Collect Codex JSONL session files sorted newest-first. */
|
|
360
515
|
function collectCodexSessionFiles(home) {
|
|
361
516
|
const base = home || os.homedir();
|
|
@@ -590,6 +745,7 @@ function writeClaudeUsageCacheFile(cache, cachePath) {
|
|
|
590
745
|
function serializeClaudeUsageSnapshot(snapshot) {
|
|
591
746
|
return {
|
|
592
747
|
capturedAt: snapshot.capturedAt?.toISOString() || null,
|
|
748
|
+
plan: snapshot.plan ?? null,
|
|
593
749
|
windows: snapshot.windows.map((window) => ({
|
|
594
750
|
key: window.key,
|
|
595
751
|
label: window.label,
|
|
@@ -626,6 +782,7 @@ function deserializeClaudeUsageSnapshot(snapshot, now) {
|
|
|
626
782
|
sourceLabel: CACHED_CLAUDE_USAGE_SOURCE_LABEL,
|
|
627
783
|
capturedAt,
|
|
628
784
|
windows,
|
|
785
|
+
plan: snapshot.plan ?? null,
|
|
629
786
|
};
|
|
630
787
|
}
|
|
631
788
|
/** Check whether a cached usage window is still relevant (not expired or reset). */
|
package/dist/lib/versions.d.ts
CHANGED
|
@@ -337,9 +337,13 @@ export declare function listRepoNames(): string[];
|
|
|
337
337
|
* sync path uses. Passing the result as an explicit `selection` means the sync
|
|
338
338
|
* touches only that repo's resources — no orphan-sweep of the other layers.
|
|
339
339
|
*
|
|
340
|
-
* `memory` is set to `[]
|
|
341
|
-
*
|
|
342
|
-
*
|
|
340
|
+
* `memory` is set to `'all'`, NOT `[]`: the composed rules-memory file is a
|
|
341
|
+
* merge of ALL layers, so scoping the sync to a single repo must still
|
|
342
|
+
* recompile it in the same pass (RUSH-1354). Leaving it out — or using the
|
|
343
|
+
* `[]` skip-sentinel — silently strands the memory file at its old content
|
|
344
|
+
* whenever a repo-scoped sync runs after a rules change. `'all'` makes
|
|
345
|
+
* `syncResourcesToVersion` recompose from every layer via the active preset,
|
|
346
|
+
* exactly as an unscoped full reconcile does.
|
|
343
347
|
*/
|
|
344
348
|
export declare function buildRepoScopedSelection(repo: string, cwd?: string): ResourceSelection;
|
|
345
349
|
/**
|
package/dist/lib/versions.js
CHANGED
|
@@ -1692,9 +1692,13 @@ function resourceSourceMap(kind, cwd, available) {
|
|
|
1692
1692
|
* sync path uses. Passing the result as an explicit `selection` means the sync
|
|
1693
1693
|
* touches only that repo's resources — no orphan-sweep of the other layers.
|
|
1694
1694
|
*
|
|
1695
|
-
* `memory` is set to `[]
|
|
1696
|
-
*
|
|
1697
|
-
*
|
|
1695
|
+
* `memory` is set to `'all'`, NOT `[]`: the composed rules-memory file is a
|
|
1696
|
+
* merge of ALL layers, so scoping the sync to a single repo must still
|
|
1697
|
+
* recompile it in the same pass (RUSH-1354). Leaving it out — or using the
|
|
1698
|
+
* `[]` skip-sentinel — silently strands the memory file at its old content
|
|
1699
|
+
* whenever a repo-scoped sync runs after a rules change. `'all'` makes
|
|
1700
|
+
* `syncResourcesToVersion` recompose from every layer via the active preset,
|
|
1701
|
+
* exactly as an unscoped full reconcile does.
|
|
1698
1702
|
*/
|
|
1699
1703
|
export function buildRepoScopedSelection(repo, cwd = process.cwd()) {
|
|
1700
1704
|
const patterns = [`${repo}:*`];
|
|
@@ -1706,8 +1710,9 @@ export function buildRepoScopedSelection(repo, cwd = process.cwd()) {
|
|
|
1706
1710
|
if (names.length > 0)
|
|
1707
1711
|
selection[kind] = names;
|
|
1708
1712
|
}
|
|
1709
|
-
//
|
|
1710
|
-
|
|
1713
|
+
// Recompile the memory file from all layers even under a repo scope — it is
|
|
1714
|
+
// composed, not a per-repo artifact (see skipMemory below and RUSH-1354).
|
|
1715
|
+
selection.memory = 'all';
|
|
1711
1716
|
return selection;
|
|
1712
1717
|
}
|
|
1713
1718
|
/**
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render a compact "What's new" summary from a CHANGELOG.md body: one bullet
|
|
3
|
+
* per feature/fix heading (the `**...**` lines) for each version in the range
|
|
4
|
+
* the user actually moved through, `(fromVersion, toVersion]`. The verbose
|
|
5
|
+
* sub-bullets are intentionally dropped — the full notes live in the changelog.
|
|
6
|
+
*
|
|
7
|
+
* Returns colored lines ready to print, empty when nothing is in range.
|
|
8
|
+
*/
|
|
9
|
+
export declare function renderWhatsNew(changelog: string, fromVersion: string, toVersion: string): string[];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { compareVersions } from './agent-spec/primitives.js';
|
|
3
|
+
/**
|
|
4
|
+
* Render a compact "What's new" summary from a CHANGELOG.md body: one bullet
|
|
5
|
+
* per feature/fix heading (the `**...**` lines) for each version in the range
|
|
6
|
+
* the user actually moved through, `(fromVersion, toVersion]`. The verbose
|
|
7
|
+
* sub-bullets are intentionally dropped — the full notes live in the changelog.
|
|
8
|
+
*
|
|
9
|
+
* Returns colored lines ready to print, empty when nothing is in range.
|
|
10
|
+
*/
|
|
11
|
+
export function renderWhatsNew(changelog, fromVersion, toVersion) {
|
|
12
|
+
const out = [];
|
|
13
|
+
let inRelevantSection = false;
|
|
14
|
+
for (const line of changelog.split('\n')) {
|
|
15
|
+
const versionMatch = line.match(/^## (\d+\.\d+\.\d+)/);
|
|
16
|
+
if (versionMatch) {
|
|
17
|
+
const currentVersion = versionMatch[1];
|
|
18
|
+
// Bounding the top end matters when upgrading to a specific older
|
|
19
|
+
// version, and guards against a changelog that lists unreleased entries.
|
|
20
|
+
inRelevantSection =
|
|
21
|
+
compareVersions(currentVersion, fromVersion) > 0 &&
|
|
22
|
+
compareVersions(currentVersion, toVersion) <= 0;
|
|
23
|
+
if (inRelevantSection) {
|
|
24
|
+
out.push('');
|
|
25
|
+
out.push(chalk.bold(`v${currentVersion}`));
|
|
26
|
+
}
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
// Only the bold headings — one bullet per feature/fix.
|
|
30
|
+
if (inRelevantSection && line.startsWith('**') && line.endsWith('**')) {
|
|
31
|
+
out.push(` ${chalk.cyan('•')} ${line.replace(/\*\*/g, '')}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phnx-labs/agents-cli",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.35",
|
|
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",
|