llm-cli-gateway 2.16.0 → 2.17.1

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.
Files changed (66) hide show
  1. package/.agents/skills/least-cost-routing/SKILL.md +123 -0
  2. package/CHANGELOG.md +37 -0
  3. package/README.md +12 -12
  4. package/dist/acp/client.js +5 -0
  5. package/dist/acp/flight-redaction.d.ts +2 -0
  6. package/dist/acp/flight-redaction.js +2 -0
  7. package/dist/acp/runtime.d.ts +1 -0
  8. package/dist/acp/runtime.js +20 -0
  9. package/dist/acp/types.d.ts +52 -0
  10. package/dist/acp/types.js +8 -0
  11. package/dist/api-provider.d.ts +1 -0
  12. package/dist/api-provider.js +1 -0
  13. package/dist/async-job-manager.d.ts +16 -0
  14. package/dist/async-job-manager.js +70 -22
  15. package/dist/claude-mcp-config.js +1 -1
  16. package/dist/compressor/transforms/ansi.js +12 -2
  17. package/dist/config.d.ts +31 -0
  18. package/dist/config.js +142 -7
  19. package/dist/db.js +4 -4
  20. package/dist/doctor.d.ts +34 -1
  21. package/dist/doctor.js +85 -3
  22. package/dist/executor.d.ts +5 -0
  23. package/dist/executor.js +11 -1
  24. package/dist/flight-recorder.d.ts +10 -0
  25. package/dist/flight-recorder.js +68 -2
  26. package/dist/http-transport.js +19 -21
  27. package/dist/index.d.ts +42 -3
  28. package/dist/index.js +666 -41
  29. package/dist/job-store.d.ts +10 -2
  30. package/dist/job-store.js +154 -43
  31. package/dist/lcr-priors.d.ts +60 -0
  32. package/dist/lcr-priors.js +190 -0
  33. package/dist/lcr-router-env.d.ts +20 -0
  34. package/dist/lcr-router-env.js +133 -0
  35. package/dist/lcr-telemetry.d.ts +2 -0
  36. package/dist/lcr-telemetry.js +17 -0
  37. package/dist/least-cost-router.d.ts +86 -0
  38. package/dist/least-cost-router.js +296 -0
  39. package/dist/least-cost-types.d.ts +34 -0
  40. package/dist/least-cost-types.js +1 -0
  41. package/dist/migrate-sessions.js +1 -1
  42. package/dist/migrate.js +1 -1
  43. package/dist/model-registry.js +1 -1
  44. package/dist/postgres-job-store-worker.js +56 -13
  45. package/dist/pricing.d.ts +17 -0
  46. package/dist/pricing.js +167 -0
  47. package/dist/provider-admin-tools.js +12 -4
  48. package/dist/provider-definitions.d.ts +4 -0
  49. package/dist/provider-definitions.js +33 -5
  50. package/dist/provider-tool-capabilities.js +6 -9
  51. package/dist/request-helpers.d.ts +3 -4
  52. package/dist/request-helpers.js +9 -10
  53. package/dist/resources.d.ts +37 -2
  54. package/dist/resources.js +96 -1
  55. package/dist/retry.d.ts +1 -0
  56. package/dist/retry.js +1 -1
  57. package/dist/token-estimator.d.ts +6 -0
  58. package/dist/token-estimator.js +59 -0
  59. package/dist/upstream-contracts.d.ts +4 -1
  60. package/dist/upstream-contracts.js +255 -71
  61. package/dist/validation-receipt.js +1 -1
  62. package/dist/validation-tools.d.ts +6 -0
  63. package/dist/validation-tools.js +174 -54
  64. package/npm-shrinkwrap.json +2 -2
  65. package/package.json +14 -5
  66. package/setup/status.schema.json +68 -0
