@phnx-labs/agents-cli 1.22.41 → 1.22.42

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 (167) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +9 -3
  3. package/dist/bin/agents +0 -0
  4. package/dist/cli/command-registry.d.ts +2 -0
  5. package/dist/cli/command-registry.js +4 -0
  6. package/dist/commands/accounts.d.ts +29 -0
  7. package/dist/commands/accounts.js +220 -29
  8. package/dist/commands/alias.js +1 -1
  9. package/dist/commands/auth.d.ts +9 -0
  10. package/dist/commands/auth.js +104 -0
  11. package/dist/commands/browser-sessions-picker.js +42 -62
  12. package/dist/commands/browser.js +30 -38
  13. package/dist/commands/computer-actions.d.ts +1 -1
  14. package/dist/commands/computer-actions.js +1 -1
  15. package/dist/commands/computer-sessions-picker.js +32 -55
  16. package/dist/commands/computer.d.ts +1 -1
  17. package/dist/commands/computer.js +2 -2
  18. package/dist/commands/doctor.d.ts +1 -1
  19. package/dist/commands/doctor.js +3 -3
  20. package/dist/commands/feed.js +1 -1
  21. package/dist/commands/hooks.js +1 -1
  22. package/dist/commands/import.js +1 -1
  23. package/dist/commands/insights.js +163 -85
  24. package/dist/commands/inspect.js +2 -2
  25. package/dist/commands/mine.js +1 -1
  26. package/dist/commands/org.d.ts +6 -0
  27. package/dist/commands/org.js +174 -0
  28. package/dist/commands/packages.js +1 -1
  29. package/dist/commands/prune.js +1 -1
  30. package/dist/commands/routines.js +1 -1
  31. package/dist/commands/run-account-picker.d.ts +19 -0
  32. package/dist/commands/run-account-picker.js +81 -0
  33. package/dist/commands/sessions-picker-factory.d.ts +40 -0
  34. package/dist/commands/sessions-picker-factory.js +67 -0
  35. package/dist/commands/setup-browser.js +4 -4
  36. package/dist/commands/setup-mine.js +1 -1
  37. package/dist/commands/setup-preferences.js +2 -2
  38. package/dist/commands/setup.js +5 -3
  39. package/dist/commands/sync.js +1 -1
  40. package/dist/commands/versions.js +1 -1
  41. package/dist/commands/view.js +1 -1
  42. package/dist/lib/account-capabilities.d.ts +10 -0
  43. package/dist/lib/account-capabilities.js +34 -0
  44. package/dist/lib/agent-spec/agents.d.ts +584 -0
  45. package/dist/lib/agent-spec/agents.js +3127 -0
  46. package/dist/lib/agent-spec/provider.js +1 -1
  47. package/dist/lib/agents.d.ts +2 -584
  48. package/dist/lib/agents.js +2 -3127
  49. package/dist/lib/browser/drivers/local.d.ts +8 -2
  50. package/dist/lib/browser/drivers/local.js +8 -2
  51. package/dist/lib/browser/drivers/ssh.d.ts +8 -2
  52. package/dist/lib/browser/drivers/ssh.js +10 -4
  53. package/dist/lib/browser/hygiene.d.ts +1 -1
  54. package/dist/lib/browser/hygiene.js +5 -1
  55. package/dist/lib/browser/profiles.d.ts +74 -1
  56. package/dist/lib/browser/profiles.js +114 -5
  57. package/dist/lib/browser/runtime-state.d.ts +11 -5
  58. package/dist/lib/browser/runtime-state.js +13 -9
  59. package/dist/lib/browser/service.d.ts +68 -30
  60. package/dist/lib/browser/service.js +305 -194
  61. package/dist/lib/browser/types.d.ts +95 -3
  62. package/dist/lib/browser/types.js +51 -0
  63. package/dist/lib/catchup.js +1 -1
  64. package/dist/lib/computer/actions.d.ts +1 -1
  65. package/dist/lib/computer/actions.js +1 -1
  66. package/dist/lib/{computer-rpc.js → computer/computer-rpc.js} +5 -5
  67. package/dist/lib/computer/dispatch.d.ts +1 -1
  68. package/dist/lib/computer/download.d.ts +1 -1
  69. package/dist/lib/computer/download.js +3 -3
  70. package/dist/lib/{ssh-tunnel.d.ts → computer/ssh-tunnel.d.ts} +1 -1
  71. package/dist/lib/{ssh-tunnel.js → computer/ssh-tunnel.js} +12 -12
  72. package/dist/lib/daemon/daemon.js +1 -1
  73. package/dist/lib/{runner.d.ts → daemon/runner.d.ts} +10 -10
  74. package/dist/lib/{runner.js → daemon/runner.js} +40 -114
  75. package/dist/lib/devices/doctor-findings.d.ts +1 -1
  76. package/dist/lib/devices/doctor-findings.js +3 -3
  77. package/dist/lib/devices/fleet-inventory.js +1 -1
  78. package/dist/lib/devices/harness-inventory.js +1 -1
  79. package/dist/lib/devices/registry.js +4 -22
  80. package/dist/lib/doctor-diff.d.ts +1 -1
  81. package/dist/lib/doctor-diff.js +1 -1
  82. package/dist/lib/drift.js +1 -1
  83. package/dist/lib/entitlement.d.ts +31 -0
  84. package/dist/lib/entitlement.js +137 -0
  85. package/dist/lib/exec.js +39 -202
  86. package/dist/lib/feed/feed.js +2 -8
  87. package/dist/lib/fs-atomic.d.ts +7 -0
  88. package/dist/lib/fs-atomic.js +9 -0
  89. package/dist/lib/harness/adapter.d.ts +160 -0
  90. package/dist/lib/harness/adapter.js +47 -0
  91. package/dist/lib/harness/adapters/claude.d.ts +2 -0
  92. package/dist/lib/harness/adapters/claude.js +110 -0
  93. package/dist/lib/harness/adapters/codex.d.ts +2 -0
  94. package/dist/lib/harness/adapters/codex.js +83 -0
  95. package/dist/lib/harness/adapters/copilot.d.ts +2 -0
  96. package/dist/lib/harness/adapters/copilot.js +23 -0
  97. package/dist/lib/harness/adapters/cursor.d.ts +2 -0
  98. package/dist/lib/harness/adapters/cursor.js +38 -0
  99. package/dist/lib/harness/adapters/droid.d.ts +2 -0
  100. package/dist/lib/harness/adapters/droid.js +17 -0
  101. package/dist/lib/harness/adapters/grok.d.ts +2 -0
  102. package/dist/lib/harness/adapters/grok.js +14 -0
  103. package/dist/lib/harness/adapters/kimi.d.ts +2 -0
  104. package/dist/lib/harness/adapters/kimi.js +49 -0
  105. package/dist/lib/harness/adapters/muse.d.ts +2 -0
  106. package/dist/lib/harness/adapters/muse.js +44 -0
  107. package/dist/lib/harness/adapters/opencode.d.ts +2 -0
  108. package/dist/lib/harness/adapters/opencode.js +14 -0
  109. package/dist/lib/harness/exec-config-version.d.ts +8 -0
  110. package/dist/lib/harness/exec-config-version.js +22 -0
  111. package/dist/lib/harness/index.d.ts +1 -0
  112. package/dist/lib/harness/index.js +34 -0
  113. package/dist/lib/{hooks.d.ts → hooks/install.d.ts} +1 -1
  114. package/dist/lib/{hooks.js → hooks/install.js} +11 -11
  115. package/dist/lib/import.js +1 -1
  116. package/dist/lib/installations/index.d.ts +4 -4
  117. package/dist/lib/installations/index.js +3 -4
  118. package/dist/lib/installations/migrate.js +6 -6
  119. package/dist/lib/{shims.d.ts → installations/shims.d.ts} +2 -2
  120. package/dist/lib/{shims.js → installations/shims.js} +12 -114
  121. package/dist/lib/installations/store.d.ts +141 -3
  122. package/dist/lib/installations/store.js +475 -5
  123. package/dist/lib/installations/versions.d.ts +1 -126
  124. package/dist/lib/installations/versions.js +5 -465
  125. package/dist/lib/isolation-boundary-report.d.ts +1 -1
  126. package/dist/lib/isolation-boundary-report.js +1 -1
  127. package/dist/lib/mailbox-gc.js +2 -3
  128. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  129. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  130. package/dist/lib/monitors/dispatch.d.ts +1 -1
  131. package/dist/lib/monitors/dispatch.js +2 -2
  132. package/dist/lib/monitors/state.d.ts +1 -1
  133. package/dist/lib/plugins/plugins.js +1 -1
  134. package/dist/lib/plugins/skills.js +1 -1
  135. package/dist/lib/prix-account.d.ts +158 -0
  136. package/dist/lib/prix-account.js +214 -0
  137. package/dist/lib/project-key.js +2 -2
  138. package/dist/lib/project-launch.js +1 -1
  139. package/dist/lib/refresh.js +2 -2
  140. package/dist/lib/resource-inventory.d.ts +1 -1
  141. package/dist/lib/resource-inventory.js +1 -1
  142. package/dist/lib/rules/rules.js +1 -1
  143. package/dist/lib/scheduling/routines.js +1 -1
  144. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  145. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  146. package/dist/lib/self-heal/checks/hook-runtime.js +1 -1
  147. package/dist/lib/self-heal/checks/path.js +1 -1
  148. package/dist/lib/self-heal/checks/shadowing.js +1 -1
  149. package/dist/lib/self-heal/checks/shims.js +1 -1
  150. package/dist/lib/session/discover.d.ts +39 -0
  151. package/dist/lib/session/discover.js +3 -3
  152. package/dist/lib/session/parse.js +24 -42
  153. package/dist/lib/session/recovery.js +1 -1
  154. package/dist/lib/staleness/prune.d.ts +1 -1
  155. package/dist/lib/staleness/prune.js +1 -1
  156. package/dist/lib/staleness/writers/hooks.js +1 -1
  157. package/dist/lib/startup/command-registry.js +1 -1
  158. package/dist/lib/teams/agents.js +2 -19
  159. package/dist/lib/teams/parsers.js +20 -26
  160. package/dist/lib/teams/registry.js +2 -21
  161. package/dist/lib/triggers/handlers.js +1 -1
  162. package/dist/lib/triggers/webhook.js +1 -1
  163. package/dist/lib/uninstall.js +1 -1
  164. package/dist/lib/version.d.ts +9 -2
  165. package/dist/lib/version.js +11 -9
  166. package/package.json +1 -1
  167. /package/dist/lib/{computer-rpc.d.ts → computer/computer-rpc.d.ts} +0 -0
