llm-cli-gateway 2.5.0 → 2.6.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/index.js CHANGED
@@ -7,7 +7,7 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, unlinkSyn
7
7
  import { dirname, join } from "path";
8
8
  import { fileURLToPath } from "url";
9
9
  import { z } from "zod/v3";
10
- import { executeCli, killAllProcessGroups } from "./executor.js";
10
+ import { executeCli, killAllProcessGroups, providerCommandName } from "./executor.js";
11
11
  import { parseStreamJson } from "./stream-json-parser.js";
12
12
  import { parseCodexJsonStream } from "./codex-json-parser.js";
13
13
  import { parseGeminiJson, parseGeminiStreamJson } from "./gemini-json-parser.js";
@@ -27,7 +27,7 @@ import { createJobStore } from "./job-store.js";
27
27
  import { ApprovalManager } from "./approval-manager.js";
28
28
  import { checkReviewIntegrity } from "./review-integrity.js";
29
29
  import { buildClaudeMcpConfig, CLAUDE_MCP_SERVER_NAMES, } from "./claude-mcp-config.js";
30
- import { resolveGrokSessionArgs, resolveMistralSessionArgs, resolveCodexSessionArgs, sanitizeCliArgValues, prepareMistralRequest as buildMistralCliInvocation, MISTRAL_AGENT_MODES, GATEWAY_SESSION_PREFIX, resolveClaudePermissionFlags, resolveCodexSandboxFlags, CLAUDE_PERMISSION_MODES, GEMINI_APPROVAL_MODES, CODEX_SANDBOX_MODES, CODEX_ASK_FOR_APPROVAL_MODES, CLAUDE_EFFORT_LEVELS, prepareClaudeHighImpactFlags, validateClaudeAgentsMap, prepareCodexHighImpactFlags, prepareCodexForkRequest, CODEX_CONFIG_OVERRIDES_SCHEMA, prepareGeminiHighImpactFlags, prependGeminiAttachments, resolveGeminiSessionPlan, GEMINI_HIGH_IMPACT_PARAMS_SCHEMA, } from "./request-helpers.js";
30
+ import { resolveGrokSessionArgs, resolveMistralSessionArgs, resolveCodexSessionArgs, sanitizeCliArgValues, prepareMistralRequest as buildMistralCliInvocation, MISTRAL_AGENT_MODES, GATEWAY_SESSION_PREFIX, resolveClaudePermissionFlags, resolveCodexSandboxFlags, CLAUDE_PERMISSION_MODES, GEMINI_APPROVAL_MODES, CODEX_SANDBOX_MODES, CODEX_ASK_FOR_APPROVAL_MODES, CLAUDE_EFFORT_LEVELS, prepareClaudeHighImpactFlags, validateClaudeAgentsMap, prepareCodexHighImpactFlags, prepareCodexForkRequest, CODEX_CONFIG_OVERRIDES_SCHEMA, resolveGeminiSessionPlan, GEMINI_HIGH_IMPACT_PARAMS_SCHEMA, } from "./request-helpers.js";
31
31
  import { createFlightRecorder } from "./flight-recorder.js";
32
32
  import { resolvePromptInput, PromptPartsSchema, assembleClaudeCacheBlocks, } from "./prompt-parts.js";
33
33
  import { computeSessionCacheStats, computeTtlRemaining, readPersistedRequest, PERSISTED_REQUEST_DEFAULT_MAX_CHARS, } from "./cache-stats.js";
@@ -38,7 +38,8 @@ import { printDoctorJson } from "./doctor.js";
38
38
  import { createWorkspace, describeWorkspace, getWorkspace, loadWorkspaceRegistry, registerExistingWorkspace, resolveWorkspaceForProvider, validatePathInsideWorkspace, } from "./workspace-registry.js";
39
39
  import { generateSecret, hashSecret } from "./oauth.js";
40
40
  import { registerValidationTools } from "./validation-tools.js";
41
- import { assertUpstreamCliArgs, assertUpstreamCliEnv, buildProviderSubcommandsCompactCatalog, buildUpstreamContractReport, getCliSubcommandContract, probeInstalledCliContract, serializeCliSubcommandContract, } from "./upstream-contracts.js";
41
+ import { assertUpstreamCliArgs, assertUpstreamCliEnv, buildProviderSubcommandsCompactCatalog, buildUpstreamContractReport, getCliSubcommandContract, probeInstalledCliContract, serializeCliSubcommandContract, UPSTREAM_CLI_CONTRACTS, } from "./upstream-contracts.js";
42
+ import { buildArgvFromGeneration, deriveZodShapeFromGeneration, GROK_FLAG_GENERATION, GROK_GEN_OUTPUT_FORMAT, GROK_GEN_MAIN, GROK_GEN_PROMPT_FILE, GROK_GEN_SINGLE, GROK_GEN_TAIL, } from "./provider-codegen.js";
42
43
  import { entrypointFileURL } from "./entrypoint-url.js";