@@ -0,0 +1,59 @@
1
+ const CJK_RE = /[\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff00-\uffef\uac00-\ud7af]/g;
2
+ const CODE_SYMBOL_RE = /[{}[\]()<>;=+\-*/\\|&%$#@`~]/g;
3
+ const CODE_KEYWORD_RE = /\b(function|const|let|var|return|import|export|class|def|public|private|static|void|for|while|switch|case)\b/;
4
+ const DIVISOR_BY_TYPE = new Map([
5
+ ["prose", 4],
6
+ ["code", 3],
7
+ ["cjk", 1.5],
8
+ ]);
9
+ const FAMILY_MULTIPLIERS = new Map([
10
+ ["openai", 1.0],
11
+ ["o200k", 1.0],
12
+ ["cl100k", 1.02],
13
+ ["claude", 1.08],
14
+ ["gemini", 0.98],
15
+ ["sentencepiece", 0.98],
16
+ ["grok", 1.0],
17
+ ["mistral", 1.05],
18
+ ]);
19
+ export function classifyContent(text) {
20
+ if (!text)
21
+ return "prose";
22
+ const nonSpace = text.replace(/\s+/g, "").length;
23
+ if (nonSpace === 0)
24
+ return "prose";
25
+ const cjkMatches = text.match(CJK_RE);
26
+ const cjkCount = cjkMatches ? cjkMatches.length : 0;
27
+ if (cjkCount / nonSpace >= 0.2)
28
+ return "cjk";
29
+ const trimmed = text.trim();
30
+ const looksJson = /^[[{]/.test(trimmed) && /[}\]]/.test(trimmed) && /[:,]/.test(trimmed);
31
+ const symbolMatches = trimmed.match(CODE_SYMBOL_RE);
32
+ const symbolCount = symbolMatches ? symbolMatches.length : 0;
33
+ const symbolRatio = symbolCount / nonSpace;
34
+ const hasKeyword = CODE_KEYWORD_RE.test(trimmed);
35
+ if (looksJson || symbolRatio >= 0.08 || (hasKeyword && symbolRatio >= 0.03)) {
36
+ return "code";
37
+ }
38
+ return "prose";
39
+ }
40
+ function familyMultiplier(family) {
41
+ if (!family)
42
+ return 1;
43
+ const f = family.toLowerCase();
44
+ for (const [key, multiplier] of FAMILY_MULTIPLIERS) {
45
+ if (f === key || f.includes(key))
46
+ return multiplier;
47
+ }
48
+ return 1;
49
+ }
50
+ export function estimateInputTokens(text, opts) {
51
+ if (!text)
52
+ return 0;
53
+ const type = classifyContent(text);
54
+ const divisor = DIVISOR_BY_TYPE.get(type) ?? 4;
55
+ const base = text.length / divisor;
56
+ const familyMult = familyMultiplier(opts?.family);
57
+ const k = opts?.calibrationK ?? 1;
58
+ return Math.ceil(base * familyMult * k);
59
+ }
@@ -1,5 +1,6 @@
1
1
  import { type CliType } from "./provider-definitions.js";
2
2
  export type CliFlagArity = "none" | "one" | "optional" | "variadic";
3
+ export type CliPositionalLimit = number | "variadic";
3
4
  export interface CliFlagContract {
4
5
  arity: CliFlagArity;
5
6
  values?: readonly string[];
@@ -52,12 +53,13 @@ export interface CliSubcommandContract {
52
53
  commandPath: readonly string[];
53
54
  helpArgs: readonly string[][];
54
55
  flags: Record<string, CliFlagContract>;
55
- maxPositionals: number;
56
+ maxPositionals: CliPositionalLimit;
56
57
  acknowledgedUpstreamFlags?: readonly string[];
57
58
  aliases?: readonly string[];
58
59
  children?: Record<string, CliSubcommandContract>;
59
60
  risk: CliSubcommandRisk;
60
61
  exposure: CliSubcommandExposure;
62
+ adminProjection?: "not_exposed";
61
63
  tier: CliSubcommandTier;
62
64
  tokenCost: CliSubcommandTokenCost;
63
65
  summary: string;
@@ -122,6 +124,7 @@ export interface AcpEntrypointContract {
122
124
  docsRef: string;
123
125
  }
124
126
  export declare const ACP_ENTRYPOINT_CONTRACTS: Record<CliType, AcpEntrypointContract>;
127
+ export declare const CLAUDE_WIRE_PERMISSION_MODES: readonly ["acceptEdits", "auto", "bypassPermissions", "manual", "dontAsk", "plan"];
125
128
  export declare const UPSTREAM_CLI_CONTRACTS: Record<CliType, CliContract>;
126
129
  export declare function validateUpstreamCliArgs(cli: CliType, args: readonly string[]): ContractValidationResult;
127
130
  export declare function assertUpstreamCliArgs(cli: CliType, args: readonly string[]): void;
@@ -67,7 +67,7 @@ export const ACP_ENTRYPOINT_CONTRACTS = {
67
67
  executable: "devin",
68
68
  entrypointArgs: ["acp"],
69
69
  targetVersion: PROVIDER_TARGET_VERSIONS.devin,
70
- probeArgs: [["--version"]],
70
+ probeArgs: [["acp", "--help"]],
71
71
  evidence: 'Native ACP entrypoint `devin acp` (stdio JSON-RPC). Slice D1 manual initialize + session/new smoke passed (protocolVersion 1, agent "Affogato", session created). Third native runtime pilot; routing stays config-gated.',
72
72
  docsRef: "docs/plans/first-class-acp-gateway-extension.dag.toml#provider_matrix.devin",
73
73
  },
@@ -83,13 +83,21 @@ export const ACP_ENTRYPOINT_CONTRACTS = {
83
83
  docsRef: "docs/plans/first-class-acp-gateway-extension.dag.toml#provider_matrix.cursor",
84
84
  },
85
85
  };
86
- const PERMISSION_MODES = [
87
- "default",
86
+ export const CLAUDE_WIRE_PERMISSION_MODES = [
88
87
  "acceptEdits",
88
+ "auto",
89
+ "bypassPermissions",
90
+ "manual",
91
+ "dontAsk",
89
92
  "plan",
93
+ ];
94
+ const GROK_PERMISSION_MODES = [
95
+ "default",
96
+ "acceptEdits",
90
97
  "auto",
91
98
  "dontAsk",
92
99
  "bypassPermissions",
100
+ "plan",
93
101
  ];
94
102
  const EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
95
103
  function scFlag(name, arity = "optional") {
@@ -114,6 +122,7 @@ function subcommand(commandPath, summary, risk, flags = [], options = {}) {
114
122
  children: options.children ?? {},
115
123
  risk,
116
124
  exposure: options.exposure ?? "tracked_only",
125
+ ...(options.adminProjection ? { adminProjection: options.adminProjection } : {}),
117
126
  tier: options.tier ?? "catalog",
118
127
  tokenCost: options.tokenCost ?? "small",
119
128
  summary,
@@ -150,6 +159,10 @@ export const UPSTREAM_CLI_CONTRACTS = {
150
159
  doctor: subcommand(["doctor"], "Run Claude Code diagnostic checks.", "read_only", [], {
151
160
  tier: "diagnostic",
152
161
  }),
162
+ gateway: subcommand(["gateway"], "Run Claude enterprise auth and telemetry gateway mode.", "starts_server", ["--config"], {
163
+ exposure: "not_exposed",
164
+ flagArities: { "--config": "one" },
165
+ }),
153
166
  mcp: subcommand(["mcp"], "Manage Claude MCP server configuration.", "writes_local_config"),
154
167
  plugin: subcommand(["plugin"], "Manage Claude plugins.", "writes_local_config", [], {
155
168
  aliases: ["plugins"],
@@ -244,7 +257,7 @@ export const UPSTREAM_CLI_CONTRACTS = {
244
257
  },
245
258
  "--output-format": {
246
259
  arity: "one",
247
- values: ["json", "stream-json"],
260
+ values: ["text", "json", "stream-json"],
248
261
  description: "Machine-readable output format",
249
262
  },
250
263
  "--include-partial-messages": {
@@ -259,7 +272,7 @@ export const UPSTREAM_CLI_CONTRACTS = {
259
272
  "--disallowed-tools": { arity: "variadic", description: "Disallowed tool names/patterns" },
260
273
  "--permission-mode": {
261
274
  arity: "one",
262
- values: PERMISSION_MODES,
275
+ values: CLAUDE_WIRE_PERMISSION_MODES,
263
276
  description: "Claude permission mode",
264
277
  },
265
278
  "--mcp-config": { arity: "one", description: "MCP config path" },
@@ -392,6 +405,18 @@ export const UPSTREAM_CLI_CONTRACTS = {
392
405
  args: ["-p", "hello"],
393
406
  expect: "pass",
394
407
  },
408
+ {
409
+ id: "claude-permission-mode-manual",
410
+ description: "Claude 2.1.207 accepts the manual permission mode literal",
411
+ args: ["-p", "hello", "--permission-mode", "manual"],
412
+ expect: "pass",
413
+ },
414
+ {
415
+ id: "claude-permission-mode-default-gateway-only",
416
+ description: "Gateway default is represented by omitting the upstream flag",
417
+ args: ["-p", "hello", "--permission-mode", "default"],
418
+ expect: "fail",
419
+ },
395
420
  {
396
421
  id: "claude-unsupported-flag",
397
422
  description: "Unsupported flag is rejected before spawn",
@@ -404,6 +429,12 @@ export const UPSTREAM_CLI_CONTRACTS = {
404
429
  args: ["-p", "hello", "--fallback-model", "claude-haiku-4-5-20251001"],
405
430
  expect: "pass",
406
431
  },
432
+ {
433
+ id: "claude-output-format-text",
434
+ description: "Claude 2.1.207 accepts explicit text output format",
435
+ args: ["-p", "hello", "--output-format", "text"],
436
+ expect: "pass",
437
+ },
407
438
  {
408
439
  id: "claude-json-schema",
409
440
  description: "Phase 4 slice η: --json-schema accepts inline JSON literal",
@@ -508,8 +539,8 @@ export const UPSTREAM_CLI_CONTRACTS = {
508
539
  upstream: "OpenAI Codex CLI",
509
540
  upstreamMetadata: {
510
541
  sourceUrls: [
511
- "https://github.com/openai/codex/releases",
512
- "https://developers.openai.com/codex/changelog",
542
+ "https://api.github.com/repos/openai/codex/releases/latest",
543
+ "https://learn.chatgpt.com/docs/changelog/rss.xml",
513
544
  ],
514
545
  packageName: "@openai/codex",
515
546
  repo: "https://github.com/openai/codex",
@@ -668,6 +699,76 @@ export const UPSTREAM_CLI_CONTRACTS = {
668
699
  ], { exposure: "not_exposed" }),
669
700
  debug: subcommand(["debug"], "Run Codex debugging utilities.", "read_only", ["--config", "--disable", "--enable"], { tier: "diagnostic" }),
670
701
  apply: subcommand(["apply"], "Apply a Codex patch to the workspace.", "destructive", ["--config", "--disable", "--enable"], { exposure: "not_exposed" }),
702
+ resume: subcommand(["resume"], "Resume a saved interactive Codex session.", "executes_agent", [
703
+ "--add-dir",
704
+ "--all",
705
+ "--ask-for-approval",
706
+ "--cd",
707
+ "--config",
708
+ "--dangerously-bypass-approvals-and-sandbox",
709
+ "--dangerously-bypass-hook-trust",
710
+ "--disable",
711
+ "--enable",
712
+ "--image",
713
+ "--include-non-interactive",
714
+ "--last",
715
+ "--local-provider",
716
+ "--model",
717
+ "--no-alt-screen",
718
+ "--oss",
719
+ "--profile",
720
+ "--remote",
721
+ "--remote-auth-token-env",
722
+ "--sandbox",
723
+ "--search",
724
+ "--strict-config",
725
+ "--version",
726
+ ], {
727
+ exposure: "not_exposed",
728
+ maxPositionals: 2,
729
+ flagArities: {
730
+ "--all": "none",
731
+ "--dangerously-bypass-approvals-and-sandbox": "none",
732
+ "--dangerously-bypass-hook-trust": "none",
733
+ "--include-non-interactive": "none",
734
+ "--last": "none",
735
+ "--no-alt-screen": "none",
736
+ "--oss": "none",
737
+ "--search": "none",
738
+ "--strict-config": "none",
739
+ "--version": "none",
740
+ },
741
+ }),
742
+ delete: subcommand(["delete"], "Permanently delete a saved Codex session.", "destructive", [
743
+ "--add-dir",
744
+ "--cd",
745
+ "--config",
746
+ "--dangerously-bypass-approvals-and-sandbox",
747
+ "--dangerously-bypass-hook-trust",
748
+ "--disable",
749
+ "--enable",
750
+ "--force",
751
+ "--image",
752
+ "--local-provider",
753
+ "--model",
754
+ "--oss",
755
+ "--profile",
756
+ "--remote",
757
+ "--remote-auth-token-env",
758
+ "--sandbox",
759
+ "--strict-config",
760
+ ], {
761
+ exposure: "not_exposed",
762
+ adminProjection: "not_exposed",
763
+ maxPositionals: 1,
764
+ flagArities: {
765
+ "--dangerously-bypass-approvals-and-sandbox": "none",
766
+ "--dangerously-bypass-hook-trust": "none",
767
+ "--force": "none",
768
+ "--oss": "none",
769
+ "--strict-config": "none",
770
+ },
771
+ }),
671
772
  archive: subcommand(["archive"], "Archive Codex session state.", "writes_local_config", [
672
773
  "--add-dir",
673
774
  "--cd",
@@ -960,7 +1061,7 @@ export const UPSTREAM_CLI_CONTRACTS = {
960
1061
  upstreamMetadata: {
961
1062
  sourceUrls: [
962
1063
  "https://antigravity.google/docs/cli-overview",
963
- "https://github.com/google-antigravity/antigravity-cli/releases",
1064
+ "https://api.github.com/repos/google-antigravity/antigravity-cli/releases/latest",
964
1065
  ],
965
1066
  repo: "https://github.com/google-antigravity/antigravity-cli",
966
1067
  installDocsUrl: "https://antigravity.google/docs/cli-getting-started",
@@ -969,6 +1070,11 @@ export const UPSTREAM_CLI_CONTRACTS = {
969
1070
  },
970
1071
  helpArgs: [["--help"]],
971
1072
  subcommands: {
1073
+ agent: subcommand(["agent"], "List available Antigravity agents.", "read_only", [], {
1074
+ aliases: ["agents"],
1075
+ tier: "inspect",
1076
+ tokenCost: "tiny",
1077
+ }),
972
1078
  changelog: subcommand(["changelog"], "Show Antigravity CLI changelog and release notes.", "read_only", [], { tokenCost: "small" }),
973
1079
  install: subcommand(["install"], "Configure Antigravity CLI environment paths and shell settings.", "writes_local_config", ["--dir", "--skip-aliases", "--skip-path"], {
974
1080
  flagArities: { "--dir": "one", "--skip-aliases": "none", "--skip-path": "none" },
@@ -1033,7 +1139,7 @@ export const UPSTREAM_CLI_CONTRACTS = {
1033
1139
  description: "Print-mode wait timeout as a Go duration string (e.g. 5m0s)",
1034
1140
  },
1035
1141
  },
1036
- acknowledgedUpstreamFlags: ["--log-file", "--mode", "--prompt-interactive"],
1142
+ acknowledgedUpstreamFlags: ["--agent", "--log-file", "--mode", "--prompt-interactive"],
1037
1143
  env: {},
1038
1144
  conformanceFixtures: [
1039
1145
  {
@@ -1048,6 +1154,12 @@ export const UPSTREAM_CLI_CONTRACTS = {
1048
1154
  args: ["--print", "hello", "--not-a-gemini-flag"],
1049
1155
  expect: "fail",
1050
1156
  },
1157
+ {
1158
+ id: "gemini-agent-selection-acknowledged-not-emitted",
1159
+ description: "Antigravity 1.1.1 advertises --agent, but gateway request argv stays closed until its security model is explicitly wired",
1160
+ args: ["--print", "hello", "--agent", "reviewer"],
1161
+ expect: "fail",
1162
+ },
1051
1163
  {
1052
1164
  id: "gemini-antigravity-workspace-flags",
1053
1165
  description: "Antigravity workspace and sandbox flags are accepted",
@@ -1181,49 +1293,9 @@ export const UPSTREAM_CLI_CONTRACTS = {
1181
1293
  sessions: subcommand(["sessions"], "Inspect Grok sessions.", "read_only", ["--leader-socket"], {
1182
1294
  tier: "inspect",
1183
1295
  }),
1184
- setup: subcommand(["setup"], "Configure Grok CLI local setup.", "writes_local_config", ["--leader-socket"], { exposure: "not_exposed" }),
1185
- ssh: subcommand(["ssh"], "Manage Grok SSH integration.", "network", ["--leader-socket"], {
1186
- acknowledgedUpstreamFlags: [
1187
- "--agent",
1188
- "--agents",
1189
- "--allow",
1190
- "--always-approve",
1191
- "--best-of-n",
1192
- "--check",
1193
- "--continue",
1194
- "--cwd",
1195
- "--deny",
1196
- "--disable-web-search",
1197
- "--disallowed-tools",
1198
- "--experimental-memory",
1199
- "--fork-session",
1200
- "--json-schema",
1201
- "--max-turns",
1202
- "--minimal",
1203
- "--model",
1204
- "--no-alt-screen",
1205
- "--no-memory",
1206
- "--no-plan",
1207
- "--no-subagents",
1208
- "--oauth",
1209
- "--output-format",
1210
- "--permission-mode",
1211
- "--prompt-file",
1212
- "--prompt-json",
1213
- "--reasoning-effort",
1214
- "--restore-code",
1215
- "--resume",
1216
- "--rules",
1217
- "--sandbox",
1218
- "--session-id",
1219
- "--single",
1220
- "--system-prompt-override",
1221
- "--tools",
1222
- "--verbatim",
1223
- "--version",
1224
- "--worktree",
1225
- "--worktree-ref",
1226
- ],
1296
+ setup: subcommand(["setup"], "Configure Grok CLI local setup.", "writes_local_config", ["--json", "--leader-socket"], {
1297
+ exposure: "not_exposed",
1298
+ flagArities: { "--json": "none", "--leader-socket": "one" },
1227
1299
  }),
1228
1300
  trace: subcommand(["trace"], "Inspect Grok trace data.", "read_only", ["--json", "--leader-socket", "--local", "--output"], { tier: "diagnostic" }),
1229
1301
  update: subcommand(["update"], "Update the Grok CLI binary.", "updates_binary", [
@@ -1237,9 +1309,20 @@ export const UPSTREAM_CLI_CONTRACTS = {
1237
1309
  ], { exposure: "not_exposed" }),
1238
1310
  version: subcommand(["version"], "Print Grok version information.", "read_only", ["--json", "--leader-socket"], { tier: "diagnostic" }),
1239
1311
  worktree: subcommand(["worktree"], "Manage Grok worktree sessions.", "writes_local_config", ["--leader-socket"]),
1312
+ wrap: subcommand(["wrap"], "Run an arbitrary command inside a local clipboard-forwarding PTY.", "destructive", ["--leader-socket"], {
1313
+ exposure: "not_exposed",
1314
+ tier: "execute_candidate",
1315
+ maxPositionals: "variadic",
1316
+ flagArities: { "--leader-socket": "one" },
1317
+ }),
1240
1318
  }, GROK_DEBUG_HELP_FLAGS),
1241
1319
  maxPositionals: 0,
1242
- acknowledgedUpstreamFlags: [...GROK_DEBUG_HELP_FLAGS, "--minimal", "--session-id"],
1320
+ acknowledgedUpstreamFlags: [
1321
+ ...GROK_DEBUG_HELP_FLAGS,
1322
+ "--fullscreen",
1323
+ "--minimal",
1324
+ "--session-id",
1325
+ ],
1243
1326
  mcpTools: ["grok_request", "grok_request_async"],
1244
1327
  mcpParameters: [
1245
1328
  "prompt",
@@ -1299,7 +1382,7 @@ export const UPSTREAM_CLI_CONTRACTS = {
1299
1382
  "--always-approve": { arity: "none", description: "Approve tool use automatically" },
1300
1383
  "--permission-mode": {
1301
1384
  arity: "one",
1302
- values: PERMISSION_MODES,
1385
+ values: GROK_PERMISSION_MODES,
1303
1386
  description: "Permission mode",
1304
1387
  },
1305
1388
  "--effort": { arity: "one", values: EFFORT_LEVELS, description: "Reasoning effort" },
@@ -1648,6 +1731,7 @@ export const UPSTREAM_CLI_CONTRACTS = {
1648
1731
  description: "Agent/permission mode (builtin, install-gated, or custom agent name)",
1649
1732
  },
1650
1733
  "--enabled-tools": { arity: "one", description: "Enabled tool" },
1734
+ "--disabled-tools": { arity: "one", description: "Disabled tool" },
1651
1735
  "--resume": {
1652
1736
  arity: "optional",
1653
1737
  description: "Resume session by ID, or interactive picker when omitted",
@@ -1681,17 +1765,11 @@ export const UPSTREAM_CLI_CONTRACTS = {
1681
1765
  description: "Additional writable workspace directory (Phase 4 slice ζ; repeat once per directory)",
1682
1766
  },
1683
1767
  },
1684
- acknowledgedUpstreamFlags: [
1685
- "--auto-approve",
1686
- "--check-upgrade",
1687
- "--disabled-tools",
1688
- "--worktree",
1689
- "--yolo",
1690
- ],
1768
+ acknowledgedUpstreamFlags: ["--auto-approve", "--check-upgrade", "--worktree", "--yolo"],
1691
1769
  env: {
1692
1770
  VIBE_ACTIVE_MODEL: {
1693
1771
  arity: "one",
1694
- pattern: /^[^\s\u0000-\u001f\u007f]+$/,
1772
+ pattern: /^[^\s\p{Cc}]+$/u,
1695
1773
  description: "Active model selector; Vibe uses env instead of a --model flag",
1696
1774
  },
1697
1775
  },
@@ -1813,11 +1891,11 @@ export const UPSTREAM_CLI_CONTRACTS = {
1813
1891
  expect: "fail",
1814
1892
  },
1815
1893
  {
1816
- id: "mistral-disabled-tools-rejected",
1817
- description: "Vibe 2.19.1 adds --disabled-tools (denylist counterpart to --enabled-tools); the gateway does not emit it (disallowedTools is accepted but ignored) and rejects raw --disabled-tools as caller argv",
1894
+ id: "mistral-disabled-tools",
1895
+ description: "Vibe 2.19.1 --disabled-tools denylist is accepted once per tool",
1818
1896
  args: ["-p", "hello", "--disabled-tools", "shell"],
1819
1897
  env: { VIBE_ACTIVE_MODEL: "mistral-medium-3.5" },
1820
- expect: "fail",
1898
+ expect: "pass",
1821
1899
  },
1822
1900
  {
1823
1901
  id: "mistral-resume-bare",
@@ -1833,14 +1911,63 @@ export const UPSTREAM_CLI_CONTRACTS = {
1833
1911
  executable: "devin",
1834
1912
  upstream: "Cognition Devin CLI",
1835
1913
  upstreamMetadata: {
1836
- sourceUrls: ["https://cli.devin.ai/docs/reference/commands", "https://docs.devin.ai/cli"],
1914
+ sourceUrls: [
1915
+ "https://cli.devin.ai/docs/reference/commands",
1916
+ "https://docs.devin.ai/cli",
1917
+ "https://docs.devin.ai/cli/changelog/stable",
1918
+ ],
1837
1919
  packageName: "devin",
1838
1920
  installDocsUrl: "https://docs.devin.ai/cli",
1839
1921
  releaseChannel: "vendor",
1840
1922
  watchCategories: ["flags", "subcommands", "permission-modes", "acp-entrypoint"],
1841
1923
  },
1842
1924
  helpArgs: [["--help"]],
1843
- subcommands: {},
1925
+ subcommands: {
1926
+ acp: subcommand(["acp"], "Run the Devin Agent Client Protocol server over stdio.", "starts_server", ["--agent-type"], {
1927
+ exposure: "not_exposed",
1928
+ flagArities: { "--agent-type": "one" },
1929
+ }),
1930
+ auth: subcommand(["auth"], "Manage Devin authentication state.", "auth", [], {
1931
+ exposure: "not_exposed",
1932
+ maxPositionals: "variadic",
1933
+ }),
1934
+ cloud: subcommand(["cloud"], "Manage Devin Cloud environments, sandboxes, and builds.", "network", [], { exposure: "not_exposed", maxPositionals: "variadic" }),
1935
+ list: subcommand(["list"], "List Devin sessions in the current directory.", "read_only", ["--format"], {
1936
+ aliases: ["ls"],
1937
+ tier: "inspect",
1938
+ flagArities: { "--format": "one" },
1939
+ }),
1940
+ mcp: subcommand(["mcp"], "Manage Devin MCP server connections.", "writes_local_config", [], {
1941
+ exposure: "not_exposed",
1942
+ maxPositionals: "variadic",
1943
+ }),
1944
+ plugins: subcommand(["plugins"], "Manage Devin plugins.", "writes_local_config", [], {
1945
+ exposure: "not_exposed",
1946
+ maxPositionals: "variadic",
1947
+ }),
1948
+ rules: subcommand(["rules"], "Manage Devin always-on agent rules.", "writes_local_config", [], { exposure: "not_exposed", maxPositionals: "variadic" }),
1949
+ sandbox: subcommand(["sandbox"], "Manage Devin process sandboxing.", "writes_local_config", [], { exposure: "not_exposed", maxPositionals: "variadic" }),
1950
+ setup: subcommand(["setup"], "Run Devin interactive setup.", "writes_local_config", ["--force-manual-token-flow"], {
1951
+ exposure: "not_exposed",
1952
+ flagArities: { "--force-manual-token-flow": "none" },
1953
+ }),
1954
+ shell: subcommand(["shell"], "Integrate Devin with the local shell.", "writes_local_config", [], { exposure: "not_exposed", maxPositionals: "variadic" }),
1955
+ skills: subcommand(["skills"], "Manage Devin skills.", "writes_local_config", [], {
1956
+ exposure: "not_exposed",
1957
+ maxPositionals: "variadic",
1958
+ }),
1959
+ uninstall: subcommand(["uninstall"], "Uninstall Devin and remove local data.", "destructive", ["--clean", "--force"], {
1960
+ exposure: "not_exposed",
1961
+ flagArities: { "--clean": "none", "--force": "none" },
1962
+ }),
1963
+ update: subcommand(["update"], "Check for or install Devin CLI updates.", "updates_binary", ["--force"], {
1964
+ exposure: "not_exposed",
1965
+ flagArities: { "--force": "none" },
1966
+ }),
1967
+ version: subcommand(["version"], "Print Devin version information.", "read_only", [], {
1968
+ tier: "diagnostic",
1969
+ }),
1970
+ },
1844
1971
  maxPositionals: 0,
1845
1972
  mcpTools: ["devin_request", "devin_request_async"],
1846
1973
  mcpParameters: [
@@ -1865,8 +1992,8 @@ export const UPSTREAM_CLI_CONTRACTS = {
1865
1992
  "--model": { arity: "one", description: "AI model for this session" },
1866
1993
  "--permission-mode": {
1867
1994
  arity: "one",
1868
- values: ["auto", "smart", "dangerous"],
1869
- description: "Permission mode (auto = read-only auto-approve; smart = additionally auto-runs safe actions per fast model; dangerous = approve all)",
1995
+ values: ["auto", "accept-edits", "smart", "dangerous"],
1996
+ description: "Permission mode (auto = read-only auto-approve; accept-edits = also auto-approve workspace edits; smart = additionally auto-runs safe actions per fast model; dangerous = approve all)",
1870
1997
  },
1871
1998
  "--prompt-file": { arity: "one", description: "Load the initial prompt from a file" },
1872
1999
  "--config": { arity: "one", description: "Config file path" },
@@ -1917,6 +2044,12 @@ export const UPSTREAM_CLI_CONTRACTS = {
1917
2044
  args: ["-p", "hello", "--permission-mode", "auto"],
1918
2045
  expect: "pass",
1919
2046
  },
2047
+ {
2048
+ id: "devin-permission-mode-accept-edits",
2049
+ description: "Valid --permission-mode 'accept-edits' accepted",
2050
+ args: ["-p", "hello", "--permission-mode", "accept-edits"],
2051
+ expect: "pass",
2052
+ },
1920
2053
  {
1921
2054
  id: "devin-permission-mode-smart",
1922
2055
  description: "Valid --permission-mode 'smart' accepted",
@@ -2007,7 +2140,57 @@ export const UPSTREAM_CLI_CONTRACTS = {
2007
2140
  ],
2008
2141
  },
2009
2142
  helpArgs: [["--help"]],
2010
- subcommands: {},
2143
+ subcommands: {
2144
+ about: subcommand(["about"], "Display Cursor Agent version, system, and account information.", "read_only", ["--format"], { tier: "diagnostic", flagArities: { "--format": "one" } }),
2145
+ agent: subcommand(["agent"], "Start an interactive Cursor Agent session.", "executes_agent", [], { exposure: "not_exposed", maxPositionals: "variadic" }),
2146
+ "create-chat": subcommand(["create-chat"], "Create a new Cursor chat and return its ID.", "network", [], { exposure: "not_exposed" }),
2147
+ "generate-rule": subcommand(["generate-rule"], "Generate a Cursor rule through interactive prompts.", "writes_local_config", [], { aliases: ["rule"], exposure: "not_exposed", maxPositionals: "variadic" }),
2148
+ "install-shell-integration": subcommand(["install-shell-integration"], "Install Cursor shell integration.", "writes_local_config", [], { exposure: "not_exposed" }),
2149
+ login: subcommand(["login"], "Authenticate with Cursor.", "auth", [], {
2150
+ exposure: "not_exposed",
2151
+ }),
2152
+ logout: subcommand(["logout"], "Clear Cursor authentication state.", "auth", [], {
2153
+ exposure: "not_exposed",
2154
+ }),
2155
+ ls: subcommand(["ls"], "Resume a Cursor chat session.", "executes_agent", [], {
2156
+ exposure: "not_exposed",
2157
+ maxPositionals: "variadic",
2158
+ }),
2159
+ mcp: subcommand(["mcp"], "Manage Cursor MCP server configuration.", "writes_local_config", [], { exposure: "not_exposed", maxPositionals: "variadic" }),
2160
+ models: subcommand(["models"], "List Cursor account models.", "read_only", [], {
2161
+ tier: "inspect",
2162
+ }),
2163
+ resume: subcommand(["resume"], "Resume the latest Cursor chat.", "executes_agent", [], {
2164
+ exposure: "not_exposed",
2165
+ maxPositionals: "variadic",
2166
+ }),
2167
+ status: subcommand(["status"], "View Cursor authentication status.", "read_only", ["--format"], {
2168
+ aliases: ["whoami"],
2169
+ tier: "inspect",
2170
+ flagArities: { "--format": "one" },
2171
+ }),
2172
+ "uninstall-shell-integration": subcommand(["uninstall-shell-integration"], "Remove Cursor shell integration.", "writes_local_config", [], { exposure: "not_exposed" }),
2173
+ update: subcommand(["update"], "Update Cursor Agent.", "updates_binary", [], {
2174
+ exposure: "not_exposed",
2175
+ }),
2176
+ worker: subcommand(["worker"], "Start a private Cursor cloud worker for local agent runs.", "starts_server", [
2177
+ "--auth-token-file",
2178
+ "--data-dir",
2179
+ "--debug",
2180
+ "--idle-release-timeout",
2181
+ "--label",
2182
+ "--labels-file",
2183
+ "--management-addr",
2184
+ "--name",
2185
+ "--pool",
2186
+ "--pool-name",
2187
+ "--single-use",
2188
+ "--worker-dir",
2189
+ ], {
2190
+ exposure: "not_exposed",
2191
+ flagArities: { "--debug": "none", "--single-use": "none" },
2192
+ }),
2193
+ },
2011
2194
  maxPositionals: 1,
2012
2195
  mcpTools: ["cursor_request", "cursor_request_async"],
2013
2196
  mcpParameters: [
@@ -2297,6 +2480,7 @@ export function serializeCliSubcommandContract(cli, contract) {
2297
2480
  })),
2298
2481
  risk: contract.risk,
2299
2482
  exposure: contract.exposure,
2483
+ adminProjection: contract.adminProjection ?? null,
2300
2484
  tier: contract.tier,
2301
2485
  tokenCost: contract.tokenCost,
2302
2486
  summary: contract.summary,
@@ -2441,7 +2625,7 @@ export function validateUpstreamCliSubcommandArgs(cli, commandPath, args) {
2441
2625
  });
2442
2626
  }
2443
2627
  }
2444
- if (positionals.length > contract.maxPositionals) {
2628
+ if (contract.maxPositionals !== "variadic" && positionals.length > contract.maxPositionals) {
2445
2629
  violations.push({
2446
2630
  cli,
2447
2631
  message: `${cli} subcommand "${subcommandKey(commandPath)}" has ${positionals.length} positional values; upstream subcommand contract allows ${contract.maxPositionals}`,
@@ -230,7 +230,7 @@ export function eagerMintFromJobId(deps, jobId) {
230
230
  const store = deps.validationRunStore;
231
231
  if (!store)
232
232
  return;
233
- let validationId = null;
233
+ let validationId;
234
234
  try {
235
235
  validationId = store.getValidationRunIdByJobId(jobId);
236
236
  }
@@ -1,9 +1,15 @@
1
1
  import { z } from "zod/v3";
2
2
  import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import type { AsyncJobManager } from "./async-job-manager.js";
4
+ import { PerformanceMetrics } from "./metrics.js";
5
+ import { type LeastCostConfig } from "./config.js";
6
+ import type { FlightRecorderQuery } from "./flight-recorder.js";
4
7
  import { type ValidationOrchestratorDeps } from "./validation-orchestrator.js";
5
8
  export interface ValidationToolDeps extends ValidationOrchestratorDeps {
6
9
  asyncJobManager: AsyncJobManager;
10
+ leastCost?: LeastCostConfig;
11
+ performanceMetrics?: PerformanceMetrics;
12
+ flightRecorder?: FlightRecorderQuery;
7
13
  }
8
14
  export declare function buildValidationSchemas(deps: ValidationToolDeps): {
9
15
  providerSchema: z.ZodEnum<[string, ...string[]]>;