llm-cli-gateway 2.6.3 → 2.8.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.
@@ -1,4 +1,5 @@
1
1
  export interface GatewayRequestContext {
2
+ transport?: "stdio" | "http";
2
3
  authKind?: "disabled" | "gateway_bearer" | "oauth";
3
4
  authScopes: string[];
4
5
  authClientId?: string;
@@ -98,8 +98,8 @@ export declare const CLAUDE_HIGH_IMPACT_PARAMS_SCHEMA: z.ZodEffects<z.ZodObject<
98
98
  effort: z.ZodOptional<z.ZodEnum<["low", "medium", "high", "xhigh", "max"]>>;
99
99
  excludeDynamicSystemPromptSections: z.ZodOptional<z.ZodBoolean>;
100
100
  }, "strip", z.ZodTypeAny, {
101
- agents?: Record<string, Record<string, unknown>> | undefined;
102
101
  agent?: string | undefined;
102
+ agents?: Record<string, Record<string, unknown>> | undefined;
103
103
  forkSession?: boolean | undefined;
104
104
  systemPrompt?: string | undefined;
105
105
  appendSystemPrompt?: string | undefined;
@@ -108,8 +108,8 @@ export declare const CLAUDE_HIGH_IMPACT_PARAMS_SCHEMA: z.ZodEffects<z.ZodObject<
108
108
  effort?: "medium" | "low" | "high" | "xhigh" | "max" | undefined;
109
109
  excludeDynamicSystemPromptSections?: boolean | undefined;
110
110
  }, {
111
- agents?: Record<string, Record<string, unknown>> | undefined;
112
111
  agent?: string | undefined;
112
+ agents?: Record<string, Record<string, unknown>> | undefined;
113
113
  forkSession?: boolean | undefined;
114
114
  systemPrompt?: string | undefined;
115
115
  appendSystemPrompt?: string | undefined;
@@ -118,8 +118,8 @@ export declare const CLAUDE_HIGH_IMPACT_PARAMS_SCHEMA: z.ZodEffects<z.ZodObject<
118
118
  effort?: "medium" | "low" | "high" | "xhigh" | "max" | undefined;
119
119
  excludeDynamicSystemPromptSections?: boolean | undefined;
120
120
  }>, {
121
- agents?: Record<string, Record<string, unknown>> | undefined;
122
121
  agent?: string | undefined;
122
+ agents?: Record<string, Record<string, unknown>> | undefined;
123
123
  forkSession?: boolean | undefined;
124
124
  systemPrompt?: string | undefined;
125
125
  appendSystemPrompt?: string | undefined;
@@ -128,8 +128,8 @@ export declare const CLAUDE_HIGH_IMPACT_PARAMS_SCHEMA: z.ZodEffects<z.ZodObject<
128
128
  effort?: "medium" | "low" | "high" | "xhigh" | "max" | undefined;
129
129
  excludeDynamicSystemPromptSections?: boolean | undefined;
130
130
  }, {
131
- agents?: Record<string, Record<string, unknown>> | undefined;
132
131
  agent?: string | undefined;
132
+ agents?: Record<string, Record<string, unknown>> | undefined;
133
133
  forkSession?: boolean | undefined;
134
134
  systemPrompt?: string | undefined;
135
135
  appendSystemPrompt?: string | undefined;
package/dist/resources.js CHANGED
@@ -2,6 +2,7 @@ import { CLI_TYPES, PROVIDER_TYPES } from "./session-manager.js";
2
2
  import { getAvailableCliInfo } from "./model-registry.js";
3
3
  import { computeGlobalCacheStats, computePrefixCacheStats, computeSessionCacheStats, computeTtlRemaining, } from "./cache-stats.js";
4
4
  import { buildProviderSubcommandsCompactCatalog, getCliSubcommandContract, serializeCliSubcommandContract, } from "./upstream-contracts.js";
5
+ import { getOneProviderToolCapabilities, getProviderToolCapabilities, providerCapabilityIds, } from "./provider-tool-capabilities.js";
5
6
  export class ResourceProvider {
6
7
  sessionManager;
7
8
  performanceMetrics;
@@ -176,6 +177,28 @@ export class ResourceProvider {
176
177
  priority: 0.7,
177
178
  },
178
179
  },
180
+ {
181
+ uri: "provider-tools://catalog",
182
+ name: "Provider Tool Capabilities Catalog",
183
+ title: "Provider Tool Capabilities Catalog",
184
+ description: "Read-only catalog of gateway tool controls and discovered provider skills",
185
+ mimeType: "application/json",
186
+ annotations: {
187
+ audience: ["user", "assistant"],
188
+ priority: 0.8,
189
+ },
190
+ },
191
+ ...providerCapabilityIds().map(cli => ({
192
+ uri: `provider-tools://${cli}`,
193
+ name: `${cli} Tool Capabilities`,
194
+ title: `${cli} Tool Capabilities`,
195
+ description: `Gateway tool controls and discovered local skills for ${cli}`,
196
+ mimeType: "application/json",
197
+ annotations: {
198
+ audience: ["user", "assistant"],
199
+ priority: 0.8,
200
+ },
201
+ })),
179
202
  ];
