llm-cli-gateway 1.16.2 → 1.17.0
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 +30 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -2
- package/dist/upstream-contracts.d.ts +39 -0
- package/dist/upstream-contracts.js +62 -0
- package/package.json +3 -1
- package/socket.yml +30 -15
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,36 @@ All notable changes to the llm-cli-gateway project.
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## [1.17.0] - 2026-05-30 — upstream provider tracking
|
|
8
|
+
|
|
9
|
+
Feature release adding repeatable upstream-provider contract tracking for the
|
|
10
|
+
gateway's supported CLIs.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Added provider-specific maintenance skills for Claude Code, Codex, Gemini,
|
|
15
|
+
Grok, and Mistral Vibe.
|
|
16
|
+
- Added upstream source metadata to the CLI contract table and mirrored it into
|
|
17
|
+
`docs/upstream/provider-sources.dag.toml`.
|
|
18
|
+
- Added `scripts/upstream-scan.mjs` plus `npm run upstream:contracts` and
|
|
19
|
+
`npm run upstream:scan` for offline contract checks and advisory live source
|
|
20
|
+
scans.
|
|
21
|
+
- Added upstream source tests covering contract/TOML synchronization.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Pointed Claude Code tracking at the markdown changelog, Codex tracking at the
|
|
26
|
+
GitHub releases feed plus product changelog, Gemini tracking at the Gemini CLI
|
|
27
|
+
changelog plus GitHub releases, and Grok tracking at the markdown xAI release
|
|
28
|
+
notes.
|
|
29
|
+
- Ignored local-only agent/worktree artifacts that should not enter source
|
|
30
|
+
control.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Fixed the `maxTokens` request schema so token budgets no longer reuse the
|
|
35
|
+
`maxTurns` limit.
|
|
36
|
+
|
|
7
37
|
## [1.16.2] - 2026-05-29 — release formatting follow-up
|
|
8
38
|
|
|
9
39
|
Patch release that keeps the Mistral Vibe CLI contract fixes from `1.16.1`
|
package/dist/index.d.ts
CHANGED
|
@@ -66,6 +66,7 @@ type GatewayLogger = typeof logger;
|
|
|
66
66
|
* upper bound — no plausible single agent loop exceeds 10k turns or 10k USD.
|
|
67
67
|
*/
|
|
68
68
|
export declare const MAX_TURNS_SCHEMA: z.ZodNumber;
|
|
69
|
+
export declare const MAX_TOKENS_SCHEMA: z.ZodNumber;
|
|
69
70
|
export declare const MAX_PRICE_SCHEMA: z.ZodNumber;
|
|
70
71
|
/**
|
|
71
72
|
* Slice λ: shared worktree directive for all 10 `*_request` / `*_request_async`
|
package/dist/index.js
CHANGED
|
@@ -242,6 +242,10 @@ const MCP_SERVER_ENUM = z.enum(CLAUDE_MCP_SERVER_NAMES);
|
|
|
242
242
|
* upper bound — no plausible single agent loop exceeds 10k turns or 10k USD.
|
|
243
243
|
*/
|
|
244
244
|
export const MAX_TURNS_SCHEMA = z.number().int().positive().safe().max(10_000);
|
|
245
|
+
// Token budgets can legitimately exceed the agent-turn cap by orders of
|
|
246
|
+
// magnitude. Keep a finite operational guardrail while avoiding the 10k turn
|
|
247
|
+
// ceiling that would make large-context Vibe sessions unusable.
|
|
248
|
+
export const MAX_TOKENS_SCHEMA = z.number().int().positive().safe().max(100_000_000);
|
|
245
249
|
// `.min(1e-6)` keeps the value in JS's decimal-stringify range:
|
|
246
250
|
// String(1e-6) === "0.000001" but String(1e-7) === "1e-7", which both
|
|
247
251
|
// upstream CLIs would reject. 1µUSD per request is fine-grained enough
|
|
@@ -3826,7 +3830,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
3826
3830
|
.describe("Emit `--trust` so Vibe trusts the cwd for this invocation only (not persisted to trusted_folders.toml) and skips the interactive trust prompt (Phase 4 slice γ)."),
|
|
3827
3831
|
maxTurns: MAX_TURNS_SCHEMA.optional().describe("Vibe `--max-turns N`: cap the agent-loop iteration count (programmatic mode only, Phase 4 slice δ). Bounded to safe integers ≤ 10000."),
|
|
3828
3832
|
maxPrice: MAX_PRICE_SCHEMA.optional().describe("Vibe `--max-price DOLLARS`: interrupt the session when cumulative cost crosses this cap (programmatic mode only, Phase 4 slice δ). Bounded to finite values ≤ 10000 USD."),
|
|
3829
|
-
maxTokens:
|
|
3833
|
+
maxTokens: MAX_TOKENS_SCHEMA.optional().describe("Vibe `--max-tokens N`: cap cumulative prompt + completion tokens for the session (programmatic mode only). Bounded to safe integers ≤ 100000000."),
|
|
3830
3834
|
// Phase 4 slice ζ — Vibe working-directory + additional-dirs parity.
|
|
3831
3835
|
workingDir: z
|
|
3832
3836
|
.string()
|
|
@@ -4548,7 +4552,7 @@ export function createGatewayServer(deps = {}) {
|
|
|
4548
4552
|
.describe("Emit `--trust` so Vibe trusts the cwd for this invocation only (not persisted to trusted_folders.toml) and skips the interactive trust prompt (Phase 4 slice γ)."),
|
|
4549
4553
|
maxTurns: MAX_TURNS_SCHEMA.optional().describe("Vibe `--max-turns N`: cap the agent-loop iteration count (programmatic mode only, Phase 4 slice δ). Bounded to safe integers ≤ 10000."),
|
|
4550
4554
|
maxPrice: MAX_PRICE_SCHEMA.optional().describe("Vibe `--max-price DOLLARS`: interrupt the session when cumulative cost crosses this cap (programmatic mode only, Phase 4 slice δ). Bounded to finite values ≤ 10000 USD."),
|
|
4551
|
-
maxTokens:
|
|
4555
|
+
maxTokens: MAX_TOKENS_SCHEMA.optional().describe("Vibe `--max-tokens N`: cap cumulative prompt + completion tokens for the session (programmatic mode only). Bounded to safe integers ≤ 100000000."),
|
|
4552
4556
|
// Phase 4 slice ζ — Vibe working-directory + additional-dirs parity.
|
|
4553
4557
|
workingDir: z
|
|
4554
4558
|
.string()
|
|
@@ -13,6 +13,43 @@ export interface CliFlagContract {
|
|
|
13
13
|
pattern?: RegExp;
|
|
14
14
|
description: string;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Pure upstream-tracking metadata for a provider CLI.
|
|
18
|
+
*
|
|
19
|
+
* IMPORTANT — non-duplication invariant: nothing here encodes mechanical
|
|
20
|
+
* behaviour. Flags, output modes, session/resume rules, permission modes,
|
|
21
|
+
* forbidden flags, env contracts, and positional limits live ONLY in the
|
|
22
|
+
* surrounding {@link CliContract} and are validated ONLY by
|
|
23
|
+
* {@link validateUpstreamCliArgs} / {@link validateUpstreamCliEnv}. The fields
|
|
24
|
+
* below are descriptive pointers used by the upstream changelog scanner
|
|
25
|
+
* (`scripts/upstream-scan.mjs`) and surfaced in the contract report — they
|
|
26
|
+
* never drive argv/env enforcement.
|
|
27
|
+
*
|
|
28
|
+
* `docs/upstream/provider-sources.dag.toml` mirrors `sourceUrls` and
|
|
29
|
+
* `watchCategories` for the scanner's offline scan plan; a unit test
|
|
30
|
+
* (`upstream-sources.test.ts`) asserts the TOML stays in sync with these
|
|
31
|
+
* fields so the two cannot drift. The TypeScript values here are authoritative;
|
|
32
|
+
* the TOML is scanner input only and is never consulted for contract
|
|
33
|
+
* enforcement.
|
|
34
|
+
*/
|
|
35
|
+
export interface CliUpstreamMetadata {
|
|
36
|
+
/** Canonical changelog / release-notes URLs the scanner fetches with --live. */
|
|
37
|
+
sourceUrls: readonly string[];
|
|
38
|
+
/** Distribution package identifier (npm package name, PyPI project, …). */
|
|
39
|
+
packageName?: string;
|
|
40
|
+
/** Source repository URL, when distinct from the changelog source. */
|
|
41
|
+
repo?: string;
|
|
42
|
+
/** Human-facing install / getting-started docs. */
|
|
43
|
+
installDocsUrl?: string;
|
|
44
|
+
/** Distribution channel the gateway expects the CLI to ship through. */
|
|
45
|
+
releaseChannel?: "npm" | "pypi" | "github-release" | "vendor";
|
|
46
|
+
/**
|
|
47
|
+
* Contract surfaces worth watching in upstream release notes (e.g. "flags",
|
|
48
|
+
* "output-formats", "session-resume"). Descriptive labels for the scanner and
|
|
49
|
+
* report ONLY — never a validation input.
|
|
50
|
+
*/
|
|
51
|
+
watchCategories: readonly string[];
|
|
52
|
+
}
|
|
16
53
|
export interface CliContract {
|
|
17
54
|
cli: CliType;
|
|
18
55
|
executable: string;
|
|
@@ -31,6 +68,8 @@ export interface CliContract {
|
|
|
31
68
|
resumeMaxPositionals?: number;
|
|
32
69
|
resumeOnlyFlags?: readonly string[];
|
|
33
70
|
resumeForbiddenFlags?: readonly string[];
|
|
71
|
+
/** Non-mechanical upstream-tracking metadata. See {@link CliUpstreamMetadata}. */
|
|
72
|
+
upstreamMetadata?: CliUpstreamMetadata;
|
|
34
73
|
}
|
|
35
74
|
export interface CliContractFixture {
|
|
36
75
|
id: string;
|
|
@@ -14,6 +14,13 @@ export const UPSTREAM_CLI_CONTRACTS = {
|
|
|
14
14
|
cli: "claude",
|
|
15
15
|
executable: "claude",
|
|
16
16
|
upstream: "Claude Code CLI",
|
|
17
|
+
upstreamMetadata: {
|
|
18
|
+
sourceUrls: ["https://code.claude.com/docs/en/changelog.md"],
|
|
19
|
+
packageName: "@anthropic-ai/claude-code",
|
|
20
|
+
installDocsUrl: "https://code.claude.com/docs/en/overview",
|
|
21
|
+
releaseChannel: "npm",
|
|
22
|
+
watchCategories: ["flags", "output-formats", "permission-modes", "session-resume", "models"],
|
|
23
|
+
},
|
|
17
24
|
helpArgs: [["--help"]],
|
|
18
25
|
maxPositionals: 0,
|
|
19
26
|
mcpTools: ["claude_request", "claude_request_async"],
|
|
@@ -197,6 +204,23 @@ export const UPSTREAM_CLI_CONTRACTS = {
|
|
|
197
204
|
cli: "codex",
|
|
198
205
|
executable: "codex",
|
|
199
206
|
upstream: "OpenAI Codex CLI",
|
|
207
|
+
upstreamMetadata: {
|
|
208
|
+
sourceUrls: [
|
|
209
|
+
"https://github.com/openai/codex/releases",
|
|
210
|
+
"https://developers.openai.com/codex/changelog",
|
|
211
|
+
],
|
|
212
|
+
packageName: "@openai/codex",
|
|
213
|
+
repo: "https://github.com/openai/codex",
|
|
214
|
+
installDocsUrl: "https://developers.openai.com/codex/cli",
|
|
215
|
+
releaseChannel: "npm",
|
|
216
|
+
watchCategories: [
|
|
217
|
+
"flags",
|
|
218
|
+
"sandbox-modes",
|
|
219
|
+
"approval-modes",
|
|
220
|
+
"session-resume",
|
|
221
|
+
"output-schema",
|
|
222
|
+
],
|
|
223
|
+
},
|
|
200
224
|
helpArgs: [
|
|
201
225
|
["exec", "--help"],
|
|
202
226
|
["exec", "resume", "--help"],
|
|
@@ -343,6 +367,17 @@ export const UPSTREAM_CLI_CONTRACTS = {
|
|
|
343
367
|
cli: "gemini",
|
|
344
368
|
executable: "gemini",
|
|
345
369
|
upstream: "Google Gemini CLI",
|
|
370
|
+
upstreamMetadata: {
|
|
371
|
+
sourceUrls: [
|
|
372
|
+
"https://geminicli.com/docs/changelogs/",
|
|
373
|
+
"https://github.com/google-gemini/gemini-cli/releases",
|
|
374
|
+
],
|
|
375
|
+
packageName: "@google/gemini-cli",
|
|
376
|
+
repo: "https://github.com/google-gemini/gemini-cli",
|
|
377
|
+
installDocsUrl: "https://geminicli.com/docs/",
|
|
378
|
+
releaseChannel: "npm",
|
|
379
|
+
watchCategories: ["flags", "approval-modes", "output-formats", "session-resume"],
|
|
380
|
+
},
|
|
346
381
|
helpArgs: [["--help"]],
|
|
347
382
|
maxPositionals: 0,
|
|
348
383
|
mcpTools: ["gemini_request", "gemini_request_async"],
|
|
@@ -428,6 +463,12 @@ export const UPSTREAM_CLI_CONTRACTS = {
|
|
|
428
463
|
cli: "grok",
|
|
429
464
|
executable: "grok",
|
|
430
465
|
upstream: "xAI Grok CLI",
|
|
466
|
+
upstreamMetadata: {
|
|
467
|
+
sourceUrls: ["https://docs.x.ai/developers/release-notes.md"],
|
|
468
|
+
installDocsUrl: "https://docs.x.ai/build/overview",
|
|
469
|
+
releaseChannel: "vendor",
|
|
470
|
+
watchCategories: ["flags", "permission-modes", "session-resume", "sandbox", "output-formats"],
|
|
471
|
+
},
|
|
431
472
|
helpArgs: [["--help"]],
|
|
432
473
|
maxPositionals: 0,
|
|
433
474
|
mcpTools: ["grok_request", "grok_request_async"],
|
|
@@ -582,6 +623,14 @@ export const UPSTREAM_CLI_CONTRACTS = {
|
|
|
582
623
|
cli: "mistral",
|
|
583
624
|
executable: "vibe",
|
|
584
625
|
upstream: "Mistral Vibe CLI",
|
|
626
|
+
upstreamMetadata: {
|
|
627
|
+
sourceUrls: ["https://github.com/mistralai/mistral-vibe/releases"],
|
|
628
|
+
packageName: "mistral-vibe",
|
|
629
|
+
repo: "https://github.com/mistralai/mistral-vibe",
|
|
630
|
+
installDocsUrl: "https://github.com/mistralai/mistral-vibe#installation",
|
|
631
|
+
releaseChannel: "pypi",
|
|
632
|
+
watchCategories: ["flags", "agent-modes", "session-logging", "output-formats", "env-model"],
|
|
633
|
+
},
|
|
585
634
|
helpArgs: [["--help"]],
|
|
586
635
|
maxPositionals: 0,
|
|
587
636
|
mcpTools: ["mistral_request", "mistral_request_async"],
|
|
@@ -960,6 +1009,19 @@ export function buildUpstreamContractReport(options = {}) {
|
|
|
960
1009
|
{
|
|
961
1010
|
executable: contract.executable,
|
|
962
1011
|
upstream: contract.upstream,
|
|
1012
|
+
// Pure metadata pointers (changelog URLs, package name, watch
|
|
1013
|
+
// categories). Enriched from the CliContract — the single source of
|
|
1014
|
+
// truth — so report consumers and the scanner read the same values.
|
|
1015
|
+
upstreamMetadata: contract.upstreamMetadata
|
|
1016
|
+
? {
|
|
1017
|
+
sourceUrls: contract.upstreamMetadata.sourceUrls,
|
|
1018
|
+
packageName: contract.upstreamMetadata.packageName ?? null,
|
|
1019
|
+
repo: contract.upstreamMetadata.repo ?? null,
|
|
1020
|
+
installDocsUrl: contract.upstreamMetadata.installDocsUrl ?? null,
|
|
1021
|
+
releaseChannel: contract.upstreamMetadata.releaseChannel ?? null,
|
|
1022
|
+
watchCategories: contract.upstreamMetadata.watchCategories,
|
|
1023
|
+
}
|
|
1024
|
+
: null,
|
|
963
1025
|
command: contract.command ?? null,
|
|
964
1026
|
helpArgs: contract.helpArgs,
|
|
965
1027
|
mcpTools: contract.mcpTools,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "llm-cli-gateway",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.0",
|
|
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",
|
|
@@ -71,6 +71,8 @@
|
|
|
71
71
|
"test:pg": "bash ./scripts/test-pg.sh",
|
|
72
72
|
"test:all": "npm run test && npm run test:pg",
|
|
73
73
|
"smoke:cache-control": "node docs/plans/slice-kappa-smoke-test.mjs",
|
|
74
|
+
"upstream:contracts": "node scripts/upstream-scan.mjs --contracts-check",
|
|
75
|
+
"upstream:scan": "node scripts/upstream-scan.mjs",
|
|
74
76
|
"lint": "eslint src/**/*.ts",
|
|
75
77
|
"lint:fix": "eslint src/**/*.ts --fix",
|
|
76
78
|
"format": "prettier --write 'src/**/*.ts'",
|
package/socket.yml
CHANGED
|
@@ -22,11 +22,36 @@ version: 2
|
|
|
22
22
|
# (SQLite, sessions.json) or explicit local CLI process I/O.
|
|
23
23
|
#
|
|
24
24
|
# shellAccess
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
25
|
+
# This alert fires on every module that imports node:child_process, and
|
|
26
|
+
# because spawning provider CLIs and git is the entire purpose of the
|
|
27
|
+
# package it surfaces on every release BY DESIGN — we keep it visible
|
|
28
|
+
# rather than silencing it. It is a capability description, not a finding.
|
|
29
|
+
#
|
|
30
|
+
# INVARIANT enforced across ALL sites below: arguments are always passed
|
|
31
|
+
# as an array and `shell: true` is NEVER set, so there is no shell
|
|
32
|
+
# interpolation path for user input. `scripts/release-security-audit.sh`
|
|
33
|
+
# guards the dynamic-execution surface. When you add a new module that
|
|
34
|
+
# imports child_process, add it to this list so the alert location set
|
|
35
|
+
# stays documented instead of reading like a regression.
|
|
36
|
+
#
|
|
37
|
+
# Current production child_process sites (dist/*.js mirrors of src/*.ts):
|
|
38
|
+
# - src/executor.ts spawn(cmd, args) — provider CLI allow-list
|
|
39
|
+
# (claude / codex / gemini / grok / vibe).
|
|
40
|
+
# - src/worktree-manager.ts spawn("git", args) — gateway-owned git
|
|
41
|
+
# worktree lifecycle (add / list / prune /
|
|
42
|
+
# remove / branch -D).
|
|
43
|
+
# - src/cli-updater.ts spawnSync(cmd, args) — provider CLI version
|
|
44
|
+
# + upgrade checks.
|
|
45
|
+
# - src/provider-status.ts spawnSync(cmd, args) — provider login-status
|
|
46
|
+
# probe.
|
|
47
|
+
# - src/upstream-contracts.ts spawnSync(cmd, ["--help"]) — optional
|
|
48
|
+
# installed-CLI contract probe.
|
|
49
|
+
# - src/endpoint-exposure.ts spawnSync(process.execPath, ["-e", …]) —
|
|
50
|
+
# out-of-process HEAD reachability probe
|
|
51
|
+
# (opt-in via the start:http path only).
|
|
52
|
+
# - src/async-job-manager.ts imports the ChildProcess *type* only for
|
|
53
|
+
# job lifecycle tracking; it spawns via
|
|
54
|
+
# executor.ts (spawnCliProcess), not directly.
|
|
30
55
|
#
|
|
31
56
|
# usesEval
|
|
32
57
|
# Not in our source. Transitive via @modelcontextprotocol/sdk → ajv@8,
|
|
@@ -40,16 +65,6 @@ version: 2
|
|
|
40
65
|
# gateway does not call db.pragma() from production code; SQLite setup
|
|
41
66
|
# uses fixed literal db.exec("PRAGMA ...") statements, and the release
|
|
42
67
|
# security audit fails future production `.pragma()` calls.
|
|
43
|
-
#
|
|
44
|
-
# ioredis obfuscated code / base64 strings
|
|
45
|
-
# Socket may flag ioredis@5.10.1 built/constants/TLSProfiles.js because it
|
|
46
|
-
# contains base64-looking strings. This is a reviewed false positive: the
|
|
47
|
-
# strings are PEM-encoded Redis Cloud TLS CA certificates. The file exports
|
|
48
|
-
# static TLS profile data only; it contains no decoder loop, dynamic eval,
|
|
49
|
-
# network call, or hidden execution path. The same file is byte-for-byte
|
|
50
|
-
# identical in ioredis@5.9.2. ioredis is not installed by the default
|
|
51
|
-
# production dependency tree; it is an optional peer for PostgreSQL/Redis
|
|
52
|
-
# session storage and a pinned dev dependency for tests.
|
|
53
68
|
|
|
54
69
|
issueRules:
|
|
55
70
|
# Defaults from Socket. Listed explicitly so future contributors see what
|