43
44
  const logger = {
44
45
  info: (message, ...args) => {
@@ -162,7 +163,7 @@ Other: list_models, cli_versions, upstream_contracts, provider_subcommands_* (re
162
163
 
163
164
  Key behaviors:
164
165
  ${deferralLine}
165
- - Sessions: Claude --continue, Gemini --resume, Grok --resume/--continue, Mistral --resume/--continue (current Vibe defaults session logging on; doctor flags explicit session_logging.enabled=false), Codex \`exec resume <ID>\` / \`exec resume --last\` (all real CLI continuity). For Codex, sessionId must be a real Codex UUID (from ~/.codex/sessions/); gateway-generated gw-* IDs are rejected.
166
+ - Sessions: Claude --continue, Gemini (Antigravity) --conversation <id>/--continue, Grok --resume/--continue, Mistral --resume/--continue (current Vibe defaults session logging on; doctor flags explicit session_logging.enabled=false), Codex \`exec resume <ID>\` / \`exec resume --last\` (all real CLI continuity). For Codex, sessionId must be a real Codex UUID (from ~/.codex/sessions/); gateway-generated gw-* IDs are rejected.
166
167
  - Approval gates: opt-in via approvalStrategy:"mcp_managed".
167
168
  - Upstream drift detection: After upgrading any provider CLI (especially grok), use upstream_contracts with probeInstalled:true and provider_subcommand_drift for declared subcommand help surfaces. Probes are safe, read-only --help checks.
168
169
  - Idle timeout kills stuck processes (default 10min, configurable via idleTimeoutMs).
@@ -230,6 +231,7 @@ function getApprovalManager(runtimeLogger = logger) {
230
231
  const MCP_SERVER_ENUM = z.enum(CLAUDE_MCP_SERVER_NAMES);
231
232
  const CLI_TYPE_ENUM = z.enum(CLI_TYPES);
232
233
  export const MAX_TURNS_SCHEMA = z.number().int().positive().safe().max(10_000);
234
+ const GROK_GENERATED_SHAPE = deriveZodShapeFromGeneration(UPSTREAM_CLI_CONTRACTS.grok, GROK_FLAG_GENERATION);
233
235
  export const MAX_TOKENS_SCHEMA = z.number().int().positive().safe().max(100_000_000);
234
236
  export const MAX_PRICE_SCHEMA = z.number().positive().finite().min(1e-6).max(10_000);
235
237
  export const WORKTREE_SCHEMA = z
@@ -340,7 +342,7 @@ async function awaitJobOrDefer(cli, args, corrId, idleTimeoutMs, outputFormat, f
340
342
  runtime.persistence.asyncJobsEnabled &&
341
343
  runtime.asyncJobManager.hasStore();
342
344
  if (SYNC_DEADLINE_MS === 0 || !deferralAvailable) {
343
- const command = cli === "mistral" ? "vibe" : cli;
345
+ const command = providerCommandName(cli);
344
346
  try {
345
347
  return await executeCli(command, args, {
346
348
  idleTimeout: idleTimeoutMs,
@@ -687,6 +689,7 @@ function createErrorResponse(cli, code, stderr, correlationId, error) {
687
689
  content: [{ type: "text", text: errorMessage }],
688
690
  isError: true,
689
691
  structuredContent: {
692
+ response: errorMessage,
690
693
  correlationId: correlationId || null,
691
694
  cli,
692
695
  exitCode: code,
@@ -1111,7 +1114,7 @@ export function prepareClaudeRequest(params, runtime = resolveGatewayServerRunti
1111
1114
  logOptimizationTokens("prompt", corrId, effectivePrompt, optimized);
1112
1115
  effectivePrompt = optimized;
1113
1116
  }
1114
- const requestedMcpServers = normalizeMcpServers(params.mcpServers);
1117
+ const requestedMcpServers = params.mcpServers ? [...new Set(params.mcpServers)] : [];
1115
1118
  const mcpConfigResolution = resolveClaudeMcpConfig(params.operation, corrId, requestedMcpServers, params.strictMcpConfig);
1116
1119
  if ("errorResponse" in mcpConfigResolution) {
1117
1120
  return mcpConfigResolution.errorResponse;
@@ -1320,7 +1323,7 @@ export function prepareCodexRequest(params, runtime = resolveGatewayServerRuntim
1320
1323
  logOptimizationTokens("prompt", corrId, effectivePrompt, optimized);
1321
1324
  effectivePrompt = optimized;
1322
1325
  }
1323
- const requestedMcpServers = normalizeMcpServers(params.mcpServers);
1326
+ const requestedMcpServers = params.mcpServers ? [...new Set(params.mcpServers)] : [];
1324
1327
  let approvalDecision = null;
1325
1328
  if (params.approvalStrategy === "mcp_managed") {
1326
1329
  approvalDecision = runtime.approvalManager.decide({
@@ -1478,7 +1481,7 @@ export function prepareGeminiRequest(params, runtime = resolveGatewayServerRunti
1478
1481
  logOptimizationTokens("prompt", corrId, effectivePrompt, optimized);
1479
1482
  effectivePrompt = optimized;
1480
1483
  }
1481
- const requestedMcpServers = normalizeMcpServers(params.mcpServers);
1484
+ const requestedMcpServers = params.mcpServers ? [...new Set(params.mcpServers)] : [];
1482
1485
  let approvalDecision = null;
1483
1486
  if (params.approvalStrategy === "mcp_managed") {
1484
1487
  approvalDecision = runtime.approvalManager.decide({
@@ -1498,51 +1501,45 @@ export function prepareGeminiRequest(params, runtime = resolveGatewayServerRunti
1498
1501
  }
1499
1502
  }
1500
1503
  const effectiveApprovalMode = params.approvalStrategy === "mcp_managed" ? "yolo" : params.approvalMode;
1501
- const highImpact = prepareGeminiHighImpactFlags({
1502
- sandbox: params.sandbox,
1503
- policyFiles: params.policyFiles,
1504
- adminPolicyFiles: params.adminPolicyFiles,
1505
- });
1506
- if (highImpact.missingPolicyPath) {
1507
- return createErrorResponse(params.operation, 1, "", corrId, new Error(`${highImpact.missingPolicyField}: path does not exist: ${highImpact.missingPolicyPath}`));
1508
- }
1509
- if (params.attachments && params.attachments.length > 0) {
1510
- try {
1511
- effectivePrompt = prependGeminiAttachments(effectivePrompt, params.attachments);
1512
- }
1513
- catch (err) {
1514
- return createErrorResponse(params.operation, 1, "", corrId, err instanceof Error ? err : new Error(String(err)));
1515
- }
1516
- }
1517
- const args = ["-p", effectivePrompt];
1518
- if (resolvedModel)
1519
- args.push("--model", resolvedModel);
1520
- if (effectiveApprovalMode)
1521
- args.push("--approval-mode", effectiveApprovalMode);
1522
- if (params.yolo && effectiveApprovalMode !== "yolo") {
1523
- args.push("--yolo");
1504
+ const unsupported = (field, detail) => createErrorResponse(params.operation, 1, "", corrId, new Error(`${field} is not supported by Antigravity CLI (agy): ${detail}`));
1505
+ if (effectiveApprovalMode &&
1506
+ effectiveApprovalMode !== "default" &&
1507
+ effectiveApprovalMode !== "yolo") {
1508
+ return unsupported("approvalMode", "use 'default' for prompted execution or 'yolo'/yolo=true for --dangerously-skip-permissions");
1524
1509
  }
1525
1510
  if (params.allowedTools && params.allowedTools.length > 0) {
1526
- sanitizeCliArgValues(params.allowedTools, "allowedTools");
1527
- params.allowedTools.forEach(tool => args.push("--allowed-tools", tool));
1511
+ return unsupported("allowedTools", "agy has no non-interactive allowed-tools flag");
1528
1512
  }
1529
1513
  if (requestedMcpServers.length > 0) {
1530
- sanitizeCliArgValues(requestedMcpServers, "mcpServers");
1531
- requestedMcpServers.forEach(serverName => args.push("--allowed-mcp-server-names", serverName));
1514
+ return unsupported("mcpServers", "agy has no non-interactive allowed MCP server allowlist flag");
1532
1515
  }
1533
- if (params.includeDirs && params.includeDirs.length > 0) {
1534
- sanitizeCliArgValues(params.includeDirs, "includeDirs");
1535
- params.includeDirs.forEach(dir => args.push("--include-directories", dir));
1516
+ if (params.outputFormat && params.outputFormat !== "text") {
1517
+ return unsupported("outputFormat", "agy print mode currently emits text only");
1536
1518
  }
1537
- args.push(...highImpact.args);
1538
- if (params.outputFormat === "json") {
1539
- args.push("-o", "json");
1519
+ if (params.policyFiles && params.policyFiles.length > 0) {
1520
+ return unsupported("policyFiles", "agy has no --policy flag");
1521
+ }
1522
+ if (params.adminPolicyFiles && params.adminPolicyFiles.length > 0) {
1523
+ return unsupported("adminPolicyFiles", "agy has no --admin-policy flag");
1540
1524
  }
1541
- else if (params.outputFormat === "stream-json") {
1542
- args.push("-o", "stream-json");
1525
+ if (params.attachments && params.attachments.length > 0) {
1526
+ return unsupported("attachments", "agy has no documented @path attachment-token contract");
1543
1527
  }
1544
1528
  if (params.skipTrust) {
1545
- args.push("--skip-trust");
1529
+ return unsupported("skipTrust", "agy has no --skip-trust flag");
1530
+ }
1531
+ const args = ["--print", effectivePrompt];
1532
+ if (resolvedModel)
1533
+ args.push("--model", resolvedModel);
1534
+ if (params.includeDirs && params.includeDirs.length > 0) {
1535
+ sanitizeCliArgValues(params.includeDirs, "includeDirs");
1536
+ params.includeDirs.forEach(dir => args.push("--add-dir", dir));
1537
+ }
1538
+ if (params.sandbox) {
1539
+ args.push("--sandbox");
1540
+ }
1541
+ if (params.yolo || effectiveApprovalMode === "yolo") {
1542
+ args.push("--dangerously-skip-permissions");
1546
1543
  }
1547
1544
  return {
1548
1545
  corrId,
@@ -1611,76 +1608,19 @@ export function prepareGrokRequest(params, runtime = resolveGatewayServerRuntime
1611
1608
  }
1612
1609
  }
1613
1610
  const effectiveAlwaysApprove = params.approvalStrategy === "mcp_managed" ? true : Boolean(params.alwaysApprove);
1611
+ const grokContract = UPSTREAM_CLI_CONTRACTS.grok;
1612
+ const genParams = params;
1614
1613
  const args = ["-p", effectivePrompt];
1615
1614
  if (resolvedModel)
1616
1615
  args.push("--model", resolvedModel);
1617
- if (params.outputFormat)
1618
- args.push("--output-format", params.outputFormat);
1616
+ args.push(...buildArgvFromGeneration(grokContract, GROK_GEN_OUTPUT_FORMAT, genParams));
1619
1617
  if (effectiveAlwaysApprove) {
1620
1618
  args.push("--always-approve");
1621
1619
  }
1622
1620
  else if (params.permissionMode) {
1623
1621
  args.push("--permission-mode", params.permissionMode);
1624
1622
  }
1625
- if (params.effort)
1626
- args.push("--effort", params.effort);
1627
- if (params.reasoningEffort)
1628
- args.push("--reasoning-effort", params.reasoningEffort);
1629
- if (params.allowedTools && params.allowedTools.length > 0) {
1630
- args.push("--tools", params.allowedTools.join(","));
1631
- }
1632
- if (params.disallowedTools && params.disallowedTools.length > 0) {
1633
- args.push("--disallowed-tools", params.disallowedTools.join(","));
1634
- }
1635
- if (params.maxTurns !== undefined) {
1636
- args.push("--max-turns", String(params.maxTurns));
1637
- }
1638
- if (params.workingDir) {
1639
- args.push("--cwd", params.workingDir);
1640
- }
1641
- if (params.sandbox) {
1642
- args.push("--sandbox", params.sandbox);
1643
- }
1644
- if (params.rules) {
1645
- args.push("--rules", params.rules);
1646
- }
1647
- if (params.systemPromptOverride) {
1648
- args.push("--system-prompt-override", params.systemPromptOverride);
1649
- }
1650
- if (params.allow && params.allow.length > 0) {
1651
- for (const rule of params.allow) {
1652
- args.push("--allow", rule);
1653
- }
1654
- }
1655
- if (params.deny && params.deny.length > 0) {
1656
- for (const rule of params.deny) {
1657
- args.push("--deny", rule);
1658
- }
1659
- }
1660
- if (params.compactionMode) {
1661
- args.push("--compaction-mode", params.compactionMode);
1662
- }
1663
- if (params.compactionDetail) {
1664
- args.push("--compaction-detail", params.compactionDetail);
1665
- }
1666
- if (params.agent) {
1667
- args.push("--agent", params.agent);
1668
- }
1669
- if (params.bestOfN !== undefined) {
1670
- args.push("--best-of-n", String(params.bestOfN));
1671
- }
1672
- if (params.check) {
1673
- args.push("--check");
1674
- }
1675
- if (params.disableWebSearch) {
1676
- args.push("--disable-web-search");
1677
- }
1678
- if (params.todoGate) {
1679
- args.push("--todo-gate");
1680
- }
1681
- if (params.verbatim) {
1682
- args.push("--verbatim");
1683
- }
1623
+ args.push(...buildArgvFromGeneration(grokContract, GROK_GEN_MAIN, genParams));
1684
1624
  if (params.agents !== undefined) {
1685
1625
  if (typeof params.agents === "string") {
1686
1626
  if (!params.agents.trim()) {
@@ -1696,9 +1636,7 @@ export function prepareGrokRequest(params, runtime = resolveGatewayServerRuntime
1696
1636
  args.push("--agents", JSON.stringify(agentsResult.value));
1697
1637
  }
1698
1638
  }
1699
- if (params.promptFile) {
1700
- args.push("--prompt-file", params.promptFile);
1701
- }
1639
+ args.push(...buildArgvFromGeneration(grokContract, GROK_GEN_PROMPT_FILE, genParams));
1702
1640
  if (params.promptJson !== undefined) {
1703
1641
  const promptJsonValue = typeof params.promptJson === "string" ? params.promptJson : JSON.stringify(params.promptJson);
1704
1642
  if (!promptJsonValue.trim()) {
@@ -1706,33 +1644,8 @@ export function prepareGrokRequest(params, runtime = resolveGatewayServerRuntime
1706
1644
  }
1707
1645
  args.push("--prompt-json", promptJsonValue);
1708
1646
  }
1709
- if (params.single) {
1710
- args.push("--single", params.single);
1711
- }
1712
- if (params.experimentalMemory) {
1713
- args.push("--experimental-memory");
1714
- }
1715
- if (params.noAltScreen) {
1716
- args.push("--no-alt-screen");
1717
- }
1718
- if (params.noMemory) {
1719
- args.push("--no-memory");
1720
- }
1721
- if (params.noPlan) {
1722
- args.push("--no-plan");
1723
- }
1724
- if (params.noSubagents) {
1725
- args.push("--no-subagents");
1726
- }
1727
- if (params.oauth) {
1728
- args.push("--oauth");
1729
- }
1730
- if (params.restoreCode) {
1731
- args.push("--restore-code");
1732
- }
1733
- if (params.leaderSocket) {
1734
- args.push("--leader-socket", params.leaderSocket);
1735
- }
1647
+ args.push(...buildArgvFromGeneration(grokContract, GROK_GEN_SINGLE, genParams));
1648
+ args.push(...buildArgvFromGeneration(grokContract, GROK_GEN_TAIL, genParams));
1736
1649
  if (params.nativeWorktree === true) {
1737
1650
  args.push("--worktree");
1738
1651
  }
@@ -1889,6 +1802,7 @@ function buildCliResponse(cli, stdout, optimizeResponse, corrId, sessionId, prep
1889
1802
  const response = {
1890
1803
  content: [{ type: "text", text: finalStdout }],
1891
1804
  structuredContent: {
1805
+ response: finalStdout,
1892
1806
  model: prep.resolvedModel || "default",
1893
1807
  cli,
1894
1808
  correlationId: corrId,
@@ -2024,6 +1938,7 @@ function buildGrokApiToolResponse(args) {
2024
1938
  const response = {
2025
1939
  content: [{ type: "text", text }],
2026
1940
  structuredContent: {
1941
+ response: text,
2027
1942
  provider: "grok-api",
2028
1943
  cli: "grok-api",
2029
1944
  model: args.result.model || args.prep.resolvedModel,
@@ -3967,23 +3882,23 @@ export function createGatewayServer(deps = {}) {
3967
3882
  performanceMetrics.recordRequest("codex", finalizedDurationMs, wasSuccessful);
3968
3883
  }
3969
3884
  });
3970
- server.tool("gemini_request", "Run a Google Gemini CLI request synchronously (when async jobs are enabled, auto-defers to a pollable job past the sync deadline; otherwise runs to completion). Requires exactly one of prompt or promptParts.", {
3885
+ server.tool("gemini_request", "Run a Google Antigravity CLI (`agy`) request through the Gemini-compatible gateway tool synchronously (when async jobs are enabled, auto-defers to a pollable job past the sync deadline; otherwise runs to completion). Requires exactly one of prompt or promptParts.", {
3971
3886
  prompt: z
3972
3887
  .string()
3973
3888
  .min(1, "Prompt cannot be empty")
3974
3889
  .max(100000, "Prompt too long (max 100k chars)")
3975
3890
  .optional()
3976
- .describe("Prompt text for Gemini (mutually exclusive with promptParts)"),
3891
+ .describe("Prompt text for Antigravity CLI (mutually exclusive with promptParts)"),
3977
3892
  promptParts: PromptPartsSchema.optional().describe("Cache-aware structured prompt: { system?, tools?, context?, task }. Mutually exclusive with prompt. Stable parts hash into cache_state for prefix-discipline tracking."),
3978
3893
  model: z
3979
3894
  .string()
3980
3895
  .optional()
3981
- .describe("Model name or alias (e.g. gemini-3-pro-preview, gemini-2.5-flash, pro, flash, latest)"),
3896
+ .describe("Model name or alias passed to agy --model (e.g. gemini-3-pro-preview, gemini-2.5-flash, pro, flash, latest)"),
3982
3897
  sessionId: z
3983
3898
  .string()
3984
3899
  .optional()
3985
- .describe("Gemini session ID to resume (emits --resume <id>), or 'latest' for the most recent session in this cwd"),
3986
- resumeLatest: z.boolean().default(false).describe("Resume latest session"),
3900
+ .describe("Antigravity conversation ID to resume (emits --conversation <id>)"),
3901
+ resumeLatest: z.boolean().default(false).describe("Continue the most recent conversation"),
3987
3902
  createNewSession: z.boolean().default(false).describe("Force new session"),
3988
3903
  approvalMode: z
3989
3904
  .enum(GEMINI_APPROVAL_MODES)
@@ -3999,13 +3914,16 @@ export function createGatewayServer(deps = {}) {
3999
3914
  .describe("Approval policy override"),
4000
3915
  mcpServers: z
4001
3916
  .array(MCP_SERVER_ENUM)
4002
- .default(["sqry"])
4003
- .describe("MCP server names passed to Gemini as --allowed-mcp-server-names"),
3917
+ .default([])
3918
+ .describe("Unsupported for Antigravity CLI; non-empty values are rejected"),
4004
3919
  allowedTools: z
4005
3920
  .array(z.string())
4006
3921
  .optional()
4007
- .describe("Allowed tools (['Write','Edit','Bash'])"),
4008
- includeDirs: z.array(z.string()).optional().describe("Additional workspace directories"),
3922
+ .describe("Unsupported for Antigravity CLI; non-empty values are rejected"),
3923
+ includeDirs: z
3924
+ .array(z.string())
3925
+ .optional()
3926
+ .describe("Additional workspace directories passed as --add-dir"),
4009
3927
  correlationId: z.string().optional().describe("Request trace ID (auto if omitted)"),
4010
3928
  optimizePrompt: z.boolean().default(false).describe("Optimize prompt before execution"),
4011
3929
  optimizeResponse: z.boolean().default(false).describe("Optimize response output"),
@@ -4023,19 +3941,19 @@ export function createGatewayServer(deps = {}) {
4023
3941
  outputFormat: z
4024
3942
  .enum(["text", "json", "stream-json"])
4025
3943
  .default("text")
4026
- .describe("Gemini output format. `json` emits `-o json` (single JSON with usageMetadata). `stream-json` emits `-o stream-json` (NDJSON event stream — `init`/`message`/`result` lines, usage extracted from the terminal `result.stats` event). Both report usage to the flight recorder."),
4027
- sandbox: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.sandbox.describe("Run Gemini in sandbox mode (-s)"),
4028
- policyFiles: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.policyFiles.describe("Policy file paths (--policy <path>, one per file). Paths must exist."),
4029
- adminPolicyFiles: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.adminPolicyFiles.describe("Admin policy file paths (--admin-policy <path>, one per file). Paths must exist."),
4030
- attachments: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.attachments.describe("Absolute file paths prepended as @<path> tokens to the prompt"),
3944
+ .describe("Antigravity CLI currently supports text output only through the gateway; json and stream-json are rejected."),
3945
+ sandbox: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.sandbox.describe("Run Antigravity in sandbox mode (--sandbox)"),
3946
+ policyFiles: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.policyFiles.describe("Unsupported for Antigravity CLI; non-empty values are rejected."),
3947
+ adminPolicyFiles: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.adminPolicyFiles.describe("Unsupported for Antigravity CLI; non-empty values are rejected."),
3948
+ attachments: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.attachments.describe("Unsupported for Antigravity CLI; non-empty values are rejected."),
4031
3949
  skipTrust: z
4032
3950
  .boolean()
4033
3951
  .default(false)
4034
- .describe("Emit `--skip-trust` so Gemini trusts the workspace for this session and skips the interactive trust prompt (Phase 4 slice γ). Required for headless runs in fresh workspaces."),
3952
+ .describe("Unsupported for Antigravity CLI; true is rejected."),
4035
3953
  yolo: z
4036
3954
  .boolean()
4037
3955
  .optional()
4038
- .describe("Emit `--yolo` to auto-approve all actions. Equivalent to approvalMode 'yolo'; routed through the same approval gate. Under mcp_managed the gate still decides."),
3956
+ .describe("Emit `--dangerously-skip-permissions` to auto-approve all actions. Routed through the same approval gate. Under mcp_managed the gate still decides."),
4039
3957
  workspace: WORKSPACE_ALIAS_SCHEMA.optional(),
4040
3958
  worktree: WORKTREE_SCHEMA.optional(),
4041
3959
  }, {
@@ -4083,10 +4001,7 @@ export function createGatewayServer(deps = {}) {
4083
4001
  .describe("Prompt text for Grok (mutually exclusive with promptParts)"),
4084
4002
  promptParts: PromptPartsSchema.optional().describe("Cache-aware structured prompt: { system?, tools?, context?, task }. Mutually exclusive with prompt. Stable parts hash into cache_state for prefix-discipline tracking."),
4085
4003
  model: z.string().optional().describe("Model name or alias (e.g. grok-build, latest)"),
4086
- outputFormat: z
4087
- .enum(["plain", "json", "streaming-json"])
4088
- .optional()
4089
- .describe("Output format (plain|json|streaming-json). Grok default is plain."),
4004
+ ...GROK_GENERATED_SHAPE,
4090
4005
  sessionId: z
4091
4006
  .string()
4092
4007
  .optional()
@@ -4104,11 +4019,6 @@ export function createGatewayServer(deps = {}) {
4104
4019
  .enum(["default", "acceptEdits", "auto", "dontAsk", "bypassPermissions", "plan"])
4105
4020
  .optional()
4106
4021
  .describe("Grok permission mode"),
4107
- effort: z
4108
- .enum(["low", "medium", "high", "xhigh", "max"])
4109
- .optional()
4110
- .describe("Grok effort level"),
4111
- reasoningEffort: z.string().optional().describe("Reasoning effort for reasoning models"),
4112
4022
  approvalStrategy: z
4113
4023
  .enum(["legacy", "mcp_managed"])
4114
4024
  .default("legacy")
@@ -4121,14 +4031,6 @@ export function createGatewayServer(deps = {}) {
4121
4031
  .array(MCP_SERVER_ENUM)
4122
4032
  .default(["sqry"])
4123
4033
  .describe("MCP server names for approval tracking (Grok manages its own MCP config via `grok mcp`)"),
4124
- allowedTools: z
4125
- .array(z.string())
4126
- .optional()
4127
- .describe("Allowed built-in tools (passed as --tools comma list)"),
4128
- disallowedTools: z
4129
- .array(z.string())
4130
- .optional()
4131
- .describe("Disallowed built-in tools (passed as --disallowed-tools comma list)"),
4132
4034
  correlationId: z.string().optional().describe("Request trace ID (auto if omitted)"),
4133
4035
  optimizePrompt: z.boolean().default(false).describe("Optimize prompt before execution"),
4134
4036
  optimizeResponse: z.boolean().default(false).describe("Optimize response output"),
@@ -4143,107 +4045,14 @@ export function createGatewayServer(deps = {}) {
4143
4045
  .boolean()
4144
4046
  .default(false)
4145
4047
  .describe("Bypass dedup and force a fresh CLI run even if a recent identical request exists"),
4146
- maxTurns: MAX_TURNS_SCHEMA.optional().describe("Grok `--max-turns N`: cap on agent-loop iterations for cost / latency control (Phase 4 slice δ). Bounded to safe integers ≤ 10000."),
4147
- workingDir: z
4148
- .string()
4149
- .min(1)
4150
- .optional()
4151
- .describe("Grok --cwd <DIR>: working directory for this invocation. Lets headless callers run Grok against a directory other than the gateway process's cwd."),
4152
- sandbox: z
4153
- .string()
4154
- .min(1)
4155
- .optional()
4156
- .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."),
4157
- rules: z
4158
- .string()
4159
- .min(1)
4160
- .optional()
4161
- .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."),
4162
- systemPromptOverride: z
4163
- .string()
4164
- .min(1)
4165
- .optional()
4166
- .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)."),
4167
- allow: z
4168
- .array(z.string())
4169
- .optional()
4170
- .describe('Grok --allow <RULE>: permission allow rules. Each entry is emitted as its own --allow instance (per `grok --help`: "Repeat to add multiple rules").'),
4171
- deny: z
4172
- .array(z.string())
4173
- .optional()
4174
- .describe('Grok --deny <RULE>: permission deny rules. Each entry is emitted as its own --deny instance (per `grok --help`: "Repeat to add multiple rules").'),
4175
- compactionMode: z
4176
- .enum(["summary", "transcript", "segments"])
4177
- .optional()
4178
- .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."),
4179
- compactionDetail: z
4180
- .enum(["none", "minimal", "balanced", "verbose"])
4181
- .optional()
4182
- .describe("Grok --compaction-detail: verbatim segment detail (none|minimal|balanced|verbose, default verbose). Only affects `--compaction-mode segments`. Sets GROK_COMPACTION_DETAIL."),
4183
- agent: z
4184
- .string()
4185
- .min(1)
4186
- .optional()
4187
- .describe("Grok --agent <NAME>: agent name or definition file path."),
4188
- bestOfN: MAX_TURNS_SCHEMA.optional().describe("Grok --best-of-n <N>: run the task N ways in parallel and pick the best (headless only)."),
4189
- check: z
4190
- .boolean()
4191
- .optional()
4192
- .describe("Grok --check: append a self-verification loop to the prompt (headless only)."),
4193
- disableWebSearch: z
4194
- .boolean()
4195
- .optional()
4196
- .describe("Grok --disable-web-search: disable web search and remote retrieval tools."),
4197
- todoGate: z
4198
- .boolean()
4199
- .optional()
4200
- .describe("Grok --todo-gate: enable runtime turn-end TodoGate for this session (session-scoped, not persisted)."),
4201
- verbatim: z
4202
- .boolean()
4203
- .optional()
4204
- .describe("Grok --verbatim: send the prompt exactly as given. Also skips gateway optimizePrompt when true."),
4205
4048
  agents: z
4206
4049
  .union([z.string().min(1), z.record(z.string(), z.record(z.string(), z.unknown()))])
4207
4050
  .optional()
4208
4051
  .describe("Grok --agents <JSON>: inline subagent definitions (JSON string or name → { description, prompt, … } map)."),
4209
- promptFile: z
4210
- .string()
4211
- .min(1)
4212
- .optional()
4213
- .describe("Grok --prompt-file <PATH>: single-turn prompt loaded from a file."),
4214
4052
  promptJson: z
4215
4053
  .union([z.string(), z.array(z.unknown()), z.record(z.string(), z.unknown())])
4216
4054
  .optional()
4217
4055
  .describe("Grok --prompt-json <JSON>: single-turn prompt JSON blocks (string or serializable value)."),
4218
- single: z
4219
- .string()
4220
- .min(1)
4221
- .optional()
4222
- .describe("Grok --single <PROMPT>: single-turn prompt (in addition to gateway -p)."),
4223
- experimentalMemory: z
4224
- .boolean()
4225
- .optional()
4226
- .describe("Grok --experimental-memory: enable cross-session memory."),
4227
- noAltScreen: z
4228
- .boolean()
4229
- .optional()
4230
- .describe("Grok --no-alt-screen: run inline without alt screen."),
4231
- noMemory: z.boolean().optional().describe("Grok --no-memory: disable cross-session memory."),
4232
- noPlan: z.boolean().optional().describe("Grok --no-plan: disable plan mode."),
4233
- noSubagents: z
4234
- .boolean()
4235
- .optional()
4236
- .describe("Grok --no-subagents: disable subagent spawning."),
4237
- oauth: z.boolean().optional().describe("Grok --oauth: use OAuth during authentication."),
4238
- restoreCode: z
4239
- .boolean()
4240
- .optional()
4241
- .describe("Grok --restore-code: check out the original session commit when resuming."),
4242
- leaderSocket: z
4243
- .string()
4244
- .min(1)
4245
- .optional()
4246
- .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."),
4247
4056
  nativeWorktree: z
4248
4057
  .union([z.boolean(), z.string().min(1)])
4249
4058
  .optional()
@@ -4835,23 +4644,23 @@ export function createGatewayServer(deps = {}) {
4835
4644
  worktree,
4836
4645
  });
4837
4646
  });
4838
- server.tool("gemini_request_async", "Start a Google Gemini CLI request as a durable background job. Poll with llm_job_status, collect with llm_job_result.", {
4647
+ server.tool("gemini_request_async", "Start a Google Antigravity CLI (`agy`) request as a durable background job through the Gemini-compatible gateway tool. Poll with llm_job_status, collect with llm_job_result.", {
4839
4648
  prompt: z
4840
4649
  .string()
4841
4650
  .min(1, "Prompt cannot be empty")
4842
4651
  .max(100000, "Prompt too long (max 100k chars)")
4843
4652
  .optional()
4844
- .describe("Prompt text for Gemini (mutually exclusive with promptParts)"),
4653
+ .describe("Prompt text for Antigravity CLI (mutually exclusive with promptParts)"),
4845
4654
  promptParts: PromptPartsSchema.optional().describe("Cache-aware structured prompt: { system?, tools?, context?, task }. Mutually exclusive with prompt. Stable parts hash into cache_state for prefix-discipline tracking."),
4846
4655
  model: z
4847
4656
  .string()
4848
4657
  .optional()
4849
- .describe("Model name or alias (e.g. gemini-3-pro-preview, gemini-2.5-flash, pro, flash, latest)"),
4658
+ .describe("Model name or alias passed to agy --model (e.g. gemini-3-pro-preview, gemini-2.5-flash, pro, flash, latest)"),
4850
4659
  sessionId: z
4851
4660
  .string()
4852
4661
  .optional()
4853
- .describe("Gemini session ID to resume (emits --resume <id>), or 'latest' for the most recent session in this cwd"),
4854
- resumeLatest: z.boolean().default(false).describe("Resume latest session"),
4662
+ .describe("Antigravity conversation ID to resume (emits --conversation <id>)"),
4663
+ resumeLatest: z.boolean().default(false).describe("Continue the most recent conversation"),
4855
4664
  createNewSession: z.boolean().default(false).describe("Force new session"),
4856
4665
  approvalMode: z
4857
4666
  .enum(GEMINI_APPROVAL_MODES)
@@ -4867,13 +4676,16 @@ export function createGatewayServer(deps = {}) {
4867
4676
  .describe("Approval policy override"),
4868
4677
  mcpServers: z
4869
4678
  .array(MCP_SERVER_ENUM)
4870
- .default(["sqry"])
4871
- .describe("MCP server names passed to Gemini as --allowed-mcp-server-names"),
4679
+ .default([])
4680
+ .describe("Unsupported for Antigravity CLI; non-empty values are rejected"),
4872
4681
  allowedTools: z
4873
4682
  .array(z.string())
4874
4683
  .optional()
4875
- .describe("Allowed tools (['Write','Edit','Bash'])"),
4876
- includeDirs: z.array(z.string()).optional().describe("Additional workspace directories"),
4684
+ .describe("Unsupported for Antigravity CLI; non-empty values are rejected"),
4685
+ includeDirs: z
4686
+ .array(z.string())
4687
+ .optional()
4688
+ .describe("Additional workspace directories passed as --add-dir"),
4877
4689
  correlationId: z.string().optional().describe("Request trace ID (auto if omitted)"),
4878
4690
  optimizePrompt: z.boolean().default(false).describe("Optimize prompt before execution"),
4879
4691
  idleTimeoutMs: z
@@ -4890,19 +4702,19 @@ export function createGatewayServer(deps = {}) {
4890
4702
  outputFormat: z
4891
4703
  .enum(["text", "json", "stream-json"])
4892
4704
  .default("text")
4893
- .describe("Gemini output format. `json` emits `-o json` (single JSON with usageMetadata). `stream-json` emits `-o stream-json` (NDJSON event stream — `init`/`message`/`result` lines, usage extracted from the terminal `result.stats` event). Both report usage to the flight recorder."),
4894
- sandbox: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.sandbox.describe("Run Gemini in sandbox mode (-s)"),
4895
- policyFiles: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.policyFiles.describe("Policy file paths (--policy <path>, one per file). Paths must exist."),
4896
- adminPolicyFiles: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.adminPolicyFiles.describe("Admin policy file paths (--admin-policy <path>, one per file). Paths must exist."),
4897
- attachments: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.attachments.describe("Absolute file paths prepended as @<path> tokens to the prompt"),
4705
+ .describe("Antigravity CLI currently supports text output only through the gateway; json and stream-json are rejected."),
4706
+ sandbox: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.sandbox.describe("Run Antigravity in sandbox mode (--sandbox)"),
4707
+ policyFiles: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.policyFiles.describe("Unsupported for Antigravity CLI; non-empty values are rejected."),
4708
+ adminPolicyFiles: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.adminPolicyFiles.describe("Unsupported for Antigravity CLI; non-empty values are rejected."),
4709
+ attachments: GEMINI_HIGH_IMPACT_PARAMS_SCHEMA.shape.attachments.describe("Unsupported for Antigravity CLI; non-empty values are rejected."),
4898
4710
  skipTrust: z
4899
4711
  .boolean()
4900
4712
  .default(false)
4901
- .describe("Emit `--skip-trust` so Gemini trusts the workspace for this session and skips the interactive trust prompt (Phase 4 slice γ). Required for headless runs in fresh workspaces."),
4713
+ .describe("Unsupported for Antigravity CLI; true is rejected."),
4902
4714
  yolo: z
4903
4715
  .boolean()
4904
4716
  .optional()
4905
- .describe("Emit `--yolo` to auto-approve all actions. Equivalent to approvalMode 'yolo'; routed through the same approval gate. Under mcp_managed the gate still decides."),
4717
+ .describe("Emit `--dangerously-skip-permissions` to auto-approve all actions. Routed through the same approval gate. Under mcp_managed the gate still decides."),
4906
4718
  workspace: WORKSPACE_ALIAS_SCHEMA.optional(),
4907
4719
  worktree: WORKTREE_SCHEMA.optional(),
4908
4720
  }, {
@@ -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[];