180
203
  }
181
204
  async readResource(uri) {
@@ -320,6 +343,21 @@ export class ResourceProvider {
320
343
  text: JSON.stringify(buildProviderSubcommandsCompactCatalog()),
321
344
  };
322
345
  }
346
+ if (uri === "provider-tools://catalog" || uri === "provider_tools://catalog") {
347
+ return {
348
+ uri,
349
+ mimeType: "application/json",
350
+ text: JSON.stringify(getProviderToolCapabilities(), null, 2),
351
+ };
352
+ }
353
+ const providerToolsResource = parseProviderToolsUri(uri);
354
+ if (providerToolsResource) {
355
+ return {
356
+ uri,
357
+ mimeType: "application/json",
358
+ text: JSON.stringify(getOneProviderToolCapabilities(providerToolsResource.provider), null, 2),
359
+ };
360
+ }
323
361
  const subcommandResource = parseProviderSubcommandUri(uri);
324
362
  if (subcommandResource) {
325
363
  const contract = getCliSubcommandContract(subcommandResource.provider, subcommandResource.commandPath);
@@ -354,3 +392,16 @@ function parseProviderSubcommandUri(uri) {
354
392
  commandPath: pathParts.map(part => decodeURIComponent(part)).filter(Boolean),
355
393
  };
356
394
  }
395
+ function parseProviderToolsUri(uri) {
396
+ const prefix = uri.startsWith("provider-tools://")
397
+ ? "provider-tools://"
398
+ : uri.startsWith("provider_tools://")
399
+ ? "provider_tools://"
400
+ : null;
401
+ if (!prefix || uri === `${prefix}catalog`)
402
+ return null;
403
+ const provider = uri.slice(prefix.length);
404
+ if (!providerCapabilityIds().includes(provider))
405
+ return null;
406
+ return { provider: provider };
407
+ }
@@ -107,6 +107,20 @@ export interface ProviderSubcommandCompactCatalog {
107
107
  ];
108
108
  rows: readonly (readonly string[])[];
109
109
  }
110
+ export type AcpEntrypointStatus = "native" | "adapter_mediated_deferred" | "absent_watchlist";
111
+ export interface AcpEntrypointContract {
112
+ cli: CliType;
113
+ displayName: string;
114
+ status: AcpEntrypointStatus;
115
+ executable: string;
116
+ entrypointArgs: readonly string[];
117
+ targetVersion: string;
118
+ probeArgs: readonly (readonly string[])[];
119
+ adapterCandidates?: readonly string[];
120
+ evidence: string;
121
+ docsRef: string;
122
+ }
123
+ export declare const ACP_ENTRYPOINT_CONTRACTS: Record<CliType, AcpEntrypointContract>;
110
124
  export declare const UPSTREAM_CLI_CONTRACTS: Record<CliType, CliContract>;