@@ -0,0 +1,584 @@
1
+ import type { AgentConfig, AgentId } from '../types.js';
2
+ /** Represents the installation state of an agent's CLI binary. */
3
+ export interface CliState {
4
+ installed: boolean;
5
+ version: string | null;
6
+ path: string | null;
7
+ }
8
+ /**
9
+ * Minimum Codex CLI version that supports hooks.
10
+ * Mirrored on `AGENTS.codex.capabilities.hooks.since` -- kept exported for
11
+ * legacy import sites that haven't migrated to `supports()` yet.
12
+ */
13
+ export declare const CODEX_HOOKS_MIN_VERSION = "0.116.0";
14
+ /** Minimum Gemini CLI version that supports the hooks system (v0.26.0, Jan 2026). */
15
+ export declare const GEMINI_HOOKS_MIN_VERSION = "0.26.0";
16
+ /**
17
+ * Synchronous PATH search -- no subprocess. Returns first matching binary path.
18
+ *
19
+ * Skips our own shims dir (`~/.agents/.cache/shims/`) — those shims are
20
+ * dispatch helpers, not real installs. Counting them as installed produced a
21
+ * false positive where agents with NO real binary on the host (e.g. a
22
+ * never-installed Cursor whose only PATH entry was our `cursor-agent` shim
23
+ * dispatcher) showed up under `agents view`'s "Not Managed by Agents CLI"
24
+ * section, even though the user had nothing to import.
25
+ */
26
+ interface NativeBinaryResolutionOptions {
27
+ shimsDir?: string;
28
+ historyDir?: string;
29
+ }
30
+ /**
31
+ * Resolve a PATH candidate to the immutable native executable agents-cli may
32
+ * safely register. An adopted launcher can live outside the shims directory
33
+ * while resolving back into it; in that case its durable adoption record is
34
+ * the source of truth for the original executable.
35
+ */
36
+ export declare function resolveNativeBinaryPath(command: string, candidate: string, options?: NativeBinaryResolutionOptions): string | null;
37
+ export declare function findInPath(command: string, options?: NativeBinaryResolutionOptions): string | null;
38
+ /**
39
+ * Per-harness dispatch data that used to live in `if (agentId === …)` /
40
+ * `switch (agentId)` arms inside this file. These are stable properties of a
41
+ * harness, not per-call-site quirks — a new AgentId must declare every field
42
+ * (the completeness test in agents.test.ts pins that).
43
+ *
44
+ * Left as call-site specials (not registry data): `getAccountInfo` and
45
+ * `readAuthAccountIdentity` — those are parsers, not flags.
46
+ */
47
+ export type VersionStdoutMatch = 'semver' | 'openclaw';
48
+ export type UnmanagedBinaryResolver = 'path' | 'grok-downloads';
49
+ export type McpRegisterPath = 'cli' | 'config';
50
+ export type McpAddHttpStyle = 'transport' | 'url';
51
+ export type McpAddStdioStyle = 'scope' | 'simple';
52
+ export type McpConfigWriteStyle = 'json-mcpServers' | 'yaml-mcp_servers';
53
+ export interface AgentRegistryConfig extends AgentConfig {
54
+ /**
55
+ * Session-transcript directory as path segments under a HOME root, or null
56
+ * when this harness has no local session tree `agents` can walk.
57
+ */
58
+ sessionDir: string[] | null;
59
+ /** File extension of session transcripts, or null when unknown. */
60
+ sessionFileExt: '.jsonl' | '.json' | null;
61
+ /** How to parse `cli --version` stdout. */
62
+ versionStdoutMatch: VersionStdoutMatch;
63
+ /** How to find an unmanaged (non-version-home) binary. */
64
+ unmanagedBinary: UnmanagedBinaryResolver;
65
+ /**
66
+ * How `registerMcp` / `unregisterMcp` talk to the harness. `config` writes
67
+ * the file directly (no `mcp add` CLI); `cli` shells out.
68
+ */
69
+ mcpRegister: McpRegisterPath;
70
+ /** Argv shape for `mcp add` over HTTP. */
71
+ mcpAddHttp: McpAddHttpStyle;
72
+ /** Argv shape for `mcp add` over stdio. */
73
+ mcpAddStdio: McpAddStdioStyle;
74
+ /** On-disk map key + serialization when writing MCP config directly. */
75
+ mcpConfigWrite: McpConfigWriteStyle;
76
+ }
77
+ /**
78
+ * Master registry of all supported agents keyed by AgentId.
79
+ *
80
+ * Each entry defines the agent's CLI command, npm package, config directory layout,
81
+ * instructions file name, slash-command format, and capability flags. This is the
82
+ * single source of truth for agent metadata consumed throughout the codebase.
83
+ */
84
+ export declare const AGENTS: Record<AgentId, AgentRegistryConfig>;
85
+ /** All current and legacy agent IDs derived from the AGENTS registry. */
86
+ export declare const ALL_AGENT_IDS: AgentId[];
87
+ /**
88
+ * CLI command templates per agent for daemon-fired routine jobs, with
89
+ * {prompt} as a placeholder. Lives here (not runner.ts) so routines.ts can
90
+ * import ROUTINE_AGENT_IDS for schedule-time validation without a circular
91
+ * import (runner.ts already imports from routines.ts).
92
+ */
93
+ export declare const ROUTINE_AGENT_COMMANDS: Record<string, string[]>;
94
+ /** Agents the routine daemon can actually run when firing locally, derived
95
+ * from the command table above so the `--agent` help and validateJob's
96
+ * schedule-time check can never drift from it. */
97
+ export declare const ROUTINE_AGENT_IDS: readonly string[];
98
+ /** Agents retained only for legacy reads, not install/import/sync targets. */
99
+ export declare const HARD_DEPRECATED_AGENT_IDS: AgentId[];
100
+ /** Agents that can receive managed installs, imports, and resource sync writes. */
101
+ export declare const MANAGED_AGENT_IDS: AgentId[];
102
+ /**
103
+ * A self-updating agent is a single global binary installed by an official
104
+ * `curl … | sh` / `brew install` script that carries NO version token — the
105
+ * installer can only ever fetch the *current* release, and the binary then keeps
106
+ * itself up to date in place (droid, grok, antigravity, cursor, hermes,
107
+ * kiro, goose). There is no semver to pin, so agents-cli must not model these as
108
+ * having multiple installable version-homes the way it does for npm-packaged
109
+ * agents (claude, codex, kimi, …).
110
+ *
111
+ * The predicate is `!npmPackage && installScript && !installScript.includes('VERSION')`:
112
+ * - `npmPackage` empty → not installed from npm, so `agents add x@1.2.3`
113
+ * can't resolve a registry version.
114
+ * - `installScript` present → it IS installed by a script (not unmanaged).
115
+ * - no `VERSION` placeholder → the script has no slot for a pinned version
116
+ * (contrast: an installer templated with `VERSION`
117
+ * could pin, and is NOT self-updating).
118
+ *
119
+ * Route every "is this a pinnable, multi-version agent?" decision through here —
120
+ * never a scattered `agent === 'droid'`.
121
+ */
122
+ export declare function isSelfUpdatingAgent(agent: AgentId): boolean;
123
+ export declare function isAgentHardDeprecated(agent: AgentId): boolean;
124
+ /** Get the chalk color function for an agent. Works for any AgentId or SessionAgentId. */
125
+ export declare function colorAgent(agentId: string): (s: string) => string;
126
+ /** Return the agent's display name, colored. */
127
+ export declare function agentLabel(agentId: string): string;
128
+ /** Check whether the given agent's CLI binary is present on PATH. */
129
+ export declare function isCliInstalled(agentId: AgentId): Promise<boolean>;
130
+ /** Return the installed CLI version for the given agent, or null if not found. */
131
+ export declare function getCliVersion(agentId: AgentId): Promise<string | null>;
132
+ /** Return the absolute path to the agent's CLI binary on PATH, or null. */
133
+ export declare function getCliPath(agentId: AgentId): Promise<string | null>;
134
+ /**
135
+ * Resolve the full CLI state for an agent: whether it is installed, its version,
136
+ * and the path to the binary. Checks version-managed installs first, then falls
137
+ * back to a plain PATH lookup.
138
+ */
139
+ export declare function getCliState(agentId: AgentId): Promise<CliState>;
140
+ /**
141
+ * Resolve the agent's OWN install — the one agents-cli does not manage — by plain
142
+ * PATH lookup, ignoring the version dirs entirely.
143
+ *
144
+ * Callers that specifically mean "the user's own globally-installed CLI" must use
145
+ * this rather than `getCliState`, whose managed fast path reports an installed
146
+ * version (any version dir, in readdir order) and would therefore hand back an
147
+ * isolated copy — a copy that is deliberately unreachable from PATH — labelled as
148
+ * the global install.
149
+ */
150
+ export declare function getUnmanagedCliState(agentId: AgentId): Promise<CliState>;
151
+ /** Resolve CLI state for all registered agents in parallel. */
152
+ export declare function getAllCliStates(): Promise<Partial<Record<AgentId, CliState>>>;
153
+ /** Info about an existing unmanaged agent installation. */
154
+ export interface UnmanagedInstall {
155
+ agentId: AgentId;
156
+ configDir: string;
157
+ version: string | null;
158
+ }
159
+ /**
160
+ * Agents that `agents setup` probes for pre-existing native installations
161
+ * (i.e., a config dir present before agents-cli took over). Derived from
162
+ * `sessionDir` so a new harness cannot be walkable yet missing from setup.
163
+ */
164
+ export declare const UNMANAGED_DETECTION_CANDIDATES: AgentId[];
165
+ /**
166
+ * Detect existing agent installations that are NOT yet managed by agents-cli.
167
+ * Returns agents whose config dir exists as a real directory (not a symlink).
168
+ */
169
+ export declare function getUnmanagedAgentInstalls(): Promise<UnmanagedInstall[]>;
170
+ /** Create the agent's slash-commands directory if it does not exist. */
171
+ export declare function ensureCommandsDir(agentId: AgentId): void;
172
+ /** Create the agent's skills directory if it does not exist. */
173
+ export declare function ensureSkillsDir(agentId: AgentId): void;
174
+ /**
175
+ * The agent's config-dir name relative to $HOME — e.g. '.claude',
176
+ * '.gemini/antigravity-cli', '.config/amp', '.kimi-code'.
177
+ *
178
+ * Path segment to join onto a (version) home root when locating an agent's
179
+ * commands/skills/plugins. Do NOT hardcode `.${agentId}`: it is wrong for
180
+ * every agent whose config dir is nested or under ~/.config — antigravity
181
+ * (~/.gemini/antigravity-cli), amp (~/.config/amp), goose (~/.config/goose),
182
+ * kimi (~/.kimi-code). Mirrors the shim configDirName derivation in shims.ts.
183
+ *
184
+ * Relativized against the module-level HOME constant (the same value used to
185
+ * build every `configDir`), NOT a fresh `os.homedir()` — so the result stays a
186
+ * clean relative name even when HOME is overridden after module load (tests,
187
+ * sandboxes). Using `os.homedir()` here would yield `../../real/home/.claude`.
188
+ */
189
+ export declare function agentConfigDirName(agentId: AgentId): string;
190
+ /** Account identity and billing information extracted from an agent's auth config. */
191
+ export interface AccountInfo {
192
+ accountKey: string | null;
193
+ usageKey: string | null;
194
+ accountId: string | null;
195
+ organizationId: string | null;
196
+ userId: string | null;
197
+ email: string | null;
198
+ plan: string | null;
199
+ usageStatus: 'available' | 'rate_limited' | 'out_of_credits' | null;
200
+ overageCredits: {
201
+ amount: number;
202
+ currency: string;
203
+ } | null;
204
+ lastActive: Date | null;
205
+ signedIn: boolean;
206
+ organizationType?: string | null;
207
+ organizationName?: string | null;
208
+ }
209
+ /**
210
+ * Human-readable label for a Claude account's organizationType as read from
211
+ * .claude.json's oauthAccount ("claude_team" -> "Team"). Unrecognized values
212
+ * (future tiers) are rendered by stripping the "claude_" prefix and
213
+ * title-casing the rest — an unfamiliar-but-visible label beats silence.
214
+ * Returns null for missing input.
215
+ */
216
+ export declare function formatClaudeOrgLabel(orgType: string | null | undefined): string | null;
217
+ /**
218
+ * Short badge identifying which ORG an account belongs to — "Turing Labs" for a
219
+ * multi-seat Team/Enterprise org, whose name is real identity that disambiguates
220
+ * a Team seat from a same-email personal plan. Returns null for personal plans
221
+ * (Max/Pro/Free): the tier label now lives in the aligned plan column, so a badge
222
+ * would only duplicate it, and a personal org's name is auto-generated boilerplate
223
+ * ("<email>'s Organization"), not identity. Also null when the account carries no
224
+ * organizationType (signed out, non-Claude agents, configs predating the field).
225
+ */
226
+ export declare function accountOrgBadge(info?: Pick<AccountInfo, 'organizationType' | 'organizationName'> | null): string | null;
227
+ /** Agents whose local credential formats expose enough state for account selection. */
228
+ export declare const ACCOUNT_INSPECTION_AGENT_IDS: readonly ["claude", "codex", "gemini", "cursor", "grok", "antigravity", "kimi", "droid", "opencode", "muse"];
229
+ /** Whether agents-cli can determine this agent's per-version sign-in state. */
230
+ export declare function supportsAccountInspection(agentId: AgentId): boolean;
231
+ /**
232
+ * Human-readable account identity shared by every account-aware surface.
233
+ * Prefer email, append a multi-seat Claude organization name when present,
234
+ * then fall back to a non-secret account id or a generic signed-in label.
235
+ */
236
+ export declare function accountDisplayLabel(info?: Pick<AccountInfo, 'email' | 'accountId' | 'signedIn' | 'organizationType' | 'organizationName'> | null): string;
237
+ /** Return the email address associated with the agent's auth config, or null. */
238
+ export declare function getAccountEmail(agentId: AgentId, home?: string): Promise<string | null>;
239
+ /** Where an agent's credential file lives, split into the per-version copy and
240
+ * the active/global copy under the real HOME. */
241
+ export interface CredentialPresence {
242
+ /** The credential file exists inside the passed version home. */
243
+ perVersion: boolean;
244
+ /** The credential file exists under the active/global HOME (the one the login
245
+ * symlink actually targets), independent of the version home. */
246
+ active: boolean;
247
+ /** Whether agents-cli knows WHERE this agent's credential lives at all — i.e.
248
+ * the agent has an entry in {@link CREDENTIAL_FILE_SEGMENTS}. When false both
249
+ * probes are trivially false because there is nothing to look for, so absence
250
+ * is NOT evidence of a logout and no caller may treat it as provable.
251
+ *
252
+ * This is deliberately separate from `supportsAccountInspection`: the two
253
+ * registries move independently, and an agent has already been added to the
254
+ * inspection set without a credential path (cursor), which without this flag
255
+ * produced a false "logged out" critical for every installed version. */
256
+ knownLocation: boolean;
257
+ }
258
+ /**
259
+ * File-presence probe for an agent's credential, split by location: whether it
260
+ * exists in a SPECIFIC version home (`perVersion`) and whether it exists under
261
+ * the active/global HOME (`active`). A logged-out claim is only *provable* when
262
+ * BOTH are absent — a version that merely lacks its own copy but shares the
263
+ * global login is signed in, not logged out. Pure file existence; no decrypt,
264
+ * no network, no keychain prompt. Agents with no inspectable identity return
265
+ * `{ perVersion: false, active: false }` and must NEVER yield a provable-logout
266
+ * claim (the caller gates on {@link supportsAccountInspection}).
267
+ */
268
+ export declare function credentialPresence(agentId: AgentId, versionHome: string): CredentialPresence;
269
+ /** Decrypted contents of Droid's auth.v2.file (subset we consume). */
270
+ export interface DroidAuthPayload {
271
+ access_token?: string;
272
+ active_organization_id?: string | null;
273
+ }
274
+ /**
275
+ * Factory Droid stores its OAuth credential encrypted at ~/.factory/auth.v2.file
276
+ * (AES-256-GCM, format `ivB64:tagB64:ctB64`) with the 32-byte key base64-stored
277
+ * in ~/.factory/auth.v2.key. On the keyfile-v2 source there is no OS-keychain /
278
+ * device binding — the key is on disk — so we can decrypt locally with no
279
+ * network call. Every failure (missing key file — e.g. a keyring-v2/legacy
280
+ * login with no on-disk key, a bad GCM tag, or malformed JSON) returns null.
281
+ * Never throws. Shared by account identity below and the Droid usage fetcher
282
+ * in usage.ts.
283
+ */
284
+ export declare function decryptDroidAuthPayload(base: string): DroidAuthPayload | null;
285
+ /**
286
+ * Decrypt a Droid `auth.v2.file` (AES-256-GCM `ivB64:tagB64:ctB64`) using the
287
+ * raw 32-byte key stored base64 in `auth.v2.key`, given the EXACT paths to both.
288
+ * Same crypto as decryptDroidAuthPayload but without the account-global HOME
289
+ * fallback, so the identity of a SPECIFIC version home resolves against only
290
+ * that home's files (carryForwardAuthFiles needs per-dir identity). Returns null
291
+ * on any failure (missing file/key, wrong key length, bad GCM tag, malformed
292
+ * JSON). Never throws.
293
+ */
294
+ export declare function decryptDroidAuthFile(filePath: string, keyPath: string): DroidAuthPayload | null;
295
+ /**
296
+ * Stable account identity for a *file-auth* agent's credential directory
297
+ * (droid / kimi / antigravity), or null when the directory holds no decodable
298
+ * account claim. Unlike a naive top-level JSON key-scan (which matched NO real
299
+ * credential file), this decrypts / decodes each agent's REAL on-disk format so
300
+ * the identity resolves against production credentials:
301
+ * - droid: AES-256-GCM auth.v2.file (+ auth.v2.key) -> WorkOS access-token JWT
302
+ * -> email / org_id / sub.
303
+ * - kimi: credentials/kimi-code.json -> access-token JWT -> user_id / sub.
304
+ * - antigravity: antigravity-oauth-token -> token.refresh_token -> JWT sub
305
+ * when the token is a JWT, else a SHA-256 hash of the raw refresh-token
306
+ * value (opaque Google consumer tokens are stable per login — hashed so
307
+ * the identity key, which is persisted as a usage-cache key, never carries
308
+ * a live credential).
309
+ * Two directories for the SAME account compare equal; two DIFFERENT accounts
310
+ * compare distinct. Used by carryForwardAuthFiles to refuse overwriting one
311
+ * account's login with a credential that belongs to a DIFFERENT account
312
+ * (RUSH-1764). Never throws.
313
+ */
314
+ export declare function readAuthAccountIdentity(agent: AgentId, configDir: string): string | null;
315
+ /**
316
+ * Antigravity (`agy`) stores its OAuth token via the Go keyring library
317
+ * (zalando/go-keyring), which is platform-split:
318
+ *
319
+ * - macOS: login keychain, service `gemini`, account `antigravity` — no file.
320
+ * - Linux with Secret Service (libsecret / gnome-keyring): attributes
321
+ * service=`gemini`, username=`antigravity` (go-keyring's Secret Service
322
+ * mapping of service+user). Prefer this over the file when a keyring
323
+ * daemon is running.
324
+ * - Linux without Secret Service: file fallback at
325
+ * `~/.gemini/antigravity-cli/antigravity-oauth-token`.
326
+ *
327
+ * Probe the OS keyring for existence after the file check. On macOS,
328
+ * `security find-generic-password` without `-w` is metadata-only (never
329
+ * prompts). On Linux, `secret-tool lookup` exit 0 means the item exists
330
+ * (stdout is the secret — discarded, never logged). Cached per process —
331
+ * the keyring is account-global, so one probe covers every installed version.
332
+ * Returns false when the platform has no probe (Windows) or the tool is
333
+ * missing. Guard with `AGENTS_NO_KEYCHAIN_PROBE=1` for hermetic tests.
334
+ */
335
+ export declare function antigravityOsKeyringProbe(platform?: NodeJS.Platform): {
336
+ cmd: string;
337
+ args: string[];
338
+ } | null;
339
+ /** @internal test hook — clear the per-process keyring probe cache. */
340
+ export declare function __resetAntigravityKeychainCacheForTest(): void;
341
+ /**
342
+ * OpenCode's account identity: the sorted, "+"-joined list of provider ids
343
+ * that hold a valid credential in `auth.json` (e.g. `"anthropic+muse-spark"`).
344
+ * `auth.json` carries no email/identity claim (see `isValidOpenCodeCredential`),
345
+ * so this join is the closest thing to "which account is this" available — the
346
+ * same value `agents view`/`agents doctor` show for OpenCode's signed-in state.
347
+ *
348
+ * This is the ONLY correct source for an OpenCode "account". OpenCode's SQLite
349
+ * `opencode.db` also carries `account`/`account_state`/`control_account` tables,
350
+ * but on a real, actively-used install (yosemite-s1, 1.16.0, 35 applied
351
+ * migrations) all three are permanently empty — no migration ever populates
352
+ * them, and no session has ever written a row. Reading from them instead of
353
+ * `auth.json` always yields `undefined`, credential or not; `session/discover.ts`
354
+ * uses this function rather than duplicating a sqlite lookup against those
355
+ * dead tables.
356
+ *
357
+ * Sync (`fs.readFileSync`), no network. Returns undefined when `auth.json` is
358
+ * missing, unreadable, or carries no valid credential.
359
+ */
360
+ export declare function resolveOpenCodeAccountId(base: string): string | undefined;
361
+ /**
362
+ * Whether a Claude version home's credential file is present but carries no
363
+ * token — the "must have a real credential" floor (see
364
+ * `isValidOpenCodeCredential`) applied to claude.
365
+ *
366
+ * A FAILED OAuth refresh leaves exactly this state behind: Claude Code rewrites
367
+ * `.claude/.credentials.json` with `accessToken: ""`, `refreshToken: ""` and
368
+ * `expiresAt: 0`, keeping only the descriptive fields (`subscriptionType`,
369
+ * `rateLimitTier`, `refreshTokenExpiresAt`). Everything we derive from
370
+ * `.claude.json` — email, plan — still looks healthy, so the install reported
371
+ * `signedIn: true`, `agents view` drew usage bars for it, and balanced rotation
372
+ * (whose `authValid` is just "email present") kept picking it — every pick dying
373
+ * at spawn on "OAuth session expired and could not be refreshed".
374
+ *
375
+ * Only decidable off macOS: there the login Keychain is the canonical store and
376
+ * this file is not authoritative, and probing the Keychain would raise an
377
+ * authorization sheet per installed version on every `agents run` — the reason
378
+ * rotation stopped calling `isClaudeAuthValid` at all. Off macOS the file IS the
379
+ * only store, so a token-less file is proof of signed-out. `platform` is a
380
+ * parameter so both branches are testable on any host.
381
+ *
382
+ * Sync, no Keychain, no network — safe on the `agents run` hot path.
383
+ */
384
+ export declare function isClaudeCredentialFileBlank(base: string, platform?: NodeJS.Platform): boolean;
385
+ /**
386
+ * Identity of the Claude account a version home is (or was) logged into, read
387
+ * straight from `.claude.json`'s `oauthAccount`.
388
+ *
389
+ * Deliberately independent of whether the credential still works. `getAccountInfo`
390
+ * applies a credential floor so `agents view` and rotation route around an install
391
+ * that would die at spawn; attribution of *history* must not. A transcript written
392
+ * under an org is still that org's work after the token is revoked or the home is
393
+ * trashed, and on Linux/Windows the floor would otherwise erase the identity of
394
+ * every retired home (`isClaudeCredentialFileBlank` short-circuits only on darwin).
395
+ */
396
+ export interface ClaudeHomeIdentity {
397
+ email: string | null;
398
+ accountId: string | null;
399
+ organizationId: string | null;
400
+ organizationName: string | null;
401
+ organizationType: string | null;
402
+ /**
403
+ * Org-scoped identity — the rate-limit bucket, and the correct key to group by.
404
+ * Two orgs under one email (a Team seat and a personal Max plan) are separate
405
+ * buckets and MUST stay distinct; see `candidateIdentity` in lib/rotate.ts.
406
+ */
407
+ usageKey: string | null;
408
+ /** Account+org identity, narrower than `usageKey`. */
409
+ accountKey: string | null;
410
+ }
411
+ /** A version home's `.claude.json` plus the identity derived from it. */
412
+ export interface ClaudeHomeConfig {
413
+ /** The config file actually read. */
414
+ path: string;
415
+ config: Record<string, any>;
416
+ identity: ClaudeHomeIdentity;
417
+ }
418
+ /**
419
+ * Read a Claude home's config and account identity. Returns null when the home has
420
+ * no readable `.claude.json`, or has one with no `oauthAccount` (never signed in).
421
+ *
422
+ * Sync because the session scanner calls it once per home on a hot path, and the
423
+ * file is a few KB of local JSON. No Keychain access — see `getAccountInfo`.
424
+ */
425
+ export declare function readClaudeHomeConfig(base: string): ClaudeHomeConfig | null;
426
+ export declare function getAccountInfo(agentId: AgentId, home?: string): Promise<AccountInfo>;
427
+ /**
428
+ * Determine when the agent was last used by checking session file mtimes,
429
+ * falling back to config mtime.
430
+ *
431
+ * The session walk stats every transcript under the home's session dir —
432
+ * thousands of files on long-lived installs — and `agents run` rotation calls
433
+ * this once per installed version on every launch. The walk result is cached
434
+ * on disk for a short window so back-to-back launches skip it entirely.
435
+ * Cache read/write is best-effort: any failure falls back to walking.
436
+ */
437
+ export declare function resolveLastActive(agentId: AgentId, base: string, configPath?: string, cachePath?: string, now?: Date): Date | null;
438
+ /**
439
+ * Quick count of session files for an agent (without full DB scan).
440
+ * Used during init to show approximate session count to user.
441
+ */
442
+ export declare function countSessionFiles(agentId: AgentId): number;
443
+ /** Decode the payload section of a JWT token without verifying its signature. */
444
+ export declare function decodeJwtPayload(token: string): Record<string, any> | null;
445
+ /** Register an MCP server with an agent's CLI via `mcp add`. */
446
+ export declare function registerMcp(agentId: AgentId, name: string, command: string, scope?: 'user' | 'project', transport?: string, options?: {
447
+ home?: string;
448
+ binary?: string;
449
+ headers?: Record<string, string>;
450
+ }): Promise<{
451
+ success: boolean;
452
+ error?: string;
453
+ }>;
454
+ /** Unregister (remove) a named MCP server from an agent's CLI config. */
455
+ export declare function unregisterMcp(agentId: AgentId, name: string, options?: {
456
+ home?: string;
457
+ binary?: string;
458
+ }): Promise<{
459
+ success: boolean;
460
+ error?: string;
461
+ }>;
462
+ /** Result of an MCP registration or removal operation targeting a specific agent and optional version. */
463
+ export interface McpTargetOperationResult {
464
+ agentId: AgentId;
465
+ version?: string;
466
+ success: boolean;
467
+ error?: string;
468
+ }
469
+ /**
470
+ * Register an MCP server across multiple agent targets, including both direct
471
+ * (non-version-managed) agents and specific version-managed installs.
472
+ */
473
+ export declare function registerMcpToTargets(targets: {
474
+ directAgents: AgentId[];
475
+ versionSelections: Map<AgentId, string[]>;
476
+ }, name: string, command: string, scope?: 'user' | 'project', transport?: string, options?: {
477
+ headers?: Record<string, string>;
478
+ }): Promise<McpTargetOperationResult[]>;
479
+ /**
480
+ * Unregister an MCP server from multiple agent targets, including both direct
481
+ * agents and specific version-managed installs.
482
+ */
483
+ export declare function unregisterMcpFromTargets(targets: {
484
+ directAgents: AgentId[];
485
+ versionSelections: Map<AgentId, string[]>;
486
+ }, name: string): Promise<McpTargetOperationResult[]>;
487
+ /** Scope at which an MCP server is registered: user-global or per-project. */
488
+ export type McpScope = 'user' | 'project';
489
+ /** Describes an MCP server discovered in an agent's config, with its scope and command. */
490
+ export interface InstalledMcp {
491
+ name: string;
492
+ scope: McpScope;
493
+ command?: string;
494
+ version?: string;
495
+ }
496
+ interface McpConfigEntry {
497
+ command?: string;
498
+ args?: string[];
499
+ env?: Record<string, string>;
500
+ type?: string;
501
+ url?: string;
502
+ }
503
+ /**
504
+ * Strip JSON comments for JSONC parsing.
505
+ * Only removes comments outside of strings.
506
+ *
507
+ * Exported because the MCP writer needs the SAME parser the reader uses: a
508
+ * naive `//`-to-end-of-line regex eats the `//` inside
509
+ * `"$schema": "https://opencode.ai/config.json"`, which every opencode-generated
510
+ * config carries.
511
+ */
512
+ export declare function stripJsonComments(content: string): string;
513
+ /**
514
+ * Get user-scoped MCP config path for an agent.
515
+ *
516
+ * All three MCP path resolvers read `MCP_TARGETS`, so the file the writer
517
+ * targets, the file the parser reads, and the file the staleness detector
518
+ * watches cannot drift apart. An agent with no MCP target (the hard-deprecated
519
+ * `gemini`) keeps the historical settings.json default so old configs still
520
+ * parse.
521
+ */
522
+ export declare function getUserMcpConfigPath(agentId: AgentId): string;
523
+ /**
524
+ * Get MCP config path for a specific HOME directory (used for version-managed agents).
525
+ */
526
+ export declare function getMcpConfigPathForHome(agentId: AgentId, home: string): string;
527
+ /**
528
+ * Get project-scoped MCP config path for an agent.
529
+ */
530
+ export declare function getProjectMcpConfigPath(agentId: AgentId, cwd?: string): string;
531
+ /**
532
+ * Parse MCP config based on agent type.
533
+ */
534
+ export declare function parseMcpConfig(agentId: AgentId, configPath: string): Record<string, McpConfigEntry>;
535
+ /**
536
+ * List installed MCP servers with scope information.
537
+ * Pass options.home to read from a version-managed agent's home directory.
538
+ */
539
+ export declare function listInstalledMcpsWithScope(agentId: AgentId, cwd?: string, options?: {
540
+ home?: string;
541
+ }): InstalledMcp[];
542
+ /** Map of agent name aliases and shorthand identifiers to canonical AgentId values. */
543
+ export declare const AGENT_NAME_ALIASES: Record<string, AgentId>;
544
+ /**
545
+ * Resolve a user-provided agent name (alias, shorthand, or canonical) to its AgentId.
546
+ * Tolerates a single typo (insertion/deletion/substitution/transposition) against
547
+ * canonical ids and aliases — `cladue` -> claude, `kim` -> kimi, `codx` -> codex —
548
+ * but only when the correction is unambiguous (all distance-1 candidates agree on
549
+ * one agent). Two-letter shorthands are excluded as fuzzy candidates.
550
+ */
551
+ export declare function resolveAgentName(input: string): AgentId | null;
552
+ /** Check whether the input string matches any known agent name or alias. */
553
+ export declare function isAgentName(input: string): boolean;
554
+ /**
555
+ * Split a CLI-provided `<agent>[@<version>]` spec into its bare agent id and
556
+ * optional exact version token, the same way `agents run` does
557
+ * (commands/exec.ts parses its positional with a plain `split('@')`) — NOT the
558
+ * agent-spec qualifier engine (`@latest`/`@all`), which enumerates installed
559
+ * versions for read/diagnostic commands, not a single launch target. Returns an
560
+ * error message rather than throwing so callers decide exit-vs-continue.
561
+ */
562
+ export declare function parseAgentVersionSpec(raw: string): {
563
+ agent: AgentId;
564
+ version?: string;
565
+ } | {
566
+ error: string;
567
+ };
568
+ /**
569
+ * Build the deprecation notice lines for an agent, or null if it isn't
570
+ * deprecated. Split from the printer so tests can assert the content without
571
+ * capturing stdout. Lines are plain (uncolored) text.
572
+ */
573
+ export declare function deprecationNotice(agent: AgentId): string[] | null;
574
+ export declare function hardDeprecationNotice(agent: AgentId): string[] | null;
575
+ export declare function hardDeprecationError(agent: AgentId): string;
576
+ /**
577
+ * Print a deprecation warning (yellow) if the agent's registry entry carries a
578
+ * `deprecated` marker; no-op otherwise. Call from any user entry point that
579
+ * acts on a chosen agent — install (`agents add`) and `agents teams add`.
580
+ */
581
+ export declare function warnAgentDeprecated(agent: AgentId): void;
582
+ /** Format an error message for an unrecognized agent name, listing valid options. */
583
+ export declare function formatAgentError(agentName: string, validAgents?: AgentId[]): string;
584
+ export {};