llm-cli-gateway 1.5.24 → 1.5.26
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 +12 -0
- package/dist/index.js +8 -9
- package/dist/request-helpers.d.ts +5 -26
- package/dist/request-helpers.js +4 -28
- package/dist/upstream-contracts.d.ts +2 -0
- package/dist/upstream-contracts.js +17 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the llm-cli-gateway project.
|
|
4
4
|
|
|
5
|
+
## [1.5.26] - 2026-05-25
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Make `upstream_contracts --probe-installed` use the same extended provider PATH and Windows shim resolver as request execution and `doctor --json`, avoiding false `ENOENT` diagnostics for npm-installed CLIs such as Gemini.
|
|
10
|
+
|
|
11
|
+
## [1.5.25] - 2026-05-25
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Stop passing unsupported Gemini `--session-id` arguments for fresh or `createNewSession` requests. The gateway now lets Gemini CLI create fresh sessions with its own default behavior and only emits `--resume` for explicit resume requests, fixing Gemini CLI 0.43 exit-code-1 failures misreported as spawn errors.
|
|
16
|
+
|
|
5
17
|
## [1.5.24] - 2026-05-25
|
|
6
18
|
|
|
7
19
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -1253,9 +1253,8 @@ export async function handleGeminiRequest(deps, params) {
|
|
|
1253
1253
|
}, runtime);
|
|
1254
1254
|
deps.logger.info(`[${corrId}] gemini_request invoked with model=${prep.resolvedModel || "default"}, approvalMode=${params.approvalMode}, prompt length=${params.prompt.length}`);
|
|
1255
1255
|
try {
|
|
1256
|
-
//
|
|
1257
|
-
//
|
|
1258
|
-
// For resume flows, fall back to `--resume <id>` (existing behavior).
|
|
1256
|
+
// Gemini CLI 0.43 supports `--resume`, but not a supported fresh
|
|
1257
|
+
// `--session-id` flag. Fresh sessions emit no session flag.
|
|
1259
1258
|
const sessionPlan = resolveGeminiSessionPlan({
|
|
1260
1259
|
sessionId: params.sessionId,
|
|
1261
1260
|
resumeLatest: params.resumeLatest,
|
|
@@ -1263,7 +1262,7 @@ export async function handleGeminiRequest(deps, params) {
|
|
|
1263
1262
|
});
|
|
1264
1263
|
args.push(...sessionPlan.args);
|
|
1265
1264
|
const userProvidedSession = sessionPlan.resumed;
|
|
1266
|
-
const effectiveSessionIdHint = sessionPlan.
|
|
1265
|
+
const effectiveSessionIdHint = sessionPlan.resumed ? params.sessionId : undefined;
|
|
1267
1266
|
const result = await awaitJobOrDefer("gemini", args, corrId, resolveIdleTimeout("gemini", params.idleTimeoutMs), params.outputFormat, params.forceRefresh, runtime);
|
|
1268
1267
|
// Deferred — job still running, return async reference
|
|
1269
1268
|
if (isDeferredResponse(result)) {
|
|
@@ -1286,9 +1285,9 @@ export async function handleGeminiRequest(deps, params) {
|
|
|
1286
1285
|
return createErrorResponse("gemini", code, stderr, corrId);
|
|
1287
1286
|
}
|
|
1288
1287
|
wasSuccessful = true;
|
|
1289
|
-
//
|
|
1290
|
-
//
|
|
1291
|
-
//
|
|
1288
|
+
// Post-success session I/O for explicit resume flows. Fresh Gemini sessions
|
|
1289
|
+
// are owned by the CLI because the current CLI has no supported fresh
|
|
1290
|
+
// session-id flag the gateway can inject.
|
|
1292
1291
|
let effectiveSessionId = effectiveSessionIdHint;
|
|
1293
1292
|
if (effectiveSessionId) {
|
|
1294
1293
|
const existing = await deps.sessionManager.getSession(effectiveSessionId);
|
|
@@ -1368,7 +1367,7 @@ export async function handleGeminiRequestAsync(deps, params) {
|
|
|
1368
1367
|
return prep;
|
|
1369
1368
|
const { corrId, args, requestedMcpServers, approvalDecision } = prep;
|
|
1370
1369
|
try {
|
|
1371
|
-
//
|
|
1370
|
+
// Gemini CLI 0.43 supports `--resume`, but fresh sessions emit no session flag.
|
|
1372
1371
|
const sessionPlan = resolveGeminiSessionPlan({
|
|
1373
1372
|
sessionId: params.sessionId,
|
|
1374
1373
|
resumeLatest: params.resumeLatest,
|
|
@@ -1376,7 +1375,7 @@ export async function handleGeminiRequestAsync(deps, params) {
|
|
|
1376
1375
|
});
|
|
1377
1376
|
args.push(...sessionPlan.args);
|
|
1378
1377
|
// Pre-start session I/O (async handlers: prevent orphaned jobs)
|
|
1379
|
-
let effectiveSessionId = sessionPlan.
|
|
1378
|
+
let effectiveSessionId = sessionPlan.resumed ? params.sessionId : undefined;
|
|
1380
1379
|
if (effectiveSessionId) {
|
|
1381
1380
|
const existing = await deps.sessionManager.getSession(effectiveSessionId);
|
|
1382
1381
|
if (!existing) {
|
|
@@ -457,14 +457,6 @@ export interface CodexForkRequestInput {
|
|
|
457
457
|
export declare function prepareCodexForkRequest(input: CodexForkRequestInput): {
|
|
458
458
|
args: string[];
|
|
459
459
|
};
|
|
460
|
-
/**
|
|
461
|
-
* Strict UUID v4 regex. Gemini's CLI is reportedly stricter about session id
|
|
462
|
-
* shape than the gateway's internal handles, so caller-supplied IDs (and IDs
|
|
463
|
-
* generated by `crypto.randomUUID()`) are validated against this regex before
|
|
464
|
-
* being emitted as `--session-id <uuid>`.
|
|
465
|
-
*/
|
|
466
|
-
export declare const GEMINI_SESSION_ID_REGEX: RegExp;
|
|
467
|
-
export declare function isValidGeminiSessionId(id: string): boolean;
|
|
468
460
|
/**
|
|
469
461
|
* Prepend `@<abs-path>` tokens to a Gemini prompt so the CLI's attachment
|
|
470
462
|
* resolver picks them up. Each path MUST be absolute and exist on disk.
|
|
@@ -520,34 +512,21 @@ export interface GeminiHighImpactFlagsResult {
|
|
|
520
512
|
*/
|
|
521
513
|
export declare function prepareGeminiHighImpactFlags(input: GeminiHighImpactFlagsInput): GeminiHighImpactFlagsResult;
|
|
522
514
|
/**
|
|
523
|
-
* Result of resolving Gemini's session
|
|
524
|
-
*
|
|
525
|
-
* U27 introduces deterministic `--session-id <uuid>` emission for fresh
|
|
526
|
-
* sessions, mapping the gateway-side session ID 1:1 to Gemini's authoritative
|
|
527
|
-
* store. The existing `--resume <id>` flow is preserved for user-supplied
|
|
528
|
-
* session IDs.
|
|
515
|
+
* Result of resolving Gemini's session strategy.
|
|
529
516
|
*/
|
|
530
517
|
export interface GeminiSessionPlan {
|
|
531
|
-
/** Flag pair to inject into argv (one of `["--
|
|
518
|
+
/** Flag pair to inject into argv (one of `["--resume", id]`, `["--resume", "latest"]`, or `[]`). */
|
|
532
519
|
args: string[];
|
|
533
|
-
/** The UUID emitted via `--session-id`, if any. Gateway should persist this. */
|
|
534
|
-
emittedSessionId?: string;
|
|
535
520
|
/** True iff `--resume <id>` was emitted with a user-supplied id. */
|
|
536
521
|
resumed: boolean;
|
|
537
522
|
}
|
|
538
523
|
/**
|
|
539
|
-
* Resolve Gemini session
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
* identifier from the first turn.
|
|
543
|
-
*
|
|
544
|
-
* Falls back to `--resume <id>` when the caller supplies a sessionId, and
|
|
545
|
-
* `--resume latest` for `resumeLatest` (existing behavior preserved).
|
|
524
|
+
* Resolve Gemini session args. Gemini CLI 0.43 exposes `--resume` but not a
|
|
525
|
+
* supported `--session-id` flag for fresh sessions, so new-session requests
|
|
526
|
+
* intentionally emit no session flag and let the CLI create its own session.
|
|
546
527
|
*/
|
|
547
528
|
export declare function resolveGeminiSessionPlan(opts: {
|
|
548
529
|
sessionId?: string;
|
|
549
530
|
resumeLatest?: boolean;
|
|
550
531
|
createNewSession?: boolean;
|
|
551
|
-
/** Override generator for deterministic tests. Must produce a v4 UUID. */
|
|
552
|
-
generateId?: () => string;
|
|
553
532
|
}): GeminiSessionPlan;
|
package/dist/request-helpers.js
CHANGED
|
@@ -580,16 +580,6 @@ export function prepareCodexForkRequest(input) {
|
|
|
580
580
|
//──────────────────────────────────────────────────────────────────────────────
|
|
581
581
|
// U27: Gemini high-impact features
|
|
582
582
|
//──────────────────────────────────────────────────────────────────────────────
|
|
583
|
-
/**
|
|
584
|
-
* Strict UUID v4 regex. Gemini's CLI is reportedly stricter about session id
|
|
585
|
-
* shape than the gateway's internal handles, so caller-supplied IDs (and IDs
|
|
586
|
-
* generated by `crypto.randomUUID()`) are validated against this regex before
|
|
587
|
-
* being emitted as `--session-id <uuid>`.
|
|
588
|
-
*/
|
|
589
|
-
export const GEMINI_SESSION_ID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
590
|
-
export function isValidGeminiSessionId(id) {
|
|
591
|
-
return GEMINI_SESSION_ID_REGEX.test(id);
|
|
592
|
-
}
|
|
593
583
|
/**
|
|
594
584
|
* Prepend `@<abs-path>` tokens to a Gemini prompt so the CLI's attachment
|
|
595
585
|
* resolver picks them up. Each path MUST be absolute and exist on disk.
|
|
@@ -674,16 +664,11 @@ export function prepareGeminiHighImpactFlags(input) {
|
|
|
674
664
|
return { args, missingPolicyPath: null, missingPolicyField: null };
|
|
675
665
|
}
|
|
676
666
|
/**
|
|
677
|
-
* Resolve Gemini session
|
|
678
|
-
*
|
|
679
|
-
*
|
|
680
|
-
* identifier from the first turn.
|
|
681
|
-
*
|
|
682
|
-
* Falls back to `--resume <id>` when the caller supplies a sessionId, and
|
|
683
|
-
* `--resume latest` for `resumeLatest` (existing behavior preserved).
|
|
667
|
+
* Resolve Gemini session args. Gemini CLI 0.43 exposes `--resume` but not a
|
|
668
|
+
* supported `--session-id` flag for fresh sessions, so new-session requests
|
|
669
|
+
* intentionally emit no session flag and let the CLI create its own session.
|
|
684
670
|
*/
|
|
685
671
|
export function resolveGeminiSessionPlan(opts) {
|
|
686
|
-
const gen = opts.generateId ?? randomUUID;
|
|
687
672
|
if (opts.sessionId && !opts.createNewSession) {
|
|
688
673
|
validateSessionId(opts.sessionId);
|
|
689
674
|
return {
|
|
@@ -694,14 +679,5 @@ export function resolveGeminiSessionPlan(opts) {
|
|
|
694
679
|
if (opts.resumeLatest && !opts.createNewSession) {
|
|
695
680
|
return { args: ["--resume", "latest"], resumed: false };
|
|
696
681
|
}
|
|
697
|
-
|
|
698
|
-
const candidate = gen();
|
|
699
|
-
if (!isValidGeminiSessionId(candidate)) {
|
|
700
|
-
throw new Error(`Generated session id "${candidate}" does not match Gemini's UUID v4 format`);
|
|
701
|
-
}
|
|
702
|
-
return {
|
|
703
|
-
args: ["--session-id", candidate],
|
|
704
|
-
emittedSessionId: candidate,
|
|
705
|
-
resumed: false,
|
|
706
|
-
};
|
|
682
|
+
return { args: [], resumed: false };
|
|
707
683
|
}
|
|
@@ -50,6 +50,8 @@ export declare function assertUpstreamCliEnv(cli: CliType, env: Record<string, s
|
|
|
50
50
|
export interface InstalledCliContractProbe {
|
|
51
51
|
cli: CliType;
|
|
52
52
|
executable: string;
|
|
53
|
+
resolvedCommand?: string;
|
|
54
|
+
resolvedArgs?: string[];
|
|
53
55
|
available: boolean;
|
|
54
56
|
checkedHelpCommands: string[][];
|
|
55
57
|
missingFlags: string[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { envWithExtendedPath, getExtendedPath, resolveCommandForSpawn } from "./executor.js";
|
|
2
3
|
const PERMISSION_MODES = [
|
|
3
4
|
"default",
|
|
4
5
|
"acceptEdits",
|
|
@@ -234,7 +235,6 @@ export const UPSTREAM_CLI_CONTRACTS = {
|
|
|
234
235
|
"--policy": { arity: "one", description: "Policy file path" },
|
|
235
236
|
"--admin-policy": { arity: "one", description: "Admin policy file path" },
|
|
236
237
|
"-o": { arity: "one", values: ["json"], description: "Output format" },
|
|
237
|
-
"--session-id": { arity: "one", description: "Fresh session UUID" },
|
|
238
238
|
"--resume": { arity: "one", description: "Resume session" },
|
|
239
239
|
},
|
|
240
240
|
env: {},
|
|
@@ -535,16 +535,29 @@ export function probeInstalledCliContract(cli, timeoutMs = 5_000) {
|
|
|
535
535
|
const contract = UPSTREAM_CLI_CONTRACTS[cli];
|
|
536
536
|
const outputs = [];
|
|
537
537
|
const warnings = [];
|
|
538
|
+
let resolvedCommand;
|
|
539
|
+
let resolvedArgs;
|
|
538
540
|
for (const helpArgs of contract.helpArgs) {
|
|
539
|
-
const
|
|
541
|
+
const extendedPath = getExtendedPath();
|
|
542
|
+
const env = envWithExtendedPath(process.env, extendedPath);
|
|
543
|
+
const resolved = resolveCommandForSpawn(contract.executable, helpArgs, {
|
|
544
|
+
envPath: extendedPath,
|
|
545
|
+
});
|
|
546
|
+
resolvedCommand ??= resolved.command;
|
|
547
|
+
resolvedArgs ??= resolved.args;
|
|
548
|
+
const result = spawnSync(resolved.command, resolved.args, {
|
|
540
549
|
encoding: "utf8",
|
|
541
550
|
timeout: timeoutMs,
|
|
542
551
|
maxBuffer: 1024 * 1024,
|
|
552
|
+
env,
|
|
553
|
+
windowsHide: true,
|
|
543
554
|
});
|
|
544
555
|
if (result.error) {
|
|
545
556
|
return {
|
|
546
557
|
cli,
|
|
547
558
|
executable: contract.executable,
|
|
559
|
+
resolvedCommand: resolved.command,
|
|
560
|
+
resolvedArgs: resolved.args,
|
|
548
561
|
available: false,
|
|
549
562
|
checkedHelpCommands: contract.helpArgs,
|
|
550
563
|
missingFlags: [],
|
|
@@ -561,6 +574,8 @@ export function probeInstalledCliContract(cli, timeoutMs = 5_000) {
|
|
|
561
574
|
return {
|
|
562
575
|
cli,
|
|
563
576
|
executable: contract.executable,
|
|
577
|
+
resolvedCommand,
|
|
578
|
+
resolvedArgs,
|
|
564
579
|
available: true,
|
|
565
580
|
checkedHelpCommands: contract.helpArgs,
|
|
566
581
|
missingFlags,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "llm-cli-gateway",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.26",
|
|
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",
|