@phnx-labs/agents-cli 1.20.32 → 1.20.34
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 +7 -0
- package/README.md +28 -2
- package/dist/commands/commands.js +3 -3
- package/dist/commands/computer-actions.js +1 -0
- package/dist/commands/computer.d.ts +23 -0
- package/dist/commands/computer.js +45 -3
- package/dist/commands/cost.js +2 -2
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.js +51 -2
- package/dist/commands/exec.js +56 -1
- package/dist/commands/hooks.js +3 -3
- package/dist/commands/import.js +1 -1
- package/dist/commands/inspect.js +13 -17
- package/dist/commands/mcp.js +3 -3
- package/dist/commands/permissions.js +3 -3
- package/dist/commands/rules.js +3 -3
- package/dist/commands/secrets-migrate.js +23 -11
- package/dist/commands/secrets.d.ts +20 -0
- package/dist/commands/secrets.js +53 -1
- package/dist/commands/sessions.js +18 -1
- package/dist/commands/skills.js +3 -3
- package/dist/commands/status.d.ts +12 -0
- package/dist/commands/status.js +81 -0
- package/dist/commands/sync.js +2 -2
- package/dist/commands/teams.js +77 -18
- package/dist/commands/usage.js +2 -2
- package/dist/commands/utils.d.ts +8 -0
- package/dist/commands/utils.js +20 -0
- package/dist/commands/versions.js +4 -3
- package/dist/commands/view.d.ts +39 -0
- package/dist/commands/view.js +217 -84
- package/dist/commands/workflows.js +3 -3
- package/dist/index.js +16 -2
- package/dist/lib/acp/harnesses.d.ts +1 -1
- package/dist/lib/acp/harnesses.js +2 -2
- package/dist/lib/agent-spec/index.d.ts +18 -0
- package/dist/lib/agent-spec/index.js +35 -0
- package/dist/lib/agent-spec/primitives.d.ts +28 -0
- package/dist/lib/agent-spec/primitives.js +57 -0
- package/dist/lib/agent-spec/provider.d.ts +2 -0
- package/dist/lib/agent-spec/provider.js +9 -0
- package/dist/lib/agent-spec/resolve.d.ts +33 -0
- package/dist/lib/agent-spec/resolve.js +174 -0
- package/dist/lib/agent-spec/types.d.ts +57 -0
- package/dist/lib/agent-spec/types.js +18 -0
- package/dist/lib/agents.d.ts +12 -0
- package/dist/lib/agents.js +115 -32
- package/dist/lib/browser/chrome.js +20 -0
- package/dist/lib/browser/drivers/ssh.d.ts +19 -0
- package/dist/lib/browser/drivers/ssh.js +18 -3
- package/dist/lib/crabbox/cli.d.ts +98 -0
- package/dist/lib/crabbox/cli.js +218 -0
- package/dist/lib/crabbox/lease.d.ts +41 -0
- package/dist/lib/crabbox/lease.js +73 -0
- package/dist/lib/crabbox/runtimes.d.ts +57 -0
- package/dist/lib/crabbox/runtimes.js +109 -0
- 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/exec.d.ts +15 -0
- package/dist/lib/exec.js +21 -11
- package/dist/lib/hosts/dispatch.d.ts +27 -10
- package/dist/lib/hosts/dispatch.js +55 -19
- package/dist/lib/hosts/option.d.ts +14 -0
- package/dist/lib/hosts/option.js +19 -0
- package/dist/lib/hosts/passthrough.d.ts +30 -0
- package/dist/lib/hosts/passthrough.js +141 -0
- package/dist/lib/hosts/remote-cmd.d.ts +36 -0
- package/dist/lib/hosts/remote-cmd.js +56 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/platform/winpath.d.ts +31 -2
- package/dist/lib/platform/winpath.js +133 -24
- 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 +61 -21
- package/dist/lib/secrets/filestore.js +31 -1
- package/dist/lib/secrets/index.d.ts +44 -1
- package/dist/lib/secrets/index.js +108 -10
- package/dist/lib/secrets/linux.d.ts +14 -0
- package/dist/lib/secrets/linux.js +21 -0
- package/dist/lib/secrets/windows.d.ts +74 -0
- package/dist/lib/secrets/windows.js +440 -0
- package/dist/lib/session/active.d.ts +8 -0
- package/dist/lib/session/active.js +18 -1
- package/dist/lib/session/provenance.d.ts +56 -0
- package/dist/lib/session/provenance.js +157 -0
- package/dist/lib/shims.d.ts +20 -0
- package/dist/lib/shims.js +53 -20
- package/dist/lib/ssh-exec.d.ts +22 -0
- package/dist/lib/ssh-exec.js +59 -2
- package/dist/lib/ssh-tunnel.d.ts +0 -5
- package/dist/lib/ssh-tunnel.js +65 -8
- package/dist/lib/startup/command-registry.d.ts +1 -0
- package/dist/lib/startup/command-registry.js +2 -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/types.d.ts +20 -1
- package/dist/lib/usage.d.ts +30 -0
- package/dist/lib/usage.js +159 -2
- package/dist/lib/versions.d.ts +2 -4
- package/dist/lib/versions.js +7 -20
- package/package.json +2 -1
- package/dist/lib/agent-spec.d.ts +0 -36
- package/dist/lib/agent-spec.js +0 -157
package/dist/commands/view.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import type { Command } from 'commander';
|
|
10
10
|
import type { AgentId } from '../lib/types.js';
|
|
11
11
|
import { type ProfileSummary } from '../lib/profiles.js';
|
|
12
|
+
type SyncState = 'synced' | 'new' | 'modified' | 'deleted';
|
|
12
13
|
/** Per-section filter flags. When any are true, only those sections render. */
|
|
13
14
|
export interface ViewSectionFilter {
|
|
14
15
|
commands?: boolean;
|
|
@@ -27,6 +28,7 @@ export interface ViewJsonVersion {
|
|
|
27
28
|
isDefault: boolean;
|
|
28
29
|
signedIn: boolean;
|
|
29
30
|
email: string | null;
|
|
31
|
+
accountId?: string | null;
|
|
30
32
|
plan: string | null;
|
|
31
33
|
usageStatus: 'available' | 'rate_limited' | 'out_of_credits' | null;
|
|
32
34
|
overageCredits?: {
|
|
@@ -40,6 +42,9 @@ export interface ViewJsonVersion {
|
|
|
40
42
|
}>;
|
|
41
43
|
lastActive: string | null;
|
|
42
44
|
path: string;
|
|
45
|
+
/** Present only when --resources / --detailed (or --json with a section
|
|
46
|
+
* flag) is passed: this version's resource inventory with git sync-state. */
|
|
47
|
+
resources?: VersionResourcesJson;
|
|
43
48
|
}
|
|
44
49
|
/** Machine-readable entry for one agent's installed versions. */
|
|
45
50
|
export interface ViewJsonAgent {
|
|
@@ -47,6 +52,37 @@ export interface ViewJsonAgent {
|
|
|
47
52
|
versions: ViewJsonVersion[];
|
|
48
53
|
profiles: ProfileSummary[];
|
|
49
54
|
}
|
|
55
|
+
/** Resource sections that --resources can include in --json output. */
|
|
56
|
+
export type ResourceSection = 'commands' | 'skills' | 'mcp' | 'memory' | 'hooks' | 'workflows' | 'plugins';
|
|
57
|
+
/** One resource entry in `--json --resources` output. */
|
|
58
|
+
export interface ResourceItemJson {
|
|
59
|
+
name: string;
|
|
60
|
+
scope?: 'user' | 'project';
|
|
61
|
+
/** Git sync-state vs ~/.agents. Omitted for project-scoped resources or when
|
|
62
|
+
* ~/.agents isn't a git repo. When queried via --host it reflects the
|
|
63
|
+
* remote's ~/.agents — i.e. per-host resource drift. */
|
|
64
|
+
syncState?: SyncState;
|
|
65
|
+
description?: string;
|
|
66
|
+
/** Skills only, when > 0. */
|
|
67
|
+
ruleCount?: number;
|
|
68
|
+
}
|
|
69
|
+
/** Per-version resource inventory; one key per requested section. */
|
|
70
|
+
export interface VersionResourcesJson {
|
|
71
|
+
commands?: ResourceItemJson[];
|
|
72
|
+
skills?: ResourceItemJson[];
|
|
73
|
+
mcp?: ResourceItemJson[];
|
|
74
|
+
memory?: ResourceItemJson[];
|
|
75
|
+
hooks?: ResourceItemJson[];
|
|
76
|
+
workflows?: ResourceItemJson[];
|
|
77
|
+
plugins?: ResourceItemJson[];
|
|
78
|
+
}
|
|
79
|
+
/** Build the set of resource sections to include in `--json` from the
|
|
80
|
+
* `--resources` / `--detailed` flags, plus (in --json mode) the per-section
|
|
81
|
+
* boolean filters (`--skills` etc.) that plain `--json` historically ignored. */
|
|
82
|
+
export declare function parseResourceSections(options: {
|
|
83
|
+
resources?: string | boolean;
|
|
84
|
+
detailed?: boolean;
|
|
85
|
+
} & ViewSectionFilter, jsonMode: boolean): Set<ResourceSection>;
|
|
50
86
|
/**
|
|
51
87
|
* Prune older installed versions that share an email with a newer installed
|
|
52
88
|
* version. Keeps the highest semver per email, skips the global default (with
|
|
@@ -66,6 +102,9 @@ export declare function viewAction(agentArg?: string, options?: {
|
|
|
66
102
|
prune?: boolean;
|
|
67
103
|
yes?: boolean;
|
|
68
104
|
dryRun?: boolean;
|
|
105
|
+
resources?: string | boolean;
|
|
106
|
+
detailed?: boolean;
|
|
69
107
|
} & ViewSectionFilter): Promise<void>;
|
|
70
108
|
/** Register the `agents view` command. */
|
|
71
109
|
export declare function registerViewCommand(program: Command): void;
|
|
110
|
+
export {};
|
package/dist/commands/view.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { addHostOption } from '../lib/hosts/option.js';
|
|
1
2
|
import chalk from 'chalk';
|
|
2
3
|
import ora from 'ora';
|
|
3
4
|
import * as fs from 'fs';
|
|
@@ -5,9 +6,10 @@ import * as path from 'path';
|
|
|
5
6
|
import { AGENTS, ALL_AGENT_IDS, getAllCliStates, getAccountInfo, resolveAgentName, formatAgentError, agentLabel, colorAgent, } from '../lib/agents.js';
|
|
6
7
|
import { deriveUsageStatusFromSnapshot, formatUsageSection, formatUsageSummary, formatUsageStatusBadge, getUsageInfoForIdentity, getUsageInfoByIdentity, getUsageLookupKey, } from '../lib/usage.js';
|
|
7
8
|
import { readManifest } from '../lib/manifest.js';
|
|
8
|
-
import { listInstalledVersions, listInstalledVersionDirs, getGlobalDefault, getVersionHomePath, getVersionDir,
|
|
9
|
+
import { listInstalledVersions, listInstalledVersionDirs, getGlobalDefault, getVersionHomePath, getVersionDir, getAvailableResources, getActuallySyncedResources, getNewResources, getProjectOnlyResources, hasNewResources, promptNewResourceSelection, syncResourcesToVersion, removeVersion, printTrashFooter, reconcileStaleLatestForAgent, } from '../lib/versions.js';
|
|
9
10
|
import { ensureVersionedAliasCurrent, removeShim, } from '../lib/shims.js';
|
|
10
11
|
import { getAgentResources } from '../lib/resources.js';
|
|
12
|
+
import { resolveVersionFilter, AgentSpecError } from '../lib/agent-spec/index.js';
|
|
11
13
|
import { listCliStatus } from '../lib/cli-resources.js';
|
|
12
14
|
import { isCapable } from '../lib/capabilities.js';
|
|
13
15
|
import { discoverPlugins, pluginSupportsAgent } from '../lib/plugins.js';
|
|
@@ -22,8 +24,24 @@ import { loadManifest, isStale } from '../lib/staleness/index.js';
|
|
|
22
24
|
import { confirm } from '@inquirer/prompts';
|
|
23
25
|
import { formatPath, isInteractiveTerminal, isPromptCancelled } from './utils.js';
|
|
24
26
|
// Shown in the email column for agents that are signed in but expose no email
|
|
25
|
-
// address locally (Antigravity
|
|
27
|
+
// address locally (Antigravity stores an opaque OAuth grant with no identity).
|
|
26
28
|
const SIGNED_IN_LABEL = 'signed in';
|
|
29
|
+
/**
|
|
30
|
+
* Text for the account (email) column. Prefers the real email; otherwise, for a
|
|
31
|
+
* signed-in agent whose credential carries no email but does carry an opaque
|
|
32
|
+
* account id (Kimi's user_id), show `id:<user_id>` so distinct accounts read
|
|
33
|
+
* distinctly instead of a generic "signed in". Falls back to "signed in" when we
|
|
34
|
+
* have neither (Antigravity), and empty when signed out.
|
|
35
|
+
*/
|
|
36
|
+
function accountColumnLabel(info) {
|
|
37
|
+
if (!info)
|
|
38
|
+
return '';
|
|
39
|
+
if (info.email)
|
|
40
|
+
return info.email;
|
|
41
|
+
if (info.signedIn)
|
|
42
|
+
return info.accountId ? `id:${info.accountId}` : SIGNED_IN_LABEL;
|
|
43
|
+
return '';
|
|
44
|
+
}
|
|
27
45
|
/**
|
|
28
46
|
* Group profile summaries by their host harness, optionally filtered to a
|
|
29
47
|
* single agent. Profile YAMLs that fail validation are silently skipped by
|
|
@@ -308,7 +326,10 @@ async function showInstalledVersions(filterAgentId) {
|
|
|
308
326
|
return info;
|
|
309
327
|
return {
|
|
310
328
|
...info,
|
|
311
|
-
plan
|
|
329
|
+
// Prefer a plan the live usage fetch surfaced (Kimi reports membership
|
|
330
|
+
// tier in /usages; its local auth file has none) and fall back to the
|
|
331
|
+
// account-derived plan (Claude's billingType).
|
|
332
|
+
plan: usageByKey.get(key)?.snapshot?.plan ?? canon.plan,
|
|
312
333
|
// Throttle state comes from the live usage windows, not the pay-as-you-go
|
|
313
334
|
// overage flag that AccountInfo.usageStatus used to carry. A maxed window
|
|
314
335
|
// means rate-limited; no snapshot means no badge. See
|
|
@@ -351,10 +372,9 @@ async function showInstalledVersions(filterAgentId) {
|
|
|
351
372
|
maxVerLabel = Math.max(maxVerLabel, label.length);
|
|
352
373
|
const rawInfo = infoMap.get(`${agentId}:${v}`);
|
|
353
374
|
const info = rawInfo ? mergeCanonical(rawInfo) : undefined;
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
maxEmail = Math.max(maxEmail, SIGNED_IN_LABEL.length);
|
|
375
|
+
const accountLabel = accountColumnLabel(info);
|
|
376
|
+
if (accountLabel)
|
|
377
|
+
maxEmail = Math.max(maxEmail, accountLabel.length);
|
|
358
378
|
if (info?.plan)
|
|
359
379
|
maxPlanWidth = Math.max(maxPlanWidth, info.plan.length);
|
|
360
380
|
}
|
|
@@ -430,9 +450,10 @@ async function showInstalledVersions(filterAgentId) {
|
|
|
430
450
|
}
|
|
431
451
|
else {
|
|
432
452
|
if (hasEmail || hasUsage || hasActive || signedIn) {
|
|
433
|
-
// Signed-in agents without a local email
|
|
434
|
-
// "signed in" placeholder so they
|
|
435
|
-
|
|
453
|
+
// Signed-in agents without a local email show their account id
|
|
454
|
+
// (Kimi's user_id) or a "signed in" placeholder (Antigravity) so they
|
|
455
|
+
// read as logged in, not blank.
|
|
456
|
+
const display = accountColumnLabel(vInfo);
|
|
436
457
|
const emailCol = display.padEnd(maxEmail);
|
|
437
458
|
parts.push(display ? chalk.cyan(emailCol) : ' '.repeat(maxEmail));
|
|
438
459
|
}
|
|
@@ -513,7 +534,7 @@ async function showInstalledVersions(filterAgentId) {
|
|
|
513
534
|
const gUsageStr = formatUsageSummary(gInfo?.plan || null, gUsage?.snapshot || null);
|
|
514
535
|
const gActiveStr = gInfo ? formatLastActive(gInfo.lastActive) : '';
|
|
515
536
|
if (gInfo?.email || gUsageStr || gActiveStr || gInfo?.signedIn) {
|
|
516
|
-
const gDisplay =
|
|
537
|
+
const gDisplay = accountColumnLabel(gInfo);
|
|
517
538
|
parts.push(gDisplay ? chalk.cyan(gDisplay) : '');
|
|
518
539
|
}
|
|
519
540
|
if (gUsageStr || gActiveStr)
|
|
@@ -684,53 +705,9 @@ async function showAgentResources(agentId, requestedVersion, filter) {
|
|
|
684
705
|
}
|
|
685
706
|
}
|
|
686
707
|
const home = getVersionHomePath(agentId, version);
|
|
687
|
-
//
|
|
688
|
-
|
|
689
|
-
const hasGitRepo =
|
|
690
|
-
const commandsSync = hasGitRepo ? await getGitSyncStatus(userAgentsDir, 'commands') : null;
|
|
691
|
-
const skillsSync = hasGitRepo ? await getGitSyncStatus(userAgentsDir, 'skills') : null;
|
|
692
|
-
const hooksSync = hasGitRepo ? await getGitSyncStatus(userAgentsDir, 'hooks') : null;
|
|
693
|
-
const memorySync = hasGitRepo ? await getGitSyncStatus(userAgentsDir, 'rules') : null;
|
|
694
|
-
// Helper to determine sync state for a resource
|
|
695
|
-
const getSyncState = (resourceName, resourceType, syncStatus) => {
|
|
696
|
-
if (!syncStatus)
|
|
697
|
-
return undefined;
|
|
698
|
-
let relativePath;
|
|
699
|
-
if (resourceType === 'commands') {
|
|
700
|
-
relativePath = `commands/${resourceName}.md`;
|
|
701
|
-
}
|
|
702
|
-
else if (resourceType === 'skills') {
|
|
703
|
-
relativePath = `skills/${resourceName}`;
|
|
704
|
-
}
|
|
705
|
-
else if (resourceType === 'hooks') {
|
|
706
|
-
relativePath = `hooks/${resourceName}`;
|
|
707
|
-
}
|
|
708
|
-
else {
|
|
709
|
-
// Rules files: map agent-specific name (CLAUDE.md) back to canonical (AGENTS.md)
|
|
710
|
-
const centralName = getCentralRulesFileName(agentId);
|
|
711
|
-
relativePath = `rules/${centralName}`;
|
|
712
|
-
}
|
|
713
|
-
const matchesPath = (f) => f === relativePath || f.startsWith(relativePath + '/');
|
|
714
|
-
const isNew = syncStatus.new.some(matchesPath);
|
|
715
|
-
const isStaged = syncStatus.staged.some(matchesPath);
|
|
716
|
-
const isModified = syncStatus.modified.some(matchesPath);
|
|
717
|
-
const isDeleted = syncStatus.deleted.some(matchesPath);
|
|
718
|
-
const isSynced = syncStatus.synced.some(matchesPath);
|
|
719
|
-
if (isNew || isStaged) {
|
|
720
|
-
return 'new';
|
|
721
|
-
}
|
|
722
|
-
if (isModified) {
|
|
723
|
-
return 'modified';
|
|
724
|
-
}
|
|
725
|
-
if (isDeleted) {
|
|
726
|
-
return 'deleted';
|
|
727
|
-
}
|
|
728
|
-
if (isSynced) {
|
|
729
|
-
return 'synced';
|
|
730
|
-
}
|
|
731
|
-
// Not in any array = local-only (untracked with no files)
|
|
732
|
-
return 'new';
|
|
733
|
-
};
|
|
708
|
+
// Git sync status if ~/.agents/ is a git repo (shared loader — see
|
|
709
|
+
// loadResourceSyncData / resolveResourceSyncState, reused by --json --resources).
|
|
710
|
+
const { hasGitRepo, commands: commandsSync, skills: skillsSync, hooks: hooksSync, memory: memorySync } = await loadResourceSyncData();
|
|
734
711
|
const resources = getAgentResources(agentId, {
|
|
735
712
|
cwd,
|
|
736
713
|
scope: 'all',
|
|
@@ -743,23 +720,23 @@ async function showAgentResources(agentId, requestedVersion, filter) {
|
|
|
743
720
|
version,
|
|
744
721
|
commands: resources.commands.map(r => ({
|
|
745
722
|
...r,
|
|
746
|
-
syncState: r.scope === 'project' ? undefined :
|
|
723
|
+
syncState: r.scope === 'project' ? undefined : resolveResourceSyncState(agentId, r.name, 'commands', commandsSync),
|
|
747
724
|
})),
|
|
748
725
|
skills: resources.skills.map(r => ({
|
|
749
726
|
...r,
|
|
750
727
|
// ruleCount of 0 is noise — every skill has 0 unless it ships subrules, which is rare.
|
|
751
728
|
ruleCount: r.ruleCount && r.ruleCount > 0 ? r.ruleCount : undefined,
|
|
752
|
-
syncState: r.scope === 'project' ? undefined :
|
|
729
|
+
syncState: r.scope === 'project' ? undefined : resolveResourceSyncState(agentId, r.name, 'skills', skillsSync),
|
|
753
730
|
})),
|
|
754
731
|
skillErrors: resources.skillErrors,
|
|
755
732
|
mcp: resources.mcp.map(r => ({ name: r.name, scope: r.scope, syncState: r.scope === 'project' ? undefined : 'synced' })),
|
|
756
733
|
memory: resources.memory.map(r => ({
|
|
757
734
|
...r,
|
|
758
|
-
syncState: r.scope === 'project' ? undefined :
|
|
735
|
+
syncState: r.scope === 'project' ? undefined : resolveResourceSyncState(agentId, r.name, 'memory', memorySync),
|
|
759
736
|
})),
|
|
760
737
|
hooks: resources.hooks.map(r => ({
|
|
761
738
|
...r,
|
|
762
|
-
syncState: r.scope === 'project' ? undefined :
|
|
739
|
+
syncState: r.scope === 'project' ? undefined : resolveResourceSyncState(agentId, r.name, 'hooks', hooksSync),
|
|
763
740
|
})),
|
|
764
741
|
workflows: resources.workflows.map(r => ({ name: r.name, path: r.path, scope: r.scope })),
|
|
765
742
|
};
|
|
@@ -825,13 +802,10 @@ async function showAgentResources(agentId, requestedVersion, filter) {
|
|
|
825
802
|
cliVersion: version,
|
|
826
803
|
info: accountInfo,
|
|
827
804
|
});
|
|
828
|
-
const
|
|
829
|
-
|
|
830
|
-
: accountInfo.signedIn
|
|
831
|
-
? chalk.cyan(` ${SIGNED_IN_LABEL}`)
|
|
832
|
-
: '';
|
|
805
|
+
const accountLabel = accountColumnLabel(accountInfo);
|
|
806
|
+
const emailStr = accountLabel ? chalk.cyan(` ${accountLabel}`) : '';
|
|
833
807
|
const status = chalk.green(version);
|
|
834
|
-
const usageStr = formatUsageSummary(accountInfo.plan, null);
|
|
808
|
+
const usageStr = formatUsageSummary(usageInfo.snapshot?.plan ?? accountInfo.plan, null);
|
|
835
809
|
const usagePart = usageStr ? ` ${usageStr}` : '';
|
|
836
810
|
console.log(` ${colorAgent(agentId)(AGENTS[agentId].name.padEnd(14))} ${status}${emailStr}${usagePart}`);
|
|
837
811
|
const usageLines = formatUsageSection(usageInfo);
|
|
@@ -971,14 +945,144 @@ async function showAgentResources(agentId, requestedVersion, filter) {
|
|
|
971
945
|
console.log(chalk.gray('Legend:'), chalk.green('Tracked'), chalk.blue('Local-only'), chalk.yellow('Modified'), chalk.red('Deleted'));
|
|
972
946
|
}
|
|
973
947
|
}
|
|
948
|
+
const ALL_RESOURCE_SECTIONS = ['commands', 'skills', 'mcp', 'memory', 'hooks', 'workflows', 'plugins'];
|
|
949
|
+
/** Load git sync-state for the tracked resource kinds. Shared by the human
|
|
950
|
+
* detail view (showAgentResources) and the `--json --resources` path. */
|
|
951
|
+
async function loadResourceSyncData() {
|
|
952
|
+
const userAgentsDir = getUserAgentsDir();
|
|
953
|
+
const hasGitRepo = isGitRepo(userAgentsDir);
|
|
954
|
+
return {
|
|
955
|
+
hasGitRepo,
|
|
956
|
+
commands: hasGitRepo ? await getGitSyncStatus(userAgentsDir, 'commands') : null,
|
|
957
|
+
skills: hasGitRepo ? await getGitSyncStatus(userAgentsDir, 'skills') : null,
|
|
958
|
+
hooks: hasGitRepo ? await getGitSyncStatus(userAgentsDir, 'hooks') : null,
|
|
959
|
+
memory: hasGitRepo ? await getGitSyncStatus(userAgentsDir, 'rules') : null,
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
/** Resolve one resource's git sync-state. Extracted from showAgentResources so
|
|
963
|
+
* the human view and the JSON path derive drift identically. */
|
|
964
|
+
function resolveResourceSyncState(agentId, resourceName, resourceType, syncStatus) {
|
|
965
|
+
if (!syncStatus)
|
|
966
|
+
return undefined;
|
|
967
|
+
let relativePath;
|
|
968
|
+
if (resourceType === 'commands') {
|
|
969
|
+
relativePath = `commands/${resourceName}.md`;
|
|
970
|
+
}
|
|
971
|
+
else if (resourceType === 'skills') {
|
|
972
|
+
relativePath = `skills/${resourceName}`;
|
|
973
|
+
}
|
|
974
|
+
else if (resourceType === 'hooks') {
|
|
975
|
+
relativePath = `hooks/${resourceName}`;
|
|
976
|
+
}
|
|
977
|
+
else {
|
|
978
|
+
// Rules files: map agent-specific name (CLAUDE.md) back to canonical (AGENTS.md)
|
|
979
|
+
const centralName = getCentralRulesFileName(agentId);
|
|
980
|
+
relativePath = `rules/${centralName}`;
|
|
981
|
+
}
|
|
982
|
+
const matchesPath = (f) => f === relativePath || f.startsWith(relativePath + '/');
|
|
983
|
+
if (syncStatus.new.some(matchesPath) || syncStatus.staged.some(matchesPath))
|
|
984
|
+
return 'new';
|
|
985
|
+
if (syncStatus.modified.some(matchesPath))
|
|
986
|
+
return 'modified';
|
|
987
|
+
if (syncStatus.deleted.some(matchesPath))
|
|
988
|
+
return 'deleted';
|
|
989
|
+
if (syncStatus.synced.some(matchesPath))
|
|
990
|
+
return 'synced';
|
|
991
|
+
// Not in any array = local-only (untracked with no files)
|
|
992
|
+
return 'new';
|
|
993
|
+
}
|
|
994
|
+
/** Collect one version's resources for `--json`, limited to `sections`. Scans
|
|
995
|
+
* the version's `home`, so per-version differences are reported accurately. */
|
|
996
|
+
function collectVersionResources(agentId, home, cwd, cliInstalled, sections, sync) {
|
|
997
|
+
const res = getAgentResources(agentId, { cwd, scope: 'all', cliInstalled, home });
|
|
998
|
+
const out = {};
|
|
999
|
+
const withSync = (r, type, syncStatus) => {
|
|
1000
|
+
const item = { name: r.name, scope: r.scope };
|
|
1001
|
+
if (r.scope !== 'project') {
|
|
1002
|
+
const s = resolveResourceSyncState(agentId, r.name, type, syncStatus);
|
|
1003
|
+
if (s)
|
|
1004
|
+
item.syncState = s;
|
|
1005
|
+
}
|
|
1006
|
+
if (r.description)
|
|
1007
|
+
item.description = r.description;
|
|
1008
|
+
return item;
|
|
1009
|
+
};
|
|
1010
|
+
if (sections.has('commands'))
|
|
1011
|
+
out.commands = res.commands.map((r) => withSync(r, 'commands', sync.commands));
|
|
1012
|
+
if (sections.has('skills')) {
|
|
1013
|
+
out.skills = res.skills.map((r) => {
|
|
1014
|
+
const item = withSync(r, 'skills', sync.skills);
|
|
1015
|
+
// ruleCount of 0 is noise — every skill has 0 unless it ships subrules.
|
|
1016
|
+
if (r.ruleCount && r.ruleCount > 0)
|
|
1017
|
+
item.ruleCount = r.ruleCount;
|
|
1018
|
+
return item;
|
|
1019
|
+
});
|
|
1020
|
+
}
|
|
1021
|
+
if (sections.has('mcp')) {
|
|
1022
|
+
out.mcp = res.mcp.map((r) => {
|
|
1023
|
+
const item = { name: r.name, scope: r.scope };
|
|
1024
|
+
if (r.scope !== 'project')
|
|
1025
|
+
item.syncState = 'synced';
|
|
1026
|
+
return item;
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
if (sections.has('memory'))
|
|
1030
|
+
out.memory = res.memory.map((r) => withSync(r, 'memory', sync.memory));
|
|
1031
|
+
if (sections.has('hooks'))
|
|
1032
|
+
out.hooks = res.hooks.map((r) => withSync(r, 'hooks', sync.hooks));
|
|
1033
|
+
if (sections.has('workflows'))
|
|
1034
|
+
out.workflows = res.workflows.map((r) => ({ name: r.name, scope: r.scope }));
|
|
1035
|
+
if (sections.has('plugins')) {
|
|
1036
|
+
out.plugins = discoverPlugins()
|
|
1037
|
+
.filter((p) => pluginSupportsAgent(p, agentId))
|
|
1038
|
+
.map((p) => ({ name: p.name }));
|
|
1039
|
+
}
|
|
1040
|
+
return out;
|
|
1041
|
+
}
|
|
1042
|
+
/** Build the set of resource sections to include in `--json` from the
|
|
1043
|
+
* `--resources` / `--detailed` flags, plus (in --json mode) the per-section
|
|
1044
|
+
* boolean filters (`--skills` etc.) that plain `--json` historically ignored. */
|
|
1045
|
+
export function parseResourceSections(options, jsonMode) {
|
|
1046
|
+
const set = new Set();
|
|
1047
|
+
const addAll = () => ALL_RESOURCE_SECTIONS.forEach((s) => set.add(s));
|
|
1048
|
+
if (options.detailed)
|
|
1049
|
+
addAll();
|
|
1050
|
+
const rv = options.resources;
|
|
1051
|
+
if (rv !== undefined) {
|
|
1052
|
+
if (rv === true || String(rv).trim() === '' || String(rv).toLowerCase() === 'all') {
|
|
1053
|
+
addAll();
|
|
1054
|
+
}
|
|
1055
|
+
else {
|
|
1056
|
+
for (const raw of String(rv).split(',').map((s) => s.trim().toLowerCase()).filter(Boolean)) {
|
|
1057
|
+
const section = raw === 'rules' ? 'memory' : raw; // --rules is the memory file
|
|
1058
|
+
if (ALL_RESOURCE_SECTIONS.includes(section))
|
|
1059
|
+
set.add(section);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
if (jsonMode) {
|
|
1064
|
+
const flagToSection = [
|
|
1065
|
+
['commands', 'commands'], ['skills', 'skills'], ['mcp', 'mcp'],
|
|
1066
|
+
['workflows', 'workflows'], ['plugins', 'plugins'], ['hooks', 'hooks'], ['rules', 'memory'],
|
|
1067
|
+
];
|
|
1068
|
+
for (const [flag, section] of flagToSection)
|
|
1069
|
+
if (options[flag])
|
|
1070
|
+
set.add(section);
|
|
1071
|
+
}
|
|
1072
|
+
return set;
|
|
1073
|
+
}
|
|
974
1074
|
/**
|
|
975
1075
|
* Collect structured info for one or more agents without rendering to the
|
|
976
1076
|
* terminal. Used by `--json` output and any programmatic consumer (e.g. the
|
|
977
1077
|
* agents-cli extension's "resume current session in best available version"
|
|
978
1078
|
* command).
|
|
979
1079
|
*/
|
|
980
|
-
async function collectAgentsJson(filterAgentId) {
|
|
1080
|
+
async function collectAgentsJson(filterAgentId, resourceSections) {
|
|
981
1081
|
const agentsToShow = filterAgentId ? [filterAgentId] : ALL_AGENT_IDS;
|
|
1082
|
+
const wantResources = !!resourceSections && resourceSections.size > 0;
|
|
1083
|
+
// Only pay for the git-status + resource scans when resources were requested.
|
|
1084
|
+
const resourceSync = wantResources ? await loadResourceSyncData() : null;
|
|
1085
|
+
const cliStates = wantResources ? await getAllCliStates() : null;
|
|
982
1086
|
const infoFetches = [];
|
|
983
1087
|
for (const agentId of agentsToShow) {
|
|
984
1088
|
for (const ver of listInstalledVersions(agentId)) {
|
|
@@ -1002,7 +1106,10 @@ async function collectAgentsJson(filterAgentId) {
|
|
|
1002
1106
|
return info;
|
|
1003
1107
|
return {
|
|
1004
1108
|
...info,
|
|
1005
|
-
plan
|
|
1109
|
+
// Prefer a plan the live usage fetch surfaced (Kimi reports membership
|
|
1110
|
+
// tier in /usages; its local auth file has none) and fall back to the
|
|
1111
|
+
// account-derived plan (Claude's billingType).
|
|
1112
|
+
plan: usageByKey.get(key)?.snapshot?.plan ?? canon.plan,
|
|
1006
1113
|
// Throttle state comes from the live usage windows, not the pay-as-you-go
|
|
1007
1114
|
// overage flag that AccountInfo.usageStatus used to carry. A maxed window
|
|
1008
1115
|
// means rate-limited; no snapshot means no badge. See
|
|
@@ -1012,7 +1119,7 @@ async function collectAgentsJson(filterAgentId) {
|
|
|
1012
1119
|
};
|
|
1013
1120
|
};
|
|
1014
1121
|
const byAgent = new Map();
|
|
1015
|
-
for (const { agentId, version, info: rawInfo } of infoResults) {
|
|
1122
|
+
for (const { agentId, version, home, info: rawInfo } of infoResults) {
|
|
1016
1123
|
const info = mergeCanonical(rawInfo);
|
|
1017
1124
|
const globalDefault = getGlobalDefault(agentId);
|
|
1018
1125
|
const usageKey = getUsageLookupKey(info);
|
|
@@ -1023,6 +1130,7 @@ async function collectAgentsJson(filterAgentId) {
|
|
|
1023
1130
|
isDefault: version === globalDefault,
|
|
1024
1131
|
signedIn: info.signedIn,
|
|
1025
1132
|
email: info.email,
|
|
1133
|
+
accountId: info.accountId,
|
|
1026
1134
|
plan: info.plan,
|
|
1027
1135
|
usageStatus: info.usageStatus,
|
|
1028
1136
|
overageCredits: info.overageCredits,
|
|
@@ -1036,6 +1144,9 @@ async function collectAgentsJson(filterAgentId) {
|
|
|
1036
1144
|
lastActive: info.lastActive ? info.lastActive.toISOString() : null,
|
|
1037
1145
|
path: getVersionDir(agentId, version),
|
|
1038
1146
|
};
|
|
1147
|
+
if (wantResources && resourceSync) {
|
|
1148
|
+
entry.resources = collectVersionResources(agentId, home, process.cwd(), cliStates?.[agentId]?.installed ?? false, resourceSections, resourceSync);
|
|
1149
|
+
}
|
|
1039
1150
|
const existing = byAgent.get(agentId);
|
|
1040
1151
|
if (existing)
|
|
1041
1152
|
existing.push(entry);
|
|
@@ -1246,7 +1357,10 @@ export async function pruneDuplicates(filterAgentId, yes, dryRun) {
|
|
|
1246
1357
|
* Exported for use by deprecated aliases.
|
|
1247
1358
|
*/
|
|
1248
1359
|
export async function viewAction(agentArg, options) {
|
|
1249
|
-
|
|
1360
|
+
// --resources / --detailed imply --json (they only shape structured output).
|
|
1361
|
+
const explicitResources = options?.detailed === true || options?.resources !== undefined;
|
|
1362
|
+
const json = options?.json === true || explicitResources;
|
|
1363
|
+
const resourceSections = parseResourceSections(options ?? {}, json);
|
|
1250
1364
|
const prune = options?.prune === true;
|
|
1251
1365
|
const yes = options?.yes === true;
|
|
1252
1366
|
const dryRun = options?.dryRun === true;
|
|
@@ -1278,7 +1392,7 @@ export async function viewAction(agentArg, options) {
|
|
|
1278
1392
|
return;
|
|
1279
1393
|
}
|
|
1280
1394
|
if (json) {
|
|
1281
|
-
const data = await collectAgentsJson();
|
|
1395
|
+
const data = await collectAgentsJson(undefined, resourceSections);
|
|
1282
1396
|
console.log(JSON.stringify(data, null, 2));
|
|
1283
1397
|
return;
|
|
1284
1398
|
}
|
|
@@ -1298,12 +1412,25 @@ export async function viewAction(agentArg, options) {
|
|
|
1298
1412
|
console.log(chalk.red(formatAgentError(agentName)));
|
|
1299
1413
|
process.exit(1);
|
|
1300
1414
|
}
|
|
1301
|
-
//
|
|
1302
|
-
//
|
|
1303
|
-
//
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1415
|
+
// Resolve the @version filter through the agent-spec engine:
|
|
1416
|
+
// bare/@any → null (show all versions), @default/@pinned → 'default'
|
|
1417
|
+
// (showAgentResources handles it), @latest/@oldest/@x.y.z → concrete.
|
|
1418
|
+
let requestedVersion;
|
|
1419
|
+
try {
|
|
1420
|
+
requestedVersion = resolveVersionFilter(agentId, parts[1]).version;
|
|
1421
|
+
}
|
|
1422
|
+
catch (e) {
|
|
1423
|
+
if (e instanceof AgentSpecError) {
|
|
1424
|
+
if (json) {
|
|
1425
|
+
console.log(JSON.stringify({ error: e.message }));
|
|
1426
|
+
}
|
|
1427
|
+
else {
|
|
1428
|
+
console.log(chalk.red(e.message));
|
|
1429
|
+
}
|
|
1430
|
+
process.exit(1);
|
|
1431
|
+
}
|
|
1432
|
+
throw e;
|
|
1433
|
+
}
|
|
1307
1434
|
if (prune) {
|
|
1308
1435
|
if (requestedVersion) {
|
|
1309
1436
|
console.log(chalk.red('--prune does not take a @version suffix.'));
|
|
@@ -1314,9 +1441,9 @@ export async function viewAction(agentArg, options) {
|
|
|
1314
1441
|
return;
|
|
1315
1442
|
}
|
|
1316
1443
|
if (json) {
|
|
1317
|
-
// --json ignores the @version suffix
|
|
1318
|
-
//
|
|
1319
|
-
const data = await collectAgentsJson(agentId);
|
|
1444
|
+
// --json ignores the @version suffix, but --resources/--detailed (or a
|
|
1445
|
+
// section flag) now attach each version's resource inventory + sync-state.
|
|
1446
|
+
const data = await collectAgentsJson(agentId, resourceSections);
|
|
1320
1447
|
console.log(JSON.stringify(data[0] ?? { agent: agentId, versions: [], profiles: [] }, null, 2));
|
|
1321
1448
|
return;
|
|
1322
1449
|
}
|
|
@@ -1336,10 +1463,11 @@ export async function viewAction(agentArg, options) {
|
|
|
1336
1463
|
}
|
|
1337
1464
|
/** Register the `agents view` command. */
|
|
1338
1465
|
export function registerViewCommand(program) {
|
|
1339
|
-
program
|
|
1340
|
-
.command('view [agent]')
|
|
1466
|
+
addHostOption(program.command('view [agent]'))
|
|
1341
1467
|
.description('Show what agent CLIs are installed and which versions you have. Inspect resources when you pass agent@version.')
|
|
1342
1468
|
.option('--json', 'Emit machine-readable JSON (version list, usage, signed-in status).')
|
|
1469
|
+
.option('--resources [sections]', 'In --json mode, include each version\'s resources: "all" (default) or a comma list (skills,plugins,mcp,commands,workflows,memory,hooks). Implies --json.')
|
|
1470
|
+
.option('--detailed', 'Include all resources in --json output (alias for --resources all). Implies --json.')
|
|
1343
1471
|
.option('--prune', 'Remove older installed versions that share an account with a newer installed version. Skips the global default.')
|
|
1344
1472
|
.option('--dry-run', 'With --prune, show duplicate versions without deleting')
|
|
1345
1473
|
.option('-y, --yes', 'Skip the prune confirmation prompt.')
|
|
@@ -1367,6 +1495,11 @@ Examples:
|
|
|
1367
1495
|
# Machine-readable output (used by tools that pick a version programmatically)
|
|
1368
1496
|
agents view claude --json
|
|
1369
1497
|
|
|
1498
|
+
# One call: full inventory + what's synced on a host (installed agents,
|
|
1499
|
+
# versions, accounts, usage, and per-version resource sync-state)
|
|
1500
|
+
agents view claude --host yosemite-s0 --json --resources all
|
|
1501
|
+
agents view claude --json --resources skills,plugins # just those sections
|
|
1502
|
+
|
|
1370
1503
|
# Prune older versions that duplicate an account already used by a newer version
|
|
1371
1504
|
agents view --prune --dry-run
|
|
1372
1505
|
agents view claude --prune
|
|
@@ -8,9 +8,9 @@ import { resolveAgentName, agentLabel } from '../lib/agents.js';
|
|
|
8
8
|
import { capableAgents } from '../lib/capabilities.js';
|
|
9
9
|
import { cloneRepo } from '../lib/git.js';
|
|
10
10
|
import { discoverWorkflowsFromRepo, installWorkflowCentrally, removeWorkflow, listInstalledWorkflows, listWorkflowsForAgent, removeWorkflowFromVersion, iterWorkflowsCapableVersions, } from '../lib/workflows.js';
|
|
11
|
-
import { getVersionHomePath, getGlobalDefault,
|
|
11
|
+
import { getVersionHomePath, getGlobalDefault, syncResourcesToVersion, promptAgentVersionSelection, } from '../lib/versions.js';
|
|
12
12
|
import { recordVersionResources, getUserWorkflowsDir } from '../lib/state.js';
|
|
13
|
-
import { isPromptCancelled, isInteractiveTerminal, requireInteractiveSelection, printWithPager, promptRemovalTargets, parseCommaSeparatedList, resolveAgentTargetsAutoInstalling, } from './utils.js';
|
|
13
|
+
import { isPromptCancelled, isInteractiveTerminal, requireInteractiveSelection, printWithPager, promptRemovalTargets, parseCommaSeparatedList, resolveAgentTargetsAutoInstalling, resolveListFilterOrExit, } from './utils.js';
|
|
14
14
|
import { showResourceList, buildTargetsSection, } from './resource-view.js';
|
|
15
15
|
/** Register the `agents workflows` command tree (list, view, add, remove). */
|
|
16
16
|
export function registerWorkflowsCommands(program) {
|
|
@@ -73,7 +73,7 @@ Examples:
|
|
|
73
73
|
process.exit(1);
|
|
74
74
|
}
|
|
75
75
|
filterAgent = resolved;
|
|
76
|
-
filterVersion =
|
|
76
|
+
filterVersion = resolveListFilterOrExit(resolved, parts[1]);
|
|
77
77
|
}
|
|
78
78
|
const rows = buildWorkflowRows({ filterAgent, filterVersion });
|
|
79
79
|
spinner.stop();
|
package/dist/index.js
CHANGED
|
@@ -51,7 +51,7 @@ if (IS_DEV_BUILD) {
|
|
|
51
51
|
// module on each invocation (which loaded the whole ~50-module tree before the
|
|
52
52
|
// first byte of output), the registry maps a command name to a thunk that
|
|
53
53
|
// imports only what that command needs. See src/lib/startup/command-registry.ts.
|
|
54
|
-
import { COMMAND_LOADERS, LAZY_COMMAND_NAMES, loadView, loadInspect, loadFeedback, loadCommands, loadHooks, loadSkills, loadRules, loadPermissions, loadMcp, loadCli, loadSubagents, loadPlugins, loadWorkflows, loadWorktree, loadVersions, loadImport, loadPackages, loadDaemon, loadRoutines, loadRun, loadDefaults, loadModels, loadPrune, loadTrash, loadRestore, loadDoctor, loadProfiles, loadSecrets, loadWallet, loadHelper, loadMenubar, loadBeta, loadSync, loadRefreshRules, loadDrive, loadFactory, loadUsage, loadCost, loadBudget, loadAlias, loadPty, loadTmux, loadBrowser, loadComputer, loadHosts, loadSsh, loadPull, loadPush, loadRepo, loadSetup, } from './lib/startup/command-registry.js';
|
|
54
|
+
import { COMMAND_LOADERS, LAZY_COMMAND_NAMES, loadView, loadInspect, loadFeedback, loadCommands, loadHooks, loadSkills, loadRules, loadPermissions, loadMcp, loadCli, loadSubagents, loadPlugins, loadWorkflows, loadWorktree, loadVersions, loadImport, loadPackages, loadDaemon, loadRoutines, loadRun, loadDefaults, loadModels, loadPrune, loadTrash, loadRestore, loadDoctor, loadStatus, loadProfiles, loadSecrets, loadWallet, loadHelper, loadMenubar, loadBeta, loadSync, loadRefreshRules, loadDrive, loadFactory, loadUsage, loadCost, loadBudget, loadAlias, loadPty, loadTmux, loadBrowser, loadComputer, loadHosts, loadSsh, loadPull, loadPush, loadRepo, loadSetup, } from './lib/startup/command-registry.js';
|
|
55
55
|
import { applyGlobalHelpConventions } from './lib/help.js';
|
|
56
56
|
import { IS_WINDOWS } from './lib/platform/index.js';
|
|
57
57
|
// Transparent shim delegate: the generated Windows `.cmd` shims invoke
|
|
@@ -764,6 +764,7 @@ async function registerAllEagerCommands() {
|
|
|
764
764
|
await reg(loadTrash);
|
|
765
765
|
await reg(loadRestore);
|
|
766
766
|
await reg(loadDoctor);
|
|
767
|
+
await reg(loadStatus);
|
|
767
768
|
registerExecAliasCommand(program);
|
|
768
769
|
await reg(loadProfiles);
|
|
769
770
|
await reg(loadSecrets);
|
|
@@ -847,6 +848,18 @@ const requestedCommand = passedArgs.find((arg) => !arg.startsWith('-'));
|
|
|
847
848
|
// Help and version output are pure documentation — they must never gate on
|
|
848
849
|
// setup, otherwise `agents <cmd> --help` becomes useless on a fresh box.
|
|
849
850
|
const helpOrVersionRequested = passedArgs.some((arg) => arg === '--help' || arg === '-h' || arg === '--version' || arg === '-V');
|
|
851
|
+
// `--host` passthrough: run this invocation on a remote machine over SSH instead
|
|
852
|
+
// of locally. Handled before any local command registration / update check /
|
|
853
|
+
// background sync — a remote run needs none of that. Only the allowlisted
|
|
854
|
+
// read-only + config + teams commands route here; `run`/`sessions` are absent
|
|
855
|
+
// from the table and fall through to their own richer `--host` handling below.
|
|
856
|
+
// `--help`/`--version` stay local (docs must work without a reachable host).
|
|
857
|
+
if (requestedCommand !== undefined && !helpOrVersionRequested) {
|
|
858
|
+
const { maybeRunOnHost } = await import('./lib/hosts/passthrough.js');
|
|
859
|
+
if (await maybeRunOnHost(requestedCommand, passedArgs)) {
|
|
860
|
+
process.exit(process.exitCode ?? 0);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
850
863
|
// Register only the command(s) this invocation actually uses. Lazy commands
|
|
851
864
|
// (sessions/teams/cloud) are handled after applyGlobalHelpConventions below.
|
|
852
865
|
const isLazyRequest = requestedCommand !== undefined && LAZY_COMMAND_NAMES.has(requestedCommand);
|
|
@@ -882,7 +895,8 @@ if (!helpOrVersionRequested) {
|
|
|
882
895
|
// fire-and-forget the next background sync. System repo gets a real fast-forward
|
|
883
896
|
// pull (read-only locally, safe). User repo and extras get fetch-only + a
|
|
884
897
|
// status marker that we'll print on the *next* invocation.
|
|
885
|
-
const { spawnDetachedSync } = await import('./lib/auto-pull.js');
|
|
898
|
+
const { spawnDetachedSync, printPendingUpdateNotices } = await import('./lib/auto-pull.js');
|
|
899
|
+
printPendingUpdateNotices();
|
|
886
900
|
spawnDetachedSync();
|
|
887
901
|
}
|
|
888
902
|
// First-run experience: no args + no config yet + TTY -> launch interactive setup.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Per-harness spawn configuration for Agent Client Protocol (ACP) mode.
|
|
3
3
|
*
|
|
4
4
|
* Each entry describes how to launch a coding agent CLI as an ACP server
|
|
5
|
-
* (stdio JSON-RPC). Unsupported harnesses (amp,
|
|
5
|
+
* (stdio JSON-RPC). Unsupported harnesses (amp, goose-stdio) are omitted;
|
|
6
6
|
* callers should fall back to the legacy direct-exec path for those.
|
|
7
7
|
*
|
|
8
8
|
* Sources: https://agentclientprotocol.com/get-started/agents + vendor docs.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Per-harness spawn configuration for Agent Client Protocol (ACP) mode.
|
|
3
3
|
*
|
|
4
4
|
* Each entry describes how to launch a coding agent CLI as an ACP server
|
|
5
|
-
* (stdio JSON-RPC). Unsupported harnesses (amp,
|
|
5
|
+
* (stdio JSON-RPC). Unsupported harnesses (amp, goose-stdio) are omitted;
|
|
6
6
|
* callers should fall back to the legacy direct-exec path for those.
|
|
7
7
|
*
|
|
8
8
|
* Sources: https://agentclientprotocol.com/get-started/agents + vendor docs.
|
|
@@ -61,7 +61,7 @@ export const ACP_HARNESSES = {
|
|
|
61
61
|
// goose: ACP over HTTP via `goosed`, not a clean stdio subcommand.
|
|
62
62
|
// copilot, kiro: excluded for now (not installed in the reference environment,
|
|
63
63
|
// no local verification possible).
|
|
64
|
-
// amp
|
|
64
|
+
// amp: not on the ACP agents list.
|
|
65
65
|
};
|
|
66
66
|
/** Returns the ACP spawn spec for an agent, or undefined if the harness does not speak ACP. */
|
|
67
67
|
export function getAcpSpec(agent) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AgentId } from '../types.js';
|
|
2
|
+
import type { AgentTarget, ResolveOptions, VersionFilter } from './types.js';
|
|
3
|
+
export * from './types.js';
|
|
4
|
+
export * from './primitives.js';
|
|
5
|
+
/** Shared `--help` epilog so every agent-spec command documents the same grammar. */
|
|
6
|
+
export declare const AGENT_SPEC_HELP: string;
|
|
7
|
+
/** Resolve a spec (single or comma-list) into concrete installed targets. */
|
|
8
|
+
export declare function resolveAgentTargets(spec: string, opts?: ResolveOptions): AgentTarget[];
|
|
9
|
+
/** Resolve a spec that must name exactly one installed version. */
|
|
10
|
+
export declare function resolveSingleAgentTarget(spec: string, opts?: ResolveOptions): {
|
|
11
|
+
agent: AgentId;
|
|
12
|
+
version: string;
|
|
13
|
+
source: import('./types.js').VersionSource;
|
|
14
|
+
};
|
|
15
|
+
/** Resolve a read/list command's version filter (undefined → all, @default → the default, else concrete). */
|
|
16
|
+
export declare function resolveVersionFilter(agent: AgentId, qualifier: string | undefined | null, opts?: ResolveOptions): VersionFilter;
|
|
17
|
+
/** Concrete version filter for list/display commands (undefined → show all, @default → the default version). */
|
|
18
|
+
export declare function resolveListFilter(agent: AgentId, qualifier: string | undefined | null, opts?: ResolveOptions): string | undefined;
|