llm-cli-gateway 2.5.0 → 2.6.3

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.
@@ -60,14 +60,17 @@ export function assembleClaudeCacheBlocks(parts) {
60
60
  for (const [name, value] of stableEntries) {
61
61
  if (value === undefined || value.length === 0)
62
62
  continue;
63
- const block = { type: "text", text: value };
63
+ const block = {
64
+ type: "text",
65
+ text: blocks.length > 0 ? `${SEPARATOR}${value}` : value,
66
+ };
64
67
  if (cc[name]) {
65
68
  block.cache_control = { type: "ephemeral", ttl: "1h" };
66
69
  markedBlockCount += 1;
67
70
  }
68
71
  blocks.push(block);
69
72
  }
70
- blocks.push({ type: "text", text: parts.task });
73
+ blocks.push({ type: "text", text: blocks.length > 0 ? `${SEPARATOR}${parts.task}` : parts.task });
71
74
  return {
72
75
  payload: {
73
76
  type: "user",
@@ -0,0 +1,27 @@
1
+ import { z } from "zod/v3";
2
+ import type { CliContract } from "./upstream-contracts.js";
3
+ export type FlagEmitRule = "value_if_present" | "value_if_defined" | "flag_if_true" | "csv_if_nonempty" | "repeat_if_nonempty";
4
+ export interface FlagGenerationMeta {
5
+ flag: string;
6
+ requestParameter: string;
7
+ emit: FlagEmitRule;
8
+ inputType: "string" | "number" | "boolean" | "string[]";
9
+ describe?: string;
10
+ minLength?: number;
11
+ numeric?: {
12
+ int?: boolean;
13
+ positive?: boolean;
14
+ safe?: boolean;
15
+ max?: number;
16
+ min?: number;
17
+ };
18
+ }
19
+ export declare function buildArgvFromGeneration(contract: CliContract, generation: readonly FlagGenerationMeta[], params: Record<string, unknown>): string[];
20
+ export declare function deriveZodShapeFromGeneration(contract: CliContract, generation: readonly FlagGenerationMeta[]): Record<string, z.ZodTypeAny>;
21
+ export declare const GROK_GEN_OUTPUT_FORMAT: readonly FlagGenerationMeta[];
22
+ export declare const GROK_GEN_MAIN: readonly FlagGenerationMeta[];
23
+ export declare const GROK_GEN_PROMPT_FILE: readonly FlagGenerationMeta[];
24
+ export declare const GROK_GEN_SINGLE: readonly FlagGenerationMeta[];
25
+ export declare const GROK_GEN_TAIL: readonly FlagGenerationMeta[];
26
+ export declare const GROK_FLAG_GENERATION: readonly FlagGenerationMeta[];
27
+ export declare const UNGENERATED_GROK_FLAGS: readonly string[];
@@ -0,0 +1,335 @@
1
+ import { z } from "zod/v3";
2
+ export function buildArgvFromGeneration(contract, generation, params) {
3
+ const args = [];
4
+ for (const gen of generation) {
5
+ if (!contract.flags[gen.flag]) {
6
+ throw new Error(`provider-codegen: generation references flag '${gen.flag}' absent from ${contract.cli} contract.flags`);
7
+ }
8
+ const value = params[gen.requestParameter];
9
+ switch (gen.emit) {
10
+ case "value_if_present":
11
+ if (value)
12
+ args.push(gen.flag, String(value));
13
+ break;
14
+ case "value_if_defined":
15
+ if (value !== undefined && value !== null)
16
+ args.push(gen.flag, String(value));
17
+ break;
18
+ case "flag_if_true":
19
+ if (value)
20
+ args.push(gen.flag);
21
+ break;
22
+ case "csv_if_nonempty":
23
+ if (Array.isArray(value) && value.length > 0) {
24
+ args.push(gen.flag, value.map(String).join(","));
25
+ }
26
+ break;
27
+ case "repeat_if_nonempty":
28
+ if (Array.isArray(value) && value.length > 0) {
29
+ for (const item of value)
30
+ args.push(gen.flag, String(item));
31
+ }
32
+ break;
33
+ }
34
+ }
35
+ return args;
36
+ }
37
+ export function deriveZodShapeFromGeneration(contract, generation) {
38
+ const shape = {};
39
+ for (const gen of generation) {
40
+ const flagContract = contract.flags[gen.flag];
41
+ if (!flagContract) {
42
+ throw new Error(`provider-codegen: generation references flag '${gen.flag}' absent from ${contract.cli} contract.flags`);
43
+ }
44
+ let field;
45
+ switch (gen.inputType) {
46
+ case "string": {
47
+ if (flagContract.values && flagContract.values.length > 0) {
48
+ field = z.enum(flagContract.values);
49
+ }
50
+ else {
51
+ let s = z.string();
52
+ if (gen.minLength !== undefined)
53
+ s = s.min(gen.minLength);
54
+ field = s;
55
+ }
56
+ break;
57
+ }
58
+ case "number": {
59
+ let n = z.number();
60
+ if (gen.numeric?.int)
61
+ n = n.int();
62
+ if (gen.numeric?.positive)
63
+ n = n.positive();
64
+ if (gen.numeric?.safe)
65
+ n = n.safe();
66
+ if (gen.numeric?.min !== undefined)
67
+ n = n.min(gen.numeric.min);
68
+ if (gen.numeric?.max !== undefined)
69
+ n = n.max(gen.numeric.max);
70
+ field = n;
71
+ break;
72
+ }
73
+ case "boolean":
74
+ field = z.boolean();
75
+ break;
76
+ case "string[]":
77
+ field = z.array(z.string());
78
+ break;
79
+ }
80
+ let optional = field.optional();
81
+ if (gen.describe !== undefined)
82
+ optional = optional.describe(gen.describe);
83
+ shape[gen.requestParameter] = optional;
84
+ }
85
+ return shape;
86
+ }
87
+ export const GROK_GEN_OUTPUT_FORMAT = [
88
+ {
89
+ flag: "--output-format",
90
+ requestParameter: "outputFormat",
91
+ emit: "value_if_present",
92
+ inputType: "string",
93
+ describe: "Output format (plain|json|streaming-json). Grok default is plain.",
94
+ },
95
+ ];
96
+ const MAX_TURNS_NUMERIC = { int: true, positive: true, safe: true, max: 10_000 };
97
+ export const GROK_GEN_MAIN = [
98
+ {
99
+ flag: "--effort",
100
+ requestParameter: "effort",
101
+ emit: "value_if_present",
102
+ inputType: "string",
103
+ describe: "Grok effort level",
104
+ },
105
+ {
106
+ flag: "--reasoning-effort",
107
+ requestParameter: "reasoningEffort",
108
+ emit: "value_if_present",
109
+ inputType: "string",
110
+ describe: "Reasoning effort for reasoning models",
111
+ },
112
+ {
113
+ flag: "--tools",
114
+ requestParameter: "allowedTools",
115
+ emit: "csv_if_nonempty",
116
+ inputType: "string[]",
117
+ describe: "Allowed built-in tools (passed as --tools comma list)",
118
+ },
119
+ {
120
+ flag: "--disallowed-tools",
121
+ requestParameter: "disallowedTools",
122
+ emit: "csv_if_nonempty",
123
+ inputType: "string[]",
124
+ describe: "Disallowed built-in tools (passed as --disallowed-tools comma list)",
125
+ },
126
+ {
127
+ flag: "--max-turns",
128
+ requestParameter: "maxTurns",
129
+ emit: "value_if_defined",
130
+ inputType: "number",
131
+ numeric: MAX_TURNS_NUMERIC,
132
+ describe: "Grok `--max-turns N`: cap on agent-loop iterations for cost / latency control (Phase 4 slice δ). Bounded to safe integers ≤ 10000.",
133
+ },
134
+ {
135
+ flag: "--cwd",
136
+ requestParameter: "workingDir",
137
+ emit: "value_if_present",
138
+ inputType: "string",
139
+ minLength: 1,
140
+ describe: "Grok --cwd <DIR>: working directory for this invocation. Lets headless callers run Grok against a directory other than the gateway process's cwd.",
141
+ },
142
+ {
143
+ flag: "--sandbox",
144
+ requestParameter: "sandbox",
145
+ emit: "value_if_present",
146
+ inputType: "string",
147
+ minLength: 1,
148
+ describe: "Grok --sandbox <PROFILE>: sandbox profile for filesystem and network access. Freeform per `grok --help` (no enum constraint on Grok 0.1.210); also settable via GROK_SANDBOX env var. Caller responsibility to pass a valid profile name.",
149
+ },
150
+ {
151
+ flag: "--rules",
152
+ requestParameter: "rules",
153
+ emit: "value_if_present",
154
+ inputType: "string",
155
+ minLength: 1,
156
+ describe: "Grok --rules <RULES>: extra rules to append to the system prompt. Supports `@file` prefix per `grok --help` to load from a file; gateway passes the value verbatim and lets Grok parse the prefix.",
157
+ },
158
+ {
159
+ flag: "--system-prompt-override",
160
+ requestParameter: "systemPromptOverride",
161
+ emit: "value_if_present",
162
+ inputType: "string",
163
+ minLength: 1,
164
+ describe: "Grok --system-prompt-override <PROMPT>: replace the agent's system prompt entirely. Distinct from Claude's --system-prompt / --append-system-prompt (Grok has only one override flag, not a pair).",
165
+ },
166
+ {
167
+ flag: "--allow",
168
+ requestParameter: "allow",
169
+ emit: "repeat_if_nonempty",
170
+ inputType: "string[]",
171
+ describe: 'Grok --allow <RULE>: permission allow rules. Each entry is emitted as its own --allow instance (per `grok --help`: "Repeat to add multiple rules").',
172
+ },
173
+ {
174
+ flag: "--deny",
175
+ requestParameter: "deny",
176
+ emit: "repeat_if_nonempty",
177
+ inputType: "string[]",
178
+ describe: 'Grok --deny <RULE>: permission deny rules. Each entry is emitted as its own --deny instance (per `grok --help`: "Repeat to add multiple rules").',
179
+ },
180
+ {
181
+ flag: "--compaction-mode",
182
+ requestParameter: "compactionMode",
183
+ emit: "value_if_present",
184
+ inputType: "string",
185
+ describe: "Grok --compaction-mode: summary (default; no pointer) | transcript (points at the raw transcript) | segments (persists per-segment markdown to grep). Sets GROK_COMPACTION_MODE.",
186
+ },
187
+ {
188
+ flag: "--compaction-detail",
189
+ requestParameter: "compactionDetail",
190
+ emit: "value_if_present",
191
+ inputType: "string",
192
+ describe: "Grok --compaction-detail: verbatim segment detail (none|minimal|balanced|verbose, default verbose). Only affects `--compaction-mode segments`. Sets GROK_COMPACTION_DETAIL.",
193
+ },
194
+ {
195
+ flag: "--agent",
196
+ requestParameter: "agent",
197
+ emit: "value_if_present",
198
+ inputType: "string",
199
+ minLength: 1,
200
+ describe: "Grok --agent <NAME>: agent name or definition file path.",
201
+ },
202
+ {
203
+ flag: "--best-of-n",
204
+ requestParameter: "bestOfN",
205
+ emit: "value_if_defined",
206
+ inputType: "number",
207
+ numeric: MAX_TURNS_NUMERIC,
208
+ describe: "Grok --best-of-n <N>: run the task N ways in parallel and pick the best (headless only).",
209
+ },
210
+ {
211
+ flag: "--check",
212
+ requestParameter: "check",
213
+ emit: "flag_if_true",
214
+ inputType: "boolean",
215
+ describe: "Grok --check: append a self-verification loop to the prompt (headless only).",
216
+ },
217
+ {
218
+ flag: "--disable-web-search",
219
+ requestParameter: "disableWebSearch",
220
+ emit: "flag_if_true",
221
+ inputType: "boolean",
222
+ describe: "Grok --disable-web-search: disable web search and remote retrieval tools.",
223
+ },
224
+ {
225
+ flag: "--todo-gate",
226
+ requestParameter: "todoGate",
227
+ emit: "flag_if_true",
228
+ inputType: "boolean",
229
+ describe: "Grok --todo-gate: enable runtime turn-end TodoGate for this session (session-scoped, not persisted).",
230
+ },
231
+ {
232
+ flag: "--verbatim",
233
+ requestParameter: "verbatim",
234
+ emit: "flag_if_true",
235
+ inputType: "boolean",
236
+ describe: "Grok --verbatim: send the prompt exactly as given. Also skips gateway optimizePrompt when true.",
237
+ },
238
+ ];
239
+ export const GROK_GEN_PROMPT_FILE = [
240
+ {
241
+ flag: "--prompt-file",
242
+ requestParameter: "promptFile",
243
+ emit: "value_if_present",
244
+ inputType: "string",
245
+ minLength: 1,
246
+ describe: "Grok --prompt-file <PATH>: single-turn prompt loaded from a file.",
247
+ },
248
+ ];
249
+ export const GROK_GEN_SINGLE = [
250
+ {
251
+ flag: "--single",
252
+ requestParameter: "single",
253
+ emit: "value_if_present",
254
+ inputType: "string",
255
+ minLength: 1,
256
+ describe: "Grok --single <PROMPT>: single-turn prompt (in addition to gateway -p).",
257
+ },
258
+ ];
259
+ export const GROK_GEN_TAIL = [
260
+ {
261
+ flag: "--experimental-memory",
262
+ requestParameter: "experimentalMemory",
263
+ emit: "flag_if_true",
264
+ inputType: "boolean",
265
+ describe: "Grok --experimental-memory: enable cross-session memory.",
266
+ },
267
+ {
268
+ flag: "--no-alt-screen",
269
+ requestParameter: "noAltScreen",
270
+ emit: "flag_if_true",
271
+ inputType: "boolean",
272
+ describe: "Grok --no-alt-screen: run inline without alt screen.",
273
+ },
274
+ {
275
+ flag: "--no-memory",
276
+ requestParameter: "noMemory",
277
+ emit: "flag_if_true",
278
+ inputType: "boolean",
279
+ describe: "Grok --no-memory: disable cross-session memory.",
280
+ },
281
+ {
282
+ flag: "--no-plan",
283
+ requestParameter: "noPlan",
284
+ emit: "flag_if_true",
285
+ inputType: "boolean",
286
+ describe: "Grok --no-plan: disable plan mode.",
287
+ },
288
+ {
289
+ flag: "--no-subagents",
290
+ requestParameter: "noSubagents",
291
+ emit: "flag_if_true",
292
+ inputType: "boolean",
293
+ describe: "Grok --no-subagents: disable subagent spawning.",
294
+ },
295
+ {
296
+ flag: "--oauth",
297
+ requestParameter: "oauth",
298
+ emit: "flag_if_true",
299
+ inputType: "boolean",
300
+ describe: "Grok --oauth: use OAuth during authentication.",
301
+ },
302
+ {
303
+ flag: "--restore-code",
304
+ requestParameter: "restoreCode",
305
+ emit: "flag_if_true",
306
+ inputType: "boolean",
307
+ describe: "Grok --restore-code: check out the original session commit when resuming.",
308
+ },
309
+ {
310
+ flag: "--leader-socket",
311
+ requestParameter: "leaderSocket",
312
+ emit: "value_if_present",
313
+ inputType: "string",
314
+ minLength: 1,
315
+ describe: "Grok 0.2.32+ --leader-socket <PATH>: custom leader socket path (default ~/.grok/leader.sock). Targets an isolated leader process, e.g. a local/branch Grok build; name it ~/.grok/leader-*.sock to keep `grok leader list/kill` discovery working.",
316
+ },
317
+ ];
318
+ export const GROK_FLAG_GENERATION = [
319
+ ...GROK_GEN_OUTPUT_FORMAT,
320
+ ...GROK_GEN_MAIN,
321
+ ...GROK_GEN_PROMPT_FILE,
322
+ ...GROK_GEN_SINGLE,
323
+ ...GROK_GEN_TAIL,
324
+ ];
325
+ export const UNGENERATED_GROK_FLAGS = [
326
+ "--model",
327
+ "--always-approve",
328
+ "--permission-mode",
329
+ "--agents",
330
+ "--prompt-json",
331
+ "--worktree",
332
+ "-p",
333
+ "--resume",
334
+ "--continue",
335
+ ];
@@ -37,20 +37,20 @@ const GUIDANCE = {
37
37
  },
38
38
  gemini: {
39
39
  provider: "gemini",
40
- displayName: "Gemini CLI",
40
+ displayName: "Google Antigravity CLI",
41
41
  install: {
42
- summary: "Install Gemini CLI using Google's npm package or current official installer.",
43
- commands: ["npm install -g @google/gemini-cli"],
44
- documentationUrl: "https://github.com/google-gemini/gemini-cli",
42
+ summary: "Install Google Antigravity CLI using Google's current official installer.",
43
+ commands: ["curl -fsSL https://antigravity.google/cli/install.sh | bash"],
44
+ documentationUrl: "https://antigravity.google/docs/cli-overview",
45
45
  },
46
46
  login: {
47
- summary: "Run Gemini CLI and complete Google's official sign-in flow when prompted.",
48
- commands: ["gemini"],
49
- credentialHandling: "Let Gemini CLI store credentials in its own local store. Do not paste OAuth files or API keys into chat.",
47
+ summary: "Run Antigravity CLI and complete Google's official sign-in flow when prompted.",
48
+ commands: ["agy"],
49
+ credentialHandling: "Let Antigravity store credentials in its own local store. Do not paste OAuth files or API keys into chat.",
50
50
  },
51
51
  verification: {
52
- command: "gemini --version",
53
- expected: "CLI is installed; doctor checks the local Gemini credential store for login evidence",
52
+ command: "agy --version",
53
+ expected: "CLI is installed; doctor checks local Gemini-compatible credential stores for login evidence",
54
54
  },
55
55
  },
56
56
  grok: {
@@ -3,7 +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
+ import { envWithExtendedPath, getExtendedPath, providerCommandName, resolveCommandForSpawn, } from "./executor.js";
7
7
  const PROVIDERS = ["claude", "codex", "gemini", "grok", "mistral"];
8
8
  const VERSION_ARGS = {
9
9
  claude: ["--version"],
@@ -15,9 +15,9 @@ const VERSION_ARGS = {
15
15
  export const PROVIDER_COMMANDS = {
16
16
  claude: "claude",
17
17
  codex: "codex",
18
- gemini: "gemini",
18
+ gemini: providerCommandName("gemini"),
19
19
  grok: "grok",
20
- mistral: "vibe",
20
+ mistral: providerCommandName("mistral"),
21
21
  };
22
22
  const LOGIN_CHECKS = {
23
23
  claude: ["auth", "status", "--json"],
@@ -68,8 +68,8 @@ export function getProviderRuntimeStatus(provider) {
68
68
  command: null,
69
69
  credentialStore: store,
70
70
  detail: store === "present"
71
- ? `Gemini auth detected via: ${matchedMethods.join(", ")}; contents were not inspected.`
72
- : "Gemini CLI is installed, but no credential store or auth env vars were found (oauth_creds.json, GEMINI_API_KEY, GOOGLE_API_KEY, or GOOGLE_CLOUD_PROJECT+GOOGLE_GENAI_USE_VERTEXAI).",
71
+ ? `Antigravity auth detected via Gemini-compatible stores: ${matchedMethods.join(", ")}; contents were not inspected.`
72
+ : "Antigravity CLI is installed, but no Gemini-compatible credential store or auth env vars were found (oauth_creds.json, GEMINI_API_KEY, GOOGLE_API_KEY, or GOOGLE_CLOUD_PROJECT+GOOGLE_GENAI_USE_VERTEXAI).",
73
73
  },
74
74
  };
75
75
  }
@@ -514,12 +514,12 @@ export function resolveGeminiSessionPlan(opts) {
514
514
  if (opts.sessionId && !opts.createNewSession) {
515
515
  validateSessionId(opts.sessionId);
516
516
  return {
517
- args: ["--resume", opts.sessionId],
517
+ args: ["--conversation", opts.sessionId],
518
518
  resumed: true,
519
519
  };
520
520
  }
521
521
  if (opts.resumeLatest && !opts.createNewSession) {
522
- return { args: ["--resume", "latest"], resumed: false };
522
+ return { args: ["--continue"], resumed: false };
523
523
  }
524
524
  return { args: [], resumed: false };
525
525
  }