llm-cli-gateway 2.3.0 → 2.4.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/dist/metrics.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type CliType } from "./session-manager.js";
1
+ import { type ProviderType } from "./session-manager.js";
2
2
  export interface ToolMetricsSnapshot {
3
3
  requestCount: number;
4
4
  successCount: number;
@@ -13,11 +13,11 @@ export interface PerformanceMetricsSnapshot {
13
13
  totalFailures: number;
14
14
  overallSuccessRate: number;
15
15
  overallFailureRate: number;
16
- byTool: Record<CliType, ToolMetricsSnapshot>;
16
+ byTool: Record<ProviderType, ToolMetricsSnapshot>;
17
17
  generatedAt: string;
18
18
  }
19
19
  export declare class PerformanceMetrics {
20
20
  private metrics;
21
- recordRequest(cli: CliType, durationMs: number, success: boolean): void;
21
+ recordRequest(provider: ProviderType, durationMs: number, success: boolean): void;
22
22
  snapshot(): PerformanceMetricsSnapshot;
23
23
  }
package/dist/metrics.js CHANGED
@@ -1,12 +1,12 @@
1
- import { CLI_TYPES } from "./session-manager.js";
2
- const createEmptyMetrics = () => Object.fromEntries(CLI_TYPES.map(cli => [
3
- cli,
1
+ import { PROVIDER_TYPES } from "./session-manager.js";
2
+ const createEmptyMetrics = () => Object.fromEntries(PROVIDER_TYPES.map(provider => [
3
+ provider,
4
4
  { requestCount: 0, successCount: 0, failureCount: 0, totalResponseTimeMs: 0 },
5
5
  ]));
6
6
  export class PerformanceMetrics {
7
7
  metrics = createEmptyMetrics();
8
- recordRequest(cli, durationMs, success) {
9
- const metrics = this.metrics[cli];
8
+ recordRequest(provider, durationMs, success) {
9
+ const metrics = this.metrics[provider];
10
10
  metrics.requestCount += 1;
11
11
  const normalizedDurationMs = Number.isFinite(durationMs) ? Math.max(0, durationMs) : 0;
12
12
  metrics.totalResponseTimeMs += normalizedDurationMs;
@@ -22,12 +22,12 @@ export class PerformanceMetrics {
22
22
  let totalRequests = 0;
23
23
  let totalSuccesses = 0;
24
24
  let totalFailures = 0;
25
- for (const cli of CLI_TYPES) {
26
- const metrics = this.metrics[cli];
25
+ for (const provider of PROVIDER_TYPES) {
26
+ const metrics = this.metrics[provider];
27
27
  const averageResponseTimeMs = metrics.requestCount > 0 ? metrics.totalResponseTimeMs / metrics.requestCount : 0;
28
28
  const successRate = metrics.requestCount > 0 ? metrics.successCount / metrics.requestCount : 0;
29
29
  const failureRate = metrics.requestCount > 0 ? metrics.failureCount / metrics.requestCount : 0;
30
- byTool[cli] = {
30
+ byTool[provider] = {
31
31
  requestCount: metrics.requestCount,
32
32
  successCount: metrics.successCount,
33
33
  failureCount: metrics.failureCount,
@@ -98,44 +98,44 @@ 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
- agent?: string | undefined;
102
101
  agents?: Record<string, Record<string, unknown>> | undefined;
102
+ agent?: string | undefined;
103
103
  forkSession?: boolean | undefined;
104
104
  systemPrompt?: string | undefined;
105
105
  appendSystemPrompt?: string | undefined;
106
106
  maxBudgetUsd?: number | undefined;
107
107
  maxTurns?: number | undefined;
108
- effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
108
+ effort?: "medium" | "low" | "high" | "xhigh" | "max" | undefined;
109
109
  excludeDynamicSystemPromptSections?: boolean | undefined;
110
110
  }, {
111
- agent?: string | undefined;
112
111
  agents?: Record<string, Record<string, unknown>> | undefined;
112
+ agent?: string | undefined;
113
113
  forkSession?: boolean | undefined;
114
114
  systemPrompt?: string | undefined;
115
115
  appendSystemPrompt?: string | undefined;
116
116
  maxBudgetUsd?: number | undefined;
117
117
  maxTurns?: number | undefined;
118
- effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
118
+ effort?: "medium" | "low" | "high" | "xhigh" | "max" | undefined;
119
119
  excludeDynamicSystemPromptSections?: boolean | undefined;
120
120
  }>, {
121
- agent?: string | undefined;
122
121
  agents?: Record<string, Record<string, unknown>> | undefined;
122
+ agent?: string | undefined;
123
123
  forkSession?: boolean | undefined;
124
124
  systemPrompt?: string | undefined;
125
125
  appendSystemPrompt?: string | undefined;
126
126
  maxBudgetUsd?: number | undefined;
127
127
  maxTurns?: number | undefined;
128
- effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
128
+ effort?: "medium" | "low" | "high" | "xhigh" | "max" | undefined;
129
129
  excludeDynamicSystemPromptSections?: boolean | undefined;
130
130
  }, {
131
- agent?: string | undefined;
132
131
  agents?: Record<string, Record<string, unknown>> | undefined;
132
+ agent?: string | undefined;
133
133
  forkSession?: boolean | undefined;
134
134
  systemPrompt?: string | undefined;
135
135
  appendSystemPrompt?: string | undefined;
136
136
  maxBudgetUsd?: number | undefined;
137
137
  maxTurns?: number | undefined;
138
- effort?: "low" | "medium" | "high" | "xhigh" | "max" | undefined;
138
+ effort?: "medium" | "low" | "high" | "xhigh" | "max" | undefined;
139
139
  excludeDynamicSystemPromptSections?: boolean | undefined;
140
140
  }>;
141
141
  export declare const CLAUDE_AGENT_DEFINITION_SCHEMA: z.ZodObject<{
package/dist/resources.js CHANGED
@@ -1,5 +1,7 @@
1
+ import { CLI_TYPES, PROVIDER_TYPES } from "./session-manager.js";
1
2
  import { getAvailableCliInfo } from "./model-registry.js";
2
3
  import { computeGlobalCacheStats, computePrefixCacheStats, computeSessionCacheStats, computeTtlRemaining, } from "./cache-stats.js";
4
+ import { buildProviderSubcommandsCompactCatalog, getCliSubcommandContract, serializeCliSubcommandContract, } from "./upstream-contracts.js";
3
5
  export class ResourceProvider {
4
6
  sessionManager;
5
7
  performanceMetrics;
@@ -163,11 +165,26 @@ export class ResourceProvider {
163
165
  priority: 0.9,
164
166
  },
165
167
  },
168
+ {
169
+ uri: "provider-subcommands://catalog",
170
+ name: "Provider Subcommands Catalog",
171
+ title: "Provider Subcommands Catalog",
172
+ description: "Compact read-only catalog of declared provider CLI subcommands",
173
+ mimeType: "application/json",
174
+ annotations: {
175
+ audience: ["user", "assistant"],
176
+ priority: 0.7,
177
+ },
178
+ },
166
179
  ];
167
180
  }
168
181
  async readResource(uri) {
169
182
  if (uri === "sessions://all") {
170
183
  const sessions = await this.sessionManager.listSessions();
184
+ const activeSessions = Object.fromEntries(await Promise.all(PROVIDER_TYPES.map(async (provider) => [
185
+ provider,
186
+ (await this.sessionManager.getActiveSession(provider))?.id || null,
187
+ ])));
171
188
  return {
172
189
  uri,
173
190
  mimeType: "application/json",
@@ -180,13 +197,7 @@ export class ResourceProvider {
180
197
  createdAt: s.createdAt,
181
198
  lastUsedAt: s.lastUsedAt,
182
199
  })),
183
- activeSessions: {
184
- claude: (await this.sessionManager.getActiveSession("claude"))?.id || null,
185
- codex: (await this.sessionManager.getActiveSession("codex"))?.id || null,
186
- gemini: (await this.sessionManager.getActiveSession("gemini"))?.id || null,
187
- grok: (await this.sessionManager.getActiveSession("grok"))?.id || null,
188
- mistral: (await this.sessionManager.getActiveSession("mistral"))?.id || null,
189
- },
200
+ activeSessions,
190
201
  }, null, 2),
191
202
  };
192
203
  }
@@ -302,6 +313,44 @@ export class ResourceProvider {
302
313
  text: JSON.stringify(this.performanceMetrics.snapshot(), null, 2),
303
314
  };
304
315
  }
316
+ if (uri === "provider-subcommands://catalog" || uri === "provider_subcommands://catalog") {
317
+ return {
318
+ uri,
319
+ mimeType: "application/json",
320
+ text: JSON.stringify(buildProviderSubcommandsCompactCatalog()),
321
+ };
322
+ }
323
+ const subcommandResource = parseProviderSubcommandUri(uri);
324
+ if (subcommandResource) {
325
+ const contract = getCliSubcommandContract(subcommandResource.provider, subcommandResource.commandPath);
326
+ if (!contract)
327
+ return null;
328
+ return {
329
+ uri,
330
+ mimeType: "application/json",
331
+ text: JSON.stringify({
332
+ schemaVersion: "provider-subcommand-contract.v1",
333
+ contract: serializeCliSubcommandContract(subcommandResource.provider, contract),
334
+ }, null, 2),
335
+ };
336
+ }
305
337
  return null;
306
338
  }
307
339
  }
340
+ function parseProviderSubcommandUri(uri) {
341
+ const prefix = uri.startsWith("provider-subcommands://")
342
+ ? "provider-subcommands://"
343
+ : uri.startsWith("provider_subcommands://")
344
+ ? "provider_subcommands://"
345
+ : null;
346
+ if (!prefix || uri === `${prefix}catalog`)
347
+ return null;
348
+ const rest = uri.slice(prefix.length);
349
+ const [providerRaw, ...pathParts] = rest.split("/");
350
+ if (!CLI_TYPES.includes(providerRaw) || pathParts.length === 0)
351
+ return null;
352
+ return {
353
+ provider: providerRaw,
354
+ commandPath: pathParts.map(part => decodeURIComponent(part)).filter(Boolean),
355
+ };
356
+ }
@@ -1,16 +1,16 @@
1
1
  import type { Pool } from "pg";
2
- import { Session, CliType } from "./session-manager.js";
2
+ import { Session, ProviderType } from "./session-manager.js";
3
3
  export type { Logger } from "./logger.js";
4
4
  export declare class PostgreSQLSessionManager {
5
5
  private pool;
6
6
  constructor(pool: Pool);
7
- createSession(cli: CliType, description?: string, sessionId?: string): Promise<Session>;
7
+ createSession(cli: ProviderType, description?: string, sessionId?: string): Promise<Session>;
8
8
  getSession(sessionId: string): Promise<Session | null>;
9
- listSessions(cli?: CliType): Promise<Session[]>;
9
+ listSessions(cli?: ProviderType): Promise<Session[]>;
10
10
  deleteSession(sessionId: string): Promise<boolean>;
11
- setActiveSession(cli: CliType, sessionId: string | null): Promise<boolean>;
12
- getActiveSession(cli: CliType): Promise<Session | null>;
11
+ setActiveSession(cli: ProviderType, sessionId: string | null): Promise<boolean>;
12
+ getActiveSession(cli: ProviderType): Promise<Session | null>;
13
13
  updateSessionUsage(sessionId: string): Promise<void>;
14
14
  updateSessionMetadata(sessionId: string, metadata: Record<string, any>): Promise<boolean>;
15
- clearAllSessions(cli?: CliType): Promise<number>;
15
+ clearAllSessions(cli?: ProviderType): Promise<number>;
16
16
  }
@@ -5,6 +5,7 @@ const DEFAULT_SESSION_DESCRIPTIONS = {
5
5
  gemini: "Gemini Session",
6
6
  grok: "Grok Session",
7
7
  mistral: "Mistral Session",
8
+ "grok-api": "Grok API Session",
8
9
  };
9
10
  export class PostgreSQLSessionManager {
10
11
  pool;
@@ -3,9 +3,13 @@ import type { DatabaseConnection } from "./db.js";
3
3
  import type { Logger } from "./logger.js";
4
4
  export declare const CLI_TYPES: readonly ["claude", "codex", "gemini", "grok", "mistral"];
5
5
  export type CliType = (typeof CLI_TYPES)[number];
6
+ export declare const API_PROVIDER_TYPES: readonly ["grok-api"];
7
+ export type ApiProviderType = (typeof API_PROVIDER_TYPES)[number];
8
+ export declare const PROVIDER_TYPES: readonly ["claude", "codex", "gemini", "grok", "mistral", "grok-api"];
9
+ export type ProviderType = (typeof PROVIDER_TYPES)[number];
6
10
  export interface Session {
7
11
  id: string;
8
- cli: CliType;
12
+ cli: ProviderType;
9
13
  createdAt: string;
10
14
  lastUsedAt: string;
11
15
  description?: string;
@@ -13,7 +17,7 @@ export interface Session {
13
17
  }
14
18
  export interface SessionStorage {
15
19
  sessions: Record<string, Session>;
16
- activeSession: Record<CliType, string | null>;
20
+ activeSession: Record<ProviderType, string | null>;
17
21
  }
18
22
  export type SessionCleanupHook = (session: Session) => void | Promise<void>;
19
23
  export declare class FileSessionManager {
@@ -32,27 +36,27 @@ export declare class FileSessionManager {
32
36
  private ensureStorageDirectory;
33
37
  private loadStorage;
34
38
  private saveStorage;
35
- createSession(cli: CliType, description?: string, sessionId?: string): Session;
39
+ createSession(cli: ProviderType, description?: string, sessionId?: string): Session;
36
40
  getSession(sessionId: string): Session | null;
37
- listSessions(cli?: CliType): Session[];
41
+ listSessions(cli?: ProviderType): Session[];
38
42
  deleteSession(sessionId: string): boolean;
39
- setActiveSession(cli: CliType, sessionId: string | null): boolean;
40
- getActiveSession(cli: CliType): Session | null;
43
+ setActiveSession(cli: ProviderType, sessionId: string | null): boolean;
44
+ getActiveSession(cli: ProviderType): Session | null;
41
45
  updateSessionUsage(sessionId: string): void;
42
46
  updateSessionMetadata(sessionId: string, metadata: Record<string, any>): boolean;
43
- clearAllSessions(cli?: CliType): number;
47
+ clearAllSessions(cli?: ProviderType): number;
44
48
  }
45
49
  export declare const SessionManager: typeof FileSessionManager;
46
50
  export interface ISessionManager {
47
- createSession(cli: CliType, description?: string, sessionId?: string): Session | Promise<Session>;
51
+ createSession(cli: ProviderType, description?: string, sessionId?: string): Session | Promise<Session>;
48
52
  getSession(sessionId: string): Session | null | Promise<Session | null>;
49
- listSessions(cli?: CliType): Session[] | Promise<Session[]>;
53
+ listSessions(cli?: ProviderType): Session[] | Promise<Session[]>;
50
54
  deleteSession(sessionId: string): boolean | Promise<boolean>;
51
- setActiveSession(cli: CliType, sessionId: string | null): boolean | Promise<boolean>;
52
- getActiveSession(cli: CliType): Session | null | Promise<Session | null>;
55
+ setActiveSession(cli: ProviderType, sessionId: string | null): boolean | Promise<boolean>;
56
+ getActiveSession(cli: ProviderType): Session | null | Promise<Session | null>;
53
57
  updateSessionUsage(sessionId: string): void | Promise<void>;
54
58
  updateSessionMetadata(sessionId: string, metadata: Record<string, any>): boolean | Promise<boolean>;
55
- clearAllSessions(cli?: CliType): number | Promise<number>;
59
+ clearAllSessions(cli?: ProviderType): number | Promise<number>;
56
60
  }
57
61
  export declare function createSessionManager(config?: Config, db?: DatabaseConnection, logger?: Logger, opts?: {
58
62
  cleanupHook?: SessionCleanupHook;
@@ -5,13 +5,16 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, openSyn
5
5
  import { DEFAULT_SESSION_TTL_SECONDS } from "./config.js";
6
6
  import { noopLogger } from "./logger.js";
7
7
  export const CLI_TYPES = ["claude", "codex", "gemini", "grok", "mistral"];
8
- const createEmptyActiveSessions = () => Object.fromEntries(CLI_TYPES.map(cli => [cli, null]));
8
+ export const API_PROVIDER_TYPES = ["grok-api"];
9
+ export const PROVIDER_TYPES = [...CLI_TYPES, ...API_PROVIDER_TYPES];
10
+ const createEmptyActiveSessions = () => Object.fromEntries(PROVIDER_TYPES.map(provider => [provider, null]));
9
11
  const DEFAULT_SESSION_DESCRIPTIONS = {
10
12
  claude: "Claude Session",
11
13
  codex: "Codex Session",
12
14
  gemini: "Gemini Session",
13
15
  grok: "Grok Session",
14
16
  mistral: "Mistral Session",
17
+ "grok-api": "Grok API Session",
15
18
  };
16
19
  export class FileSessionManager {
17
20
  storagePath;
@@ -21,6 +21,7 @@ export interface CliContract {
21
21
  upstream: string;
22
22
  helpArgs: string[][];
23
23
  flags: Record<string, CliFlagContract>;
24
+ subcommands?: Record<string, CliSubcommandContract>;
24
25
  env?: Record<string, CliFlagContract>;
25
26
  mcpTools: readonly string[];
26
27
  mcpParameters: readonly string[];
@@ -43,6 +44,25 @@ export interface CliContractFixture {
43
44
  env?: Record<string, string>;
44
45
  expect: "pass" | "fail";
45
46
  }
47
+ export type CliSubcommandRisk = "read_only" | "writes_local_config" | "auth" | "network" | "starts_server" | "updates_binary" | "destructive" | "executes_agent";
48
+ export type CliSubcommandExposure = "tracked_only" | "mcp_readonly" | "mcp_requires_approval" | "not_exposed";
49
+ export type CliSubcommandTier = "catalog" | "inspect" | "execute_candidate" | "diagnostic";
50
+ export type CliSubcommandTokenCost = "tiny" | "small" | "medium" | "large";
51
+ export interface CliSubcommandContract {
52
+ commandPath: readonly string[];
53
+ helpArgs: readonly string[][];
54
+ flags: Record<string, CliFlagContract>;
55
+ maxPositionals: number;
56
+ acknowledgedUpstreamFlags?: readonly string[];
57
+ aliases?: readonly string[];
58
+ children?: Record<string, CliSubcommandContract>;
59
+ risk: CliSubcommandRisk;
60
+ exposure: CliSubcommandExposure;
61
+ tier: CliSubcommandTier;
62
+ tokenCost: CliSubcommandTokenCost;
63
+ summary: string;
64
+ conformanceFixtures: readonly CliContractFixture[];
65
+ }
46
66
  export interface ContractViolation {
47
67
  cli: CliType;
48
68
  arg?: string;
@@ -53,9 +73,55 @@ export interface ContractValidationResult {
53
73
  ok: boolean;
54
74
  violations: ContractViolation[];
55
75
  }
76
+ export interface SubcommandContractValidationResult extends ContractValidationResult {
77
+ commandPath: readonly string[];
78
+ risk?: CliSubcommandRisk;
79
+ exposure?: CliSubcommandExposure;
80
+ tier?: CliSubcommandTier;
81
+ }
82
+ export interface ProviderSubcommandCatalogRow {
83
+ provider: CliType;
84
+ commandPath: readonly string[];
85
+ aliases: readonly string[];
86
+ tier: CliSubcommandTier;
87
+ risk: CliSubcommandRisk;
88
+ exposure: CliSubcommandExposure;
89
+ tokenCost: CliSubcommandTokenCost;
90
+ summary: string;
91
+ driftStatus: "unknown" | "clean" | "drift";
92
+ resourceUri: string;
93
+ }
94
+ export interface ProviderSubcommandCompactCatalog {
95
+ schemaVersion: "provider-subcommands-catalog.v1";
96
+ columns: readonly [
97
+ "provider",
98
+ "commandPath",
99
+ "aliases",
100
+ "tier",
101
+ "risk",
102
+ "exposure",
103
+ "tokenCost",
104
+ "summary",
105
+ "driftStatus",
106
+ "resourceUri"
107
+ ];
108
+ rows: readonly (readonly string[])[];
109
+ }
56
110
  export declare const UPSTREAM_CLI_CONTRACTS: Record<CliType, CliContract>;
57
111
  export declare function validateUpstreamCliArgs(cli: CliType, args: readonly string[]): ContractValidationResult;
58
112
  export declare function assertUpstreamCliArgs(cli: CliType, args: readonly string[]): void;
113
+ export declare function flattenCliSubcommands(subcommands: Record<string, CliSubcommandContract> | undefined): CliSubcommandContract[];
114
+ export declare function getCliSubcommandContract(cli: CliType, commandPath: readonly string[]): CliSubcommandContract | null;
115
+ export declare function serializeCliSubcommandContract(cli: CliType, contract: CliSubcommandContract): Record<string, unknown>;
116
+ export declare function listProviderSubcommands(options?: {
117
+ provider?: CliType;
118
+ tier?: CliSubcommandTier;
119
+ risk?: CliSubcommandRisk;
120
+ exposure?: CliSubcommandExposure;
121
+ commandPathPrefix?: readonly string[];
122
+ }): ProviderSubcommandCatalogRow[];
123
+ export declare function buildProviderSubcommandsCompactCatalog(options?: Parameters<typeof listProviderSubcommands>[0]): ProviderSubcommandCompactCatalog;
124
+ export declare function validateUpstreamCliSubcommandArgs(cli: CliType, commandPath: readonly string[], args: readonly string[]): SubcommandContractValidationResult;
59
125
  export declare function validateUpstreamCliEnv(cli: CliType, env: Record<string, string> | undefined): ContractValidationResult;
60
126
  export declare function assertUpstreamCliEnv(cli: CliType, env: Record<string, string> | undefined): void;
61
127
  export declare function extractDiscoveredFlags(helpText: string): readonly string[];
@@ -66,6 +132,23 @@ export interface FlagDriftResult {
66
132
  warnings: string[];
67
133
  }
68
134
  export declare function computeFlagDrift(contract: CliContract, helpText: string, discoveredFlags: readonly string[]): FlagDriftResult;
135
+ export declare function computeSubcommandFlagDrift(contract: CliSubcommandContract, executable: string, helpText: string, discoveredFlags: readonly string[]): FlagDriftResult;
136
+ export interface InstalledCliSubcommandProbe {
137
+ commandPath: readonly string[];
138
+ checkedHelpCommands: string[][];
139
+ available: boolean;
140
+ missingFlags: string[];
141
+ extraFlags: readonly string[];
142
+ acknowledgedExtraFlags: readonly string[];
143
+ discoveredFlags: readonly string[];
144
+ helpHash?: string;
145
+ probedAt: string;
146
+ warnings: string[];
147
+ risk: CliSubcommandRisk;
148
+ exposure: CliSubcommandExposure;
149
+ tier: CliSubcommandTier;
150
+ summary: string;
151
+ }
69
152
  export interface InstalledCliContractProbe {
70
153
  cli: CliType;
71
154
  executable: string;
@@ -79,6 +162,7 @@ export interface InstalledCliContractProbe {
79
162
  discoveredFlags: readonly string[];
80
163
  helpHash?: string;
81
164
  versionHint?: string;
165
+ subcommands: Record<string, InstalledCliSubcommandProbe>;
82
166
  probedAt: string;
83
167
  warnings: string[];
84
168
  }