@phnx-labs/agents-cli 1.20.4 → 1.20.5
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 +19 -0
- package/README.md +48 -17
- package/dist/commands/cli.js +1 -1
- package/dist/commands/cloud.js +1 -1
- package/dist/commands/commands.js +2 -0
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/exec.js +52 -16
- package/dist/commands/hooks.js +6 -6
- package/dist/commands/inspect.d.ts +26 -0
- package/dist/commands/inspect.js +590 -0
- package/dist/commands/mcp.js +17 -16
- package/dist/commands/models.js +1 -1
- package/dist/commands/packages.js +6 -4
- package/dist/commands/permissions.js +13 -12
- package/dist/commands/plugins.d.ts +13 -0
- package/dist/commands/plugins.js +100 -11
- package/dist/commands/prune.js +3 -2
- package/dist/commands/pull.d.ts +12 -5
- package/dist/commands/pull.js +26 -422
- package/dist/commands/push.d.ts +14 -0
- package/dist/commands/push.js +30 -0
- package/dist/commands/repo.d.ts +1 -1
- package/dist/commands/repo.js +155 -112
- package/dist/commands/resource-view.d.ts +2 -0
- package/dist/commands/resource-view.js +12 -3
- package/dist/commands/routines.js +32 -7
- package/dist/commands/rules.js +1 -1
- package/dist/commands/sessions.js +1 -0
- package/dist/commands/setup.d.ts +3 -3
- package/dist/commands/setup.js +15 -15
- package/dist/commands/skills.js +6 -5
- package/dist/commands/subagents.js +5 -4
- package/dist/commands/sync.d.ts +18 -5
- package/dist/commands/sync.js +251 -65
- package/dist/commands/teams.js +1 -0
- package/dist/commands/tmux.d.ts +25 -0
- package/dist/commands/tmux.js +415 -0
- package/dist/commands/trash.d.ts +2 -2
- package/dist/commands/trash.js +1 -1
- package/dist/commands/versions.js +2 -2
- package/dist/commands/view.js +9 -4
- package/dist/commands/workflows.js +4 -3
- package/dist/commands/worktree.d.ts +4 -5
- package/dist/commands/worktree.js +4 -4
- package/dist/index.js +68 -20
- package/dist/lib/agents.d.ts +19 -10
- package/dist/lib/agents.js +79 -25
- package/dist/lib/auto-pull-worker.d.ts +1 -1
- package/dist/lib/auto-pull-worker.js +2 -2
- package/dist/lib/auto-pull.d.ts +1 -1
- package/dist/lib/auto-pull.js +1 -1
- package/dist/lib/beta.d.ts +1 -1
- package/dist/lib/beta.js +1 -1
- package/dist/lib/capabilities.js +2 -0
- package/dist/lib/commands.d.ts +28 -1
- package/dist/lib/commands.js +125 -20
- package/dist/lib/doctor-diff.js +2 -2
- package/dist/lib/exec.d.ts +14 -0
- package/dist/lib/exec.js +39 -5
- package/dist/lib/fuzzy.d.ts +12 -2
- package/dist/lib/fuzzy.js +29 -4
- package/dist/lib/git.js +8 -1
- package/dist/lib/hooks.d.ts +2 -2
- package/dist/lib/hooks.js +97 -10
- package/dist/lib/mcp.js +32 -2
- package/dist/lib/migrate.d.ts +51 -0
- package/dist/lib/migrate.js +227 -1
- package/dist/lib/models.js +62 -15
- package/dist/lib/permissions.d.ts +36 -2
- package/dist/lib/permissions.js +217 -7
- package/dist/lib/plugin-marketplace.d.ts +98 -40
- package/dist/lib/plugin-marketplace.js +196 -93
- package/dist/lib/plugins.d.ts +21 -4
- package/dist/lib/plugins.js +130 -49
- package/dist/lib/profiles-presets.js +12 -12
- package/dist/lib/project-launch.d.ts +65 -0
- package/dist/lib/project-launch.js +367 -0
- package/dist/lib/pty-client.js +1 -1
- package/dist/lib/pty-server.d.ts +1 -1
- package/dist/lib/pty-server.js +1 -1
- package/dist/lib/refresh.d.ts +26 -0
- package/dist/lib/refresh.js +315 -0
- package/dist/lib/resource-patterns.d.ts +1 -1
- package/dist/lib/resource-patterns.js +1 -1
- package/dist/lib/resources/commands.js +2 -2
- package/dist/lib/resources/hooks.d.ts +1 -1
- package/dist/lib/resources/hooks.js +1 -1
- package/dist/lib/resources/mcp.d.ts +1 -1
- package/dist/lib/resources/mcp.js +5 -6
- package/dist/lib/resources/permissions.js +5 -2
- package/dist/lib/resources/rules.js +3 -2
- package/dist/lib/resources/skills.js +3 -2
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.js +2 -2
- package/dist/lib/rotate.d.ts +1 -1
- package/dist/lib/rotate.js +1 -1
- package/dist/lib/routines.d.ts +16 -4
- package/dist/lib/routines.js +67 -17
- package/dist/lib/rules/compile.js +22 -10
- package/dist/lib/rules/rules.js +3 -3
- package/dist/lib/runner.js +16 -3
- package/dist/lib/scheduler.js +15 -1
- 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/Agents CLI.app/Contents/_CodeSignature/CodeResources +9 -1
- package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
- package/dist/lib/secrets/linux.d.ts +44 -9
- package/dist/lib/secrets/linux.js +302 -48
- package/dist/lib/session/db.js +15 -2
- package/dist/lib/session/discover.js +118 -3
- package/dist/lib/session/parse.js +3 -0
- package/dist/lib/session/types.d.ts +1 -1
- package/dist/lib/session/types.js +1 -1
- package/dist/lib/shims.d.ts +10 -9
- package/dist/lib/shims.js +101 -50
- package/dist/lib/skills.d.ts +1 -1
- package/dist/lib/skills.js +10 -9
- package/dist/lib/staleness/detectors/commands.d.ts +3 -0
- package/dist/lib/staleness/detectors/commands.js +46 -0
- package/dist/lib/staleness/detectors/hooks.d.ts +3 -0
- package/dist/lib/staleness/detectors/hooks.js +44 -0
- package/dist/lib/staleness/detectors/mcp.d.ts +3 -0
- package/dist/lib/staleness/detectors/mcp.js +31 -0
- package/dist/lib/staleness/detectors/permissions.d.ts +3 -0
- package/dist/lib/staleness/detectors/permissions.js +201 -0
- package/dist/lib/staleness/detectors/plugins.d.ts +8 -0
- package/dist/lib/staleness/detectors/plugins.js +23 -0
- package/dist/lib/staleness/detectors/rules.d.ts +3 -0
- package/dist/lib/staleness/detectors/rules.js +34 -0
- package/dist/lib/staleness/detectors/skills.d.ts +3 -0
- package/dist/lib/staleness/detectors/skills.js +71 -0
- package/dist/lib/staleness/detectors/subagents.d.ts +3 -0
- package/dist/lib/staleness/detectors/subagents.js +50 -0
- package/dist/lib/staleness/detectors/types.d.ts +22 -0
- package/dist/lib/staleness/detectors/types.js +1 -0
- package/dist/lib/staleness/detectors/workflows.d.ts +3 -0
- package/dist/lib/staleness/detectors/workflows.js +28 -0
- package/dist/lib/staleness/registry.d.ts +26 -0
- package/dist/lib/staleness/registry.js +123 -0
- package/dist/lib/staleness/writers/commands.d.ts +3 -0
- package/dist/lib/staleness/writers/commands.js +111 -0
- package/dist/lib/staleness/writers/hooks.d.ts +3 -0
- package/dist/lib/staleness/writers/hooks.js +47 -0
- package/dist/lib/staleness/writers/kinds.d.ts +10 -0
- package/dist/lib/staleness/writers/kinds.js +15 -0
- package/dist/lib/staleness/writers/lazy-map.d.ts +13 -0
- package/dist/lib/staleness/writers/lazy-map.js +19 -0
- package/dist/lib/staleness/writers/mcp.d.ts +10 -0
- package/dist/lib/staleness/writers/mcp.js +19 -0
- package/dist/lib/staleness/writers/permissions.d.ts +13 -0
- package/dist/lib/staleness/writers/permissions.js +26 -0
- package/dist/lib/staleness/writers/plugins.d.ts +7 -0
- package/dist/lib/staleness/writers/plugins.js +31 -0
- package/dist/lib/staleness/writers/rules.d.ts +7 -0
- package/dist/lib/staleness/writers/rules.js +55 -0
- package/dist/lib/staleness/writers/skills.d.ts +3 -0
- package/dist/lib/staleness/writers/skills.js +81 -0
- package/dist/lib/staleness/writers/sources.d.ts +16 -0
- package/dist/lib/staleness/writers/sources.js +72 -0
- package/dist/lib/staleness/writers/subagents.d.ts +3 -0
- package/dist/lib/staleness/writers/subagents.js +53 -0
- package/dist/lib/staleness/writers/types.d.ts +36 -0
- package/dist/lib/staleness/writers/types.js +1 -0
- package/dist/lib/staleness/writers/workflows.d.ts +7 -0
- package/dist/lib/staleness/writers/workflows.js +31 -0
- package/dist/lib/state.d.ts +34 -11
- package/dist/lib/state.js +58 -13
- package/dist/lib/subagents.d.ts +0 -2
- package/dist/lib/subagents.js +6 -6
- package/dist/lib/teams/agents.js +1 -1
- package/dist/lib/teams/parsers.d.ts +1 -1
- package/dist/lib/tmux/binary.d.ts +67 -0
- package/dist/lib/tmux/binary.js +141 -0
- package/dist/lib/tmux/index.d.ts +8 -0
- package/dist/lib/tmux/index.js +8 -0
- package/dist/lib/tmux/paths.d.ts +17 -0
- package/dist/lib/tmux/paths.js +30 -0
- package/dist/lib/tmux/session.d.ts +122 -0
- package/dist/lib/tmux/session.js +305 -0
- package/dist/lib/types.d.ts +58 -7
- package/dist/lib/types.js +1 -1
- package/dist/lib/usage.js +1 -1
- package/dist/lib/versions.d.ts +4 -4
- package/dist/lib/versions.js +135 -493
- package/dist/lib/workflows.d.ts +2 -4
- package/dist/lib/workflows.js +3 -4
- package/package.json +2 -2
- package/scripts/postinstall.js +16 -63
- package/dist/commands/status.d.ts +0 -9
- package/dist/commands/status.js +0 -25
package/dist/lib/hooks.js
CHANGED
|
@@ -11,8 +11,8 @@ import * as fs from 'fs';
|
|
|
11
11
|
import * as path from 'path';
|
|
12
12
|
import * as yaml from 'yaml';
|
|
13
13
|
import * as TOML from 'smol-toml';
|
|
14
|
-
import { AGENTS,
|
|
15
|
-
import { supports, explainSkip } from './capabilities.js';
|
|
14
|
+
import { AGENTS, agentConfigDirName } from './agents.js';
|
|
15
|
+
import { supports, explainSkip, capableAgents } from './capabilities.js';
|
|
16
16
|
import { setGeminiAutoUpdateDisabled, updateGeminiSettings } from './gemini-settings.js';
|
|
17
17
|
import { getHooksDir as getSystemHooksDir, getUserHooksDir, getUserAgentsDir, getSystemAgentsDir, getProjectAgentsDir, getTrashHooksDir, getEnabledExtraRepos } from './state.js';
|
|
18
18
|
function getCentralHooksDir() { return getUserHooksDir(); }
|
|
@@ -117,7 +117,7 @@ function isExecutable(mode) {
|
|
|
117
117
|
function getHooksDir(agentId) {
|
|
118
118
|
const agent = AGENTS[agentId];
|
|
119
119
|
const home = getEffectiveHome(agentId);
|
|
120
|
-
return path.join(home,
|
|
120
|
+
return path.join(home, agentConfigDirName(agentId), agent.hooksDir);
|
|
121
121
|
}
|
|
122
122
|
function getProjectHooksDirs(agentId, cwd) {
|
|
123
123
|
const agent = AGENTS[agentId];
|
|
@@ -324,7 +324,7 @@ export function listInstalledHooksWithScope(agentId, cwd = process.cwd(), option
|
|
|
324
324
|
}
|
|
325
325
|
// User-scoped hooks (version-aware when home is provided)
|
|
326
326
|
const home = options?.home || getEffectiveHome(agentId);
|
|
327
|
-
const userDir = path.join(home,
|
|
327
|
+
const userDir = path.join(home, agentConfigDirName(agentId), agent.hooksDir);
|
|
328
328
|
const userHooks = listHookEntriesFromDir(userDir);
|
|
329
329
|
for (const hook of userHooks) {
|
|
330
330
|
addHook(hook, 'user', agentId);
|
|
@@ -363,7 +363,7 @@ export async function installHooks(source, agents, options = {}) {
|
|
|
363
363
|
*/
|
|
364
364
|
export function getVersionHooksDir(agent, version) {
|
|
365
365
|
const home = getVersionHomePath(agent, version);
|
|
366
|
-
return path.join(home,
|
|
366
|
+
return path.join(home, agentConfigDirName(agent), AGENTS[agent].hooksDir);
|
|
367
367
|
}
|
|
368
368
|
/**
|
|
369
369
|
* List hook entries in a specific version home.
|
|
@@ -489,7 +489,7 @@ export function removeHookFromVersion(agent, version, hookName) {
|
|
|
489
489
|
*/
|
|
490
490
|
export function iterHooksCapableVersions(filter) {
|
|
491
491
|
const pairs = [];
|
|
492
|
-
const hookAgents =
|
|
492
|
+
const hookAgents = capableAgents('hooks');
|
|
493
493
|
const agents = filter?.agent ? [filter.agent] : hookAgents;
|
|
494
494
|
for (const agent of agents) {
|
|
495
495
|
if (!hookAgents.includes(agent))
|
|
@@ -592,7 +592,7 @@ export async function installHooksCentrally(source) {
|
|
|
592
592
|
return { installed, errors };
|
|
593
593
|
}
|
|
594
594
|
/**
|
|
595
|
-
* List hooks from user (~/.agents/hooks/) and system (~/.agents
|
|
595
|
+
* List hooks from user (~/.agents/hooks/) and system (~/.agents/.system/hooks/) dirs.
|
|
596
596
|
* User dir takes priority; deduplication preserves first occurrence.
|
|
597
597
|
*/
|
|
598
598
|
export function listCentralHooks() {
|
|
@@ -609,7 +609,7 @@ export function listCentralHooks() {
|
|
|
609
609
|
return results;
|
|
610
610
|
}
|
|
611
611
|
/**
|
|
612
|
-
* Parse hook manifests. Reads system hooks from ~/.agents
|
|
612
|
+
* Parse hook manifests. Reads system hooks from ~/.agents/.system/hooks.yaml
|
|
613
613
|
* (npm-shipped defaults) and user hooks from the `hooks:` section of
|
|
614
614
|
* ~/.agents/agents.yaml. Merges with user-wins-on-key-collision precedence.
|
|
615
615
|
* A user entry with `enabled: false` disables the system-shipped hook of
|
|
@@ -663,7 +663,7 @@ const CODEX_MATCHER_EVENTS = new Set(['PreToolUse', 'PostToolUse', 'SessionStart
|
|
|
663
663
|
* Register hooks as lifecycle events in an agent's config.
|
|
664
664
|
* Reads hooks.yaml manifest, merges into the agent's config file(s).
|
|
665
665
|
* Only manages hooks whose command paths are under ~/.agents/hooks/ or
|
|
666
|
-
* ~/.agents
|
|
666
|
+
* ~/.agents/.system/hooks/. Does not remove user-added hooks.
|
|
667
667
|
*
|
|
668
668
|
* @param agentsDirOverride - When provided, treats this single dir as the
|
|
669
669
|
* only managed hook root. Used by tests to inject a temp path. In normal
|
|
@@ -702,7 +702,7 @@ export function registerHooksToSettings(agentId, versionHome, hookManifest, agen
|
|
|
702
702
|
// Scripts are copied into the version home during sync — prefer that stable
|
|
703
703
|
// local path so registered commands don't break when source dirs change.
|
|
704
704
|
const localHooksDir = !overrideRoots
|
|
705
|
-
? path.join(versionHome,
|
|
705
|
+
? path.join(versionHome, agentConfigDirName(agentId), AGENTS[agentId].hooksDir)
|
|
706
706
|
: null;
|
|
707
707
|
const resolveScript = (script) => {
|
|
708
708
|
if (overrideRoots) {
|
|
@@ -740,6 +740,9 @@ export function registerHooksToSettings(agentId, versionHome, hookManifest, agen
|
|
|
740
740
|
if (agentId === 'grok') {
|
|
741
741
|
return registerHooksForGrok(versionHome, manifest, resolveScript, managedPrefixes);
|
|
742
742
|
}
|
|
743
|
+
if (agentId === 'kimi') {
|
|
744
|
+
return registerHooksForKimi(versionHome, manifest, resolveScript, managedPrefixes);
|
|
745
|
+
}
|
|
743
746
|
return { registered: [], errors: [] };
|
|
744
747
|
}
|
|
745
748
|
/**
|
|
@@ -1217,3 +1220,87 @@ function registerHooksForGrok(versionHome, manifest, resolveScript, managedPrefi
|
|
|
1217
1220
|
}
|
|
1218
1221
|
return { registered, errors };
|
|
1219
1222
|
}
|
|
1223
|
+
function registerHooksForKimi(versionHome, manifest, resolveScript, managedPrefixes) {
|
|
1224
|
+
const registered = [];
|
|
1225
|
+
const errors = [];
|
|
1226
|
+
const configPath = path.join(versionHome, '.kimi-code', 'config.toml');
|
|
1227
|
+
// Read existing config.toml
|
|
1228
|
+
let config = {};
|
|
1229
|
+
if (fs.existsSync(configPath)) {
|
|
1230
|
+
try {
|
|
1231
|
+
config = TOML.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
1232
|
+
}
|
|
1233
|
+
catch {
|
|
1234
|
+
errors.push('Failed to parse config.toml');
|
|
1235
|
+
return { registered, errors };
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
// Build set of current manifest command paths for GC
|
|
1239
|
+
const currentManifestPaths = new Set();
|
|
1240
|
+
for (const [hookName, hookDef] of Object.entries(manifest)) {
|
|
1241
|
+
if (!hookDef.events || hookDef.events.length === 0)
|
|
1242
|
+
continue;
|
|
1243
|
+
const resolved = resolveHookCommand(hookName, hookDef, resolveScript);
|
|
1244
|
+
if (resolved)
|
|
1245
|
+
currentManifestPaths.add(resolved);
|
|
1246
|
+
}
|
|
1247
|
+
// Remove stale managed hooks from existing hooks array
|
|
1248
|
+
let hooksArray = [];
|
|
1249
|
+
if (Array.isArray(config.hooks)) {
|
|
1250
|
+
hooksArray = config.hooks;
|
|
1251
|
+
}
|
|
1252
|
+
const filteredHooks = hooksArray.filter((h) => {
|
|
1253
|
+
const cmd = typeof h.command === 'string' ? h.command : '';
|
|
1254
|
+
if (!cmd)
|
|
1255
|
+
return true;
|
|
1256
|
+
const isManaged = managedPrefixes.some((p) => cmd.startsWith(p));
|
|
1257
|
+
if (!isManaged)
|
|
1258
|
+
return true;
|
|
1259
|
+
return currentManifestPaths.has(cmd);
|
|
1260
|
+
});
|
|
1261
|
+
// Add/update hooks from manifest
|
|
1262
|
+
for (const [name, hookDef] of Object.entries(manifest)) {
|
|
1263
|
+
if (!hookDef.events || hookDef.events.length === 0)
|
|
1264
|
+
continue;
|
|
1265
|
+
const commandPath = resolveHookCommand(name, hookDef, resolveScript);
|
|
1266
|
+
if (!commandPath) {
|
|
1267
|
+
errors.push(`${name}: script not found in user or system hooks dir`);
|
|
1268
|
+
continue;
|
|
1269
|
+
}
|
|
1270
|
+
const timeout = hookDef.timeout ?? 30;
|
|
1271
|
+
for (const event of hookDef.events) {
|
|
1272
|
+
const matcher = hookDef.matcher;
|
|
1273
|
+
// Find existing hook with same event, command, and matcher
|
|
1274
|
+
const existingIdx = filteredHooks.findIndex((h) => {
|
|
1275
|
+
const sameEvent = h.event === event;
|
|
1276
|
+
const sameCmd = h.command === commandPath;
|
|
1277
|
+
const sameMatcher = (h.matcher ?? '') === (matcher ?? '');
|
|
1278
|
+
return sameEvent && sameCmd && sameMatcher;
|
|
1279
|
+
});
|
|
1280
|
+
const hookEntry = {
|
|
1281
|
+
event,
|
|
1282
|
+
command: commandPath,
|
|
1283
|
+
timeout,
|
|
1284
|
+
};
|
|
1285
|
+
if (matcher) {
|
|
1286
|
+
hookEntry.matcher = matcher;
|
|
1287
|
+
}
|
|
1288
|
+
if (existingIdx >= 0) {
|
|
1289
|
+
filteredHooks[existingIdx] = hookEntry;
|
|
1290
|
+
}
|
|
1291
|
+
else {
|
|
1292
|
+
filteredHooks.push(hookEntry);
|
|
1293
|
+
}
|
|
1294
|
+
registered.push(`${name} -> ${event}`);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
config.hooks = filteredHooks;
|
|
1298
|
+
try {
|
|
1299
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
1300
|
+
fs.writeFileSync(configPath, TOML.stringify(config), 'utf-8');
|
|
1301
|
+
}
|
|
1302
|
+
catch (err) {
|
|
1303
|
+
errors.push(`Failed to write config.toml: ${err.message}`);
|
|
1304
|
+
}
|
|
1305
|
+
return { registered, errors };
|
|
1306
|
+
}
|
package/dist/lib/mcp.js
CHANGED
|
@@ -13,7 +13,8 @@ import * as yaml from 'yaml';
|
|
|
13
13
|
import { execFileSync } from 'child_process';
|
|
14
14
|
import { getMcpDir, getUserMcpDir, getProjectAgentsDir, getVersionsDir } from './state.js';
|
|
15
15
|
import { getBinaryPath, getVersionHomePath } from './versions.js';
|
|
16
|
-
import {
|
|
16
|
+
import { AGENTS } from './agents.js';
|
|
17
|
+
import { isCapable } from './capabilities.js';
|
|
17
18
|
import { setGeminiAutoUpdateDisabled, updateGeminiSettings } from './gemini-settings.js';
|
|
18
19
|
/**
|
|
19
20
|
* Parse an MCP server config from a YAML file.
|
|
@@ -312,6 +313,31 @@ function installMcpToCursorConfig(server, versionHome) {
|
|
|
312
313
|
/**
|
|
313
314
|
* Install MCP server to OpenCode config file.
|
|
314
315
|
*/
|
|
316
|
+
function installMcpToKimiConfig(server, versionHome) {
|
|
317
|
+
const configPath = path.join(versionHome, '.kimi-code', 'mcp.json');
|
|
318
|
+
let config = {};
|
|
319
|
+
if (fs.existsSync(configPath)) {
|
|
320
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
321
|
+
}
|
|
322
|
+
if (!config.mcpServers || typeof config.mcpServers !== 'object') {
|
|
323
|
+
config.mcpServers = {};
|
|
324
|
+
}
|
|
325
|
+
const mcpServers = config.mcpServers;
|
|
326
|
+
if (server.config.transport === 'stdio') {
|
|
327
|
+
mcpServers[server.name] = {
|
|
328
|
+
command: server.config.command,
|
|
329
|
+
args: server.config.args || [],
|
|
330
|
+
env: server.config.env || {},
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
mcpServers[server.name] = {
|
|
335
|
+
url: server.config.url,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
fs.mkdirSync(path.dirname(configPath), { recursive: true });
|
|
339
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
340
|
+
}
|
|
315
341
|
function installMcpToOpenCodeConfig(server, versionHome) {
|
|
316
342
|
const configPath = path.join(versionHome, '.opencode', 'opencode.jsonc');
|
|
317
343
|
let config = {};
|
|
@@ -354,7 +380,7 @@ function installMcpToOpenCodeConfig(server, versionHome) {
|
|
|
354
380
|
* For others: edits config files directly
|
|
355
381
|
*/
|
|
356
382
|
export function installMcpServers(agentId, version, versionHome, mcpNames, options = {}) {
|
|
357
|
-
if (!
|
|
383
|
+
if (!isCapable(agentId, 'mcp')) {
|
|
358
384
|
return { success: true, applied: [], errors: [] };
|
|
359
385
|
}
|
|
360
386
|
const servers = getMcpServersByName(mcpNames, { cwd: options.cwd });
|
|
@@ -394,6 +420,10 @@ export function installMcpServers(agentId, version, versionHome, mcpNames, optio
|
|
|
394
420
|
// For now the general sync + toml editing via agents mcp works via the path helpers.
|
|
395
421
|
applied.push(server.name);
|
|
396
422
|
}
|
|
423
|
+
else if (agentId === 'kimi') {
|
|
424
|
+
installMcpToKimiConfig(server, versionHome);
|
|
425
|
+
applied.push(server.name);
|
|
426
|
+
}
|
|
397
427
|
}
|
|
398
428
|
catch (err) {
|
|
399
429
|
const message = err.message;
|
package/dist/lib/migrate.d.ts
CHANGED
|
@@ -4,5 +4,56 @@
|
|
|
4
4
|
* Called from postinstall and as a command-time fallback from agents view/use/pull.
|
|
5
5
|
* Each migration is guarded by an existence check so re-running is safe.
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* Fold ~/.agents-system/ into ~/.agents/.system/.
|
|
9
|
+
*
|
|
10
|
+
* MUST run first in runMigration() — every other migrator reads SYSTEM_DIR
|
|
11
|
+
* (the new path), so the contents have to be there before they execute.
|
|
12
|
+
*
|
|
13
|
+
* Strategy:
|
|
14
|
+
* 1. If legacy dir doesn't exist or is already a symlink, no-op.
|
|
15
|
+
* 2. If new path doesn't exist yet, rename in one shot (fast path).
|
|
16
|
+
* 3. If both exist (mid-migration / re-run on partially-migrated state),
|
|
17
|
+
* merge legacy → new with new winning on collision, then drop legacy.
|
|
18
|
+
*
|
|
19
|
+
* After the contents move, the legacy path becomes a symlink → SYSTEM_DIR
|
|
20
|
+
* so external tooling that still references ~/.agents-system/ keeps
|
|
21
|
+
* resolving correctly. The symlink is harmless on its own and can be
|
|
22
|
+
* removed with `rm ~/.agents-system` once everything has updated.
|
|
23
|
+
*
|
|
24
|
+
* Idempotent: re-running converges to "contents at SYSTEM_DIR, symlink at
|
|
25
|
+
* LEGACY_SYSTEM_DIR" without duplicating data.
|
|
26
|
+
*/
|
|
27
|
+
export declare function foldLegacySystemRepo(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Rename the legacy `extras-extras/` plugin-marketplace dir to `agents-extras/`
|
|
30
|
+
* inside every installed agent version-home, and rewrite cross-references in
|
|
31
|
+
* `known_marketplaces.json` and the agent's `settings.json`.
|
|
32
|
+
*
|
|
33
|
+
* A previous dev build of `agents-cli` named the extras-aliased repo's
|
|
34
|
+
* synthesized marketplace dir `extras-extras` (double "extras" because the alias
|
|
35
|
+
* itself was `extras`). The new naming convention is `agents-<alias>`, so the
|
|
36
|
+
* directory should be `agents-extras`. Without this migration the orphan dir
|
|
37
|
+
* stays on disk and Claude Code loads two parallel marketplaces (the legacy
|
|
38
|
+
* `extras-extras` entry from `known_marketplaces.json` plus the freshly
|
|
39
|
+
* synthesized `agents-extras` from the new code path).
|
|
40
|
+
*
|
|
41
|
+
* Strategy per `<historyDir>/versions/<agent>/<ver>/home/.<agent>/plugins/`:
|
|
42
|
+
* 1. `marketplaces/extras-extras/` → `marketplaces/agents-extras/`
|
|
43
|
+
* (drops `extras-extras/` outright when `agents-extras/` already exists —
|
|
44
|
+
* previous incomplete migration ran)
|
|
45
|
+
* 2. Inside the renamed dir's `.claude-plugin/marketplace.json`, set
|
|
46
|
+
* `"name": "agents-extras"`.
|
|
47
|
+
* 3. In `<configDir>/plugins/known_marketplaces.json`, rename the
|
|
48
|
+
* `extras-extras` key to `agents-extras` and rewrite `source.path` /
|
|
49
|
+
* `installLocation`.
|
|
50
|
+
* 4. In `<configDir>/settings.json`'s `enabledPlugins`, rename every
|
|
51
|
+
* `<plugin>@extras-extras` key to `<plugin>@agents-extras` (preserving
|
|
52
|
+
* its boolean value, skipping if the new key already exists).
|
|
53
|
+
*
|
|
54
|
+
* Idempotent: re-running converges without further writes once everything is on
|
|
55
|
+
* the new name.
|
|
56
|
+
*/
|
|
57
|
+
export declare function migrateExtrasExtrasToAgentsExtras(historyDir?: string): void;
|
|
7
58
|
/** Run all idempotent migrations. Safe to call multiple times. */
|
|
8
59
|
export declare function runMigration(): Promise<void>;
|
package/dist/lib/migrate.js
CHANGED
|
@@ -9,10 +9,74 @@ import * as path from 'path';
|
|
|
9
9
|
import * as os from 'os';
|
|
10
10
|
import * as yaml from 'yaml';
|
|
11
11
|
const HOME = process.env.HOME ?? os.homedir();
|
|
12
|
-
const SYSTEM_DIR = path.join(HOME, '.agents-system');
|
|
13
12
|
const USER_DIR = path.join(HOME, '.agents');
|
|
13
|
+
/** Canonical system-repo location (post-fold). */
|
|
14
|
+
const SYSTEM_DIR = path.join(USER_DIR, '.system');
|
|
15
|
+
/** Legacy system-repo location — folded into SYSTEM_DIR by foldLegacySystemRepo(). */
|
|
16
|
+
const LEGACY_SYSTEM_DIR = path.join(HOME, '.agents-system');
|
|
14
17
|
const HISTORY_DIR = path.join(USER_DIR, '.history');
|
|
15
18
|
const CACHE_DIR = path.join(USER_DIR, '.cache');
|
|
19
|
+
/**
|
|
20
|
+
* Fold ~/.agents-system/ into ~/.agents/.system/.
|
|
21
|
+
*
|
|
22
|
+
* MUST run first in runMigration() — every other migrator reads SYSTEM_DIR
|
|
23
|
+
* (the new path), so the contents have to be there before they execute.
|
|
24
|
+
*
|
|
25
|
+
* Strategy:
|
|
26
|
+
* 1. If legacy dir doesn't exist or is already a symlink, no-op.
|
|
27
|
+
* 2. If new path doesn't exist yet, rename in one shot (fast path).
|
|
28
|
+
* 3. If both exist (mid-migration / re-run on partially-migrated state),
|
|
29
|
+
* merge legacy → new with new winning on collision, then drop legacy.
|
|
30
|
+
*
|
|
31
|
+
* After the contents move, the legacy path becomes a symlink → SYSTEM_DIR
|
|
32
|
+
* so external tooling that still references ~/.agents-system/ keeps
|
|
33
|
+
* resolving correctly. The symlink is harmless on its own and can be
|
|
34
|
+
* removed with `rm ~/.agents-system` once everything has updated.
|
|
35
|
+
*
|
|
36
|
+
* Idempotent: re-running converges to "contents at SYSTEM_DIR, symlink at
|
|
37
|
+
* LEGACY_SYSTEM_DIR" without duplicating data.
|
|
38
|
+
*/
|
|
39
|
+
export function foldLegacySystemRepo() {
|
|
40
|
+
let legacyStat = null;
|
|
41
|
+
try {
|
|
42
|
+
legacyStat = fs.lstatSync(LEGACY_SYSTEM_DIR);
|
|
43
|
+
}
|
|
44
|
+
catch { /* missing */ }
|
|
45
|
+
if (!legacyStat)
|
|
46
|
+
return;
|
|
47
|
+
if (legacyStat.isSymbolicLink())
|
|
48
|
+
return;
|
|
49
|
+
if (!legacyStat.isDirectory())
|
|
50
|
+
return;
|
|
51
|
+
try {
|
|
52
|
+
fs.mkdirSync(USER_DIR, { recursive: true, mode: 0o700 });
|
|
53
|
+
}
|
|
54
|
+
catch { /* best-effort */ }
|
|
55
|
+
if (!fs.existsSync(SYSTEM_DIR)) {
|
|
56
|
+
try {
|
|
57
|
+
fs.renameSync(LEGACY_SYSTEM_DIR, SYSTEM_DIR);
|
|
58
|
+
try {
|
|
59
|
+
fs.symlinkSync(SYSTEM_DIR, LEGACY_SYSTEM_DIR);
|
|
60
|
+
}
|
|
61
|
+
catch { /* best-effort */ }
|
|
62
|
+
console.error('Folded ~/.agents-system/ into ~/.agents/.system/ (left back-compat symlink)');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Cross-device rename or perm issue — fall through to copy + remove.
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
copyDirSkipExisting(LEGACY_SYSTEM_DIR, SYSTEM_DIR);
|
|
71
|
+
fs.rmSync(LEGACY_SYSTEM_DIR, { recursive: true, force: true });
|
|
72
|
+
try {
|
|
73
|
+
fs.symlinkSync(SYSTEM_DIR, LEGACY_SYSTEM_DIR);
|
|
74
|
+
}
|
|
75
|
+
catch { /* best-effort */ }
|
|
76
|
+
console.error('Merged ~/.agents-system/ into ~/.agents/.system/ (left back-compat symlink)');
|
|
77
|
+
}
|
|
78
|
+
catch { /* best-effort */ }
|
|
79
|
+
}
|
|
16
80
|
/**
|
|
17
81
|
* Move ~/.agents-system/agents.yaml -> ~/.agents/agents.yaml.
|
|
18
82
|
* No-op if user file already exists or system file absent.
|
|
@@ -1461,8 +1525,166 @@ function migrateVersionResourcesToPatterns() {
|
|
|
1461
1525
|
console.error('Migrated agents.yaml versions: entries to pattern format');
|
|
1462
1526
|
}
|
|
1463
1527
|
}
|
|
1528
|
+
/**
|
|
1529
|
+
* Rename the legacy `extras-extras/` plugin-marketplace dir to `agents-extras/`
|
|
1530
|
+
* inside every installed agent version-home, and rewrite cross-references in
|
|
1531
|
+
* `known_marketplaces.json` and the agent's `settings.json`.
|
|
1532
|
+
*
|
|
1533
|
+
* A previous dev build of `agents-cli` named the extras-aliased repo's
|
|
1534
|
+
* synthesized marketplace dir `extras-extras` (double "extras" because the alias
|
|
1535
|
+
* itself was `extras`). The new naming convention is `agents-<alias>`, so the
|
|
1536
|
+
* directory should be `agents-extras`. Without this migration the orphan dir
|
|
1537
|
+
* stays on disk and Claude Code loads two parallel marketplaces (the legacy
|
|
1538
|
+
* `extras-extras` entry from `known_marketplaces.json` plus the freshly
|
|
1539
|
+
* synthesized `agents-extras` from the new code path).
|
|
1540
|
+
*
|
|
1541
|
+
* Strategy per `<historyDir>/versions/<agent>/<ver>/home/.<agent>/plugins/`:
|
|
1542
|
+
* 1. `marketplaces/extras-extras/` → `marketplaces/agents-extras/`
|
|
1543
|
+
* (drops `extras-extras/` outright when `agents-extras/` already exists —
|
|
1544
|
+
* previous incomplete migration ran)
|
|
1545
|
+
* 2. Inside the renamed dir's `.claude-plugin/marketplace.json`, set
|
|
1546
|
+
* `"name": "agents-extras"`.
|
|
1547
|
+
* 3. In `<configDir>/plugins/known_marketplaces.json`, rename the
|
|
1548
|
+
* `extras-extras` key to `agents-extras` and rewrite `source.path` /
|
|
1549
|
+
* `installLocation`.
|
|
1550
|
+
* 4. In `<configDir>/settings.json`'s `enabledPlugins`, rename every
|
|
1551
|
+
* `<plugin>@extras-extras` key to `<plugin>@agents-extras` (preserving
|
|
1552
|
+
* its boolean value, skipping if the new key already exists).
|
|
1553
|
+
*
|
|
1554
|
+
* Idempotent: re-running converges without further writes once everything is on
|
|
1555
|
+
* the new name.
|
|
1556
|
+
*/
|
|
1557
|
+
export function migrateExtrasExtrasToAgentsExtras(historyDir = HISTORY_DIR) {
|
|
1558
|
+
const versionsRoot = path.join(historyDir, 'versions');
|
|
1559
|
+
if (!fs.existsSync(versionsRoot))
|
|
1560
|
+
return;
|
|
1561
|
+
const OLD = 'extras-extras';
|
|
1562
|
+
const NEW = 'agents-extras';
|
|
1563
|
+
let agentEntries;
|
|
1564
|
+
try {
|
|
1565
|
+
agentEntries = fs.readdirSync(versionsRoot, { withFileTypes: true });
|
|
1566
|
+
}
|
|
1567
|
+
catch {
|
|
1568
|
+
return;
|
|
1569
|
+
}
|
|
1570
|
+
let renamedDirs = 0;
|
|
1571
|
+
let rewroteKnown = 0;
|
|
1572
|
+
let rewroteSettings = 0;
|
|
1573
|
+
for (const agentEntry of agentEntries) {
|
|
1574
|
+
if (!agentEntry.isDirectory())
|
|
1575
|
+
continue;
|
|
1576
|
+
const agentId = agentEntry.name;
|
|
1577
|
+
const agentVersionsDir = path.join(versionsRoot, agentId);
|
|
1578
|
+
let verEntries;
|
|
1579
|
+
try {
|
|
1580
|
+
verEntries = fs.readdirSync(agentVersionsDir, { withFileTypes: true });
|
|
1581
|
+
}
|
|
1582
|
+
catch {
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
for (const ver of verEntries) {
|
|
1586
|
+
if (!ver.isDirectory())
|
|
1587
|
+
continue;
|
|
1588
|
+
const configDir = path.join(agentVersionsDir, ver.name, 'home', `.${agentId}`);
|
|
1589
|
+
const pluginsDir = path.join(configDir, 'plugins');
|
|
1590
|
+
if (!fs.existsSync(pluginsDir))
|
|
1591
|
+
continue;
|
|
1592
|
+
const marketplacesDir = path.join(pluginsDir, 'marketplaces');
|
|
1593
|
+
const oldDir = path.join(marketplacesDir, OLD);
|
|
1594
|
+
const newDir = path.join(marketplacesDir, NEW);
|
|
1595
|
+
const oldExists = fs.existsSync(oldDir);
|
|
1596
|
+
const newExists = fs.existsSync(newDir);
|
|
1597
|
+
if (oldExists && !newExists) {
|
|
1598
|
+
try {
|
|
1599
|
+
fs.renameSync(oldDir, newDir);
|
|
1600
|
+
renamedDirs++;
|
|
1601
|
+
}
|
|
1602
|
+
catch { /* best-effort, leave orphan */ }
|
|
1603
|
+
}
|
|
1604
|
+
else if (oldExists && newExists) {
|
|
1605
|
+
// Previous incomplete migration — drop the stale old dir.
|
|
1606
|
+
try {
|
|
1607
|
+
fs.rmSync(oldDir, { recursive: true, force: true });
|
|
1608
|
+
}
|
|
1609
|
+
catch { /* best-effort */ }
|
|
1610
|
+
}
|
|
1611
|
+
// Rewrite marketplace.json name field inside the (now) agents-extras dir.
|
|
1612
|
+
const marketplaceJson = path.join(newDir, '.claude-plugin', 'marketplace.json');
|
|
1613
|
+
if (fs.existsSync(marketplaceJson)) {
|
|
1614
|
+
try {
|
|
1615
|
+
const raw = fs.readFileSync(marketplaceJson, 'utf-8');
|
|
1616
|
+
const parsed = JSON.parse(raw);
|
|
1617
|
+
if (parsed?.name === OLD) {
|
|
1618
|
+
parsed.name = NEW;
|
|
1619
|
+
fs.writeFileSync(marketplaceJson, JSON.stringify(parsed, null, 2) + '\n', 'utf-8');
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
catch { /* best-effort */ }
|
|
1623
|
+
}
|
|
1624
|
+
// Rewrite known_marketplaces.json key + path fields.
|
|
1625
|
+
const knownFile = path.join(pluginsDir, 'known_marketplaces.json');
|
|
1626
|
+
if (fs.existsSync(knownFile)) {
|
|
1627
|
+
try {
|
|
1628
|
+
const raw = fs.readFileSync(knownFile, 'utf-8');
|
|
1629
|
+
const known = JSON.parse(raw);
|
|
1630
|
+
if (known && typeof known === 'object' && OLD in known) {
|
|
1631
|
+
const entry = known[OLD];
|
|
1632
|
+
if (!(NEW in known)) {
|
|
1633
|
+
if (entry?.source?.path)
|
|
1634
|
+
entry.source.path = entry.source.path.split(OLD).join(NEW);
|
|
1635
|
+
if (entry?.installLocation)
|
|
1636
|
+
entry.installLocation = entry.installLocation.split(OLD).join(NEW);
|
|
1637
|
+
known[NEW] = entry;
|
|
1638
|
+
}
|
|
1639
|
+
delete known[OLD];
|
|
1640
|
+
fs.writeFileSync(knownFile, JSON.stringify(known, null, 2) + '\n', 'utf-8');
|
|
1641
|
+
rewroteKnown++;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
catch { /* best-effort */ }
|
|
1645
|
+
}
|
|
1646
|
+
// Rewrite settings.json enabledPlugins keys.
|
|
1647
|
+
const settingsFile = path.join(configDir, 'settings.json');
|
|
1648
|
+
if (fs.existsSync(settingsFile)) {
|
|
1649
|
+
try {
|
|
1650
|
+
const raw = fs.readFileSync(settingsFile, 'utf-8');
|
|
1651
|
+
const settings = JSON.parse(raw);
|
|
1652
|
+
const enabled = settings?.enabledPlugins;
|
|
1653
|
+
if (enabled && typeof enabled === 'object') {
|
|
1654
|
+
const suffix = `@${OLD}`;
|
|
1655
|
+
const newSuffix = `@${NEW}`;
|
|
1656
|
+
let changed = false;
|
|
1657
|
+
for (const key of Object.keys(enabled)) {
|
|
1658
|
+
if (!key.endsWith(suffix))
|
|
1659
|
+
continue;
|
|
1660
|
+
const renamed = key.slice(0, -suffix.length) + newSuffix;
|
|
1661
|
+
if (renamed in enabled) {
|
|
1662
|
+
delete enabled[key];
|
|
1663
|
+
}
|
|
1664
|
+
else {
|
|
1665
|
+
enabled[renamed] = enabled[key];
|
|
1666
|
+
delete enabled[key];
|
|
1667
|
+
}
|
|
1668
|
+
changed = true;
|
|
1669
|
+
}
|
|
1670
|
+
if (changed) {
|
|
1671
|
+
fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
|
|
1672
|
+
rewroteSettings++;
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
catch { /* best-effort */ }
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
if (renamedDirs > 0 || rewroteKnown > 0 || rewroteSettings > 0) {
|
|
1681
|
+
console.error(`Renamed extras-extras → agents-extras (dirs: ${renamedDirs}, known_marketplaces: ${rewroteKnown}, settings: ${rewroteSettings})`);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1464
1684
|
/** Run all idempotent migrations. Safe to call multiple times. */
|
|
1465
1685
|
export async function runMigration() {
|
|
1686
|
+
// MUST run first: every other migrator reads SYSTEM_DIR (the new path).
|
|
1687
|
+
foldLegacySystemRepo();
|
|
1466
1688
|
migrateAgentsYaml();
|
|
1467
1689
|
deleteSystemPromptsJson();
|
|
1468
1690
|
migrateSystemConfigJson();
|
|
@@ -1503,6 +1725,10 @@ export async function runMigration() {
|
|
|
1503
1725
|
await migrateSystemCloudToCache();
|
|
1504
1726
|
dropDeadSystemArtifacts();
|
|
1505
1727
|
warnSystemOrphans();
|
|
1728
|
+
// Rename the legacy extras-extras marketplace dir to agents-extras across every
|
|
1729
|
+
// installed version-home. Runs after migrateRuntimeToHistory so the version
|
|
1730
|
+
// homes are at their canonical HISTORY_DIR location.
|
|
1731
|
+
migrateExtrasExtrasToAgentsExtras();
|
|
1506
1732
|
// Symlink repair runs LAST so it can find the post-move version homes.
|
|
1507
1733
|
repairAgentConfigSymlinks();
|
|
1508
1734
|
}
|
package/dist/lib/models.js
CHANGED
|
@@ -78,27 +78,72 @@ export function locateModelSource(agent, version) {
|
|
|
78
78
|
return null;
|
|
79
79
|
}
|
|
80
80
|
if (agent === 'codex') {
|
|
81
|
+
// Codex's vendored binary has moved across releases:
|
|
82
|
+
// <=0.98: @openai/codex/vendor/<triple>/codex/codex
|
|
83
|
+
// 0.99..0.13: @openai/codex-<plat>-<arch>/vendor/<triple>/codex/codex
|
|
84
|
+
// 0.134+: @openai/codex-<plat>-<arch>/vendor/<triple>/bin/codex
|
|
85
|
+
// We probe all known shapes; first hit wins.
|
|
86
|
+
const triples = ['aarch64-apple-darwin', 'x86_64-apple-darwin', 'x86_64-unknown-linux-musl', 'aarch64-unknown-linux-musl', 'x86_64-pc-windows-msvc', 'aarch64-pc-windows-msvc'];
|
|
81
87
|
const triple = currentTargetTriple();
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
const orderedTriples = triple ? [triple, ...triples.filter((t) => t !== triple)] : triples;
|
|
89
|
+
const platformPkgFor = (t) => `codex-${t.includes('apple') ? 'darwin' : t.includes('linux') ? 'linux' : 'win32'}-${t.includes('aarch64') ? 'arm64' : 'x64'}`;
|
|
90
|
+
for (const t of orderedTriples) {
|
|
91
|
+
const candidates = [
|
|
92
|
+
path.join(versionDir, 'node_modules', '@openai', platformPkgFor(t), 'vendor', t, 'bin', 'codex'),
|
|
93
|
+
path.join(versionDir, 'node_modules', '@openai', platformPkgFor(t), 'vendor', t, 'codex', 'codex'),
|
|
94
|
+
path.join(versionDir, 'node_modules', '@openai', 'codex', 'vendor', t, 'bin', 'codex'),
|
|
95
|
+
path.join(versionDir, 'node_modules', '@openai', 'codex', 'vendor', t, 'codex', 'codex'),
|
|
96
|
+
];
|
|
97
|
+
for (const p of candidates) {
|
|
98
|
+
if (fs.existsSync(p))
|
|
99
|
+
return { path: p, kind: 'binary' };
|
|
100
|
+
}
|
|
93
101
|
}
|
|
94
102
|
return null;
|
|
95
103
|
}
|
|
96
104
|
if (agent === 'gemini') {
|
|
97
|
-
//
|
|
98
|
-
//
|
|
105
|
+
// <=0.41 shipped a clean ES module at @google/gemini-cli-core/dist/src/config/models.js.
|
|
106
|
+
// 0.42+ inlines the same constants into a minified chunk under @google/gemini-cli/bundle/.
|
|
99
107
|
const modelsJs = path.join(versionDir, 'node_modules', '@google', 'gemini-cli-core', 'dist', 'src', 'config', 'models.js');
|
|
100
108
|
if (fs.existsSync(modelsJs))
|
|
101
109
|
return { path: modelsJs, kind: 'js' };
|
|
110
|
+
const bundleDir = path.join(versionDir, 'node_modules', '@google', 'gemini-cli', 'bundle');
|
|
111
|
+
if (fs.existsSync(bundleDir)) {
|
|
112
|
+
try {
|
|
113
|
+
const entries = fs.readdirSync(bundleDir);
|
|
114
|
+
// The model constants live in a single chunk; pick the first .js file
|
|
115
|
+
// whose contents contain VALID_GEMINI_MODELS. Skip subdirectories.
|
|
116
|
+
for (const name of entries) {
|
|
117
|
+
if (!name.endsWith('.js'))
|
|
118
|
+
continue;
|
|
119
|
+
const full = path.join(bundleDir, name);
|
|
120
|
+
let stat;
|
|
121
|
+
try {
|
|
122
|
+
stat = fs.statSync(full);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (!stat.isFile())
|
|
128
|
+
continue;
|
|
129
|
+
// Most chunks just re-export the constants; only the defining chunk
|
|
130
|
+
// actually has `var VALID_GEMINI_MODELS = ... new Set(`. Match that
|
|
131
|
+
// shape so we pick the chunk that the extractor can parse.
|
|
132
|
+
let body;
|
|
133
|
+
try {
|
|
134
|
+
body = fs.readFileSync(full, 'utf-8');
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (/var\s+VALID_GEMINI_MODELS\s*=[^\n]*new\s+Set/.test(body) &&
|
|
140
|
+
/var\s+DEFAULT_GEMINI_MODEL\s*=/.test(body)) {
|
|
141
|
+
return { path: full, kind: 'js' };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch { /* unreadable bundle dir */ }
|
|
146
|
+
}
|
|
102
147
|
return null;
|
|
103
148
|
}
|
|
104
149
|
if (agent === 'opencode') {
|
|
@@ -296,7 +341,9 @@ function extractCodexCatalog(text) {
|
|
|
296
341
|
* would pollute the runtime and ES-module interop is awkward from a CJS build).
|
|
297
342
|
*/
|
|
298
343
|
function extractGeminiCatalog(text) {
|
|
299
|
-
const
|
|
344
|
+
// Old (<=0.41) layout used `export const FOO = 'bar';` in models.js.
|
|
345
|
+
// New (0.42+) bundle inlines the same constants as `var FOO = "bar";`.
|
|
346
|
+
const constRe = /(?:export\s+const|var)\s+([A-Z0-9_]+)\s*=\s*['"]([^'"]+)['"]/g;
|
|
300
347
|
const constants = new Map();
|
|
301
348
|
let m;
|
|
302
349
|
while ((m = constRe.exec(text)) !== null) {
|
|
@@ -305,7 +352,7 @@ function extractGeminiCatalog(text) {
|
|
|
305
352
|
// The set of ids the CLI accepts as "valid model names". Names (not values)
|
|
306
353
|
// are listed inside `new Set([...])`, so we expand them via the constants map.
|
|
307
354
|
const validIds = new Set();
|
|
308
|
-
const setBlock = text.match(/VALID_GEMINI_MODELS\s*=\s*new\s+Set\(\[([\s\S]*?)\]\)/);
|
|
355
|
+
const setBlock = text.match(/VALID_GEMINI_MODELS\s*=\s*(?:\/\*[^*]*\*\/\s*)?new\s+Set\(\[([\s\S]*?)\]\)/);
|
|
309
356
|
if (setBlock) {
|
|
310
357
|
const nameRe = /([A-Z0-9_]+)/g;
|
|
311
358
|
let nm;
|