111
125
  export declare function validateUpstreamCliArgs(cli: CliType, args: readonly string[]): ContractValidationResult;
112
126
  export declare function assertUpstreamCliArgs(cli: CliType, args: readonly string[]): void;
@@ -167,6 +181,19 @@ export interface InstalledCliContractProbe {
167
181
  warnings: string[];
168
182
  }
169
183
  export declare function probeInstalledCliContract(cli: CliType, timeoutMs?: number): InstalledCliContractProbe;
184
+ export interface InstalledAcpEntrypointProbe {
185
+ cli: CliType;
186
+ status: AcpEntrypointStatus;
187
+ executable: string;
188
+ entrypointArgs: readonly string[];
189
+ targetVersion: string;
190
+ checkedProbeCommands: readonly (readonly string[])[];
191
+ available: boolean | null;
192
+ entrypointDrift: boolean;
193
+ warnings: string[];
194
+ probedAt: string;
195
+ }
196
+ export declare function probeInstalledAcpEntrypoint(cli: CliType, timeoutMs?: number): InstalledAcpEntrypointProbe;
170
197
  export declare function buildUpstreamContractReport(options?: {
171
198
  cli?: CliType;
172
199
  probeInstalled?: boolean;
@@ -1,6 +1,65 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  import { createHash } from "node:crypto";
3
3
  import { envWithExtendedPath, getExtendedPath, resolveCommandForSpawn } from "./executor.js";
4
+ export const ACP_ENTRYPOINT_CONTRACTS = {
5
+ mistral: {
6
+ cli: "mistral",
7
+ displayName: "Mistral Vibe",
8
+ status: "native",
9
+ executable: "vibe-acp",
10
+ entrypointArgs: [],
11
+ targetVersion: "vibe 2.14.1",
12
+ probeArgs: [["--version"], ["--help"]],
13
+ evidence: "Native ACP executable vibe-acp; manual initialize + session/new smoke passed. First runtime pilot.",
14
+ docsRef: "docs/plans/first-class-acp-gateway-extension.dag.toml#provider_matrix.mistral",
15
+ },
16
+ grok: {
17
+ cli: "grok",
18
+ displayName: "xAI Grok CLI",
19
+ status: "native",
20
+ executable: "grok",
21
+ entrypointArgs: ["agent", "stdio"],
22
+ targetVersion: "grok 0.2.50 (cadf94855)",
23
+ probeArgs: [["agent", "stdio", "--help"]],
24
+ evidence: "Native ACP via `grok agent stdio`; initialize + session/new smoke passed with isolated leader socket. Second runtime pilot.",
25
+ docsRef: "docs/plans/first-class-acp-gateway-extension.dag.toml#provider_matrix.grok",
26
+ },
27
+ codex: {
28
+ cli: "codex",
29
+ displayName: "OpenAI Codex CLI",
30
+ status: "adapter_mediated_deferred",
31
+ executable: "codex",
32
+ entrypointArgs: [],
33
+ targetVersion: "codex-cli 0.139.0",
34
+ probeArgs: [],
35
+ adapterCandidates: ["zed-industries/codex-acp", "agentclientprotocol/codex-acp"],
36
+ evidence: "No native ACP entrypoint at codex-cli 0.139.0. Adapter evidence tracked as documentation only; not native gateway ACP support.",
37
+ docsRef: "docs/plans/first-class-acp-gateway-extension.dag.toml#provider_matrix.codex",
38
+ },
39
+ claude: {
40
+ cli: "claude",
41
+ displayName: "Anthropic Claude Code",
42
+ status: "adapter_mediated_deferred",
43
+ executable: "claude",
44
+ entrypointArgs: [],
45
+ targetVersion: "claude 2.1.175",
46
+ probeArgs: [],
47
+ adapterCandidates: ["Claude Agent SDK ACP adapter"],
48
+ evidence: "No native Claude Code CLI ACP entrypoint at claude 2.1.175. Adapter ownership/permission bridging unresolved; deferred.",
49
+ docsRef: "docs/plans/first-class-acp-gateway-extension.dag.toml#provider_matrix.claude",
50
+ },
51
+ gemini: {
52
+ cli: "gemini",
53
+ displayName: "Google Antigravity",
54
+ status: "absent_watchlist",
55
+ executable: "agy",
56
+ entrypointArgs: [],
57
+ targetVersion: "agy 1.0.7",
58
+ probeArgs: [],
59
+ evidence: "agy 1.0.7 has no ACP flag or subcommand. Legacy Gemini CLI ACP evidence does not transfer. Watchlist item.",
60
+ docsRef: "docs/plans/first-class-acp-gateway-extension.dag.toml#provider_matrix.gemini",
61
+ },
62
+ };
4
63
  const PERMISSION_MODES = [
5
64
  "default",
6
65
  "acceptEdits",
@@ -2084,6 +2143,74 @@ function probeInstalledCliSubcommands(cli, timeoutMs) {
2084
2143
  }
2085
2144
  return probes;
2086
2145
  }
2146
+ export function probeInstalledAcpEntrypoint(cli, timeoutMs = 5_000) {
2147
+ const contract = ACP_ENTRYPOINT_CONTRACTS[cli];
2148
+ const warnings = [];
2149
+ const checkedProbeCommands = contract.probeArgs.map(args => [...args]);
2150
+ if (contract.status !== "native" || contract.probeArgs.length === 0) {
2151
+ return {
2152
+ cli,
2153
+ status: contract.status,
2154
+ executable: contract.executable,
2155
+ entrypointArgs: contract.entrypointArgs,
2156
+ targetVersion: contract.targetVersion,
2157
+ checkedProbeCommands,
2158
+ available: null,
2159
+ entrypointDrift: false,
2160
+ warnings,
2161
+ probedAt: new Date().toISOString(),
2162
+ };
2163
+ }
2164
+ let anyProbeSucceeded = false;
2165
+ for (const probeArgs of contract.probeArgs) {
2166
+ const extendedPath = getExtendedPath();
2167
+ const env = envWithExtendedPath(process.env, extendedPath);
2168
+ const resolved = resolveCommandForSpawn(contract.executable, [...probeArgs], {
2169
+ envPath: extendedPath,
2170
+ });
2171
+ const result = spawnSync(resolved.command, resolved.args, {
2172
+ encoding: "utf8",
2173
+ timeout: timeoutMs,
2174
+ maxBuffer: 1024 * 1024,
2175
+ env,
2176
+ windowsHide: true,
2177
+ windowsVerbatimArguments: resolved.windowsVerbatimArguments,
2178
+ });
2179
+ if (result.error) {
2180
+ warnings.push(`${contract.executable} ${probeArgs.join(" ")} unavailable: ${result.error.message}`);
2181
+ continue;
2182
+ }
2183
+ anyProbeSucceeded = true;
2184
+ if (result.status !== 0) {
2185
+ warnings.push(`${contract.executable} ${probeArgs.join(" ")} exited with status ${result.status}`);
2186
+ }
2187
+ }
2188
+ return {
2189
+ cli,
2190
+ status: contract.status,
2191
+ executable: contract.executable,
2192
+ entrypointArgs: contract.entrypointArgs,
2193
+ targetVersion: contract.targetVersion,
2194
+ checkedProbeCommands,
2195
+ available: anyProbeSucceeded,
2196
+ entrypointDrift: !anyProbeSucceeded,
2197
+ warnings,
2198
+ probedAt: new Date().toISOString(),
2199
+ };
2200
+ }
2201
+ function serializeAcpEntrypointContract(contract) {
2202
+ return {
2203
+ status: contract.status,
2204
+ native: contract.status === "native",
2205
+ executable: contract.executable,
2206
+ entrypointArgs: contract.entrypointArgs,
2207
+ targetVersion: contract.targetVersion,
2208
+ probeArgs: contract.probeArgs.map(args => [...args]),
2209
+ adapterCandidates: contract.adapterCandidates ?? [],
2210
+ evidence: contract.evidence,
2211
+ docsRef: contract.docsRef,
2212
+ };
2213
+ }
2087
2214
  export function buildUpstreamContractReport(options = {}) {
2088
2215
  const selected = options.cli ? [options.cli] : Object.keys(UPSTREAM_CLI_CONTRACTS);
2089
2216
  const contracts = Object.fromEntries(selected.map(cli => {
@@ -2130,6 +2257,7 @@ export function buildUpstreamContractReport(options = {}) {
2130
2257
  description: fixture.description,
2131
2258
  expect: fixture.expect,
2132
2259
  })),
2260
+ acpEntrypoint: serializeAcpEntrypointContract(ACP_ENTRYPOINT_CONTRACTS[cli]),
2133
2261
  },
2134
2262
  ];
2135
2263
  }));
