llm-cli-gateway 1.5.18 → 1.5.21
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 +24 -0
- package/dist/async-job-manager.js +3 -2
- package/dist/executor.d.ts +10 -0
- package/dist/executor.js +115 -10
- package/dist/index.d.ts +18 -0
- package/dist/index.js +4 -5
- package/dist/model-registry.d.ts +2 -0
- package/dist/model-registry.js +48 -0
- package/dist/provider-status.js +6 -1
- package/dist/resources.js +6 -6
- package/dist/validation-tools.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the llm-cli-gateway project.
|
|
4
4
|
|
|
5
|
+
## [1.5.21] - 2026-05-24
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Add a desktop `public-url` command that persists a public HTTPS `/mcp` endpoint for ChatGPT and other web clients.
|
|
10
|
+
- Pass the persisted public URL and verification flag into managed gateway starts and `doctor --json`, instead of relying on one-off shell environment state.
|
|
11
|
+
- Make `print-client-config` prefer the persisted public HTTPS URL while still reporting the local URL separately.
|
|
12
|
+
|
|
13
|
+
## [1.5.20] - 2026-05-24
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Do not inject Mistral `VIBE_ACTIVE_MODEL` when a request omits `model`; let Vibe use its own CLI default unless the caller explicitly asks for a model.
|
|
18
|
+
- Make `list_models`, `list_available_models`, and `models://*` omit bundled fallback entries from `models` and expose them only as `unverifiedModelHints`.
|
|
19
|
+
- Add warnings when model entries are only bundled fallback hints, so clients do not present unvalidated model names as available provider models.
|
|
20
|
+
|
|
21
|
+
## [1.5.19] - 2026-05-24
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Use the gateway's extended provider CLI PATH in `doctor --json`, not only in request execution.
|
|
26
|
+
- Add common Windows npm/Corepack/Scoop/Volta/Chocolatey CLI shim directories to provider PATH discovery.
|
|
27
|
+
- Resolve Windows PowerShell npm shims such as `gemini.ps1` and `claude.ps1` without invoking a shell command string.
|
|
28
|
+
|
|
5
29
|
## [1.5.18] - 2026-05-24
|
|
6
30
|
|
|
7
31
|
### Fixed
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
|
-
import { getExtendedPath, killProcessGroup, spawnCliProcess, unregisterProcessGroup, } from "./executor.js";
|
|
2
|
+
import { envWithExtendedPath, getExtendedPath, killProcessGroup, spawnCliProcess, unregisterProcessGroup, } from "./executor.js";
|
|
3
3
|
import { noopLogger } from "./logger.js";
|
|
4
4
|
import { ProcessMonitor } from "./process-monitor.js";
|
|
5
5
|
import { computeRequestKey } from "./job-store.js";
|
|
@@ -366,10 +366,11 @@ export class AsyncJobManager {
|
|
|
366
366
|
// Mistral Vibe ships as the `vibe` binary; the gateway uses `mistral` as the
|
|
367
367
|
// provider key but spawns `vibe` on the shell.
|
|
368
368
|
const command = cli === "mistral" ? "vibe" : cli;
|
|
369
|
+
const baseEnv = envWithExtendedPath(process.env, getExtendedPath());
|
|
369
370
|
const child = spawnCliProcess(command, args, {
|
|
370
371
|
cwd,
|
|
371
372
|
stdio: ["ignore", "pipe", "pipe"],
|
|
372
|
-
env: { ...
|
|
373
|
+
env: { ...baseEnv, ...(extraEnv ?? {}) },
|
|
373
374
|
});
|
|
374
375
|
// Single cleanup flag to prevent double-unregister
|
|
375
376
|
let groupCleaned = false;
|
package/dist/executor.d.ts
CHANGED
|
@@ -13,7 +13,17 @@ export interface ExecuteResult {
|
|
|
13
13
|
stderr: string;
|
|
14
14
|
code: number;
|
|
15
15
|
}
|
|
16
|
+
export declare function buildExtendedPath(env?: NodeJS.ProcessEnv, home?: string, nodePath?: string, platform?: NodeJS.Platform): string;
|
|
16
17
|
export declare function getExtendedPath(): string;
|
|
18
|
+
export declare function envWithExtendedPath(baseEnv?: NodeJS.ProcessEnv, extendedPath?: string, platform?: NodeJS.Platform): NodeJS.ProcessEnv;
|
|
19
|
+
export interface ResolvedSpawnCommand {
|
|
20
|
+
command: string;
|
|
21
|
+
args: string[];
|
|
22
|
+
}
|
|
23
|
+
export declare function resolveCommandForSpawn(command: string, args: string[], options?: {
|
|
24
|
+
envPath?: string;
|
|
25
|
+
platform?: NodeJS.Platform;
|
|
26
|
+
}): ResolvedSpawnCommand;
|
|
17
27
|
export declare function shouldDetachProviderProcess(platform?: NodeJS.Platform): boolean;
|
|
18
28
|
export declare function registerProcessGroup(pid: number): void;
|
|
19
29
|
export declare function unregisterProcessGroup(pid: number): void;
|
package/dist/executor.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn, spawnSync } from "child_process";
|
|
2
2
|
import { homedir } from "os";
|
|
3
|
-
import { delimiter, join, dirname } from "path";
|
|
3
|
+
import { delimiter, join, dirname, extname, win32 } from "path";
|
|
4
4
|
import { readdirSync, existsSync } from "fs";
|
|
5
5
|
import { createCircuitBreaker, withRetry } from "./retry.js";
|
|
6
6
|
const MAX_OUTPUT_SIZE = 50 * 1024 * 1024;
|
|
@@ -36,22 +36,123 @@ function getNvmPath() {
|
|
|
36
36
|
}
|
|
37
37
|
return cachedNvmPath;
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
function pathDelimiterFor(platform) {
|
|
40
|
+
return platform === "win32" ? ";" : delimiter;
|
|
41
|
+
}
|
|
42
|
+
function pathJoinFor(platform, ...segments) {
|
|
43
|
+
return platform === "win32" ? win32.join(...segments) : join(...segments);
|
|
44
|
+
}
|
|
45
|
+
function dirnameFor(platform, path) {
|
|
46
|
+
return platform === "win32" ? win32.dirname(path) : dirname(path);
|
|
47
|
+
}
|
|
48
|
+
function pathValueFromEnv(env, platform) {
|
|
49
|
+
if (platform === "win32") {
|
|
50
|
+
return env.Path || env.PATH || "";
|
|
51
|
+
}
|
|
52
|
+
return env.PATH || "";
|
|
53
|
+
}
|
|
54
|
+
function addIfPresent(paths, value) {
|
|
55
|
+
if (value)
|
|
56
|
+
paths.push(value);
|
|
57
|
+
}
|
|
58
|
+
function windowsCommonCliPaths(env, home) {
|
|
59
|
+
const paths = [];
|
|
60
|
+
addIfPresent(paths, env.APPDATA ? pathJoinFor("win32", env.APPDATA, "npm") : undefined);
|
|
61
|
+
addIfPresent(paths, env.LOCALAPPDATA ? pathJoinFor("win32", env.LOCALAPPDATA, "pnpm") : undefined);
|
|
62
|
+
addIfPresent(paths, env.LOCALAPPDATA ? pathJoinFor("win32", env.LOCALAPPDATA, "Programs", "nodejs") : undefined);
|
|
63
|
+
addIfPresent(paths, env.LOCALAPPDATA ? pathJoinFor("win32", env.LOCALAPPDATA, "Programs", "npm") : undefined);
|
|
64
|
+
addIfPresent(paths, env.ProgramFiles ? pathJoinFor("win32", env.ProgramFiles, "nodejs") : undefined);
|
|
65
|
+
addIfPresent(paths, env["ProgramFiles(x86)"] ? pathJoinFor("win32", env["ProgramFiles(x86)"], "nodejs") : undefined);
|
|
66
|
+
addIfPresent(paths, env.ProgramData ? pathJoinFor("win32", env.ProgramData, "chocolatey", "bin") : undefined);
|
|
67
|
+
paths.push(pathJoinFor("win32", home, "AppData", "Roaming", "npm"));
|
|
68
|
+
paths.push(pathJoinFor("win32", home, "AppData", "Local", "pnpm"));
|
|
69
|
+
paths.push(pathJoinFor("win32", home, ".volta", "bin"));
|
|
70
|
+
paths.push(pathJoinFor("win32", home, "scoop", "shims"));
|
|
71
|
+
return paths;
|
|
72
|
+
}
|
|
73
|
+
export function buildExtendedPath(env = process.env, home = homedir(), nodePath = process.execPath, platform = process.platform) {
|
|
42
74
|
const additionalPaths = [
|
|
43
|
-
|
|
44
|
-
|
|
75
|
+
pathJoinFor(platform, home, ".local", "bin"),
|
|
76
|
+
dirnameFor(platform, nodePath), // Current node's bin directory
|
|
45
77
|
"/usr/local/bin",
|
|
46
78
|
"/usr/bin",
|
|
47
79
|
];
|
|
80
|
+
if (platform === "win32") {
|
|
81
|
+
additionalPaths.push(...windowsCommonCliPaths(env, home));
|
|
82
|
+
}
|
|
48
83
|
// Add all nvm node version bin directories
|
|
49
84
|
const nvmPath = getNvmPath();
|
|
50
85
|
if (nvmPath) {
|
|
51
86
|
additionalPaths.push(nvmPath);
|
|
52
87
|
}
|
|
53
|
-
const currentPath =
|
|
54
|
-
return [...additionalPaths, currentPath]
|
|
88
|
+
const currentPath = pathValueFromEnv(env, platform);
|
|
89
|
+
return [...dedupePaths(additionalPaths, platform), currentPath]
|
|
90
|
+
.filter(Boolean)
|
|
91
|
+
.join(pathDelimiterFor(platform));
|
|
92
|
+
}
|
|
93
|
+
// Extend PATH to include common locations for CLI tools.
|
|
94
|
+
export function getExtendedPath() {
|
|
95
|
+
return buildExtendedPath();
|
|
96
|
+
}
|
|
97
|
+
export function envWithExtendedPath(baseEnv = process.env, extendedPath = getExtendedPath(), platform = process.platform) {
|
|
98
|
+
const env = { ...baseEnv };
|
|
99
|
+
const key = platform === "win32"
|
|
100
|
+
? Object.keys(env).find(existing => existing.toLowerCase() === "path") || "Path"
|
|
101
|
+
: "PATH";
|
|
102
|
+
env[key] = extendedPath;
|
|
103
|
+
if (platform === "win32") {
|
|
104
|
+
for (const existing of Object.keys(env)) {
|
|
105
|
+
if (existing !== key && existing.toLowerCase() === "path") {
|
|
106
|
+
delete env[existing];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return env;
|
|
111
|
+
}
|
|
112
|
+
function dedupePaths(paths, platform) {
|
|
113
|
+
const seen = new Set();
|
|
114
|
+
const result = [];
|
|
115
|
+
for (const path of paths) {
|
|
116
|
+
const normalized = platform === "win32" ? path.toLowerCase() : path;
|
|
117
|
+
if (seen.has(normalized))
|
|
118
|
+
continue;
|
|
119
|
+
seen.add(normalized);
|
|
120
|
+
result.push(path);
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
export function resolveCommandForSpawn(command, args, options = {}) {
|
|
125
|
+
const platform = options.platform ?? process.platform;
|
|
126
|
+
if (platform !== "win32") {
|
|
127
|
+
return { command, args };
|
|
128
|
+
}
|
|
129
|
+
const resolved = resolveWindowsCommandPath(command, options.envPath ?? getExtendedPath());
|
|
130
|
+
if (!resolved) {
|
|
131
|
+
return { command, args };
|
|
132
|
+
}
|
|
133
|
+
if (extname(resolved).toLowerCase() === ".ps1") {
|
|
134
|
+
return {
|
|
135
|
+
command: "powershell.exe",
|
|
136
|
+
args: ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", resolved, ...args],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return { command: resolved, args };
|
|
140
|
+
}
|
|
141
|
+
function resolveWindowsCommandPath(command, envPath) {
|
|
142
|
+
if (/[\\/]/.test(command)) {
|
|
143
|
+
return existsSync(command) ? command : null;
|
|
144
|
+
}
|
|
145
|
+
const hasExtension = extname(command) !== "";
|
|
146
|
+
const extensions = hasExtension ? [""] : ["", ".exe", ".ps1", ".cmd", ".bat"];
|
|
147
|
+
for (const dir of envPath.split(pathDelimiterFor("win32")).filter(Boolean)) {
|
|
148
|
+
for (const extension of extensions) {
|
|
149
|
+
const candidate = pathJoinFor("win32", dir, command + extension);
|
|
150
|
+
if (existsSync(candidate)) {
|
|
151
|
+
return candidate;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
55
156
|
}
|
|
56
157
|
/** Registry of active detached process groups for shutdown cleanup. */
|
|
57
158
|
const activeProcessGroups = new Set();
|
|
@@ -152,7 +253,10 @@ function killWindowsProcessTree(pid) {
|
|
|
152
253
|
}
|
|
153
254
|
export function spawnCliProcess(command, args, options) {
|
|
154
255
|
const detached = shouldDetachProviderProcess();
|
|
155
|
-
const
|
|
256
|
+
const resolved = resolveCommandForSpawn(command, args, {
|
|
257
|
+
envPath: pathValueFromEnv(options.env, process.platform),
|
|
258
|
+
});
|
|
259
|
+
const proc = spawn(resolved.command, resolved.args, {
|
|
156
260
|
cwd: options.cwd,
|
|
157
261
|
detached,
|
|
158
262
|
windowsHide: true,
|
|
@@ -167,12 +271,13 @@ export function spawnCliProcess(command, args, options) {
|
|
|
167
271
|
export async function executeCli(command, args, options = {}) {
|
|
168
272
|
const { timeout, idleTimeout, cwd, env: extraEnv } = options;
|
|
169
273
|
const extendedPath = getExtendedPath();
|
|
274
|
+
const baseEnv = envWithExtendedPath(process.env, extendedPath);
|
|
170
275
|
const circuitBreaker = getCircuitBreaker(command);
|
|
171
276
|
const runOnce = () => new Promise((resolve, reject) => {
|
|
172
277
|
const proc = spawnCliProcess(command, args, {
|
|
173
278
|
cwd,
|
|
174
279
|
stdio: ["ignore", "pipe", "pipe"],
|
|
175
|
-
env: { ...
|
|
280
|
+
env: { ...baseEnv, ...(extraEnv ?? {}) },
|
|
176
281
|
});
|
|
177
282
|
let stdout = "";
|
|
178
283
|
let stderr = "";
|
package/dist/index.d.ts
CHANGED
|
@@ -160,6 +160,24 @@ export declare function prepareGeminiRequest(params: {
|
|
|
160
160
|
adminPolicyFiles?: string[];
|
|
161
161
|
attachments?: string[];
|
|
162
162
|
}, runtime?: GatewayServerRuntime): CliRequestPrep | ExtendedToolResponse;
|
|
163
|
+
export declare function prepareMistralRequest(params: {
|
|
164
|
+
prompt: string;
|
|
165
|
+
model?: string;
|
|
166
|
+
outputFormat?: string;
|
|
167
|
+
permissionMode?: MistralAgentMode;
|
|
168
|
+
effort?: string;
|
|
169
|
+
reasoningEffort?: string;
|
|
170
|
+
allowedTools?: string[];
|
|
171
|
+
disallowedTools?: string[];
|
|
172
|
+
approvalStrategy: "legacy" | "mcp_managed";
|
|
173
|
+
approvalPolicy?: string;
|
|
174
|
+
mcpServers?: ClaudeMcpServerName[];
|
|
175
|
+
correlationId?: string;
|
|
176
|
+
optimizePrompt: boolean;
|
|
177
|
+
operation: string;
|
|
178
|
+
}, runtime?: GatewayServerRuntime): (CliRequestPrep & {
|
|
179
|
+
mistralEnv: Record<string, string>;
|
|
180
|
+
}) | ExtendedToolResponse;
|
|
163
181
|
export interface GeminiRequestParams {
|
|
164
182
|
prompt: string;
|
|
165
183
|
model?: string;
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { PerformanceMetrics } from "./metrics.js";
|
|
|
16
16
|
import { estimateTokens, optimizePrompt as optimizePromptText, optimizeResponse as optimizeResponseText, } from "./optimizer.js";
|
|
17
17
|
import { loadConfig, loadPersistenceConfig } from "./config.js";
|
|
18
18
|
import { checkHealth } from "./health.js";
|
|
19
|
-
import { clearModelRegistryCache, getCliInfo, resolveModelAlias } from "./model-registry.js";
|
|
19
|
+
import { clearModelRegistryCache, getAvailableCliInfo, getCliInfo, resolveModelAlias, } from "./model-registry.js";
|
|
20
20
|
import { AsyncJobManager } from "./async-job-manager.js";
|
|
21
21
|
import { createJobStore } from "./job-store.js";
|
|
22
22
|
import { ApprovalManager } from "./approval-manager.js";
|
|
@@ -1061,11 +1061,10 @@ function prepareGrokRequest(params, runtime = resolveGatewayServerRuntime()) {
|
|
|
1061
1061
|
args,
|
|
1062
1062
|
};
|
|
1063
1063
|
}
|
|
1064
|
-
function prepareMistralRequest(params, runtime = resolveGatewayServerRuntime()) {
|
|
1064
|
+
export function prepareMistralRequest(params, runtime = resolveGatewayServerRuntime()) {
|
|
1065
1065
|
const corrId = params.correlationId || randomUUID();
|
|
1066
1066
|
const cliInfo = getCliInfo();
|
|
1067
|
-
const
|
|
1068
|
-
const resolvedModel = resolveModelAlias("mistral", requestedModel, cliInfo);
|
|
1067
|
+
const resolvedModel = resolveModelAlias("mistral", params.model, cliInfo);
|
|
1069
1068
|
const reviewIntegrity = checkReviewIntegrity({
|
|
1070
1069
|
prompt: params.prompt,
|
|
1071
1070
|
allowedTools: params.allowedTools,
|
|
@@ -3567,7 +3566,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
3567
3566
|
.preprocess(value => (value === "" || value === null ? undefined : value), z.enum(["claude", "codex", "gemini", "grok", "mistral"]).optional())
|
|
3568
3567
|
.describe("CLI filter (claude|codex|gemini|grok|mistral)"),
|
|
3569
3568
|
}, async ({ cli }) => {
|
|
3570
|
-
const cliInfo =
|
|
3569
|
+
const cliInfo = getAvailableCliInfo();
|
|
3571
3570
|
const result = cli ? { [cli]: cliInfo[cli] } : cliInfo;
|
|
3572
3571
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
3573
3572
|
});
|
package/dist/model-registry.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface ModelMetadata {
|
|
|
10
10
|
export interface CliInfo {
|
|
11
11
|
description: string;
|
|
12
12
|
models: Record<string, string>;
|
|
13
|
+
unverifiedModelHints?: Record<string, string>;
|
|
13
14
|
defaultModel?: string;
|
|
14
15
|
defaultModelSource?: string;
|
|
15
16
|
modelOrder?: string[];
|
|
@@ -19,6 +20,7 @@ export interface CliInfo {
|
|
|
19
20
|
}
|
|
20
21
|
export type CliInfoMap = Record<CliType, CliInfo>;
|
|
21
22
|
export declare function getCliInfo(forceRefresh?: boolean): CliInfoMap;
|
|
23
|
+
export declare function getAvailableCliInfo(forceRefresh?: boolean): CliInfoMap;
|
|
22
24
|
export declare function clearModelRegistryCache(): void;
|
|
23
25
|
export declare function resolveModelAlias(cli: CliType, model: string | undefined, info: CliInfoMap): string | undefined;
|
|
24
26
|
export {};
|
package/dist/model-registry.js
CHANGED
|
@@ -75,6 +75,16 @@ export function getCliInfo(forceRefresh = false) {
|
|
|
75
75
|
cachedInfo = { loadedAt: Date.now(), info };
|
|
76
76
|
return info;
|
|
77
77
|
}
|
|
78
|
+
export function getAvailableCliInfo(forceRefresh = false) {
|
|
79
|
+
const info = getCliInfo(forceRefresh);
|
|
80
|
+
return {
|
|
81
|
+
claude: filterUnverifiedModelHints(info.claude),
|
|
82
|
+
codex: filterUnverifiedModelHints(info.codex),
|
|
83
|
+
gemini: filterUnverifiedModelHints(info.gemini),
|
|
84
|
+
grok: filterUnverifiedModelHints(info.grok),
|
|
85
|
+
mistral: filterUnverifiedModelHints(info.mistral),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
78
88
|
export function clearModelRegistryCache() {
|
|
79
89
|
cachedInfo = null;
|
|
80
90
|
}
|
|
@@ -125,6 +135,9 @@ function cloneInfo(source) {
|
|
|
125
135
|
const cloned = {
|
|
126
136
|
description: source.description,
|
|
127
137
|
models: { ...source.models },
|
|
138
|
+
unverifiedModelHints: source.unverifiedModelHints
|
|
139
|
+
? { ...source.unverifiedModelHints }
|
|
140
|
+
: undefined,
|
|
128
141
|
defaultModel: source.defaultModel,
|
|
129
142
|
defaultModelSource: source.defaultModelSource,
|
|
130
143
|
modelOrder: source.modelOrder ? [...source.modelOrder] : undefined,
|
|
@@ -141,6 +154,41 @@ function cloneInfo(source) {
|
|
|
141
154
|
});
|
|
142
155
|
return cloned;
|
|
143
156
|
}
|
|
157
|
+
function filterUnverifiedModelHints(source) {
|
|
158
|
+
const filtered = cloneInfo(source);
|
|
159
|
+
const models = {};
|
|
160
|
+
const metadata = {};
|
|
161
|
+
const hints = {};
|
|
162
|
+
Object.entries(source.models).forEach(([model, description]) => {
|
|
163
|
+
const modelMetadata = source.modelMetadata?.[model];
|
|
164
|
+
if (modelMetadata?.source === "fallback") {
|
|
165
|
+
hints[model] = description;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
models[model] = description;
|
|
169
|
+
if (modelMetadata) {
|
|
170
|
+
metadata[model] = modelMetadata;
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
filtered.models = models;
|
|
174
|
+
filtered.modelMetadata = metadata;
|
|
175
|
+
filtered.unverifiedModelHints = Object.keys(hints).length > 0 ? hints : undefined;
|
|
176
|
+
filtered.modelOrder = source.modelOrder?.filter(model => model in models);
|
|
177
|
+
if (filtered.defaultModel && !(filtered.defaultModel in models)) {
|
|
178
|
+
filtered.defaultModel = undefined;
|
|
179
|
+
filtered.defaultModelSource = undefined;
|
|
180
|
+
}
|
|
181
|
+
if (filtered.aliases) {
|
|
182
|
+
filtered.aliases = Object.fromEntries(Object.entries(filtered.aliases).filter(([, target]) => target === "default" || target in models));
|
|
183
|
+
if (Object.keys(filtered.aliases).length === 0) {
|
|
184
|
+
filtered.aliases = undefined;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (filtered.unverifiedModelHints) {
|
|
188
|
+
addWarning(filtered, "Bundled fallback model hints were omitted from models because they are not validated against the installed CLI. They are exposed as unverifiedModelHints only.");
|
|
189
|
+
}
|
|
190
|
+
return filtered;
|
|
191
|
+
}
|
|
144
192
|
function addWarning(info, warning) {
|
|
145
193
|
info.warnings = info.warnings ?? [];
|
|
146
194
|
if (!info.warnings.includes(warning)) {
|
package/dist/provider-status.js
CHANGED
|
@@ -3,6 +3,7 @@ import { homedir } from "node:os";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import { getProviderLoginGuidance } from "./provider-login-guidance.js";
|
|
6
|
+
import { envWithExtendedPath, getExtendedPath, resolveCommandForSpawn } from "./executor.js";
|
|
6
7
|
const PROVIDERS = ["claude", "codex", "gemini", "grok", "mistral"];
|
|
7
8
|
const VERSION_ARGS = {
|
|
8
9
|
claude: ["--version"],
|
|
@@ -96,8 +97,12 @@ export function getProviderRuntimeStatus(provider) {
|
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
99
|
function runCommand(command, args, timeoutMs) {
|
|
99
|
-
const
|
|
100
|
+
const extendedPath = getExtendedPath();
|
|
101
|
+
const env = envWithExtendedPath(process.env, extendedPath);
|
|
102
|
+
const resolved = resolveCommandForSpawn(command, args, { envPath: extendedPath });
|
|
103
|
+
const result = spawnSync(resolved.command, resolved.args, {
|
|
100
104
|
encoding: "utf8",
|
|
105
|
+
env,
|
|
101
106
|
input: "",
|
|
102
107
|
timeout: timeoutMs,
|
|
103
108
|
windowsHide: true,
|
package/dist/resources.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getAvailableCliInfo } from "./model-registry.js";
|
|
2
2
|
export class ResourceProvider {
|
|
3
3
|
sessionManager;
|
|
4
4
|
performanceMetrics;
|
|
@@ -238,7 +238,7 @@ export class ResourceProvider {
|
|
|
238
238
|
}
|
|
239
239
|
// Model capability resources
|
|
240
240
|
if (uri === "models://claude") {
|
|
241
|
-
const cliInfo =
|
|
241
|
+
const cliInfo = getAvailableCliInfo();
|
|
242
242
|
return {
|
|
243
243
|
uri,
|
|
244
244
|
mimeType: "application/json",
|
|
@@ -246,7 +246,7 @@ export class ResourceProvider {
|
|
|
246
246
|
};
|
|
247
247
|
}
|
|
248
248
|
if (uri === "models://codex") {
|
|
249
|
-
const cliInfo =
|
|
249
|
+
const cliInfo = getAvailableCliInfo();
|
|
250
250
|
return {
|
|
251
251
|
uri,
|
|
252
252
|
mimeType: "application/json",
|
|
@@ -254,7 +254,7 @@ export class ResourceProvider {
|
|
|
254
254
|
};
|
|
255
255
|
}
|
|
256
256
|
if (uri === "models://gemini") {
|
|
257
|
-
const cliInfo =
|
|
257
|
+
const cliInfo = getAvailableCliInfo();
|
|
258
258
|
return {
|
|
259
259
|
uri,
|
|
260
260
|
mimeType: "application/json",
|
|
@@ -262,7 +262,7 @@ export class ResourceProvider {
|
|
|
262
262
|
};
|
|
263
263
|
}
|
|
264
264
|
if (uri === "models://grok") {
|
|
265
|
-
const cliInfo =
|
|
265
|
+
const cliInfo = getAvailableCliInfo();
|
|
266
266
|
return {
|
|
267
267
|
uri,
|
|
268
268
|
mimeType: "application/json",
|
|
@@ -270,7 +270,7 @@ export class ResourceProvider {
|
|
|
270
270
|
};
|
|
271
271
|
}
|
|
272
272
|
if (uri === "models://mistral") {
|
|
273
|
-
const cliInfo =
|
|
273
|
+
const cliInfo = getAvailableCliInfo();
|
|
274
274
|
return {
|
|
275
275
|
uri,
|
|
276
276
|
mimeType: "application/json",
|
package/dist/validation-tools.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { getAvailableCliInfo } from "./model-registry.js";
|
|
3
3
|
import { collectValidationJobResult, startJudgeSynthesis, startValidationRun, } from "./validation-orchestrator.js";
|
|
4
4
|
const providerSchema = z.enum(["claude", "codex", "gemini", "grok", "mistral"]);
|
|
5
5
|
const providerListSchema = z.array(providerSchema).min(1).default(["claude", "codex"]);
|
|
@@ -160,7 +160,7 @@ export function registerValidationTools(server, deps) {
|
|
|
160
160
|
judgeProvider: judgeModel,
|
|
161
161
|
}),
|
|
162
162
|
}));
|
|
163
|
-
server.tool("list_available_models", {}, async () => textResponse({ success: true, models:
|
|
163
|
+
server.tool("list_available_models", {}, async () => textResponse({ success: true, models: getAvailableCliInfo() }));
|
|
164
164
|
server.tool("job_status", {
|
|
165
165
|
jobId: z.string().min(1).describe("Validation job ID."),
|
|
166
166
|
}, async ({ jobId }) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "llm-cli-gateway",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.21",
|
|
4
4
|
"mcpName": "io.github.verivus-oss/llm-cli-gateway",
|
|
5
5
|
"description": "MCP server providing unified access to Claude Code, Codex, Gemini, Grok, and Mistral Vibe CLIs with session management, retry logic, async job orchestration, durable job results, and cross-LLM validation.",
|
|
6
6
|
"license": "MIT",
|