@@ -2140,5 +2268,8 @@ export function buildUpstreamContractReport(options = {}) {
2140
2268
  installedProbe: options.probeInstalled
2141
2269
  ? Object.fromEntries(selected.map(cli => [cli, probeInstalledCliContract(cli)]))
2142
2270
  : null,
2271
+ acpInstalledProbe: options.probeInstalled
2272
+ ? Object.fromEntries(selected.map(cli => [cli, probeInstalledAcpEntrypoint(cli)]))
2273
+ : null,
2143
2274
  };
2144
2275
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "llm-cli-gateway",
3
- "version": "2.6.3",
3
+ "version": "2.8.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "llm-cli-gateway",
9
- "version": "2.6.3",
9
+ "version": "2.8.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@modelcontextprotocol/sdk": "^1.29.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-cli-gateway",
3
- "version": "2.6.3",
3
+ "version": "2.8.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",
@@ -16,6 +16,7 @@
16
16
  "endpoint_exposure",
17
17
  "client_config",
18
18
  "cache_awareness",
19
+ "provider_capabilities",
19
20
  "upstream",
20
21
  "next_actions"
21
22
  ],
@@ -289,12 +290,7 @@
289
290
  },
290
291
  "vibe_session_logging": {
291
292
  "type": "object",
292
- "required": [
293
- "config_path",
294
- "config_present",
295
- "session_logging_enabled",
296
- "note"
297
- ],
293
+ "required": ["config_path", "config_present", "session_logging_enabled", "note"],
298
294
  "properties": {
299
295
  "config_path": { "type": "string" },
300
296
  "config_present": { "type": "boolean" },
@@ -344,6 +340,71 @@
344
340
  },
345
341
  "additionalProperties": false
346
342
  },
343
+ "provider_capabilities": {
344
+ "type": "object",
345
+ "required": ["schema_version", "tool", "resources", "cache_ttl_ms", "providers"],
346
+ "properties": {
347
+ "schema_version": { "const": "provider-tool-capabilities.v2" },
348
+ "tool": { "const": "provider_tool_capabilities" },
349
+ "resources": {
350
+ "type": "object",
351
+ "required": ["catalog", "providers"],
352
+ "properties": {
353
+ "catalog": { "const": "provider-tools://catalog" },
354
+ "providers": {
355
+ "type": "object",
356
+ "required": ["claude", "codex", "gemini", "grok", "grok_api", "mistral"],
357
+ "additionalProperties": { "type": "string" }
358
+ }
359
+ },
360
+ "additionalProperties": false
361
+ },
362
+ "cache_ttl_ms": { "type": "integer", "minimum": 0 },
363
+ "providers": {
364
+ "type": "object",
365
+ "required": ["claude", "codex", "gemini", "grok", "grok_api", "mistral"],
366
+ "additionalProperties": {
367
+ "type": "object",
368
+ "required": [
369
+ "provider_kind",
370
+ "cli_available",
371
+ "gateway_request_tools",
372
+ "supported_features",
373
+ "unsupported_inputs",
374
+ "config_surface_count",
375
+ "discovered_skill_count",
376
+ "discovered_provider_tool_count",
377
+ "warnings"
378
+ ],
379
+ "properties": {
380
+ "provider_kind": { "enum": ["cli", "api"] },
381
+ "cli_available": { "type": "boolean" },
382
+ "gateway_request_tools": {
383
+ "type": "array",
384
+ "items": { "type": "string" }
385
+ },
386
+ "supported_features": {
387
+ "type": "array",
388
+ "items": { "type": "string" }
389
+ },
390
+ "unsupported_inputs": {
391
+ "type": "array",
392
+ "items": { "type": "string" }
393
+ },
394
+ "config_surface_count": { "type": "integer", "minimum": 0 },
395
+ "discovered_skill_count": { "type": "integer", "minimum": 0 },
396
+ "discovered_provider_tool_count": { "type": "integer", "minimum": 0 },
397
+ "warnings": {
398
+ "type": "array",
399
+ "items": { "type": "string" }
400
+ }
401
+ },
402
+ "additionalProperties": false
403
+ }
404
+ }
405
+ },
406
+ "additionalProperties": false
407
+ },
347
408
  "upstream": {
348
409
  "type": "object",
349
410
  "required": [
package/socket.yml CHANGED
@@ -35,6 +35,28 @@ version: 2
35
35
  # release security audit now hard-fails if any of those packages re-enter
36
36
  # the prod graph (and still blocks the flagged tar-stream 2.x versions).
37
37
  #
38
+ # shrinkwrap
39
+ # The published npm package intentionally includes npm-shrinkwrap.json. It
40
+ # is not an install-script bypass or a hidden dependency surface; it is a
41
+ # prod-only projection generated from package-lock.json by
42
+ # scripts/make-prod-shrinkwrap.mjs so registry consumers resolve the same
43
+ # audited tree we release. scripts/release-security-audit.sh regenerates
44
+ # that projection and hard-fails on mismatch, and
45
+ # scripts/verify-registry-install.sh publishes to a temporary registry and
46
+ # verifies a fresh consumer install has no better-sqlite3, prebuild-install,
47
+ # tar-fs, or tar-stream production chain.
48
+ #
49
+ # This is the npm-documented narrow use case for shrinkwrap: applications,
50
+ # daemons, and command-line tools published through the registry for global
51
+ # installs or devDependency use. llm-cli-gateway is a CLI/MCP appliance, not
52
+ # a library whose users need unpinned transitive dependency control.
53
+ #
54
+ # Historical note: releases that previously reported healthy public Socket
55
+ # scores, including 2.3.0, 2.4.0, and 2.5.0, also shipped
56
+ # npm-shrinkwrap.json. The same socket.yml shellAccess policy was present
57
+ # there too. A public package-page alert on 2.6.x therefore reflects Socket
58
+ # scoring/rescan behavior, not a newly introduced shrinkwrap or shell path.
59
+ #
38
60
  # shellAccess
39
61
  # This alert fires on every module that imports node:child_process, and
40
62
  # because spawning provider CLIs and git is the entire purpose of the package
@@ -93,8 +115,9 @@ issueRules:
93
115
  didYouMean: true
94
116
  installScripts: true
95
117
  telemetry: true
96
- hasNativeCode: true # devDependency-only as of 2.0.0 (better-sqlite3); prod artifact has no native code
97
- shellAccess: false # reviewed gateway capability; see rationale above
118
+ hasNativeCode: true # devDependency-only as of 2.0.0 (better-sqlite3); prod artifact has no native code
119
+ shrinkwrap: false # reviewed published CLI lockfile; see rationale above
120
+ shellAccess: false # reviewed gateway capability; see rationale above
98
121
  shellScriptOverride: true
99
122
  gitDependency: true
100
123
  httpDependency: true