@opentig/cli 0.1.6 → 0.1.8

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 (123) hide show
  1. package/dist/bin.mjs +1 -4
  2. package/dist/chunks/{cli-ABzC6-gR.mjs → cli-BgNif2D1.mjs} +1 -1
  3. package/dist/client/assets/App-9EfSdZB8.js +74 -0
  4. package/dist/client/assets/CreatePullRequestDialog-BgVrWdkH.js +2 -0
  5. package/dist/client/assets/DiffWorkspace-Ca2ZUlVn.js +26 -0
  6. package/dist/client/assets/EditableFileViewer-85aEeMBK.js +1 -0
  7. package/dist/client/assets/File-DTtWrbYf.js +1 -0
  8. package/dist/client/assets/{FilesView-DIqPfRbv.js → FilesView-rT5hzb7y.js} +1 -1
  9. package/dist/client/assets/GitHubAvatar-EO1TD_1z.js +1 -0
  10. package/dist/client/assets/HistoryView-C4c0CqMC.js +1 -0
  11. package/dist/client/assets/{HtmlFileViewer-BsewwJtM.js → HtmlFileViewer-bL6T57PQ.js} +1 -1
  12. package/dist/client/assets/{IconEdit-CxvzMyLV.js → IconEdit-DePJMGIi.js} +1 -1
  13. package/dist/client/assets/{IconFolderPlus-1vLDIzhC.js → IconFolderPlus-ByGyA0Di.js} +1 -1
  14. package/dist/client/assets/{ImageFileViewer-CoQZkgET.js → ImageFileViewer-DJaHH3hJ.js} +1 -1
  15. package/dist/client/assets/{LocalRefsDialog-sw-ROjfe.js → LocalRefsDialog-D9wYZWBg.js} +1 -1
  16. package/dist/client/assets/MarkdownFileViewer-BNPb9v8u.js +2 -0
  17. package/dist/client/assets/{PairingPage-CYJXzBZC.js → PairingPage-D9oguvKU.js} +1 -1
  18. package/dist/client/assets/PierreDiffViewer-8wTLYd5-.js +1 -0
  19. package/dist/client/assets/{PierreEditBoundary-Bb4dONIq.js → PierreEditBoundary-KzU3HDc2.js} +2 -2
  20. package/dist/client/assets/{PierreWorkerPool-BuBzE8K1.js → PierreWorkerPool-DH2jp9oe.js} +18 -18
  21. package/dist/client/assets/{PullRequestDiff-CgY4QIHC.js → PullRequestDiff-DK-m07ZP.js} +1 -1
  22. package/dist/client/assets/PullRequestViewer-CpLwq4o2.js +2 -0
  23. package/dist/client/assets/PullRequestsView-DnvXaJ4t.js +1 -0
  24. package/dist/client/assets/{QuickOpenDialog-Cn-aQRAS.js → QuickOpenDialog-DIWjfUkt.js} +1 -1
  25. package/dist/client/assets/RepositoryProjectsDialog-BsQn5Yjr.js +1 -0
  26. package/dist/client/assets/{SearchView-BtKBEJ7e.js → SearchView-D-91dtSv.js} +1 -1
  27. package/dist/client/assets/SettingsDialog-dJUYk2cP.js +9 -0
  28. package/dist/client/assets/Viewer-GH-5bJW4.js +3 -0
  29. package/dist/client/assets/{abnfDiagram-N423BO3Z-DLBLFOdy.js → abnfDiagram-N423BO3Z-CkHOGdAl.js} +1 -1
  30. package/dist/client/assets/{arc-D-Yei3Vr.js → arc-Dj8F8CO5.js} +1 -1
  31. package/dist/client/assets/{architectureDiagram-T3A2C74G-BOgBvzWh.js → architectureDiagram-T3A2C74G-g87Y5LXk.js} +1 -1
  32. package/dist/client/assets/base-ui-DT3JsyND.js +1 -0
  33. package/dist/client/assets/{blockDiagram-VBNYF7ZC-BQXRJDyR.js → blockDiagram-VBNYF7ZC-D6efB7jD.js} +1 -1
  34. package/dist/client/assets/{c4Diagram-5PPSVZJV-DTZseD56.js → c4Diagram-5PPSVZJV-DoZEC2xg.js} +1 -1
  35. package/dist/client/assets/channel-Dsy2VD23.js +1 -0
  36. package/dist/client/assets/{checkbox-BwbxYGgK.js → checkbox-DYwmgDPS.js} +1 -1
  37. package/dist/client/assets/{chunk-2GRJ4B5K-spRCgfPY.js → chunk-2GRJ4B5K-Dr44hDNV.js} +1 -1
  38. package/dist/client/assets/{chunk-2Q5K7J3B-CLVClH0M.js → chunk-2Q5K7J3B-YIEyVOOL.js} +1 -1
  39. package/dist/client/assets/{chunk-5RXB4S5H-CuQ5tYjB.js → chunk-5RXB4S5H-gjmGBtkE.js} +1 -1
  40. package/dist/client/assets/{chunk-5VM5RSS4-DyOEOe90.js → chunk-5VM5RSS4-DCOQko4g.js} +1 -1
  41. package/dist/client/assets/{chunk-6Q2QTUOP-CgMtuJIx.js → chunk-6Q2QTUOP-DfGlvPVm.js} +1 -1
  42. package/dist/client/assets/{chunk-GF5L2VYU-BH63P4Vv.js → chunk-GF5L2VYU-CCWOLPVL.js} +1 -1
  43. package/dist/client/assets/{chunk-JWPE2WC7-BANDbaPq.js → chunk-JWPE2WC7-CFRTGh8r.js} +1 -1
  44. package/dist/client/assets/{chunk-KBJHAD2P-Bfty2upo.js → chunk-KBJHAD2P-By3wsJVD.js} +1 -1
  45. package/dist/client/assets/{chunk-RYQCIY6F-Cvu8BZS9.js → chunk-RYQCIY6F-C0wmsHmy.js} +1 -1
  46. package/dist/client/assets/{chunk-XXDRQBXY-bnohf1yd.js → chunk-XXDRQBXY-t3SnJvV_.js} +1 -1
  47. package/dist/client/assets/classDiagram-JCYQIIEL-BBQJgoWd.js +1 -0
  48. package/dist/client/assets/classDiagram-v2-OCEON4UE-BBQJgoWd.js +1 -0
  49. package/dist/client/assets/{vb-D17OF-Vu.js → cmd-BW5THilD.js} +1 -1
  50. package/dist/client/assets/{cose-bilkent-JH36ORCC-DCTEAZwO.js → cose-bilkent-JH36ORCC-D3VltoVk.js} +1 -1
  51. package/dist/client/assets/{cynefin-VYW2F7L2-Bp2wXvdt.js → cynefin-VYW2F7L2-DwLwbeoe.js} +1 -1
  52. package/dist/client/assets/{cynefinDiagram-MW4NZA55-DRRWzuF0.js → cynefinDiagram-MW4NZA55-B23kuaQF.js} +1 -1
  53. package/dist/client/assets/{dagre-VZM6K2ZE-DDvsotRK.js → dagre-VZM6K2ZE-SgMrTr2p.js} +1 -1
  54. package/dist/client/assets/{diagram-7IWD3JNH-CMqhRNRq.js → diagram-7IWD3JNH-C7cQN4aD.js} +1 -1
  55. package/dist/client/assets/{diagram-B4RE2ZJO-D_PYI1ut.js → diagram-B4RE2ZJO-CzeI3yOw.js} +1 -1
  56. package/dist/client/assets/{diagram-LBJQPF4R-BSUx7mMM.js → diagram-LBJQPF4R-DhKm4hlI.js} +1 -1
  57. package/dist/client/assets/{diagram-Q27KOJAE-C8O3g6WT.js → diagram-Q27KOJAE-BXlU6Wp3.js} +1 -1
  58. package/dist/client/assets/{diagram-UB23O5K3-C5-NDsgC.js → diagram-UB23O5K3-BOwY_YwR.js} +1 -1
  59. package/dist/client/assets/{ebnfDiagram-BXEA7PRR-D71hx4Ww.js → ebnfDiagram-BXEA7PRR-CuIQuYPa.js} +1 -1
  60. package/dist/client/assets/{erDiagram-JOGREHBK-yd9B5d8I.js → erDiagram-JOGREHBK-d45NhKfk.js} +1 -1
  61. package/dist/client/assets/{flowDiagram-UKHOOZJN-CWU5VVbw.js → flowDiagram-UKHOOZJN-Dzq-6qo7.js} +1 -1
  62. package/dist/client/assets/{ganttDiagram-PKOTCBZU-D2siVjfa.js → ganttDiagram-PKOTCBZU-RVlL9mX2.js} +1 -1
  63. package/dist/client/assets/{gh-utils-B0Nlmxep.js → gh-utils-LsOSydCg.js} +1 -1
  64. package/dist/client/assets/{gitGraphDiagram-DS77QQ5N-CIvIFcxR.js → gitGraphDiagram-DS77QQ5N-8kEJVUFH.js} +1 -1
  65. package/dist/client/assets/{index-DDbUjVD9.js → index-BzmFkR37.js} +1 -1
  66. package/dist/client/assets/{index-BOPi2b1j.js → index-CQcx9aRt.js} +4 -4
  67. package/dist/client/assets/index-DMbFAH51.css +1 -0
  68. package/dist/client/assets/{infoDiagram-6WML65LV-DRvl8KfO.js → infoDiagram-6WML65LV-Co21Ql9M.js} +1 -1
  69. package/dist/client/assets/{ishikawaDiagram-WSZJBQD7-H5EQq6uE.js → ishikawaDiagram-WSZJBQD7-BvPB_G97.js} +1 -1
  70. package/dist/client/assets/{journeyDiagram-NVQOT4AX-CCwLmD-U.js → journeyDiagram-NVQOT4AX-k7x89IE9.js} +1 -1
  71. package/dist/client/assets/{kanban-definition-27J2QSJJ-DS--XHEu.js → kanban-definition-27J2QSJJ-BjrgN30t.js} +1 -1
  72. package/dist/client/assets/{linear-Q3JNM6CR.js → linear-m158kske.js} +1 -1
  73. package/dist/client/assets/{mermaid.core-EwS_m22C.js → mermaid.core-C0FKucv-.js} +4 -4
  74. package/dist/client/assets/{mindmap-definition-FAOFIHXS-D15nrwfe.js → mindmap-definition-FAOFIHXS-CF8noycK.js} +1 -1
  75. package/dist/client/assets/{pegDiagram-VL7TDLO6-DOG19gxx.js → pegDiagram-VL7TDLO6-_y7nfJFV.js} +1 -1
  76. package/dist/client/assets/{pieDiagram-7S7Q4E2Y-Bstdr7Wh.js → pieDiagram-7S7Q4E2Y-DhdWHi45.js} +1 -1
  77. package/dist/client/assets/{platform-BMNQ8V5r.js → platform-Bqt97_Jr.js} +2 -2
  78. package/dist/client/assets/{quadrantDiagram-CIZ2JOQS-DfKs4qZW.js → quadrantDiagram-CIZ2JOQS-BRvEIECQ.js} +1 -1
  79. package/dist/client/assets/{railroadDiagram-AXF67PYL-DJKxyuhV.js → railroadDiagram-AXF67PYL-BgLZ8XU1.js} +1 -1
  80. package/dist/client/assets/render-markdown-2GjhuGA-.js +280 -0
  81. package/dist/client/assets/repository-grammars-ixqpb0uW.js +1 -0
  82. package/dist/client/assets/{requirementDiagram-LRYGKXZP-SGJWVmBV.js → requirementDiagram-LRYGKXZP-CX-gxyGF.js} +1 -1
  83. package/dist/client/assets/{sankeyDiagram-W5VNT64P-CpZFct0O.js → sankeyDiagram-W5VNT64P-CLSjSU_X.js} +1 -1
  84. package/dist/client/assets/{sequenceDiagram-SI44F4Z6-B7plRik9.js → sequenceDiagram-SI44F4Z6-dGlHyZRB.js} +1 -1
  85. package/dist/client/assets/{sizeCapture-X5ZJPWSS-CNbK285t.js → sizeCapture-X5ZJPWSS-BH3qO9T3.js} +1 -1
  86. package/dist/client/assets/{stateDiagram-OKZ733FA-BIHk9QCC.js → stateDiagram-OKZ733FA-FXxo1iIM.js} +1 -1
  87. package/dist/client/assets/stateDiagram-v2-UEYNNEHI-DqxQ14yP.js +1 -0
  88. package/dist/client/assets/{swimlanes-SLNWSIFB-7g_XCosC.js → swimlanes-SLNWSIFB-VJGIuM4S.js} +2 -2
  89. package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-No0dCAkd.js +8 -0
  90. package/dist/client/assets/{tanstack-B8_amOz8.js → tanstack-CtfgE41X.js} +1 -1
  91. package/dist/client/assets/{timeline-definition-Z64GVDOM-B-cgSggY.js → timeline-definition-Z64GVDOM-BXNTAanY.js} +1 -1
  92. package/dist/client/assets/{vennDiagram-T6HMQDX7-Bt5-8VZ2.js → vennDiagram-T6HMQDX7-D9nXAts5.js} +1 -1
  93. package/dist/client/assets/{viewer-tabs-DxCOe0ut.js → viewer-tabs-DkLmDzFg.js} +1 -1
  94. package/dist/client/assets/{wardleyDiagram-T6FBY63Y-B5Imx6zh.js → wardleyDiagram-T6FBY63Y-D89EaEfa.js} +1 -1
  95. package/dist/client/assets/{xychartDiagram-ELKLHX3M-CDaY4xFS.js → xychartDiagram-ELKLHX3M-B_xFDiIh.js} +1 -1
  96. package/dist/client/index.html +4 -4
  97. package/dist/dev.mjs +1 -4
  98. package/dist/manifest.json +1 -1
  99. package/dist/server.mjs +791 -2553
  100. package/dist/utility.mjs +0 -3
  101. package/package.json +1 -1
  102. package/dist/client/assets/App-CBetJ5ZN.js +0 -74
  103. package/dist/client/assets/CreatePullRequestDialog-W82oHjYm.js +0 -2
  104. package/dist/client/assets/DiffWorkspace-BWkTIl5n.js +0 -26
  105. package/dist/client/assets/EditableFileViewer-Cv3aNJBN.js +0 -1
  106. package/dist/client/assets/File-DiOOsHOl.js +0 -1
  107. package/dist/client/assets/GitHubAvatar-DBc3Vxnk.js +0 -1
  108. package/dist/client/assets/HistoryView-DYxWYYVx.js +0 -1
  109. package/dist/client/assets/MarkdownFileViewer-BedKCXTI.js +0 -2
  110. package/dist/client/assets/PierreDiffViewer-uhTsb-F7.js +0 -1
  111. package/dist/client/assets/PullRequestViewer-KZl0osME.js +0 -2
  112. package/dist/client/assets/PullRequestsView-DkN3pW33.js +0 -1
  113. package/dist/client/assets/RepositoryProjectsDialog-F-EctLXx.js +0 -1
  114. package/dist/client/assets/SettingsDialog-wfWhEzZY.js +0 -9
  115. package/dist/client/assets/Viewer-D-oFua7K.js +0 -3
  116. package/dist/client/assets/base-ui-qeHDA5zu.js +0 -1
  117. package/dist/client/assets/channel-DrMuSkDK.js +0 -1
  118. package/dist/client/assets/classDiagram-JCYQIIEL-BKiL0hkR.js +0 -1
  119. package/dist/client/assets/classDiagram-v2-OCEON4UE-BKiL0hkR.js +0 -1
  120. package/dist/client/assets/index-CryuKDT3.css +0 -1
  121. package/dist/client/assets/render-markdown-C7X2TwRk.js +0 -280
  122. package/dist/client/assets/stateDiagram-v2-UEYNNEHI-Cqw0H5cq.js +0 -1
  123. package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-BzKpdiGK.js +0 -8
package/dist/server.mjs CHANGED
@@ -16,9 +16,6 @@ import { Buffer as Buffer$1 } from "node:buffer";
16
16
  import { Transform, getDefaultHighWaterMark, Duplex, Writable, Readable, PassThrough } from "node:stream";
17
17
  import { finished } from "node:stream/promises";
18
18
  import path$1 from "node:path/win32";
19
- import require$$0$2 from "child_process";
20
- import require$$0$1 from "path";
21
- import require$$0 from "fs";
22
19
  import { createServer, isIP } from "node:net";
23
20
  import { createServer as createServer$1 } from "node:http";
24
21
  import WebSocket, { WebSocketServer } from "ws";
@@ -769,7 +766,7 @@ const handleCommand = (filePath, rawArguments, rawOptions) => {
769
766
  verboseInfo
770
767
  };
771
768
  };
772
- function pathKey$2(options = {}) {
769
+ function pathKey$1(options = {}) {
773
770
  const {
774
771
  env = process.env,
775
772
  platform: platform2 = process.platform
@@ -798,7 +795,7 @@ function traversePathUp(startPath) {
798
795
  }
799
796
  const npmRunPath = ({
800
797
  cwd = process$3.cwd(),
801
- path: pathOption = process$3.env[pathKey$2()],
798
+ path: pathOption = process$3.env[pathKey$1()],
802
799
  preferLocal = true,
803
800
  execPath: execPath2 = process$3.execPath,
804
801
  addExecPath = true
@@ -830,7 +827,7 @@ const applyExecPath = (result, pathParts, execPath2, cwdPath) => {
830
827
  };
831
828
  const npmRunPathEnv = ({ env = process$3.env, ...options } = {}) => {
832
829
  env = { ...env };
833
- const pathName = pathKey$2({ env });
830
+ const pathName = pathKey$1({ env });
834
831
  options.path = env[pathName];
835
832
  env[pathName] = npmRunPath(options);
836
833
  return env;
@@ -5262,7 +5259,7 @@ if (process.platform === "linux") {
5262
5259
  }
5263
5260
  const processOk = (process2) => !!process2 && typeof process2 === "object" && typeof process2.removeListener === "function" && typeof process2.emit === "function" && typeof process2.reallyExit === "function" && typeof process2.listeners === "function" && typeof process2.kill === "function" && typeof process2.pid === "number" && typeof process2.on === "function";
5264
5261
  const kExitEmitter = /* @__PURE__ */ Symbol.for("signal-exit emitter");
5265
- const global$1 = globalThis;
5262
+ const global = globalThis;
5266
5263
  const ObjectDefineProperty = Object.defineProperty.bind(Object);
5267
5264
  class Emitter {
5268
5265
  emitted = {
@@ -5276,10 +5273,10 @@ class Emitter {
5276
5273
  count = 0;
5277
5274
  id = Math.random();
5278
5275
  constructor() {
5279
- if (global$1[kExitEmitter]) {
5280
- return global$1[kExitEmitter];
5276
+ if (global[kExitEmitter]) {
5277
+ return global[kExitEmitter];
5281
5278
  }
5282
- ObjectDefineProperty(global$1, kExitEmitter, {
5279
+ ObjectDefineProperty(global, kExitEmitter, {
5283
5280
  value: this,
5284
5281
  writable: false,
5285
5282
  enumerable: false,
@@ -7014,26 +7011,30 @@ function cancelled() {
7014
7011
  function processFailed() {
7015
7012
  return new AiOperationError({ code: "AI_PROCESS_FAILED", operation: "ai-process", message: "Could not start the AI tool." });
7016
7013
  }
7017
- const ALLOWED = /* @__PURE__ */ new Set(["codex", "claude", "opencode", "gh"]);
7014
+ const ALLOWED = /* @__PURE__ */ new Set(["codex", "claude", "opencode", "grok", "gh"]);
7018
7015
  const ALIASES = {
7019
7016
  codex: ["codex"],
7020
7017
  claude: ["claude"],
7021
- // OpenCode 2 installs as opencode2 and does not replace OpenCode 1's opencode binary.
7018
+ // Current v2 uses opencode; older distributions also provide opencode2.
7022
7019
  opencode: ["opencode", "opencode2"],
7020
+ grok: ["grok"],
7023
7021
  gh: ["gh"]
7024
7022
  };
7025
7023
  class CliResolver {
7026
7024
  cache = /* @__PURE__ */ new Map();
7027
7025
  async resolve(name, forceRefresh = false) {
7028
- if (!ALLOWED.has(name)) return null;
7029
- if (!forceRefresh && this.cache.has(name)) return this.cache.get(name) ?? null;
7030
- let resolved = null;
7026
+ return (await this.resolveAll(name, forceRefresh))[0] ?? null;
7027
+ }
7028
+ async resolveAll(name, forceRefresh = false) {
7029
+ if (!ALLOWED.has(name)) return [];
7030
+ if (!forceRefresh && this.cache.has(name)) return [...this.cache.get(name)];
7031
+ const resolved = [];
7031
7032
  for (const alias of ALIASES[name] ?? [name]) {
7032
- resolved = await findOnPath(alias);
7033
- if (resolved) break;
7033
+ const executable = await findOnPath(alias);
7034
+ if (executable && !resolved.includes(executable)) resolved.push(executable);
7034
7035
  }
7035
7036
  this.cache.set(name, resolved);
7036
- return resolved;
7037
+ return [...resolved];
7037
7038
  }
7038
7039
  }
7039
7040
  async function findOnPath(name) {
@@ -7286,7 +7287,7 @@ const NUMBER_FORMAT_RANGES = {
7286
7287
  float32: [-34028234663852886e22, 34028234663852886e22],
7287
7288
  float64: [-Number.MAX_VALUE, Number.MAX_VALUE]
7288
7289
  };
7289
- function pick$1(schema, mask) {
7290
+ function pick(schema, mask) {
7290
7291
  const currDef = schema._zod.def;
7291
7292
  const checks = currDef.checks;
7292
7293
  const hasChecks = checks && checks.length > 0;
@@ -9098,6 +9099,132 @@ function handleIntersectionResults(result, left, right) {
9098
9099
  result.value = merged.data;
9099
9100
  return result;
9100
9101
  }
9102
+ const $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
9103
+ $ZodType.init(inst, def);
9104
+ inst._zod.parse = (payload, ctx) => {
9105
+ const input = payload.value;
9106
+ if (!isPlainObject(input)) {
9107
+ payload.issues.push({
9108
+ expected: "record",
9109
+ code: "invalid_type",
9110
+ input,
9111
+ inst
9112
+ });
9113
+ return payload;
9114
+ }
9115
+ const proms = [];
9116
+ const values = def.keyType._zod.values;
9117
+ if (values) {
9118
+ payload.value = {};
9119
+ const recordKeys = /* @__PURE__ */ new Set();
9120
+ for (const key of values) {
9121
+ if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
9122
+ recordKeys.add(typeof key === "number" ? key.toString() : key);
9123
+ const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
9124
+ if (keyResult instanceof Promise) {
9125
+ throw new Error("Async schemas not supported in object keys currently");
9126
+ }
9127
+ if (keyResult.issues.length) {
9128
+ payload.issues.push({
9129
+ code: "invalid_key",
9130
+ origin: "record",
9131
+ issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
9132
+ input: key,
9133
+ path: [key],
9134
+ inst
9135
+ });
9136
+ continue;
9137
+ }
9138
+ const outKey = keyResult.value;
9139
+ const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
9140
+ if (result instanceof Promise) {
9141
+ proms.push(result.then((result2) => {
9142
+ if (result2.issues.length) {
9143
+ payload.issues.push(...prefixIssues(key, result2.issues));
9144
+ }
9145
+ payload.value[outKey] = result2.value;
9146
+ }));
9147
+ } else {
9148
+ if (result.issues.length) {
9149
+ payload.issues.push(...prefixIssues(key, result.issues));
9150
+ }
9151
+ payload.value[outKey] = result.value;
9152
+ }
9153
+ }
9154
+ }
9155
+ let unrecognized;
9156
+ for (const key in input) {
9157
+ if (!recordKeys.has(key)) {
9158
+ unrecognized = unrecognized ?? [];
9159
+ unrecognized.push(key);
9160
+ }
9161
+ }
9162
+ if (unrecognized && unrecognized.length > 0) {
9163
+ payload.issues.push({
9164
+ code: "unrecognized_keys",
9165
+ input,
9166
+ inst,
9167
+ keys: unrecognized
9168
+ });
9169
+ }
9170
+ } else {
9171
+ payload.value = {};
9172
+ for (const key of Reflect.ownKeys(input)) {
9173
+ if (key === "__proto__")
9174
+ continue;
9175
+ if (!Object.prototype.propertyIsEnumerable.call(input, key))
9176
+ continue;
9177
+ let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
9178
+ if (keyResult instanceof Promise) {
9179
+ throw new Error("Async schemas not supported in object keys currently");
9180
+ }
9181
+ const checkNumericKey = typeof key === "string" && number$1.test(key) && keyResult.issues.length;
9182
+ if (checkNumericKey) {
9183
+ const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
9184
+ if (retryResult instanceof Promise) {
9185
+ throw new Error("Async schemas not supported in object keys currently");
9186
+ }
9187
+ if (retryResult.issues.length === 0) {
9188
+ keyResult = retryResult;
9189
+ }
9190
+ }
9191
+ if (keyResult.issues.length) {
9192
+ if (def.mode === "loose") {
9193
+ payload.value[key] = input[key];
9194
+ } else {
9195
+ payload.issues.push({
9196
+ code: "invalid_key",
9197
+ origin: "record",
9198
+ issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
9199
+ input: key,
9200
+ path: [key],
9201
+ inst
9202
+ });
9203
+ }
9204
+ continue;
9205
+ }
9206
+ const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
9207
+ if (result instanceof Promise) {
9208
+ proms.push(result.then((result2) => {
9209
+ if (result2.issues.length) {
9210
+ payload.issues.push(...prefixIssues(key, result2.issues));
9211
+ }
9212
+ payload.value[keyResult.value] = result2.value;
9213
+ }));
9214
+ } else {
9215
+ if (result.issues.length) {
9216
+ payload.issues.push(...prefixIssues(key, result.issues));
9217
+ }
9218
+ payload.value[keyResult.value] = result.value;
9219
+ }
9220
+ }
9221
+ }
9222
+ if (proms.length) {
9223
+ return Promise.all(proms).then(() => payload);
9224
+ }
9225
+ return payload;
9226
+ };
9227
+ });
9101
9228
  const $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
9102
9229
  $ZodType.init(inst, def);
9103
9230
  const values = getEnumValues(def.entries);
@@ -10304,29 +10431,29 @@ const formatMap = {
10304
10431
  // do not set
10305
10432
  };
10306
10433
  const stringProcessor = (schema, ctx, _json, _params) => {
10307
- const json = _json;
10308
- json.type = "string";
10434
+ const json2 = _json;
10435
+ json2.type = "string";
10309
10436
  const { minimum, maximum, format: format2, patterns, contentEncoding } = schema._zod.bag;
10310
10437
  if (typeof minimum === "number")
10311
- json.minLength = minimum;
10438
+ json2.minLength = minimum;
10312
10439
  if (typeof maximum === "number")
10313
- json.maxLength = maximum;
10440
+ json2.maxLength = maximum;
10314
10441
  if (format2) {
10315
- json.format = formatMap[format2] ?? format2;
10316
- if (json.format === "")
10317
- delete json.format;
10442
+ json2.format = formatMap[format2] ?? format2;
10443
+ if (json2.format === "")
10444
+ delete json2.format;
10318
10445
  if (format2 === "time") {
10319
- delete json.format;
10446
+ delete json2.format;
10320
10447
  }
10321
10448
  }
10322
10449
  if (contentEncoding)
10323
- json.contentEncoding = contentEncoding;
10450
+ json2.contentEncoding = contentEncoding;
10324
10451
  if (patterns && patterns.size > 0) {
10325
10452
  const regexes = [...patterns];
10326
10453
  if (regexes.length === 1)
10327
- json.pattern = regexes[0].source;
10454
+ json2.pattern = regexes[0].source;
10328
10455
  else if (regexes.length > 1) {
10329
- json.allOf = [
10456
+ json2.allOf = [
10330
10457
  ...regexes.map((regex) => ({
10331
10458
  ...ctx.target === "draft-07" || ctx.target === "draft-04" || ctx.target === "openapi-3.0" ? { type: "string" } : {},
10332
10459
  pattern: regex.source
@@ -10336,40 +10463,40 @@ const stringProcessor = (schema, ctx, _json, _params) => {
10336
10463
  }
10337
10464
  };
10338
10465
  const numberProcessor = (schema, ctx, _json, _params) => {
10339
- const json = _json;
10466
+ const json2 = _json;
10340
10467
  const { minimum, maximum, format: format2, multipleOf, exclusiveMaximum, exclusiveMinimum } = schema._zod.bag;
10341
10468
  if (typeof format2 === "string" && format2.includes("int"))
10342
- json.type = "integer";
10469
+ json2.type = "integer";
10343
10470
  else
10344
- json.type = "number";
10471
+ json2.type = "number";
10345
10472
  const exMin = typeof exclusiveMinimum === "number" && exclusiveMinimum >= (minimum ?? Number.NEGATIVE_INFINITY);
10346
10473
  const exMax = typeof exclusiveMaximum === "number" && exclusiveMaximum <= (maximum ?? Number.POSITIVE_INFINITY);
10347
10474
  const legacy = ctx.target === "draft-04" || ctx.target === "openapi-3.0";
10348
10475
  if (exMin) {
10349
10476
  if (legacy) {
10350
- json.minimum = exclusiveMinimum;
10351
- json.exclusiveMinimum = true;
10477
+ json2.minimum = exclusiveMinimum;
10478
+ json2.exclusiveMinimum = true;
10352
10479
  } else {
10353
- json.exclusiveMinimum = exclusiveMinimum;
10480
+ json2.exclusiveMinimum = exclusiveMinimum;
10354
10481
  }
10355
10482
  } else if (typeof minimum === "number") {
10356
- json.minimum = minimum;
10483
+ json2.minimum = minimum;
10357
10484
  }
10358
10485
  if (exMax) {
10359
10486
  if (legacy) {
10360
- json.maximum = exclusiveMaximum;
10361
- json.exclusiveMaximum = true;
10487
+ json2.maximum = exclusiveMaximum;
10488
+ json2.exclusiveMaximum = true;
10362
10489
  } else {
10363
- json.exclusiveMaximum = exclusiveMaximum;
10490
+ json2.exclusiveMaximum = exclusiveMaximum;
10364
10491
  }
10365
10492
  } else if (typeof maximum === "number") {
10366
- json.maximum = maximum;
10493
+ json2.maximum = maximum;
10367
10494
  }
10368
10495
  if (typeof multipleOf === "number")
10369
- json.multipleOf = multipleOf;
10496
+ json2.multipleOf = multipleOf;
10370
10497
  };
10371
- const booleanProcessor = (_schema, _ctx, json, _params) => {
10372
- json.type = "boolean";
10498
+ const booleanProcessor = (_schema, _ctx, json2, _params) => {
10499
+ json2.type = "boolean";
10373
10500
  };
10374
10501
  const bigintProcessor = (_schema, ctx, _json, _params) => {
10375
10502
  if (ctx.unrepresentable === "throw") {
@@ -10381,13 +10508,13 @@ const symbolProcessor = (_schema, ctx, _json, _params) => {
10381
10508
  throw new Error("Symbols cannot be represented in JSON Schema");
10382
10509
  }
10383
10510
  };
10384
- const nullProcessor = (_schema, ctx, json, _params) => {
10511
+ const nullProcessor = (_schema, ctx, json2, _params) => {
10385
10512
  if (ctx.target === "openapi-3.0") {
10386
- json.type = "string";
10387
- json.nullable = true;
10388
- json.enum = [null];
10513
+ json2.type = "string";
10514
+ json2.nullable = true;
10515
+ json2.enum = [null];
10389
10516
  } else {
10390
- json.type = "null";
10517
+ json2.type = "null";
10391
10518
  }
10392
10519
  };
10393
10520
  const undefinedProcessor = (_schema, ctx, _json, _params) => {
@@ -10400,8 +10527,8 @@ const voidProcessor = (_schema, ctx, _json, _params) => {
10400
10527
  throw new Error("Void cannot be represented in JSON Schema");
10401
10528
  }
10402
10529
  };
10403
- const neverProcessor = (_schema, _ctx, json, _params) => {
10404
- json.not = {};
10530
+ const neverProcessor = (_schema, _ctx, json2, _params) => {
10531
+ json2.not = {};
10405
10532
  };
10406
10533
  const anyProcessor = (_schema, _ctx, _json, _params) => {
10407
10534
  };
@@ -10412,16 +10539,16 @@ const dateProcessor = (_schema, ctx, _json, _params) => {
10412
10539
  throw new Error("Date cannot be represented in JSON Schema");
10413
10540
  }
10414
10541
  };
10415
- const enumProcessor = (schema, _ctx, json, _params) => {
10542
+ const enumProcessor = (schema, _ctx, json2, _params) => {
10416
10543
  const def = schema._zod.def;
10417
10544
  const values = getEnumValues(def.entries);
10418
10545
  if (values.every((v) => typeof v === "number"))
10419
- json.type = "number";
10546
+ json2.type = "number";
10420
10547
  if (values.every((v) => typeof v === "string"))
10421
- json.type = "string";
10422
- json.enum = values;
10548
+ json2.type = "string";
10549
+ json2.enum = values;
10423
10550
  };
10424
- const literalProcessor = (schema, ctx, json, _params) => {
10551
+ const literalProcessor = (schema, ctx, json2, _params) => {
10425
10552
  const def = schema._zod.def;
10426
10553
  const vals = [];
10427
10554
  for (const val of def.values) {
@@ -10442,22 +10569,22 @@ const literalProcessor = (schema, ctx, json, _params) => {
10442
10569
  if (vals.length === 0) ;
10443
10570
  else if (vals.length === 1) {
10444
10571
  const val = vals[0];
10445
- json.type = val === null ? "null" : typeof val;
10572
+ json2.type = val === null ? "null" : typeof val;
10446
10573
  if (ctx.target === "draft-04" || ctx.target === "openapi-3.0") {
10447
- json.enum = [val];
10574
+ json2.enum = [val];
10448
10575
  } else {
10449
- json.const = val;
10576
+ json2.const = val;
10450
10577
  }
10451
10578
  } else {
10452
10579
  if (vals.every((v) => typeof v === "number"))
10453
- json.type = "number";
10580
+ json2.type = "number";
10454
10581
  if (vals.every((v) => typeof v === "string"))
10455
- json.type = "string";
10582
+ json2.type = "string";
10456
10583
  if (vals.every((v) => typeof v === "boolean"))
10457
- json.type = "boolean";
10584
+ json2.type = "boolean";
10458
10585
  if (vals.every((v) => v === null))
10459
- json.type = "null";
10460
- json.enum = vals;
10586
+ json2.type = "null";
10587
+ json2.enum = vals;
10461
10588
  }
10462
10589
  };
10463
10590
  const nanProcessor = (_schema, ctx, _json, _params) => {
@@ -10465,16 +10592,16 @@ const nanProcessor = (_schema, ctx, _json, _params) => {
10465
10592
  throw new Error("NaN cannot be represented in JSON Schema");
10466
10593
  }
10467
10594
  };
10468
- const templateLiteralProcessor = (schema, _ctx, json, _params) => {
10469
- const _json = json;
10595
+ const templateLiteralProcessor = (schema, _ctx, json2, _params) => {
10596
+ const _json = json2;
10470
10597
  const pattern = schema._zod.pattern;
10471
10598
  if (!pattern)
10472
10599
  throw new Error("Pattern not found in template literal");
10473
10600
  _json.type = "string";
10474
10601
  _json.pattern = pattern.source;
10475
10602
  };
10476
- const fileProcessor = (schema, _ctx, json, _params) => {
10477
- const _json = json;
10603
+ const fileProcessor = (schema, _ctx, json2, _params) => {
10604
+ const _json = json2;
10478
10605
  const file = {
10479
10606
  type: "string",
10480
10607
  format: "binary",
@@ -10497,8 +10624,8 @@ const fileProcessor = (schema, _ctx, json, _params) => {
10497
10624
  Object.assign(_json, file);
10498
10625
  }
10499
10626
  };
10500
- const successProcessor = (_schema, _ctx, json, _params) => {
10501
- json.type = "boolean";
10627
+ const successProcessor = (_schema, _ctx, json2, _params) => {
10628
+ json2.type = "boolean";
10502
10629
  };
10503
10630
  const customProcessor = (_schema, ctx, _json, _params) => {
10504
10631
  if (ctx.unrepresentable === "throw") {
@@ -10526,27 +10653,27 @@ const setProcessor = (_schema, ctx, _json, _params) => {
10526
10653
  }
10527
10654
  };
10528
10655
  const arrayProcessor = (schema, ctx, _json, params) => {
10529
- const json = _json;
10656
+ const json2 = _json;
10530
10657
  const def = schema._zod.def;
10531
10658
  const { minimum, maximum } = schema._zod.bag;
10532
10659
  if (typeof minimum === "number")
10533
- json.minItems = minimum;
10660
+ json2.minItems = minimum;
10534
10661
  if (typeof maximum === "number")
10535
- json.maxItems = maximum;
10536
- json.type = "array";
10537
- json.items = process$1(def.element, ctx, {
10662
+ json2.maxItems = maximum;
10663
+ json2.type = "array";
10664
+ json2.items = process$1(def.element, ctx, {
10538
10665
  ...params,
10539
10666
  path: [...params.path, "items"]
10540
10667
  });
10541
10668
  };
10542
10669
  const objectProcessor = (schema, ctx, _json, params) => {
10543
- const json = _json;
10670
+ const json2 = _json;
10544
10671
  const def = schema._zod.def;
10545
- json.type = "object";
10546
- json.properties = {};
10672
+ json2.type = "object";
10673
+ json2.properties = {};
10547
10674
  const shape = def.shape;
10548
10675
  for (const key in shape) {
10549
- json.properties[key] = process$1(shape[key], ctx, {
10676
+ json2.properties[key] = process$1(shape[key], ctx, {
10550
10677
  ...params,
10551
10678
  path: [...params.path, "properties", key]
10552
10679
  });
@@ -10561,21 +10688,21 @@ const objectProcessor = (schema, ctx, _json, params) => {
10561
10688
  }
10562
10689
  }));
10563
10690
  if (requiredKeys.size > 0) {
10564
- json.required = Array.from(requiredKeys);
10691
+ json2.required = Array.from(requiredKeys);
10565
10692
  }
10566
10693
  if (def.catchall?._zod.def.type === "never") {
10567
- json.additionalProperties = false;
10694
+ json2.additionalProperties = false;
10568
10695
  } else if (!def.catchall) {
10569
10696
  if (ctx.io === "output")
10570
- json.additionalProperties = false;
10697
+ json2.additionalProperties = false;
10571
10698
  } else if (def.catchall) {
10572
- json.additionalProperties = process$1(def.catchall, ctx, {
10699
+ json2.additionalProperties = process$1(def.catchall, ctx, {
10573
10700
  ...params,
10574
10701
  path: [...params.path, "additionalProperties"]
10575
10702
  });
10576
10703
  }
10577
10704
  };
10578
- const unionProcessor = (schema, ctx, json, params) => {
10705
+ const unionProcessor = (schema, ctx, json2, params) => {
10579
10706
  const def = schema._zod.def;
10580
10707
  const isExclusive = def.inclusive === false;
10581
10708
  const options = def.options.map((x, i2) => process$1(x, ctx, {
@@ -10583,12 +10710,12 @@ const unionProcessor = (schema, ctx, json, params) => {
10583
10710
  path: [...params.path, isExclusive ? "oneOf" : "anyOf", i2]
10584
10711
  }));
10585
10712
  if (isExclusive) {
10586
- json.oneOf = options;
10713
+ json2.oneOf = options;
10587
10714
  } else {
10588
- json.anyOf = options;
10715
+ json2.anyOf = options;
10589
10716
  }
10590
10717
  };
10591
- const intersectionProcessor = (schema, ctx, json, params) => {
10718
+ const intersectionProcessor = (schema, ctx, json2, params) => {
10592
10719
  const def = schema._zod.def;
10593
10720
  const a2 = process$1(def.left, ctx, {
10594
10721
  ...params,
@@ -10603,12 +10730,12 @@ const intersectionProcessor = (schema, ctx, json, params) => {
10603
10730
  ...isSimpleIntersection(a2) ? a2.allOf : [a2],
10604
10731
  ...isSimpleIntersection(b) ? b.allOf : [b]
10605
10732
  ];
10606
- json.allOf = allOf;
10733
+ json2.allOf = allOf;
10607
10734
  };
10608
10735
  const tupleProcessor = (schema, ctx, _json, params) => {
10609
- const json = _json;
10736
+ const json2 = _json;
10610
10737
  const def = schema._zod.def;
10611
- json.type = "array";
10738
+ json2.type = "array";
10612
10739
  const prefixPath = ctx.target === "draft-2020-12" ? "prefixItems" : "items";
10613
10740
  const restPath = ctx.target === "draft-2020-12" ? "items" : ctx.target === "openapi-3.0" ? "items" : "additionalItems";
10614
10741
  const prefixItems = def.items.map((x, i2) => process$1(x, ctx, {
@@ -10620,37 +10747,37 @@ const tupleProcessor = (schema, ctx, _json, params) => {
10620
10747
  path: [...params.path, restPath, ...ctx.target === "openapi-3.0" ? [def.items.length] : []]
10621
10748
  }) : null;
10622
10749
  if (ctx.target === "draft-2020-12") {
10623
- json.prefixItems = prefixItems;
10750
+ json2.prefixItems = prefixItems;
10624
10751
  if (rest) {
10625
- json.items = rest;
10752
+ json2.items = rest;
10626
10753
  }
10627
10754
  } else if (ctx.target === "openapi-3.0") {
10628
- json.items = {
10755
+ json2.items = {
10629
10756
  anyOf: prefixItems
10630
10757
  };
10631
10758
  if (rest) {
10632
- json.items.anyOf.push(rest);
10759
+ json2.items.anyOf.push(rest);
10633
10760
  }
10634
- json.minItems = prefixItems.length;
10761
+ json2.minItems = prefixItems.length;
10635
10762
  if (!rest) {
10636
- json.maxItems = prefixItems.length;
10763
+ json2.maxItems = prefixItems.length;
10637
10764
  }
10638
10765
  } else {
10639
- json.items = prefixItems;
10766
+ json2.items = prefixItems;
10640
10767
  if (rest) {
10641
- json.additionalItems = rest;
10768
+ json2.additionalItems = rest;
10642
10769
  }
10643
10770
  }
10644
10771
  const { minimum, maximum } = schema._zod.bag;
10645
10772
  if (typeof minimum === "number")
10646
- json.minItems = minimum;
10773
+ json2.minItems = minimum;
10647
10774
  if (typeof maximum === "number")
10648
- json.maxItems = maximum;
10775
+ json2.maxItems = maximum;
10649
10776
  };
10650
10777
  const recordProcessor = (schema, ctx, _json, params) => {
10651
- const json = _json;
10778
+ const json2 = _json;
10652
10779
  const def = schema._zod.def;
10653
- json.type = "object";
10780
+ json2.type = "object";
10654
10781
  const keyType = def.keyType;
10655
10782
  const keyBag = keyType._zod.bag;
10656
10783
  const patterns = keyBag?.patterns;
@@ -10659,18 +10786,18 @@ const recordProcessor = (schema, ctx, _json, params) => {
10659
10786
  ...params,
10660
10787
  path: [...params.path, "patternProperties", "*"]
10661
10788
  });
10662
- json.patternProperties = {};
10789
+ json2.patternProperties = {};
10663
10790
  for (const pattern of patterns) {
10664
- json.patternProperties[pattern.source] = valueSchema;
10791
+ json2.patternProperties[pattern.source] = valueSchema;
10665
10792
  }
10666
10793
  } else {
10667
10794
  if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") {
10668
- json.propertyNames = process$1(def.keyType, ctx, {
10795
+ json2.propertyNames = process$1(def.keyType, ctx, {
10669
10796
  ...params,
10670
10797
  path: [...params.path, "propertyNames"]
10671
10798
  });
10672
10799
  }
10673
- json.additionalProperties = process$1(def.valueType, ctx, {
10800
+ json2.additionalProperties = process$1(def.valueType, ctx, {
10674
10801
  ...params,
10675
10802
  path: [...params.path, "additionalProperties"]
10676
10803
  });
@@ -10679,19 +10806,19 @@ const recordProcessor = (schema, ctx, _json, params) => {
10679
10806
  if (keyValues) {
10680
10807
  const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
10681
10808
  if (validKeyValues.length > 0) {
10682
- json.required = validKeyValues;
10809
+ json2.required = validKeyValues;
10683
10810
  }
10684
10811
  }
10685
10812
  };
10686
- const nullableProcessor = (schema, ctx, json, params) => {
10813
+ const nullableProcessor = (schema, ctx, json2, params) => {
10687
10814
  const def = schema._zod.def;
10688
10815
  const inner = process$1(def.innerType, ctx, params);
10689
10816
  const seen = ctx.seen.get(schema);
10690
10817
  if (ctx.target === "openapi-3.0") {
10691
10818
  seen.ref = def.innerType;
10692
- json.nullable = true;
10819
+ json2.nullable = true;
10693
10820
  } else {
10694
- json.anyOf = [inner, { type: "null" }];
10821
+ json2.anyOf = [inner, { type: "null" }];
10695
10822
  }
10696
10823
  };
10697
10824
  const nonoptionalProcessor = (schema, ctx, _json, params) => {
@@ -10700,22 +10827,22 @@ const nonoptionalProcessor = (schema, ctx, _json, params) => {
10700
10827
  const seen = ctx.seen.get(schema);
10701
10828
  seen.ref = def.innerType;
10702
10829
  };
10703
- const defaultProcessor = (schema, ctx, json, params) => {
10830
+ const defaultProcessor = (schema, ctx, json2, params) => {
10704
10831
  const def = schema._zod.def;
10705
10832
  process$1(def.innerType, ctx, params);
10706
10833
  const seen = ctx.seen.get(schema);
10707
10834
  seen.ref = def.innerType;
10708
- json.default = JSON.parse(JSON.stringify(def.defaultValue));
10835
+ json2.default = JSON.parse(JSON.stringify(def.defaultValue));
10709
10836
  };
10710
- const prefaultProcessor = (schema, ctx, json, params) => {
10837
+ const prefaultProcessor = (schema, ctx, json2, params) => {
10711
10838
  const def = schema._zod.def;
10712
10839
  process$1(def.innerType, ctx, params);
10713
10840
  const seen = ctx.seen.get(schema);
10714
10841
  seen.ref = def.innerType;
10715
10842
  if (ctx.io === "input")
10716
- json._prefault = JSON.parse(JSON.stringify(def.defaultValue));
10843
+ json2._prefault = JSON.parse(JSON.stringify(def.defaultValue));
10717
10844
  };
10718
- const catchProcessor = (schema, ctx, json, params) => {
10845
+ const catchProcessor = (schema, ctx, json2, params) => {
10719
10846
  const def = schema._zod.def;
10720
10847
  process$1(def.innerType, ctx, params);
10721
10848
  const seen = ctx.seen.get(schema);
@@ -10726,7 +10853,7 @@ const catchProcessor = (schema, ctx, json, params) => {
10726
10853
  } catch {
10727
10854
  throw new Error("Dynamic catch values are not supported in JSON Schema");
10728
10855
  }
10729
- json.default = catchValue;
10856
+ json2.default = catchValue;
10730
10857
  };
10731
10858
  const pipeProcessor = (schema, ctx, _json, params) => {
10732
10859
  const def = schema._zod.def;
@@ -10736,12 +10863,12 @@ const pipeProcessor = (schema, ctx, _json, params) => {
10736
10863
  const seen = ctx.seen.get(schema);
10737
10864
  seen.ref = innerType;
10738
10865
  };
10739
- const readonlyProcessor = (schema, ctx, json, params) => {
10866
+ const readonlyProcessor = (schema, ctx, json2, params) => {
10740
10867
  const def = schema._zod.def;
10741
10868
  process$1(def.innerType, ctx, params);
10742
10869
  const seen = ctx.seen.get(schema);
10743
10870
  seen.ref = def.innerType;
10744
- json.readOnly = true;
10871
+ json2.readOnly = true;
10745
10872
  };
10746
10873
  const promiseProcessor = (schema, ctx, _json, params) => {
10747
10874
  const def = schema._zod.def;
@@ -11082,7 +11209,7 @@ const ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
11082
11209
  const _ZodString = /* @__PURE__ */ $constructor("_ZodString", (inst, def) => {
11083
11210
  $ZodString.init(inst, def);
11084
11211
  ZodType.init(inst, def);
11085
- inst._zod.processJSONSchema = (ctx, json, params) => stringProcessor(inst, ctx, json);
11212
+ inst._zod.processJSONSchema = (ctx, json2, params) => stringProcessor(inst, ctx, json2);
11086
11213
  const bag = inst._zod.bag;
11087
11214
  inst.format = bag.format ?? null;
11088
11215
  inst.minLength = bag.minimum ?? null;
@@ -11252,7 +11379,7 @@ const ZodJWT = /* @__PURE__ */ $constructor("ZodJWT", (inst, def) => {
11252
11379
  const ZodNumber = /* @__PURE__ */ $constructor("ZodNumber", (inst, def) => {
11253
11380
  $ZodNumber.init(inst, def);
11254
11381
  ZodType.init(inst, def);
11255
- inst._zod.processJSONSchema = (ctx, json, params) => numberProcessor(inst, ctx, json);
11382
+ inst._zod.processJSONSchema = (ctx, json2, params) => numberProcessor(inst, ctx, json2);
11256
11383
  _installLazyMethods(inst, "ZodNumber", {
11257
11384
  gt(value, params) {
11258
11385
  return this.check(/* @__PURE__ */ _gt(value, params));
@@ -11320,7 +11447,7 @@ function int(params) {
11320
11447
  const ZodBoolean = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
11321
11448
  $ZodBoolean.init(inst, def);
11322
11449
  ZodType.init(inst, def);
11323
- inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json);
11450
+ inst._zod.processJSONSchema = (ctx, json2, params) => booleanProcessor(inst, ctx, json2);
11324
11451
  });
11325
11452
  function boolean(params) {
11326
11453
  return /* @__PURE__ */ _boolean(ZodBoolean, params);
@@ -11328,7 +11455,7 @@ function boolean(params) {
11328
11455
  const ZodUnknown = /* @__PURE__ */ $constructor("ZodUnknown", (inst, def) => {
11329
11456
  $ZodUnknown.init(inst, def);
11330
11457
  ZodType.init(inst, def);
11331
- inst._zod.processJSONSchema = (ctx, json, params) => unknownProcessor();
11458
+ inst._zod.processJSONSchema = (ctx, json2, params) => unknownProcessor();
11332
11459
  });
11333
11460
  function unknown() {
11334
11461
  return /* @__PURE__ */ _unknown(ZodUnknown);
@@ -11336,7 +11463,7 @@ function unknown() {
11336
11463
  const ZodNever = /* @__PURE__ */ $constructor("ZodNever", (inst, def) => {
11337
11464
  $ZodNever.init(inst, def);
11338
11465
  ZodType.init(inst, def);
11339
- inst._zod.processJSONSchema = (ctx, json, params) => neverProcessor(inst, ctx, json);
11466
+ inst._zod.processJSONSchema = (ctx, json2, params) => neverProcessor(inst, ctx, json2);
11340
11467
  });
11341
11468
  function never(params) {
11342
11469
  return /* @__PURE__ */ _never(ZodNever, params);
@@ -11344,7 +11471,7 @@ function never(params) {
11344
11471
  const ZodArray = /* @__PURE__ */ $constructor("ZodArray", (inst, def) => {
11345
11472
  $ZodArray.init(inst, def);
11346
11473
  ZodType.init(inst, def);
11347
- inst._zod.processJSONSchema = (ctx, json, params) => arrayProcessor(inst, ctx, json, params);
11474
+ inst._zod.processJSONSchema = (ctx, json2, params) => arrayProcessor(inst, ctx, json2, params);
11348
11475
  inst.element = def.element;
11349
11476
  _installLazyMethods(inst, "ZodArray", {
11350
11477
  min(n2, params) {
@@ -11370,7 +11497,7 @@ function array(element, params) {
11370
11497
  const ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => {
11371
11498
  $ZodObjectJIT.init(inst, def);
11372
11499
  ZodType.init(inst, def);
11373
- inst._zod.processJSONSchema = (ctx, json, params) => objectProcessor(inst, ctx, json, params);
11500
+ inst._zod.processJSONSchema = (ctx, json2, params) => objectProcessor(inst, ctx, json2, params);
11374
11501
  defineLazy(inst, "shape", () => {
11375
11502
  return def.shape;
11376
11503
  });
@@ -11403,7 +11530,7 @@ const ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => {
11403
11530
  return merge(this, other);
11404
11531
  },
11405
11532
  pick(mask) {
11406
- return pick$1(this, mask);
11533
+ return pick(this, mask);
11407
11534
  },
11408
11535
  omit(mask) {
11409
11536
  return omit(this, mask);
@@ -11435,7 +11562,7 @@ function looseObject(shape, params) {
11435
11562
  const ZodUnion = /* @__PURE__ */ $constructor("ZodUnion", (inst, def) => {
11436
11563
  $ZodUnion.init(inst, def);
11437
11564
  ZodType.init(inst, def);
11438
- inst._zod.processJSONSchema = (ctx, json, params) => unionProcessor(inst, ctx, json, params);
11565
+ inst._zod.processJSONSchema = (ctx, json2, params) => unionProcessor(inst, ctx, json2, params);
11439
11566
  inst.options = def.options;
11440
11567
  });
11441
11568
  function union(options, params) {
@@ -11448,7 +11575,7 @@ function union(options, params) {
11448
11575
  const ZodIntersection = /* @__PURE__ */ $constructor("ZodIntersection", (inst, def) => {
11449
11576
  $ZodIntersection.init(inst, def);
11450
11577
  ZodType.init(inst, def);
11451
- inst._zod.processJSONSchema = (ctx, json, params) => intersectionProcessor(inst, ctx, json, params);
11578
+ inst._zod.processJSONSchema = (ctx, json2, params) => intersectionProcessor(inst, ctx, json2, params);
11452
11579
  });
11453
11580
  function intersection(left, right) {
11454
11581
  return new ZodIntersection({
@@ -11457,10 +11584,33 @@ function intersection(left, right) {
11457
11584
  right
11458
11585
  });
11459
11586
  }
11587
+ const ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
11588
+ $ZodRecord.init(inst, def);
11589
+ ZodType.init(inst, def);
11590
+ inst._zod.processJSONSchema = (ctx, json2, params) => recordProcessor(inst, ctx, json2, params);
11591
+ inst.keyType = def.keyType;
11592
+ inst.valueType = def.valueType;
11593
+ });
11594
+ function record(keyType, valueType, params) {
11595
+ if (!valueType || !valueType._zod) {
11596
+ return new ZodRecord({
11597
+ type: "record",
11598
+ keyType: string(),
11599
+ valueType: keyType,
11600
+ ...normalizeParams(valueType)
11601
+ });
11602
+ }
11603
+ return new ZodRecord({
11604
+ type: "record",
11605
+ keyType,
11606
+ valueType,
11607
+ ...normalizeParams(params)
11608
+ });
11609
+ }
11460
11610
  const ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
11461
11611
  $ZodEnum.init(inst, def);
11462
11612
  ZodType.init(inst, def);
11463
- inst._zod.processJSONSchema = (ctx, json, params) => enumProcessor(inst, ctx, json);
11613
+ inst._zod.processJSONSchema = (ctx, json2, params) => enumProcessor(inst, ctx, json2);
11464
11614
  inst.enum = def.entries;
11465
11615
  inst.options = Object.values(def.entries);
11466
11616
  const keys = new Set(Object.keys(def.entries));
@@ -11506,7 +11656,7 @@ function _enum(values, params) {
11506
11656
  const ZodTransform = /* @__PURE__ */ $constructor("ZodTransform", (inst, def) => {
11507
11657
  $ZodTransform.init(inst, def);
11508
11658
  ZodType.init(inst, def);
11509
- inst._zod.processJSONSchema = (ctx, json, params) => transformProcessor(inst, ctx);
11659
+ inst._zod.processJSONSchema = (ctx, json2, params) => transformProcessor(inst, ctx);
11510
11660
  inst._zod.parse = (payload, _ctx) => {
11511
11661
  if (_ctx.direction === "backward") {
11512
11662
  throw new $ZodEncodeError(inst.constructor.name);
@@ -11546,7 +11696,7 @@ function transform(fn) {
11546
11696
  const ZodOptional = /* @__PURE__ */ $constructor("ZodOptional", (inst, def) => {
11547
11697
  $ZodOptional.init(inst, def);
11548
11698
  ZodType.init(inst, def);
11549
- inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params);
11699
+ inst._zod.processJSONSchema = (ctx, json2, params) => optionalProcessor(inst, ctx, json2, params);
11550
11700
  inst.unwrap = () => inst._zod.def.innerType;
11551
11701
  });
11552
11702
  function optional(innerType) {
@@ -11558,7 +11708,7 @@ function optional(innerType) {
11558
11708
  const ZodExactOptional = /* @__PURE__ */ $constructor("ZodExactOptional", (inst, def) => {
11559
11709
  $ZodExactOptional.init(inst, def);
11560
11710
  ZodType.init(inst, def);
11561
- inst._zod.processJSONSchema = (ctx, json, params) => optionalProcessor(inst, ctx, json, params);
11711
+ inst._zod.processJSONSchema = (ctx, json2, params) => optionalProcessor(inst, ctx, json2, params);
11562
11712
  inst.unwrap = () => inst._zod.def.innerType;
11563
11713
  });
11564
11714
  function exactOptional(innerType) {
@@ -11570,7 +11720,7 @@ function exactOptional(innerType) {
11570
11720
  const ZodNullable = /* @__PURE__ */ $constructor("ZodNullable", (inst, def) => {
11571
11721
  $ZodNullable.init(inst, def);
11572
11722
  ZodType.init(inst, def);
11573
- inst._zod.processJSONSchema = (ctx, json, params) => nullableProcessor(inst, ctx, json, params);
11723
+ inst._zod.processJSONSchema = (ctx, json2, params) => nullableProcessor(inst, ctx, json2, params);
11574
11724
  inst.unwrap = () => inst._zod.def.innerType;
11575
11725
  });
11576
11726
  function nullable(innerType) {
@@ -11582,7 +11732,7 @@ function nullable(innerType) {
11582
11732
  const ZodDefault = /* @__PURE__ */ $constructor("ZodDefault", (inst, def) => {
11583
11733
  $ZodDefault.init(inst, def);
11584
11734
  ZodType.init(inst, def);
11585
- inst._zod.processJSONSchema = (ctx, json, params) => defaultProcessor(inst, ctx, json, params);
11735
+ inst._zod.processJSONSchema = (ctx, json2, params) => defaultProcessor(inst, ctx, json2, params);
11586
11736
  inst.unwrap = () => inst._zod.def.innerType;
11587
11737
  inst.removeDefault = inst.unwrap;
11588
11738
  });
@@ -11598,7 +11748,7 @@ function _default(innerType, defaultValue) {
11598
11748
  const ZodPrefault = /* @__PURE__ */ $constructor("ZodPrefault", (inst, def) => {
11599
11749
  $ZodPrefault.init(inst, def);
11600
11750
  ZodType.init(inst, def);
11601
- inst._zod.processJSONSchema = (ctx, json, params) => prefaultProcessor(inst, ctx, json, params);
11751
+ inst._zod.processJSONSchema = (ctx, json2, params) => prefaultProcessor(inst, ctx, json2, params);
11602
11752
  inst.unwrap = () => inst._zod.def.innerType;
11603
11753
  });
11604
11754
  function prefault(innerType, defaultValue) {
@@ -11613,7 +11763,7 @@ function prefault(innerType, defaultValue) {
11613
11763
  const ZodNonOptional = /* @__PURE__ */ $constructor("ZodNonOptional", (inst, def) => {
11614
11764
  $ZodNonOptional.init(inst, def);
11615
11765
  ZodType.init(inst, def);
11616
- inst._zod.processJSONSchema = (ctx, json, params) => nonoptionalProcessor(inst, ctx, json, params);
11766
+ inst._zod.processJSONSchema = (ctx, json2, params) => nonoptionalProcessor(inst, ctx, json2, params);
11617
11767
  inst.unwrap = () => inst._zod.def.innerType;
11618
11768
  });
11619
11769
  function nonoptional(innerType, params) {
@@ -11626,7 +11776,7 @@ function nonoptional(innerType, params) {
11626
11776
  const ZodCatch = /* @__PURE__ */ $constructor("ZodCatch", (inst, def) => {
11627
11777
  $ZodCatch.init(inst, def);
11628
11778
  ZodType.init(inst, def);
11629
- inst._zod.processJSONSchema = (ctx, json, params) => catchProcessor(inst, ctx, json, params);
11779
+ inst._zod.processJSONSchema = (ctx, json2, params) => catchProcessor(inst, ctx, json2, params);
11630
11780
  inst.unwrap = () => inst._zod.def.innerType;
11631
11781
  inst.removeCatch = inst.unwrap;
11632
11782
  });
@@ -11640,7 +11790,7 @@ function _catch(innerType, catchValue) {
11640
11790
  const ZodPipe = /* @__PURE__ */ $constructor("ZodPipe", (inst, def) => {
11641
11791
  $ZodPipe.init(inst, def);
11642
11792
  ZodType.init(inst, def);
11643
- inst._zod.processJSONSchema = (ctx, json, params) => pipeProcessor(inst, ctx, json, params);
11793
+ inst._zod.processJSONSchema = (ctx, json2, params) => pipeProcessor(inst, ctx, json2, params);
11644
11794
  inst.in = def.in;
11645
11795
  inst.out = def.out;
11646
11796
  });
@@ -11655,7 +11805,7 @@ function pipe(in_, out) {
11655
11805
  const ZodReadonly = /* @__PURE__ */ $constructor("ZodReadonly", (inst, def) => {
11656
11806
  $ZodReadonly.init(inst, def);
11657
11807
  ZodType.init(inst, def);
11658
- inst._zod.processJSONSchema = (ctx, json, params) => readonlyProcessor(inst, ctx, json, params);
11808
+ inst._zod.processJSONSchema = (ctx, json2, params) => readonlyProcessor(inst, ctx, json2, params);
11659
11809
  inst.unwrap = () => inst._zod.def.innerType;
11660
11810
  });
11661
11811
  function readonly(innerType) {
@@ -11667,7 +11817,7 @@ function readonly(innerType) {
11667
11817
  const ZodCustom = /* @__PURE__ */ $constructor("ZodCustom", (inst, def) => {
11668
11818
  $ZodCustom.init(inst, def);
11669
11819
  ZodType.init(inst, def);
11670
- inst._zod.processJSONSchema = (ctx, json, params) => customProcessor(inst, ctx);
11820
+ inst._zod.processJSONSchema = (ctx, json2, params) => customProcessor(inst, ctx);
11671
11821
  });
11672
11822
  function refine(fn, _params = {}) {
11673
11823
  return /* @__PURE__ */ _refine(ZodCustom, fn, _params);
@@ -11705,7 +11855,7 @@ const EMPTY_AI_USAGE = {
11705
11855
  };
11706
11856
  const OPERATIONS = ["commit-message", "pull-request-draft"];
11707
11857
  const STATUSES = ["success", "failed", "cancelled"];
11708
- const HARNESSES = ["codex", "claude", "opencode"];
11858
+ const HARNESSES = ["codex", "claude", "opencode", "grok"];
11709
11859
  const MAX_TEXT$1 = 200;
11710
11860
  const MAX_ERROR_TEXT = 400;
11711
11861
  const aiUsageRecordSchema = looseObject({
@@ -11884,8 +12034,8 @@ class AiLogStore {
11884
12034
  }
11885
12035
  /** Records one run. Never rejects; failures are dropped on purpose. */
11886
12036
  append(entry) {
11887
- const record = { ...entry, id: randomUUID(), at: (/* @__PURE__ */ new Date()).toISOString() };
11888
- const normalized = normalizeAiLogEntry(record);
12037
+ const record2 = { ...entry, id: randomUUID(), at: (/* @__PURE__ */ new Date()).toISOString() };
12038
+ const normalized = normalizeAiLogEntry(record2);
11889
12039
  if (!normalized) return;
11890
12040
  this.pending = this.pending.then(async () => {
11891
12041
  await mkdir(path.dirname(this.filePath), { recursive: true });
@@ -11985,23 +12135,23 @@ function parseGeneratedParts(value) {
11985
12135
  const parsed = generatedPartsSchema.safeParse(value);
11986
12136
  if (!parsed.success || `${parsed.data.subject}
11987
12137
 
11988
- ${parsed.data.body}`.length > 1e4) throw invalidOutput$3();
12138
+ ${parsed.data.body}`.length > 1e4) throw invalidOutput$4();
11989
12139
  return parsed.data;
11990
12140
  }
11991
12141
  function parseCommitSplitProposal(value, stagedPaths) {
11992
12142
  if (!value || typeof value !== "object") return { status: "absent" };
11993
- const record = value;
11994
- if (record.commits === void 0 || Array.isArray(record.commits) && record.commits.length === 0) return { status: "absent" };
11995
- if (!Array.isArray(record.commits)) return { status: "rejected", reason: "commits was not a list" };
12143
+ const record2 = value;
12144
+ if (record2.commits === void 0 || Array.isArray(record2.commits) && record2.commits.length === 0) return { status: "absent" };
12145
+ if (!Array.isArray(record2.commits)) return { status: "rejected", reason: "commits was not a list" };
11996
12146
  if (stagedPaths.length < 2) return { status: "absent" };
11997
- if (record.commits.length < 2) return { status: "rejected", reason: "fewer than two groups" };
11998
- if (record.commits.length > 8) return { status: "rejected", reason: `too many groups (${record.commits.length})` };
11999
- const rationale = cleanText(record.rationale, 1e3);
12147
+ if (record2.commits.length < 2) return { status: "rejected", reason: "fewer than two groups" };
12148
+ if (record2.commits.length > 8) return { status: "rejected", reason: `too many groups (${record2.commits.length})` };
12149
+ const rationale = cleanText(record2.rationale, 1e3);
12000
12150
  if (rationale === null) return { status: "rejected", reason: "missing or unusable rationale" };
12001
12151
  const allowed = new Set(stagedPaths);
12002
12152
  const used = /* @__PURE__ */ new Set();
12003
12153
  const commits = [];
12004
- for (const candidate of record.commits) {
12154
+ for (const candidate of record2.commits) {
12005
12155
  if (!candidate || typeof candidate !== "object") return { status: "rejected", reason: "a group was not an object" };
12006
12156
  let parts;
12007
12157
  try {
@@ -12045,14 +12195,14 @@ function parseJsonPayload(raw) {
12045
12195
  if (nested instanceof AiOperationError) throw nested;
12046
12196
  }
12047
12197
  }
12048
- throw invalidOutput$3();
12198
+ throw invalidOutput$4();
12049
12199
  }
12050
12200
  }
12051
12201
  function asRecord(value) {
12052
- if (!value || typeof value !== "object" || Array.isArray(value)) throw invalidOutput$3();
12202
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw invalidOutput$4();
12053
12203
  return value;
12054
12204
  }
12055
- function invalidOutput$3() {
12205
+ function invalidOutput$4() {
12056
12206
  return new AiOperationError({ code: "AI_INVALID_OUTPUT", operation: "ai-parse-output", message: "The AI returned a message with an invalid format.", retryable: true });
12057
12207
  }
12058
12208
  function hasControlCharacters$6(value, allowWhitespace) {
@@ -12144,7 +12294,7 @@ ${parts.body}` : parts.subject,
12144
12294
  splitBlockedReason: context.splitBlockedReason
12145
12295
  };
12146
12296
  } catch (error) {
12147
- const failure = failureLogFields(error);
12297
+ const failure2 = failureLogFields(error);
12148
12298
  recordSafely(this.log, {
12149
12299
  operation: "commit-message",
12150
12300
  harness: input.harness,
@@ -12152,10 +12302,10 @@ ${parts.body}` : parts.subject,
12152
12302
  repositoryId: input.repositoryId,
12153
12303
  // A cancellation is a decision, not a failure; merging the two would
12154
12304
  // poison any reliability figure taken from this log.
12155
- status: failure.status,
12305
+ status: failure2.status,
12156
12306
  durationMs: Date.now() - startedAt,
12157
- errorCode: failure.errorCode,
12158
- errorMessage: failure.errorMessage,
12307
+ errorCode: failure2.errorCode,
12308
+ errorMessage: failure2.errorMessage,
12159
12309
  usage,
12160
12310
  stagedFileCount,
12161
12311
  contextTruncated,
@@ -12226,10 +12376,10 @@ ${context.patch}`;
12226
12376
  }
12227
12377
  function parsePullRequestDraft(value) {
12228
12378
  const parsed = pullRequestDraftSchema.safeParse(value);
12229
- if (!parsed.success) throw invalidOutput$2();
12379
+ if (!parsed.success) throw invalidOutput$3();
12230
12380
  return parsed.data;
12231
12381
  }
12232
- function invalidOutput$2() {
12382
+ function invalidOutput$3() {
12233
12383
  return new AiOperationError({ code: "AI_INVALID_OUTPUT", operation: "ai-parse-pr-draft", message: "The AI returned a pull request draft with an invalid format.", retryable: true });
12234
12384
  }
12235
12385
  function hasControlCharacters$5(value, allowWhitespace) {
@@ -12279,8 +12429,8 @@ class PullRequestDraftService {
12279
12429
  this.record(input, "success", null, null, usage, contextTruncated, Date.now() - startedAt);
12280
12430
  return { ...parts, harness: input.harness, model: input.model, contextWasTruncated: context.truncated };
12281
12431
  } catch (error) {
12282
- const failure = failureLogFields(error);
12283
- this.record(input, failure.status, failure.errorCode, failure.errorMessage, usage, contextTruncated, Date.now() - startedAt);
12432
+ const failure2 = failureLogFields(error);
12433
+ this.record(input, failure2.status, failure2.errorCode, failure2.errorMessage, usage, contextTruncated, Date.now() - startedAt);
12284
12434
  throw error;
12285
12435
  } finally {
12286
12436
  this.active.delete(input.requestId);
@@ -12320,11 +12470,24 @@ function throwIfCancelled(signal, harness) {
12320
12470
  }
12321
12471
  const AI_PROVIDER_TIMEOUT_MS = 9 * 6e4;
12322
12472
  const AI_SERVER_TIMEOUT_MS = AI_PROVIDER_TIMEOUT_MS + 3e4;
12323
- const DEFAULT_MODEL = { id: "default", label: "Default (CLI)" };
12473
+ const DEFAULT_MODEL$1 = { id: "default", label: "Default (CLI)" };
12474
+ function grokUsage(envelope) {
12475
+ if (!envelope || typeof envelope !== "object") return { ...EMPTY_AI_USAGE };
12476
+ const record2 = envelope;
12477
+ const usage = record2.usage && typeof record2.usage === "object" ? record2.usage : {};
12478
+ return {
12479
+ inputTokens: count(usage.input_tokens),
12480
+ outputTokens: count(usage.output_tokens),
12481
+ reasoningTokens: count(usage.reasoning_tokens),
12482
+ cacheReadTokens: count(usage.cache_read_input_tokens),
12483
+ cacheWriteTokens: count(usage.cache_creation_input_tokens),
12484
+ costUsd: count(record2.total_cost_usd, true)
12485
+ };
12486
+ }
12324
12487
  function claudeUsage(envelope) {
12325
12488
  if (!envelope || typeof envelope !== "object") return { ...EMPTY_AI_USAGE };
12326
- const record = envelope;
12327
- const usage = record.usage ?? {};
12489
+ const record2 = envelope;
12490
+ const usage = record2.usage ?? {};
12328
12491
  const details = usage.output_tokens_details ?? {};
12329
12492
  return {
12330
12493
  inputTokens: count(usage.input_tokens),
@@ -12332,7 +12495,7 @@ function claudeUsage(envelope) {
12332
12495
  reasoningTokens: count(details.thinking_tokens),
12333
12496
  cacheReadTokens: count(usage.cache_read_input_tokens),
12334
12497
  cacheWriteTokens: count(usage.cache_creation_input_tokens),
12335
- costUsd: count(record.total_cost_usd, true)
12498
+ costUsd: count(record2.total_cost_usd, true)
12336
12499
  };
12337
12500
  }
12338
12501
  function codexUsage(stdout) {
@@ -12358,20 +12521,6 @@ function codexUsage(stdout) {
12358
12521
  costUsd: null
12359
12522
  };
12360
12523
  }
12361
- function openCodeUsage(info) {
12362
- if (!info || typeof info !== "object") return { ...EMPTY_AI_USAGE };
12363
- const record = info;
12364
- const tokens = record.tokens ?? {};
12365
- const cache = tokens.cache ?? {};
12366
- return {
12367
- inputTokens: count(tokens.input),
12368
- outputTokens: count(tokens.output),
12369
- reasoningTokens: count(tokens.reasoning),
12370
- cacheReadTokens: count(cache.read),
12371
- cacheWriteTokens: count(cache.write),
12372
- costUsd: count(record.cost, true)
12373
- };
12374
- }
12375
12524
  function count(value, fractional = false) {
12376
12525
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return null;
12377
12526
  return fractional ? value : Math.round(value);
@@ -12420,7 +12569,7 @@ ${diagnostic ?? ""}`.toLowerCase();
12420
12569
  });
12421
12570
  }
12422
12571
  function label(harness) {
12423
- return harness === "codex" ? "Codex" : harness === "claude" ? "Claude Code" : "OpenCode";
12572
+ return harness === "codex" ? "Codex" : harness === "claude" ? "Claude Code" : harness === "grok" ? "Grok Build" : "OpenCode";
12424
12573
  }
12425
12574
  function stripAnsi(value) {
12426
12575
  return value.replace(new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g"), "");
@@ -12431,29 +12580,29 @@ function toCodexOutputSchema(schema) {
12431
12580
  function strictify(value) {
12432
12581
  if (!value || typeof value !== "object") return value;
12433
12582
  if (Array.isArray(value)) return value.map(strictify);
12434
- const record = { ...value };
12435
- delete record.$schema;
12436
- if (record.properties && typeof record.properties === "object" && !Array.isArray(record.properties)) {
12583
+ const record2 = { ...value };
12584
+ delete record2.$schema;
12585
+ if (record2.properties && typeof record2.properties === "object" && !Array.isArray(record2.properties)) {
12437
12586
  const properties = Object.fromEntries(
12438
- Object.entries(record.properties).map(([key, item]) => [key, strictify(item)])
12587
+ Object.entries(record2.properties).map(([key, item]) => [key, strictify(item)])
12439
12588
  );
12440
- record.properties = properties;
12441
- record.required = Object.keys(properties);
12442
- record.additionalProperties = false;
12589
+ record2.properties = properties;
12590
+ record2.required = Object.keys(properties);
12591
+ record2.additionalProperties = false;
12443
12592
  }
12444
- if ("items" in record) record.items = strictify(record.items);
12593
+ if ("items" in record2) record2.items = strictify(record2.items);
12445
12594
  for (const key of ["$defs", "definitions"]) {
12446
- const defs = record[key];
12595
+ const defs = record2[key];
12447
12596
  if (defs && typeof defs === "object" && !Array.isArray(defs)) {
12448
- record[key] = Object.fromEntries(
12597
+ record2[key] = Object.fromEntries(
12449
12598
  Object.entries(defs).map(([name, item]) => [name, strictify(item)])
12450
12599
  );
12451
12600
  }
12452
12601
  }
12453
12602
  for (const key of ["anyOf", "oneOf", "allOf"]) {
12454
- if (Array.isArray(record[key])) record[key] = record[key].map(strictify);
12603
+ if (Array.isArray(record2[key])) record2[key] = record2[key].map(strictify);
12455
12604
  }
12456
- return record;
12605
+ return record2;
12457
12606
  }
12458
12607
  function cliDiagnostic(result) {
12459
12608
  let fromTurn = null;
@@ -12514,7 +12663,7 @@ function flattenWhitespace(value) {
12514
12663
  }
12515
12664
  return flattened.replace(/ {2,}/g, " ").trim();
12516
12665
  }
12517
- const MODELS = [DEFAULT_MODEL, { id: "sonnet", label: "Sonnet" }, { id: "opus", label: "Opus" }, { id: "haiku", label: "Haiku" }];
12666
+ const MODELS = [DEFAULT_MODEL$1, { id: "sonnet", label: "Sonnet" }, { id: "opus", label: "Opus" }, { id: "haiku", label: "Haiku" }];
12518
12667
  class ClaudeProvider {
12519
12668
  constructor(resolver, runner) {
12520
12669
  this.resolver = resolver;
@@ -12576,15 +12725,15 @@ class CodexProvider {
12576
12725
  async status(forceRefresh = false) {
12577
12726
  const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
12578
12727
  const executable = await this.resolver.resolve("codex", forceRefresh);
12579
- if (!executable) return { id: this.id, label: "Codex", availability: "error", installed: false, authStatus: "unknown", message: "Install Codex CLI to use this harness.", models: [DEFAULT_MODEL], checkedAt };
12728
+ if (!executable) return { id: this.id, label: "Codex", availability: "error", installed: false, authStatus: "unknown", message: "Install Codex CLI to use this harness.", models: [DEFAULT_MODEL$1], checkedAt };
12580
12729
  const version2 = await this.runner.run(executable, ["--version"]);
12581
12730
  const login = await this.runner.run(executable, ["login", "status"]);
12582
12731
  if (login.exitCode !== 0 || !/logged in/i.test(`${login.stdout}
12583
12732
  ${login.stderr}`)) {
12584
- return { id: this.id, label: "Codex", availability: "error", installed: true, authStatus: "unauthenticated", version: version2.stdout.trim() || version2.stderr.trim(), message: "Run codex login.", models: [DEFAULT_MODEL], checkedAt };
12733
+ return { id: this.id, label: "Codex", availability: "error", installed: true, authStatus: "unauthenticated", version: version2.stdout.trim() || version2.stderr.trim(), message: "Run codex login.", models: [DEFAULT_MODEL$1], checkedAt };
12585
12734
  }
12586
12735
  const catalog = await this.runner.run(executable, ["debug", "models", "--bundled"]);
12587
- const models = catalog.exitCode === 0 ? parseCodexModels(catalog.stdout) : [DEFAULT_MODEL];
12736
+ const models = catalog.exitCode === 0 ? parseCodexModels(catalog.stdout) : [DEFAULT_MODEL$1];
12588
12737
  return {
12589
12738
  id: this.id,
12590
12739
  label: "Codex",
@@ -12620,2254 +12769,223 @@ function parseCodexModels(raw) {
12620
12769
  try {
12621
12770
  const parsed = JSON.parse(raw);
12622
12771
  const options = (parsed.models ?? []).filter((item) => typeof item.slug === "string" && item.visibility !== "hidden").map((item) => ({ id: item.slug, label: typeof item.display_name === "string" ? item.display_name : item.slug }));
12623
- return [DEFAULT_MODEL, ...options];
12772
+ return [DEFAULT_MODEL$1, ...options];
12624
12773
  } catch {
12625
- return [DEFAULT_MODEL];
12626
- }
12627
- }
12628
- const createSseClient = ({ onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url, ...options }) => {
12629
- let lastEventId;
12630
- const sleep = sseSleepFn ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
12631
- const createStream = async function* () {
12632
- let retryDelay = sseDefaultRetryDelay ?? 3e3;
12633
- let attempt = 0;
12634
- const signal = options.signal ?? new AbortController().signal;
12635
- while (true) {
12636
- if (signal.aborted)
12637
- break;
12638
- attempt++;
12639
- const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
12640
- if (lastEventId !== void 0) {
12641
- headers.set("Last-Event-ID", lastEventId);
12642
- }
12643
- try {
12644
- const response = await fetch(url, { ...options, headers, signal });
12645
- if (!response.ok)
12646
- throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
12647
- if (!response.body)
12648
- throw new Error("No body in SSE response");
12649
- const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
12650
- let buffer = "";
12651
- const abortHandler = () => {
12652
- try {
12653
- void reader.cancel();
12654
- } catch {
12655
- }
12656
- };
12657
- signal.addEventListener("abort", abortHandler);
12658
- try {
12659
- while (true) {
12660
- const { done, value } = await reader.read();
12661
- if (done)
12662
- break;
12663
- buffer += value;
12664
- const chunks = buffer.split("\n\n");
12665
- buffer = chunks.pop() ?? "";
12666
- for (const chunk of chunks) {
12667
- const lines = chunk.split("\n");
12668
- const dataLines = [];
12669
- let eventName;
12670
- for (const line of lines) {
12671
- if (line.startsWith("data:")) {
12672
- dataLines.push(line.replace(/^data:\s*/, ""));
12673
- } else if (line.startsWith("event:")) {
12674
- eventName = line.replace(/^event:\s*/, "");
12675
- } else if (line.startsWith("id:")) {
12676
- lastEventId = line.replace(/^id:\s*/, "");
12677
- } else if (line.startsWith("retry:")) {
12678
- const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10);
12679
- if (!Number.isNaN(parsed)) {
12680
- retryDelay = parsed;
12681
- }
12682
- }
12683
- }
12684
- let data;
12685
- let parsedJson = false;
12686
- if (dataLines.length) {
12687
- const rawData = dataLines.join("\n");
12688
- try {
12689
- data = JSON.parse(rawData);
12690
- parsedJson = true;
12691
- } catch {
12692
- data = rawData;
12693
- }
12694
- }
12695
- if (parsedJson) {
12696
- if (responseValidator) {
12697
- await responseValidator(data);
12698
- }
12699
- if (responseTransformer) {
12700
- data = await responseTransformer(data);
12701
- }
12702
- }
12703
- onSseEvent?.({
12704
- data,
12705
- event: eventName,
12706
- id: lastEventId,
12707
- retry: retryDelay
12708
- });
12709
- if (dataLines.length) {
12710
- yield data;
12711
- }
12712
- }
12713
- }
12714
- } finally {
12715
- signal.removeEventListener("abort", abortHandler);
12716
- reader.releaseLock();
12717
- }
12718
- break;
12719
- } catch (error) {
12720
- onSseError?.(error);
12721
- if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
12722
- break;
12723
- }
12724
- const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 3e4);
12725
- await sleep(backoff);
12726
- }
12727
- }
12728
- };
12729
- const stream = createStream();
12730
- return { stream };
12731
- };
12732
- const getAuthToken = async (auth, callback) => {
12733
- const token = typeof callback === "function" ? await callback(auth) : callback;
12734
- if (!token) {
12735
- return;
12736
- }
12737
- if (auth.scheme === "bearer") {
12738
- return `Bearer ${token}`;
12739
- }
12740
- if (auth.scheme === "basic") {
12741
- return `Basic ${btoa(token)}`;
12742
- }
12743
- return token;
12744
- };
12745
- const jsonBodySerializer = {
12746
- bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value)
12747
- };
12748
- const separatorArrayExplode = (style) => {
12749
- switch (style) {
12750
- case "label":
12751
- return ".";
12752
- case "matrix":
12753
- return ";";
12754
- case "simple":
12755
- return ",";
12756
- default:
12757
- return "&";
12758
- }
12759
- };
12760
- const separatorArrayNoExplode = (style) => {
12761
- switch (style) {
12762
- case "form":
12763
- return ",";
12764
- case "pipeDelimited":
12765
- return "|";
12766
- case "spaceDelimited":
12767
- return "%20";
12768
- default:
12769
- return ",";
12770
- }
12771
- };
12772
- const separatorObjectExplode = (style) => {
12773
- switch (style) {
12774
- case "label":
12775
- return ".";
12776
- case "matrix":
12777
- return ";";
12778
- case "simple":
12779
- return ",";
12780
- default:
12781
- return "&";
12782
- }
12783
- };
12784
- const serializeArrayParam = ({ allowReserved, explode, name, style, value }) => {
12785
- if (!explode) {
12786
- const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
12787
- switch (style) {
12788
- case "label":
12789
- return `.${joinedValues2}`;
12790
- case "matrix":
12791
- return `;${name}=${joinedValues2}`;
12792
- case "simple":
12793
- return joinedValues2;
12794
- default:
12795
- return `${name}=${joinedValues2}`;
12796
- }
12797
- }
12798
- const separator = separatorArrayExplode(style);
12799
- const joinedValues = value.map((v) => {
12800
- if (style === "label" || style === "simple") {
12801
- return allowReserved ? v : encodeURIComponent(v);
12802
- }
12803
- return serializePrimitiveParam({
12804
- allowReserved,
12805
- name,
12806
- value: v
12807
- });
12808
- }).join(separator);
12809
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
12810
- };
12811
- const serializePrimitiveParam = ({ allowReserved, name, value }) => {
12812
- if (value === void 0 || value === null) {
12813
- return "";
12814
- }
12815
- if (typeof value === "object") {
12816
- throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");
12817
- }
12818
- return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
12819
- };
12820
- const serializeObjectParam = ({ allowReserved, explode, name, style, value, valueOnly }) => {
12821
- if (value instanceof Date) {
12822
- return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
12823
- }
12824
- if (style !== "deepObject" && !explode) {
12825
- let values = [];
12826
- Object.entries(value).forEach(([key, v]) => {
12827
- values = [...values, key, allowReserved ? v : encodeURIComponent(v)];
12828
- });
12829
- const joinedValues2 = values.join(",");
12830
- switch (style) {
12831
- case "form":
12832
- return `${name}=${joinedValues2}`;
12833
- case "label":
12834
- return `.${joinedValues2}`;
12835
- case "matrix":
12836
- return `;${name}=${joinedValues2}`;
12837
- default:
12838
- return joinedValues2;
12839
- }
12840
- }
12841
- const separator = separatorObjectExplode(style);
12842
- const joinedValues = Object.entries(value).map(([key, v]) => serializePrimitiveParam({
12843
- allowReserved,
12844
- name: style === "deepObject" ? `${name}[${key}]` : key,
12845
- value: v
12846
- })).join(separator);
12847
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
12848
- };
12849
- const PATH_PARAM_RE = /\{[^{}]+\}/g;
12850
- const defaultPathSerializer = ({ path: path2, url: _url2 }) => {
12851
- let url = _url2;
12852
- const matches = _url2.match(PATH_PARAM_RE);
12853
- if (matches) {
12854
- for (const match of matches) {
12855
- let explode = false;
12856
- let name = match.substring(1, match.length - 1);
12857
- let style = "simple";
12858
- if (name.endsWith("*")) {
12859
- explode = true;
12860
- name = name.substring(0, name.length - 1);
12861
- }
12862
- if (name.startsWith(".")) {
12863
- name = name.substring(1);
12864
- style = "label";
12865
- } else if (name.startsWith(";")) {
12866
- name = name.substring(1);
12867
- style = "matrix";
12868
- }
12869
- const value = path2[name];
12870
- if (value === void 0 || value === null) {
12871
- continue;
12872
- }
12873
- if (Array.isArray(value)) {
12874
- url = url.replace(match, serializeArrayParam({ explode, name, style, value }));
12875
- continue;
12876
- }
12877
- if (typeof value === "object") {
12878
- url = url.replace(match, serializeObjectParam({
12879
- explode,
12880
- name,
12881
- style,
12882
- value,
12883
- valueOnly: true
12884
- }));
12885
- continue;
12886
- }
12887
- if (style === "matrix") {
12888
- url = url.replace(match, `;${serializePrimitiveParam({
12889
- name,
12890
- value
12891
- })}`);
12892
- continue;
12893
- }
12894
- const replaceValue = encodeURIComponent(style === "label" ? `.${value}` : value);
12895
- url = url.replace(match, replaceValue);
12896
- }
12897
- }
12898
- return url;
12899
- };
12900
- const getUrl = ({ baseUrl, path: path2, query, querySerializer, url: _url2 }) => {
12901
- const pathUrl = _url2.startsWith("/") ? _url2 : `/${_url2}`;
12902
- let url = (baseUrl ?? "") + pathUrl;
12903
- if (path2) {
12904
- url = defaultPathSerializer({ path: path2, url });
12905
- }
12906
- let search = query ? querySerializer(query) : "";
12907
- if (search.startsWith("?")) {
12908
- search = search.substring(1);
12909
- }
12910
- if (search) {
12911
- url += `?${search}`;
12912
- }
12913
- return url;
12914
- };
12915
- const createQuerySerializer = ({ allowReserved, array: array2, object: object2 } = {}) => {
12916
- const querySerializer = (queryParams) => {
12917
- const search = [];
12918
- if (queryParams && typeof queryParams === "object") {
12919
- for (const name in queryParams) {
12920
- const value = queryParams[name];
12921
- if (value === void 0 || value === null) {
12922
- continue;
12923
- }
12924
- if (Array.isArray(value)) {
12925
- const serializedArray = serializeArrayParam({
12926
- allowReserved,
12927
- explode: true,
12928
- name,
12929
- style: "form",
12930
- value,
12931
- ...array2
12932
- });
12933
- if (serializedArray)
12934
- search.push(serializedArray);
12935
- } else if (typeof value === "object") {
12936
- const serializedObject = serializeObjectParam({
12937
- allowReserved,
12938
- explode: true,
12939
- name,
12940
- style: "deepObject",
12941
- value,
12942
- ...object2
12943
- });
12944
- if (serializedObject)
12945
- search.push(serializedObject);
12946
- } else {
12947
- const serializedPrimitive = serializePrimitiveParam({
12948
- allowReserved,
12949
- name,
12950
- value
12951
- });
12952
- if (serializedPrimitive)
12953
- search.push(serializedPrimitive);
12954
- }
12955
- }
12956
- }
12957
- return search.join("&");
12958
- };
12959
- return querySerializer;
12960
- };
12961
- const getParseAs = (contentType) => {
12962
- if (!contentType) {
12963
- return "stream";
12964
- }
12965
- const cleanContent = contentType.split(";")[0]?.trim();
12966
- if (!cleanContent) {
12967
- return;
12968
- }
12969
- if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
12970
- return "json";
12971
- }
12972
- if (cleanContent === "multipart/form-data") {
12973
- return "formData";
12974
- }
12975
- if (["application/", "audio/", "image/", "video/"].some((type) => cleanContent.startsWith(type))) {
12976
- return "blob";
12977
- }
12978
- if (cleanContent.startsWith("text/")) {
12979
- return "text";
12980
- }
12981
- return;
12982
- };
12983
- const checkForExistence = (options, name) => {
12984
- if (!name) {
12985
- return false;
12986
- }
12987
- if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) {
12988
- return true;
12989
- }
12990
- return false;
12991
- };
12992
- const setAuthParams = async ({ security, ...options }) => {
12993
- for (const auth of security) {
12994
- if (checkForExistence(options, auth.name)) {
12995
- continue;
12996
- }
12997
- const token = await getAuthToken(auth, options.auth);
12998
- if (!token) {
12999
- continue;
13000
- }
13001
- const name = auth.name ?? "Authorization";
13002
- switch (auth.in) {
13003
- case "query":
13004
- if (!options.query) {
13005
- options.query = {};
13006
- }
13007
- options.query[name] = token;
13008
- break;
13009
- case "cookie":
13010
- options.headers.append("Cookie", `${name}=${token}`);
13011
- break;
13012
- case "header":
13013
- default:
13014
- options.headers.set(name, token);
13015
- break;
13016
- }
13017
- }
13018
- };
13019
- const buildUrl = (options) => getUrl({
13020
- baseUrl: options.baseUrl,
13021
- path: options.path,
13022
- query: options.query,
13023
- querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
13024
- url: options.url
13025
- });
13026
- const mergeConfigs = (a2, b) => {
13027
- const config2 = { ...a2, ...b };
13028
- if (config2.baseUrl?.endsWith("/")) {
13029
- config2.baseUrl = config2.baseUrl.substring(0, config2.baseUrl.length - 1);
13030
- }
13031
- config2.headers = mergeHeaders(a2.headers, b.headers);
13032
- return config2;
13033
- };
13034
- const mergeHeaders = (...headers) => {
13035
- const mergedHeaders = new Headers();
13036
- for (const header of headers) {
13037
- if (!header || typeof header !== "object") {
13038
- continue;
13039
- }
13040
- const iterator = header instanceof Headers ? header.entries() : Object.entries(header);
13041
- for (const [key, value] of iterator) {
13042
- if (value === null) {
13043
- mergedHeaders.delete(key);
13044
- } else if (Array.isArray(value)) {
13045
- for (const v of value) {
13046
- mergedHeaders.append(key, v);
13047
- }
13048
- } else if (value !== void 0) {
13049
- mergedHeaders.set(key, typeof value === "object" ? JSON.stringify(value) : value);
13050
- }
13051
- }
13052
- }
13053
- return mergedHeaders;
13054
- };
13055
- class Interceptors {
13056
- _fns;
13057
- constructor() {
13058
- this._fns = [];
13059
- }
13060
- clear() {
13061
- this._fns = [];
13062
- }
13063
- getInterceptorIndex(id) {
13064
- if (typeof id === "number") {
13065
- return this._fns[id] ? id : -1;
13066
- } else {
13067
- return this._fns.indexOf(id);
13068
- }
12774
+ return [DEFAULT_MODEL$1];
13069
12775
  }
13070
- exists(id) {
13071
- const index = this.getInterceptorIndex(id);
13072
- return !!this._fns[index];
13073
- }
13074
- eject(id) {
13075
- const index = this.getInterceptorIndex(id);
13076
- if (this._fns[index]) {
13077
- this._fns[index] = null;
13078
- }
12776
+ }
12777
+ function isSupportedGrokVersion(raw) {
12778
+ const match = /^grok (\d+)\.(\d+)\.(\d+)\b/i.exec(stripAnsi(raw).trim());
12779
+ return !!match && Number(match[1]) === 1 && (Number(match[2]) > 0 || Number(match[3]) >= 46);
12780
+ }
12781
+ function parseGrokModels(raw) {
12782
+ const text2 = stripAnsi(raw);
12783
+ const authStatus = /You are not authenticated\./.test(text2) ? "unauthenticated" : /You are logged in with |You are using XAI_API_KEY\.|is using its own API key\.|authenticated via deployment key/.test(text2) ? "authenticated" : "unknown";
12784
+ const models = [{ id: "default", label: "Default (Grok)" }];
12785
+ const seen = /* @__PURE__ */ new Set(["default"]);
12786
+ const catalog = text2.split("Available models:")[1] ?? "";
12787
+ for (const line of catalog.split(/\r?\n/)) {
12788
+ const match = /^\s+[*-]\s+([^\s]+?)(?:\s+\(default\))?\s*$/.exec(line);
12789
+ const id = match?.[1];
12790
+ if (id && id.length <= 200 && /^[\w.:/#-]+$/.test(id) && !seen.has(id)) {
12791
+ seen.add(id);
12792
+ models.push({ id, label: id });
12793
+ }
12794
+ }
12795
+ return { authStatus, models };
12796
+ }
12797
+ function parseGrokOutput(raw) {
12798
+ let envelope;
12799
+ try {
12800
+ envelope = parseJsonPayload(stripAnsi(raw));
12801
+ } catch {
12802
+ throw invalidOutput$2();
13079
12803
  }
13080
- update(id, fn) {
13081
- const index = this.getInterceptorIndex(id);
13082
- if (this._fns[index]) {
13083
- this._fns[index] = fn;
13084
- return id;
13085
- } else {
13086
- return false;
13087
- }
12804
+ if (envelope.type === "error" || envelope.structuredOutputError || envelope.stopReason !== "end_turn") throw invalidOutput$2();
12805
+ const structured = envelope.structuredOutput;
12806
+ if (structured !== void 0) {
12807
+ if (!structured || typeof structured !== "object" || Array.isArray(structured)) throw invalidOutput$2();
12808
+ return { envelope, output: structured };
13088
12809
  }
13089
- use(fn) {
13090
- this._fns = [...this._fns, fn];
13091
- return this._fns.length - 1;
12810
+ if (typeof envelope.text !== "string") throw invalidOutput$2();
12811
+ try {
12812
+ return { envelope, output: parseJsonPayload(envelope.text) };
12813
+ } catch {
12814
+ throw invalidOutput$2();
13092
12815
  }
13093
12816
  }
13094
- const createInterceptors = () => ({
13095
- error: new Interceptors(),
13096
- request: new Interceptors(),
13097
- response: new Interceptors()
13098
- });
13099
- const defaultQuerySerializer = createQuerySerializer({
13100
- allowReserved: false,
13101
- array: {
13102
- explode: true,
13103
- style: "form"
13104
- },
13105
- object: {
13106
- explode: true,
13107
- style: "deepObject"
12817
+ function invalidOutput$2() {
12818
+ return new AiOperationError({ code: "AI_INVALID_OUTPUT", operation: "grok-generate", harness: "grok", message: "Grok returned an incomplete or invalid structured response.", retryable: true });
12819
+ }
12820
+ const DEFAULT_MODEL = { id: "default", label: "Default (Grok)" };
12821
+ const UNSUPPORTED = "Grok Build 1.0.46 or later in the 1.x series is required, with headless JSON and tool controls.";
12822
+ const CONFIG = "[cli]\nauto_update = false\n[subagents]\nenabled = false\n[managed_mcps]\nenabled = false\ngateway_tools_enabled = false\n[memory]\nenabled = false\n[features]\nmanaged_config = false\ntitle_refresh = false\nturn_summary = false\n";
12823
+ const REQUIRED_FLAGS = ["--prompt-file", "--json-schema", "--output-format", "--tools", "--disallowed-tools", "--deny", "--disable-web-search", "--max-turns", "--permission-mode", "--verbatim"];
12824
+ class GrokProvider {
12825
+ constructor(resolver, runner) {
12826
+ this.resolver = resolver;
12827
+ this.runner = runner;
13108
12828
  }
13109
- });
13110
- const defaultHeaders = {
13111
- "Content-Type": "application/json"
13112
- };
13113
- const createConfig = (override = {}) => ({
13114
- ...jsonBodySerializer,
13115
- headers: defaultHeaders,
13116
- parseAs: "auto",
13117
- querySerializer: defaultQuerySerializer,
13118
- ...override
13119
- });
13120
- const createClient = (config2 = {}) => {
13121
- let _config = mergeConfigs(createConfig(), config2);
13122
- const getConfig = () => ({ ..._config });
13123
- const setConfig = (config3) => {
13124
- _config = mergeConfigs(_config, config3);
13125
- return getConfig();
13126
- };
13127
- const interceptors = createInterceptors();
13128
- const beforeRequest = async (options) => {
13129
- const opts = {
13130
- ..._config,
13131
- ...options,
13132
- fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
13133
- headers: mergeHeaders(_config.headers, options.headers),
13134
- serializedBody: void 0
13135
- };
13136
- if (opts.security) {
13137
- await setAuthParams({
13138
- ...opts,
13139
- security: opts.security
13140
- });
13141
- }
13142
- if (opts.requestValidator) {
13143
- await opts.requestValidator(opts);
13144
- }
13145
- if (opts.body && opts.bodySerializer) {
13146
- opts.serializedBody = opts.bodySerializer(opts.body);
13147
- }
13148
- if (opts.serializedBody === void 0 || opts.serializedBody === "") {
13149
- opts.headers.delete("Content-Type");
13150
- }
13151
- const url = buildUrl(opts);
13152
- return { opts, url };
13153
- };
13154
- const request = async (options) => {
13155
- const { opts, url } = await beforeRequest(options);
13156
- const requestInit = {
13157
- redirect: "follow",
13158
- ...opts,
13159
- body: opts.serializedBody
13160
- };
13161
- let request2 = new Request(url, requestInit);
13162
- for (const fn of interceptors.request._fns) {
13163
- if (fn) {
13164
- request2 = await fn(request2, opts);
13165
- }
13166
- }
13167
- const _fetch = opts.fetch;
13168
- let response = await _fetch(request2);
13169
- for (const fn of interceptors.response._fns) {
13170
- if (fn) {
13171
- response = await fn(response, request2, opts);
13172
- }
13173
- }
13174
- const result = {
13175
- request: request2,
13176
- response
13177
- };
13178
- if (response.ok) {
13179
- if (response.status === 204 || response.headers.get("Content-Length") === "0") {
13180
- return opts.responseStyle === "data" ? {} : {
13181
- data: {},
13182
- ...result
12829
+ resolver;
12830
+ runner;
12831
+ id = "grok";
12832
+ async status(forceRefresh = false) {
12833
+ const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
12834
+ const base = { id: this.id, label: "Grok Build", checkedAt, models: [DEFAULT_MODEL] };
12835
+ const executable = await this.resolver.resolve("grok", forceRefresh);
12836
+ if (!executable) return { ...base, installed: false, availability: "error", authStatus: "unknown", message: "Install the official Grok Build CLI and run grok login." };
12837
+ return this.withEnvironment(async (options) => {
12838
+ const version2 = await this.runner.run(executable, ["--version"], options);
12839
+ const versionText = version2.stdout.trim();
12840
+ const installed = { ...base, installed: true, version: versionText };
12841
+ if (version2.exitCode !== 0 || !isSupportedGrokVersion(versionText)) return { ...installed, availability: "error", authStatus: "unknown", message: UNSUPPORTED };
12842
+ try {
12843
+ await this.checkControls(executable, options);
12844
+ const result = await this.runner.run(executable, ["models"], options);
12845
+ if (result.exitCode !== 0) return { ...installed, availability: "warning", authStatus: "unknown", message: "Could not check Grok authentication or models. Check again or run grok models in a terminal." };
12846
+ const { authStatus, models } = parseGrokModels(result.stdout);
12847
+ return {
12848
+ ...installed,
12849
+ models,
12850
+ authStatus,
12851
+ availability: authStatus === "unauthenticated" ? "error" : authStatus === "authenticated" && models.length > 1 ? "ready" : "warning",
12852
+ ...authStatus === "unauthenticated" ? { message: "Run grok login, or provide XAI_API_KEY to the OpenTig process." } : authStatus === "unknown" ? { message: "Could not confirm Grok authentication." } : {}
13183
12853
  };
12854
+ } catch (error) {
12855
+ return { ...installed, availability: "error", authStatus: "unknown", message: error instanceof AiOperationError ? error.message : "Could not verify Grok execution controls." };
13184
12856
  }
13185
- const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
13186
- let data;
13187
- switch (parseAs) {
13188
- case "arrayBuffer":
13189
- case "blob":
13190
- case "formData":
13191
- case "json":
13192
- case "text":
13193
- data = await response[parseAs]();
13194
- break;
13195
- case "stream":
13196
- return opts.responseStyle === "data" ? response.body : {
13197
- data: response.body,
13198
- ...result
13199
- };
13200
- }
13201
- if (parseAs === "json") {
13202
- if (opts.responseValidator) {
13203
- await opts.responseValidator(data);
13204
- }
13205
- if (opts.responseTransformer) {
13206
- data = await opts.responseTransformer(data);
13207
- }
13208
- }
13209
- return opts.responseStyle === "data" ? data : {
13210
- data,
13211
- ...result
13212
- };
12857
+ });
12858
+ }
12859
+ async generate(input) {
12860
+ const executable = await this.resolver.resolve("grok");
12861
+ if (!executable) throw failure("AI_CLI_NOT_FOUND", "Grok Build is not installed.");
12862
+ const timeout = AbortSignal.timeout(AI_PROVIDER_TIMEOUT_MS);
12863
+ const signal = AbortSignal.any([input.signal, timeout]);
12864
+ try {
12865
+ return await this.withEnvironment(async (options) => {
12866
+ const controlled = { ...options, signal };
12867
+ const version2 = await this.runner.run(executable, ["--version"], controlled);
12868
+ if (version2.exitCode !== 0 || !isSupportedGrokVersion(version2.stdout)) throw failure("AI_PROCESS_FAILED", UNSUPPORTED);
12869
+ await this.checkControls(executable, controlled);
12870
+ const promptFile = path.join(options.cwd, "prompt.txt");
12871
+ await writeFile(promptFile, input.prompt, { encoding: "utf8", mode: 384 });
12872
+ const args = [
12873
+ "--prompt-file",
12874
+ promptFile,
12875
+ "--output-format",
12876
+ "json",
12877
+ "--json-schema",
12878
+ JSON.stringify(input.schema),
12879
+ "--verbatim",
12880
+ "--tools",
12881
+ "read_file",
12882
+ "--disallowed-tools",
12883
+ "read_file,search_tool,use_tool,Agent",
12884
+ "--deny",
12885
+ "MCPTool",
12886
+ "--disable-web-search",
12887
+ "--max-turns",
12888
+ "1",
12889
+ "--permission-mode",
12890
+ "dontAsk",
12891
+ "--no-memory"
12892
+ ];
12893
+ if (input.model !== "default") args.push("--model", input.model);
12894
+ const result = await this.runner.run(executable, args, { ...controlled, timeoutMs: AI_PROVIDER_TIMEOUT_MS });
12895
+ requireGrokSuccess(result);
12896
+ const parsed = parseGrokOutput(result.stdout);
12897
+ return { output: parsed.output, usage: grokUsage(parsed.envelope) };
12898
+ });
12899
+ } catch (error) {
12900
+ if (input.signal.aborted) throw failure("AI_CANCELLED", "Generation canceled.");
12901
+ if (timeout.aborted) throw failure("AI_TIMEOUT", "Generation took too long.");
12902
+ throw error;
13213
12903
  }
13214
- const textError = await response.text();
13215
- let jsonError;
12904
+ }
12905
+ async checkControls(executable, options) {
12906
+ const help = await this.runner.run(executable, ["--help"], options);
12907
+ if (help.exitCode !== 0 || REQUIRED_FLAGS.some((flag2) => !help.stdout.includes(flag2))) throw failure("AI_PROCESS_FAILED", UNSUPPORTED);
12908
+ const result = await this.runner.run(executable, ["inspect", "--json"], options);
12909
+ let report;
13216
12910
  try {
13217
- jsonError = JSON.parse(textError);
12911
+ report = JSON.parse(result.stdout);
13218
12912
  } catch {
12913
+ throw failure("AI_PROCESS_FAILED", "Could not verify the isolated Grok configuration.");
13219
12914
  }
13220
- const error = jsonError ?? textError;
13221
- let finalError = error;
13222
- for (const fn of interceptors.error._fns) {
13223
- if (fn) {
13224
- finalError = await fn(error, response, request2, opts);
13225
- }
13226
- }
13227
- finalError = finalError || {};
13228
- if (opts.throwOnError) {
13229
- throw finalError;
12915
+ const surfaces = ["hooks", "plugins", "mcpServers", "projectInstructions"];
12916
+ if (result.exitCode !== 0 || !report || surfaces.some((key) => !Array.isArray(report[key]) || report[key].length > 0)) {
12917
+ throw failure("AI_PROCESS_FAILED", "Grok configuration includes hooks, plugins, MCP servers or instructions. OpenTig requires an isolated text-only configuration.");
13230
12918
  }
13231
- return opts.responseStyle === "data" ? void 0 : {
13232
- error: finalError,
13233
- ...result
13234
- };
13235
- };
13236
- const makeMethod = (method) => {
13237
- const fn = (options) => request({ ...options, method });
13238
- fn.sse = async (options) => {
13239
- const { opts, url } = await beforeRequest(options);
13240
- return createSseClient({
13241
- ...opts,
13242
- body: opts.body,
13243
- headers: opts.headers,
13244
- method,
13245
- url
13246
- });
13247
- };
13248
- return fn;
13249
- };
13250
- return {
13251
- buildUrl,
13252
- connect: makeMethod("CONNECT"),
13253
- delete: makeMethod("DELETE"),
13254
- get: makeMethod("GET"),
13255
- getConfig,
13256
- head: makeMethod("HEAD"),
13257
- interceptors,
13258
- options: makeMethod("OPTIONS"),
13259
- patch: makeMethod("PATCH"),
13260
- post: makeMethod("POST"),
13261
- put: makeMethod("PUT"),
13262
- request,
13263
- setConfig,
13264
- trace: makeMethod("TRACE")
13265
- };
13266
- };
13267
- const client = createClient(createConfig({
13268
- baseUrl: "http://localhost:4096"
13269
- }));
13270
- class _HeyApiClient {
13271
- _client = client;
13272
- constructor(args) {
13273
- if (args?.client) {
13274
- this._client = args.client;
12919
+ }
12920
+ async withEnvironment(run) {
12921
+ const temporary = await mkdtemp(path.join(os.tmpdir(), "opentig-grok-"));
12922
+ const userGrokHome = process.env.GROK_HOME || path.join(os.homedir(), ".grok");
12923
+ const authPath = path.resolve(process.env.GROK_AUTH_PATH || path.join(userGrokHome, "auth.json"));
12924
+ const privateGrokHome = path.join(temporary, ".grok");
12925
+ try {
12926
+ await mkdir(privateGrokHome, { mode: 448 });
12927
+ await writeFile(path.join(privateGrokHome, "config.toml"), CONFIG, { encoding: "utf8", mode: 384 });
12928
+ const env = {
12929
+ HOME: temporary,
12930
+ USERPROFILE: temporary,
12931
+ GROK_HOME: privateGrokHome,
12932
+ GROK_AUTH_PATH: authPath,
12933
+ XDG_CONFIG_HOME: path.join(temporary, "config"),
12934
+ XDG_DATA_HOME: path.join(temporary, "data"),
12935
+ XDG_CACHE_HOME: path.join(temporary, "cache"),
12936
+ GROK_SUBAGENTS: "0",
12937
+ GROK_MANAGED_MCPS_ENABLED: "0",
12938
+ GROK_MANAGED_MCP_GATEWAY_TOOLS_ENABLED: "0",
12939
+ GROK_TITLE_REFRESH: "0"
12940
+ };
12941
+ const preserved = /* @__PURE__ */ new Set([...Object.keys(env), "GROK_AUTH", "GROK_CODE_XAI_API_KEY"]);
12942
+ const removeEnv = Object.keys(process.env).filter((key) => key.startsWith("GROK_") && !preserved.has(key));
12943
+ return await run({ cwd: temporary, env, removeEnv });
12944
+ } finally {
12945
+ await rm(temporary, { recursive: true, force: true, maxRetries: 3 });
13275
12946
  }
13276
12947
  }
13277
12948
  }
13278
- class Global extends _HeyApiClient {
13279
- /**
13280
- * Get events
13281
- */
13282
- event(options) {
13283
- return (options?.client ?? this._client).get.sse({
13284
- url: "/global/event",
13285
- ...options
13286
- });
13287
- }
12949
+ function requireGrokSuccess(result) {
12950
+ if (result.exitCode === 0) return;
12951
+ const diagnostic = `${result.stdout}
12952
+ ${result.stderr}`.toLowerCase();
12953
+ if (/not authenticated|not logged|login required|unauth|authentication|sign in/.test(diagnostic)) throw failure("AI_AUTH_REQUIRED", "Sign in with grok login to generate content.");
12954
+ if (/rate.?limit|quota|usage limit|too many requests|credit/.test(diagnostic)) throw failure("AI_RATE_LIMITED", "Grok rejected the request because of a usage limit.");
12955
+ if (/model.*(not found|unavailable|invalid|access|not supported)|unknown model/.test(diagnostic)) throw failure("AI_MODEL_UNAVAILABLE", "The selected Grok model is unavailable.");
12956
+ throw failure("AI_PROCESS_FAILED", "Grok could not generate content.");
13288
12957
  }
13289
- class Project extends _HeyApiClient {
13290
- /**
13291
- * List all projects
13292
- */
13293
- list(options) {
13294
- return (options?.client ?? this._client).get({
13295
- url: "/project",
13296
- ...options
13297
- });
13298
- }
13299
- /**
13300
- * Get the current project
13301
- */
13302
- current(options) {
13303
- return (options?.client ?? this._client).get({
13304
- url: "/project/current",
13305
- ...options
13306
- });
13307
- }
13308
- }
13309
- class Pty extends _HeyApiClient {
13310
- /**
13311
- * List all PTY sessions
13312
- */
13313
- list(options) {
13314
- return (options?.client ?? this._client).get({
13315
- url: "/pty",
13316
- ...options
13317
- });
13318
- }
13319
- /**
13320
- * Create a new PTY session
13321
- */
13322
- create(options) {
13323
- return (options?.client ?? this._client).post({
13324
- url: "/pty",
13325
- ...options,
13326
- headers: {
13327
- "Content-Type": "application/json",
13328
- ...options?.headers
13329
- }
13330
- });
13331
- }
13332
- /**
13333
- * Remove a PTY session
13334
- */
13335
- remove(options) {
13336
- return (options.client ?? this._client).delete({
13337
- url: "/pty/{id}",
13338
- ...options
13339
- });
13340
- }
13341
- /**
13342
- * Get PTY session info
13343
- */
13344
- get(options) {
13345
- return (options.client ?? this._client).get({
13346
- url: "/pty/{id}",
13347
- ...options
13348
- });
13349
- }
13350
- /**
13351
- * Update PTY session
13352
- */
13353
- update(options) {
13354
- return (options.client ?? this._client).put({
13355
- url: "/pty/{id}",
13356
- ...options,
13357
- headers: {
13358
- "Content-Type": "application/json",
13359
- ...options.headers
13360
- }
13361
- });
13362
- }
13363
- /**
13364
- * Connect to a PTY session
13365
- */
13366
- connect(options) {
13367
- return (options.client ?? this._client).get({
13368
- url: "/pty/{id}/connect",
13369
- ...options
13370
- });
13371
- }
13372
- }
13373
- class Config extends _HeyApiClient {
13374
- /**
13375
- * Get config info
13376
- */
13377
- get(options) {
13378
- return (options?.client ?? this._client).get({
13379
- url: "/config",
13380
- ...options
13381
- });
13382
- }
13383
- /**
13384
- * Update config
13385
- */
13386
- update(options) {
13387
- return (options?.client ?? this._client).patch({
13388
- url: "/config",
13389
- ...options,
13390
- headers: {
13391
- "Content-Type": "application/json",
13392
- ...options?.headers
13393
- }
13394
- });
13395
- }
13396
- /**
13397
- * List all providers
13398
- */
13399
- providers(options) {
13400
- return (options?.client ?? this._client).get({
13401
- url: "/config/providers",
13402
- ...options
13403
- });
13404
- }
13405
- }
13406
- class Tool extends _HeyApiClient {
13407
- /**
13408
- * List all tool IDs (including built-in and dynamically registered)
13409
- */
13410
- ids(options) {
13411
- return (options?.client ?? this._client).get({
13412
- url: "/experimental/tool/ids",
13413
- ...options
13414
- });
13415
- }
13416
- /**
13417
- * List tools with JSON schema parameters for a provider/model
13418
- */
13419
- list(options) {
13420
- return (options.client ?? this._client).get({
13421
- url: "/experimental/tool",
13422
- ...options
13423
- });
13424
- }
13425
- }
13426
- class Instance extends _HeyApiClient {
13427
- /**
13428
- * Dispose the current instance
13429
- */
13430
- dispose(options) {
13431
- return (options?.client ?? this._client).post({
13432
- url: "/instance/dispose",
13433
- ...options
13434
- });
13435
- }
13436
- }
13437
- class Path extends _HeyApiClient {
13438
- /**
13439
- * Get the current path
13440
- */
13441
- get(options) {
13442
- return (options?.client ?? this._client).get({
13443
- url: "/path",
13444
- ...options
13445
- });
13446
- }
13447
- }
13448
- class Vcs extends _HeyApiClient {
13449
- /**
13450
- * Get VCS info for the current instance
13451
- */
13452
- get(options) {
13453
- return (options?.client ?? this._client).get({
13454
- url: "/vcs",
13455
- ...options
13456
- });
13457
- }
13458
- }
13459
- class Session extends _HeyApiClient {
13460
- /**
13461
- * List all sessions
13462
- */
13463
- list(options) {
13464
- return (options?.client ?? this._client).get({
13465
- url: "/session",
13466
- ...options
13467
- });
13468
- }
13469
- /**
13470
- * Create a new session
13471
- */
13472
- create(options) {
13473
- return (options?.client ?? this._client).post({
13474
- url: "/session",
13475
- ...options,
13476
- headers: {
13477
- "Content-Type": "application/json",
13478
- ...options?.headers
13479
- }
13480
- });
13481
- }
13482
- /**
13483
- * Get session status
13484
- */
13485
- status(options) {
13486
- return (options?.client ?? this._client).get({
13487
- url: "/session/status",
13488
- ...options
13489
- });
13490
- }
13491
- /**
13492
- * Delete a session and all its data
13493
- */
13494
- delete(options) {
13495
- return (options.client ?? this._client).delete({
13496
- url: "/session/{id}",
13497
- ...options
13498
- });
13499
- }
13500
- /**
13501
- * Get session
13502
- */
13503
- get(options) {
13504
- return (options.client ?? this._client).get({
13505
- url: "/session/{id}",
13506
- ...options
13507
- });
13508
- }
13509
- /**
13510
- * Update session properties
13511
- */
13512
- update(options) {
13513
- return (options.client ?? this._client).patch({
13514
- url: "/session/{id}",
13515
- ...options,
13516
- headers: {
13517
- "Content-Type": "application/json",
13518
- ...options.headers
13519
- }
13520
- });
13521
- }
13522
- /**
13523
- * Get a session's children
13524
- */
13525
- children(options) {
13526
- return (options.client ?? this._client).get({
13527
- url: "/session/{id}/children",
13528
- ...options
13529
- });
13530
- }
13531
- /**
13532
- * Get the todo list for a session
13533
- */
13534
- todo(options) {
13535
- return (options.client ?? this._client).get({
13536
- url: "/session/{id}/todo",
13537
- ...options
13538
- });
13539
- }
13540
- /**
13541
- * Analyze the app and create an AGENTS.md file
13542
- */
13543
- init(options) {
13544
- return (options.client ?? this._client).post({
13545
- url: "/session/{id}/init",
13546
- ...options,
13547
- headers: {
13548
- "Content-Type": "application/json",
13549
- ...options.headers
13550
- }
13551
- });
13552
- }
13553
- /**
13554
- * Fork an existing session at a specific message
13555
- */
13556
- fork(options) {
13557
- return (options.client ?? this._client).post({
13558
- url: "/session/{id}/fork",
13559
- ...options,
13560
- headers: {
13561
- "Content-Type": "application/json",
13562
- ...options.headers
13563
- }
13564
- });
13565
- }
13566
- /**
13567
- * Abort a session
13568
- */
13569
- abort(options) {
13570
- return (options.client ?? this._client).post({
13571
- url: "/session/{id}/abort",
13572
- ...options
13573
- });
13574
- }
13575
- /**
13576
- * Unshare the session
13577
- */
13578
- unshare(options) {
13579
- return (options.client ?? this._client).delete({
13580
- url: "/session/{id}/share",
13581
- ...options
13582
- });
13583
- }
13584
- /**
13585
- * Share a session
13586
- */
13587
- share(options) {
13588
- return (options.client ?? this._client).post({
13589
- url: "/session/{id}/share",
13590
- ...options
13591
- });
13592
- }
13593
- /**
13594
- * Get the diff for this session
13595
- */
13596
- diff(options) {
13597
- return (options.client ?? this._client).get({
13598
- url: "/session/{id}/diff",
13599
- ...options
13600
- });
13601
- }
13602
- /**
13603
- * Summarize the session
13604
- */
13605
- summarize(options) {
13606
- return (options.client ?? this._client).post({
13607
- url: "/session/{id}/summarize",
13608
- ...options,
13609
- headers: {
13610
- "Content-Type": "application/json",
13611
- ...options.headers
13612
- }
13613
- });
13614
- }
13615
- /**
13616
- * List messages for a session
13617
- */
13618
- messages(options) {
13619
- return (options.client ?? this._client).get({
13620
- url: "/session/{id}/message",
13621
- ...options
13622
- });
13623
- }
13624
- /**
13625
- * Create and send a new message to a session
13626
- */
13627
- prompt(options) {
13628
- return (options.client ?? this._client).post({
13629
- url: "/session/{id}/message",
13630
- ...options,
13631
- headers: {
13632
- "Content-Type": "application/json",
13633
- ...options.headers
13634
- }
13635
- });
13636
- }
13637
- /**
13638
- * Get a message from a session
13639
- */
13640
- message(options) {
13641
- return (options.client ?? this._client).get({
13642
- url: "/session/{id}/message/{messageID}",
13643
- ...options
13644
- });
13645
- }
13646
- /**
13647
- * Create and send a new message to a session, start if needed and return immediately
13648
- */
13649
- promptAsync(options) {
13650
- return (options.client ?? this._client).post({
13651
- url: "/session/{id}/prompt_async",
13652
- ...options,
13653
- headers: {
13654
- "Content-Type": "application/json",
13655
- ...options.headers
13656
- }
13657
- });
13658
- }
13659
- /**
13660
- * Send a new command to a session
13661
- */
13662
- command(options) {
13663
- return (options.client ?? this._client).post({
13664
- url: "/session/{id}/command",
13665
- ...options,
13666
- headers: {
13667
- "Content-Type": "application/json",
13668
- ...options.headers
13669
- }
13670
- });
13671
- }
13672
- /**
13673
- * Run a shell command
13674
- */
13675
- shell(options) {
13676
- return (options.client ?? this._client).post({
13677
- url: "/session/{id}/shell",
13678
- ...options,
13679
- headers: {
13680
- "Content-Type": "application/json",
13681
- ...options.headers
13682
- }
13683
- });
13684
- }
13685
- /**
13686
- * Revert a message
13687
- */
13688
- revert(options) {
13689
- return (options.client ?? this._client).post({
13690
- url: "/session/{id}/revert",
13691
- ...options,
13692
- headers: {
13693
- "Content-Type": "application/json",
13694
- ...options.headers
13695
- }
13696
- });
13697
- }
13698
- /**
13699
- * Restore all reverted messages
13700
- */
13701
- unrevert(options) {
13702
- return (options.client ?? this._client).post({
13703
- url: "/session/{id}/unrevert",
13704
- ...options
13705
- });
13706
- }
13707
- }
13708
- class Command extends _HeyApiClient {
13709
- /**
13710
- * List all commands
13711
- */
13712
- list(options) {
13713
- return (options?.client ?? this._client).get({
13714
- url: "/command",
13715
- ...options
13716
- });
13717
- }
13718
- }
13719
- class Oauth extends _HeyApiClient {
13720
- /**
13721
- * Authorize a provider using OAuth
13722
- */
13723
- authorize(options) {
13724
- return (options.client ?? this._client).post({
13725
- url: "/provider/{id}/oauth/authorize",
13726
- ...options,
13727
- headers: {
13728
- "Content-Type": "application/json",
13729
- ...options.headers
13730
- }
13731
- });
13732
- }
13733
- /**
13734
- * Handle OAuth callback for a provider
13735
- */
13736
- callback(options) {
13737
- return (options.client ?? this._client).post({
13738
- url: "/provider/{id}/oauth/callback",
13739
- ...options,
13740
- headers: {
13741
- "Content-Type": "application/json",
13742
- ...options.headers
13743
- }
13744
- });
13745
- }
13746
- }
13747
- class Provider extends _HeyApiClient {
13748
- /**
13749
- * List all providers
13750
- */
13751
- list(options) {
13752
- return (options?.client ?? this._client).get({
13753
- url: "/provider",
13754
- ...options
13755
- });
13756
- }
13757
- /**
13758
- * Get provider authentication methods
13759
- */
13760
- auth(options) {
13761
- return (options?.client ?? this._client).get({
13762
- url: "/provider/auth",
13763
- ...options
13764
- });
13765
- }
13766
- oauth = new Oauth({ client: this._client });
13767
- }
13768
- class Find extends _HeyApiClient {
13769
- /**
13770
- * Find text in files
13771
- */
13772
- text(options) {
13773
- return (options.client ?? this._client).get({
13774
- url: "/find",
13775
- ...options
13776
- });
13777
- }
13778
- /**
13779
- * Find files
13780
- */
13781
- files(options) {
13782
- return (options.client ?? this._client).get({
13783
- url: "/find/file",
13784
- ...options
13785
- });
13786
- }
13787
- /**
13788
- * Find workspace symbols
13789
- */
13790
- symbols(options) {
13791
- return (options.client ?? this._client).get({
13792
- url: "/find/symbol",
13793
- ...options
13794
- });
13795
- }
13796
- }
13797
- class File extends _HeyApiClient {
13798
- /**
13799
- * List files and directories
13800
- */
13801
- list(options) {
13802
- return (options.client ?? this._client).get({
13803
- url: "/file",
13804
- ...options
13805
- });
13806
- }
13807
- /**
13808
- * Read a file
13809
- */
13810
- read(options) {
13811
- return (options.client ?? this._client).get({
13812
- url: "/file/content",
13813
- ...options
13814
- });
13815
- }
13816
- /**
13817
- * Get file status
13818
- */
13819
- status(options) {
13820
- return (options?.client ?? this._client).get({
13821
- url: "/file/status",
13822
- ...options
13823
- });
13824
- }
13825
- }
13826
- class App extends _HeyApiClient {
13827
- /**
13828
- * Write a log entry to the server logs
13829
- */
13830
- log(options) {
13831
- return (options?.client ?? this._client).post({
13832
- url: "/log",
13833
- ...options,
13834
- headers: {
13835
- "Content-Type": "application/json",
13836
- ...options?.headers
13837
- }
13838
- });
13839
- }
13840
- /**
13841
- * List all agents
13842
- */
13843
- agents(options) {
13844
- return (options?.client ?? this._client).get({
13845
- url: "/agent",
13846
- ...options
13847
- });
13848
- }
13849
- }
13850
- class Auth extends _HeyApiClient {
13851
- /**
13852
- * Remove OAuth credentials for an MCP server
13853
- */
13854
- remove(options) {
13855
- return (options.client ?? this._client).delete({
13856
- url: "/mcp/{name}/auth",
13857
- ...options
13858
- });
13859
- }
13860
- /**
13861
- * Start OAuth authentication flow for an MCP server
13862
- */
13863
- start(options) {
13864
- return (options.client ?? this._client).post({
13865
- url: "/mcp/{name}/auth",
13866
- ...options
13867
- });
13868
- }
13869
- /**
13870
- * Complete OAuth authentication with authorization code
13871
- */
13872
- callback(options) {
13873
- return (options.client ?? this._client).post({
13874
- url: "/mcp/{name}/auth/callback",
13875
- ...options,
13876
- headers: {
13877
- "Content-Type": "application/json",
13878
- ...options.headers
13879
- }
13880
- });
13881
- }
13882
- /**
13883
- * Start OAuth flow and wait for callback (opens browser)
13884
- */
13885
- authenticate(options) {
13886
- return (options.client ?? this._client).post({
13887
- url: "/mcp/{name}/auth/authenticate",
13888
- ...options
13889
- });
13890
- }
13891
- /**
13892
- * Set authentication credentials
13893
- */
13894
- set(options) {
13895
- return (options.client ?? this._client).put({
13896
- url: "/auth/{id}",
13897
- ...options,
13898
- headers: {
13899
- "Content-Type": "application/json",
13900
- ...options.headers
13901
- }
13902
- });
13903
- }
13904
- }
13905
- class Mcp extends _HeyApiClient {
13906
- /**
13907
- * Get MCP server status
13908
- */
13909
- status(options) {
13910
- return (options?.client ?? this._client).get({
13911
- url: "/mcp",
13912
- ...options
13913
- });
13914
- }
13915
- /**
13916
- * Add MCP server dynamically
13917
- */
13918
- add(options) {
13919
- return (options?.client ?? this._client).post({
13920
- url: "/mcp",
13921
- ...options,
13922
- headers: {
13923
- "Content-Type": "application/json",
13924
- ...options?.headers
13925
- }
13926
- });
13927
- }
13928
- /**
13929
- * Connect an MCP server
13930
- */
13931
- connect(options) {
13932
- return (options.client ?? this._client).post({
13933
- url: "/mcp/{name}/connect",
13934
- ...options
13935
- });
13936
- }
13937
- /**
13938
- * Disconnect an MCP server
13939
- */
13940
- disconnect(options) {
13941
- return (options.client ?? this._client).post({
13942
- url: "/mcp/{name}/disconnect",
13943
- ...options
13944
- });
13945
- }
13946
- auth = new Auth({ client: this._client });
13947
- }
13948
- class Lsp extends _HeyApiClient {
13949
- /**
13950
- * Get LSP server status
13951
- */
13952
- status(options) {
13953
- return (options?.client ?? this._client).get({
13954
- url: "/lsp",
13955
- ...options
13956
- });
13957
- }
13958
- }
13959
- class Formatter extends _HeyApiClient {
13960
- /**
13961
- * Get formatter status
13962
- */
13963
- status(options) {
13964
- return (options?.client ?? this._client).get({
13965
- url: "/formatter",
13966
- ...options
13967
- });
13968
- }
13969
- }
13970
- class Control extends _HeyApiClient {
13971
- /**
13972
- * Get the next TUI request from the queue
13973
- */
13974
- next(options) {
13975
- return (options?.client ?? this._client).get({
13976
- url: "/tui/control/next",
13977
- ...options
13978
- });
13979
- }
13980
- /**
13981
- * Submit a response to the TUI request queue
13982
- */
13983
- response(options) {
13984
- return (options?.client ?? this._client).post({
13985
- url: "/tui/control/response",
13986
- ...options,
13987
- headers: {
13988
- "Content-Type": "application/json",
13989
- ...options?.headers
13990
- }
13991
- });
13992
- }
13993
- }
13994
- class Tui extends _HeyApiClient {
13995
- /**
13996
- * Append prompt to the TUI
13997
- */
13998
- appendPrompt(options) {
13999
- return (options?.client ?? this._client).post({
14000
- url: "/tui/append-prompt",
14001
- ...options,
14002
- headers: {
14003
- "Content-Type": "application/json",
14004
- ...options?.headers
14005
- }
14006
- });
14007
- }
14008
- /**
14009
- * Open the help dialog
14010
- */
14011
- openHelp(options) {
14012
- return (options?.client ?? this._client).post({
14013
- url: "/tui/open-help",
14014
- ...options
14015
- });
14016
- }
14017
- /**
14018
- * Open the session dialog
14019
- */
14020
- openSessions(options) {
14021
- return (options?.client ?? this._client).post({
14022
- url: "/tui/open-sessions",
14023
- ...options
14024
- });
14025
- }
14026
- /**
14027
- * Open the theme dialog
14028
- */
14029
- openThemes(options) {
14030
- return (options?.client ?? this._client).post({
14031
- url: "/tui/open-themes",
14032
- ...options
14033
- });
14034
- }
14035
- /**
14036
- * Open the model dialog
14037
- */
14038
- openModels(options) {
14039
- return (options?.client ?? this._client).post({
14040
- url: "/tui/open-models",
14041
- ...options
14042
- });
14043
- }
14044
- /**
14045
- * Submit the prompt
14046
- */
14047
- submitPrompt(options) {
14048
- return (options?.client ?? this._client).post({
14049
- url: "/tui/submit-prompt",
14050
- ...options
14051
- });
14052
- }
14053
- /**
14054
- * Clear the prompt
14055
- */
14056
- clearPrompt(options) {
14057
- return (options?.client ?? this._client).post({
14058
- url: "/tui/clear-prompt",
14059
- ...options
14060
- });
14061
- }
14062
- /**
14063
- * Execute a TUI command (e.g. agent_cycle)
14064
- */
14065
- executeCommand(options) {
14066
- return (options?.client ?? this._client).post({
14067
- url: "/tui/execute-command",
14068
- ...options,
14069
- headers: {
14070
- "Content-Type": "application/json",
14071
- ...options?.headers
14072
- }
14073
- });
14074
- }
14075
- /**
14076
- * Show a toast notification in the TUI
14077
- */
14078
- showToast(options) {
14079
- return (options?.client ?? this._client).post({
14080
- url: "/tui/show-toast",
14081
- ...options,
14082
- headers: {
14083
- "Content-Type": "application/json",
14084
- ...options?.headers
14085
- }
14086
- });
14087
- }
14088
- /**
14089
- * Publish a TUI event
14090
- */
14091
- publish(options) {
14092
- return (options?.client ?? this._client).post({
14093
- url: "/tui/publish",
14094
- ...options,
14095
- headers: {
14096
- "Content-Type": "application/json",
14097
- ...options?.headers
14098
- }
14099
- });
14100
- }
14101
- control = new Control({ client: this._client });
14102
- }
14103
- class Event extends _HeyApiClient {
14104
- /**
14105
- * Get events
14106
- */
14107
- subscribe(options) {
14108
- return (options?.client ?? this._client).get.sse({
14109
- url: "/event",
14110
- ...options
14111
- });
14112
- }
14113
- }
14114
- class OpencodeClient extends _HeyApiClient {
14115
- /**
14116
- * Respond to a permission request
14117
- */
14118
- postSessionIdPermissionsPermissionId(options) {
14119
- return (options.client ?? this._client).post({
14120
- url: "/session/{id}/permissions/{permissionID}",
14121
- ...options,
14122
- headers: {
14123
- "Content-Type": "application/json",
14124
- ...options.headers
14125
- }
14126
- });
14127
- }
14128
- global = new Global({ client: this._client });
14129
- project = new Project({ client: this._client });
14130
- pty = new Pty({ client: this._client });
14131
- config = new Config({ client: this._client });
14132
- tool = new Tool({ client: this._client });
14133
- instance = new Instance({ client: this._client });
14134
- path = new Path({ client: this._client });
14135
- vcs = new Vcs({ client: this._client });
14136
- session = new Session({ client: this._client });
14137
- command = new Command({ client: this._client });
14138
- provider = new Provider({ client: this._client });
14139
- find = new Find({ client: this._client });
14140
- file = new File({ client: this._client });
14141
- app = new App({ client: this._client });
14142
- mcp = new Mcp({ client: this._client });
14143
- lsp = new Lsp({ client: this._client });
14144
- formatter = new Formatter({ client: this._client });
14145
- tui = new Tui({ client: this._client });
14146
- auth = new Auth({ client: this._client });
14147
- event = new Event({ client: this._client });
14148
- }
14149
- function wrapClientError(error, response, request, opts) {
14150
- if (!opts?.throwOnError)
14151
- return error;
14152
- if (error instanceof Error)
14153
- return error;
14154
- if (typeof error === "object" && error !== null && Object.keys(error).length > 0) {
14155
- const obj = error;
14156
- const message = typeof obj.data?.message === "string" && obj.data.message || typeof obj.message === "string" && obj.message || typeof obj.name === "string" && obj.name || describe(request, response);
14157
- return new Error(message, { cause: { body: error, status: response?.status } });
14158
- }
14159
- if (typeof error === "string" && error.length > 0) {
14160
- return new Error(error, { cause: { body: error, status: response?.status } });
14161
- }
14162
- const reason = response ? "(empty response body)" : "network error (no response)";
14163
- return new Error(`opencode server ${describe(request, response)}: ${reason}`, {
14164
- cause: { body: error, status: response?.status }
14165
- });
14166
- }
14167
- function describe(request, response) {
14168
- const method = request?.method ?? "?";
14169
- const url = request?.url ?? "?";
14170
- const status = response?.status;
14171
- const statusText = response?.statusText;
14172
- return `${method} ${url}${status ? " → " + status : ""}${statusText ? " " + statusText : ""}`;
14173
- }
14174
- function pick(value, fallback) {
14175
- if (!value)
14176
- return;
14177
- if (!fallback)
14178
- return value;
14179
- if (value === fallback)
14180
- return fallback;
14181
- if (value === encodeURIComponent(fallback))
14182
- return fallback;
14183
- return value;
14184
- }
14185
- function rewrite(request, directory) {
14186
- if (request.method !== "GET" && request.method !== "HEAD")
14187
- return request;
14188
- const value = pick(request.headers.get("x-opencode-directory"), directory);
14189
- if (!value)
14190
- return request;
14191
- const url = new URL(request.url);
14192
- if (!url.searchParams.has("directory")) {
14193
- url.searchParams.set("directory", value);
14194
- }
14195
- const next = new Request(url, request);
14196
- next.headers.delete("x-opencode-directory");
14197
- return next;
14198
- }
14199
- function createOpencodeClient(config2) {
14200
- if (!config2?.fetch) {
14201
- const customFetch = (req) => {
14202
- req.timeout = false;
14203
- return fetch(req);
14204
- };
14205
- config2 = {
14206
- ...config2,
14207
- fetch: customFetch
14208
- };
14209
- }
14210
- if (config2?.directory) {
14211
- config2.headers = {
14212
- ...config2.headers,
14213
- "x-opencode-directory": encodeURIComponent(config2.directory)
14214
- };
14215
- }
14216
- const client2 = createClient(config2);
14217
- client2.interceptors.request.use((request) => rewrite(request, config2?.directory));
14218
- client2.interceptors.error.use(wrapClientError);
14219
- return new OpencodeClient({ client: client2 });
14220
- }
14221
- var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
14222
- function getDefaultExportFromCjs(x) {
14223
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
14224
- }
14225
- var crossSpawn = { exports: {} };
14226
- var windows;
14227
- var hasRequiredWindows;
14228
- function requireWindows() {
14229
- if (hasRequiredWindows) return windows;
14230
- hasRequiredWindows = 1;
14231
- windows = isexe;
14232
- isexe.sync = sync;
14233
- var fs2 = require$$0;
14234
- function checkPathExt(path2, options) {
14235
- var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
14236
- if (!pathext) {
14237
- return true;
14238
- }
14239
- pathext = pathext.split(";");
14240
- if (pathext.indexOf("") !== -1) {
14241
- return true;
14242
- }
14243
- for (var i2 = 0; i2 < pathext.length; i2++) {
14244
- var p = pathext[i2].toLowerCase();
14245
- if (p && path2.substr(-p.length).toLowerCase() === p) {
14246
- return true;
14247
- }
14248
- }
14249
- return false;
14250
- }
14251
- function checkStat(stat2, path2, options) {
14252
- if (!stat2.isSymbolicLink() && !stat2.isFile()) {
14253
- return false;
14254
- }
14255
- return checkPathExt(path2, options);
14256
- }
14257
- function isexe(path2, options, cb) {
14258
- fs2.stat(path2, function(er, stat2) {
14259
- cb(er, er ? false : checkStat(stat2, path2, options));
14260
- });
14261
- }
14262
- function sync(path2, options) {
14263
- return checkStat(fs2.statSync(path2), path2, options);
14264
- }
14265
- return windows;
14266
- }
14267
- var mode;
14268
- var hasRequiredMode;
14269
- function requireMode() {
14270
- if (hasRequiredMode) return mode;
14271
- hasRequiredMode = 1;
14272
- mode = isexe;
14273
- isexe.sync = sync;
14274
- var fs2 = require$$0;
14275
- function isexe(path2, options, cb) {
14276
- fs2.stat(path2, function(er, stat2) {
14277
- cb(er, er ? false : checkStat(stat2, options));
14278
- });
14279
- }
14280
- function sync(path2, options) {
14281
- return checkStat(fs2.statSync(path2), options);
14282
- }
14283
- function checkStat(stat2, options) {
14284
- return stat2.isFile() && checkMode(stat2, options);
14285
- }
14286
- function checkMode(stat2, options) {
14287
- var mod = stat2.mode;
14288
- var uid = stat2.uid;
14289
- var gid = stat2.gid;
14290
- var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
14291
- var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
14292
- var u2 = parseInt("100", 8);
14293
- var g = parseInt("010", 8);
14294
- var o2 = parseInt("001", 8);
14295
- var ug = u2 | g;
14296
- var ret = mod & o2 || mod & g && gid === myGid || mod & u2 && uid === myUid || mod & ug && myUid === 0;
14297
- return ret;
14298
- }
14299
- return mode;
14300
- }
14301
- var isexe_1;
14302
- var hasRequiredIsexe;
14303
- function requireIsexe() {
14304
- if (hasRequiredIsexe) return isexe_1;
14305
- hasRequiredIsexe = 1;
14306
- var core;
14307
- if (process.platform === "win32" || commonjsGlobal.TESTING_WINDOWS) {
14308
- core = requireWindows();
14309
- } else {
14310
- core = requireMode();
14311
- }
14312
- isexe_1 = isexe;
14313
- isexe.sync = sync;
14314
- function isexe(path2, options, cb) {
14315
- if (typeof options === "function") {
14316
- cb = options;
14317
- options = {};
14318
- }
14319
- if (!cb) {
14320
- if (typeof Promise !== "function") {
14321
- throw new TypeError("callback not provided");
14322
- }
14323
- return new Promise(function(resolve2, reject) {
14324
- isexe(path2, options || {}, function(er, is) {
14325
- if (er) {
14326
- reject(er);
14327
- } else {
14328
- resolve2(is);
14329
- }
14330
- });
14331
- });
14332
- }
14333
- core(path2, options || {}, function(er, is) {
14334
- if (er) {
14335
- if (er.code === "EACCES" || options && options.ignoreErrors) {
14336
- er = null;
14337
- is = false;
14338
- }
14339
- }
14340
- cb(er, is);
14341
- });
14342
- }
14343
- function sync(path2, options) {
14344
- try {
14345
- return core.sync(path2, options || {});
14346
- } catch (er) {
14347
- if (options && options.ignoreErrors || er.code === "EACCES") {
14348
- return false;
14349
- } else {
14350
- throw er;
14351
- }
14352
- }
14353
- }
14354
- return isexe_1;
14355
- }
14356
- var which_1;
14357
- var hasRequiredWhich;
14358
- function requireWhich() {
14359
- if (hasRequiredWhich) return which_1;
14360
- hasRequiredWhich = 1;
14361
- const isWindows2 = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
14362
- const path2 = require$$0$1;
14363
- const COLON = isWindows2 ? ";" : ":";
14364
- const isexe = requireIsexe();
14365
- const getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
14366
- const getPathInfo = (cmd, opt) => {
14367
- const colon = opt.colon || COLON;
14368
- const pathEnv = cmd.match(/\//) || isWindows2 && cmd.match(/\\/) ? [""] : [
14369
- // windows always checks the cwd first
14370
- ...isWindows2 ? [process.cwd()] : [],
14371
- ...(opt.path || process.env.PATH || /* istanbul ignore next: very unusual */
14372
- "").split(colon)
14373
- ];
14374
- const pathExtExe = isWindows2 ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : "";
14375
- const pathExt = isWindows2 ? pathExtExe.split(colon) : [""];
14376
- if (isWindows2) {
14377
- if (cmd.indexOf(".") !== -1 && pathExt[0] !== "")
14378
- pathExt.unshift("");
14379
- }
14380
- return {
14381
- pathEnv,
14382
- pathExt,
14383
- pathExtExe
14384
- };
14385
- };
14386
- const which = (cmd, opt, cb) => {
14387
- if (typeof opt === "function") {
14388
- cb = opt;
14389
- opt = {};
14390
- }
14391
- if (!opt)
14392
- opt = {};
14393
- const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
14394
- const found = [];
14395
- const step = (i2) => new Promise((resolve2, reject) => {
14396
- if (i2 === pathEnv.length)
14397
- return opt.all && found.length ? resolve2(found) : reject(getNotFoundError(cmd));
14398
- const ppRaw = pathEnv[i2];
14399
- const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
14400
- const pCmd = path2.join(pathPart, cmd);
14401
- const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
14402
- resolve2(subStep(p, i2, 0));
14403
- });
14404
- const subStep = (p, i2, ii) => new Promise((resolve2, reject) => {
14405
- if (ii === pathExt.length)
14406
- return resolve2(step(i2 + 1));
14407
- const ext = pathExt[ii];
14408
- isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
14409
- if (!er && is) {
14410
- if (opt.all)
14411
- found.push(p + ext);
14412
- else
14413
- return resolve2(p + ext);
14414
- }
14415
- return resolve2(subStep(p, i2, ii + 1));
14416
- });
14417
- });
14418
- return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
14419
- };
14420
- const whichSync = (cmd, opt) => {
14421
- opt = opt || {};
14422
- const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
14423
- const found = [];
14424
- for (let i2 = 0; i2 < pathEnv.length; i2++) {
14425
- const ppRaw = pathEnv[i2];
14426
- const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
14427
- const pCmd = path2.join(pathPart, cmd);
14428
- const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
14429
- for (let j = 0; j < pathExt.length; j++) {
14430
- const cur = p + pathExt[j];
14431
- try {
14432
- const is = isexe.sync(cur, { pathExt: pathExtExe });
14433
- if (is) {
14434
- if (opt.all)
14435
- found.push(cur);
14436
- else
14437
- return cur;
14438
- }
14439
- } catch (ex) {
14440
- }
14441
- }
14442
- }
14443
- if (opt.all && found.length)
14444
- return found;
14445
- if (opt.nothrow)
14446
- return null;
14447
- throw getNotFoundError(cmd);
14448
- };
14449
- which_1 = which;
14450
- which.sync = whichSync;
14451
- return which_1;
14452
- }
14453
- var pathKey$1 = { exports: {} };
14454
- var hasRequiredPathKey;
14455
- function requirePathKey() {
14456
- if (hasRequiredPathKey) return pathKey$1.exports;
14457
- hasRequiredPathKey = 1;
14458
- const pathKey2 = (options = {}) => {
14459
- const environment = options.env || process.env;
14460
- const platform2 = options.platform || process.platform;
14461
- if (platform2 !== "win32") {
14462
- return "PATH";
14463
- }
14464
- return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path";
14465
- };
14466
- pathKey$1.exports = pathKey2;
14467
- pathKey$1.exports.default = pathKey2;
14468
- return pathKey$1.exports;
14469
- }
14470
- var resolveCommand_1;
14471
- var hasRequiredResolveCommand;
14472
- function requireResolveCommand() {
14473
- if (hasRequiredResolveCommand) return resolveCommand_1;
14474
- hasRequiredResolveCommand = 1;
14475
- const path2 = require$$0$1;
14476
- const which = requireWhich();
14477
- const getPathKey = requirePathKey();
14478
- function resolveCommandAttempt(parsed, withoutPathExt) {
14479
- const env = parsed.options.env || process.env;
14480
- const cwd = process.cwd();
14481
- const hasCustomCwd = parsed.options.cwd != null;
14482
- const shouldSwitchCwd = hasCustomCwd && process.chdir !== void 0 && !process.chdir.disabled;
14483
- if (shouldSwitchCwd) {
14484
- try {
14485
- process.chdir(parsed.options.cwd);
14486
- } catch (err) {
14487
- }
14488
- }
14489
- let resolved;
14490
- try {
14491
- resolved = which.sync(parsed.command, {
14492
- path: env[getPathKey({ env })],
14493
- pathExt: withoutPathExt ? path2.delimiter : void 0
14494
- });
14495
- } catch (e) {
14496
- } finally {
14497
- if (shouldSwitchCwd) {
14498
- process.chdir(cwd);
14499
- }
14500
- }
14501
- if (resolved) {
14502
- resolved = path2.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
14503
- }
14504
- return resolved;
14505
- }
14506
- function resolveCommand(parsed) {
14507
- return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true);
14508
- }
14509
- resolveCommand_1 = resolveCommand;
14510
- return resolveCommand_1;
14511
- }
14512
- var _escape = {};
14513
- var hasRequired_escape;
14514
- function require_escape() {
14515
- if (hasRequired_escape) return _escape;
14516
- hasRequired_escape = 1;
14517
- const metaCharsRegExp2 = /([()\][%!^"`<>&|;, *?])/g;
14518
- function escapeCommand(arg) {
14519
- arg = arg.replace(metaCharsRegExp2, "^$1");
14520
- return arg;
14521
- }
14522
- function escapeArgument2(arg, doubleEscapeMetaChars) {
14523
- arg = `${arg}`;
14524
- arg = arg.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"');
14525
- arg = arg.replace(/(?=(\\+?)?)\1$/, "$1$1");
14526
- arg = `"${arg}"`;
14527
- arg = arg.replace(metaCharsRegExp2, "^$1");
14528
- if (doubleEscapeMetaChars) {
14529
- arg = arg.replace(metaCharsRegExp2, "^$1");
14530
- }
14531
- return arg;
14532
- }
14533
- _escape.command = escapeCommand;
14534
- _escape.argument = escapeArgument2;
14535
- return _escape;
14536
- }
14537
- var shebangRegex;
14538
- var hasRequiredShebangRegex;
14539
- function requireShebangRegex() {
14540
- if (hasRequiredShebangRegex) return shebangRegex;
14541
- hasRequiredShebangRegex = 1;
14542
- shebangRegex = /^#!(.*)/;
14543
- return shebangRegex;
14544
- }
14545
- var shebangCommand;
14546
- var hasRequiredShebangCommand;
14547
- function requireShebangCommand() {
14548
- if (hasRequiredShebangCommand) return shebangCommand;
14549
- hasRequiredShebangCommand = 1;
14550
- const shebangRegex2 = requireShebangRegex();
14551
- shebangCommand = (string2 = "") => {
14552
- const match = string2.match(shebangRegex2);
14553
- if (!match) {
14554
- return null;
14555
- }
14556
- const [path2, argument] = match[0].replace(/#! ?/, "").split(" ");
14557
- const binary = path2.split("/").pop();
14558
- if (binary === "env") {
14559
- return argument;
14560
- }
14561
- return argument ? `${binary} ${argument}` : binary;
14562
- };
14563
- return shebangCommand;
14564
- }
14565
- var readShebang_1;
14566
- var hasRequiredReadShebang;
14567
- function requireReadShebang() {
14568
- if (hasRequiredReadShebang) return readShebang_1;
14569
- hasRequiredReadShebang = 1;
14570
- const fs2 = require$$0;
14571
- const shebangCommand2 = requireShebangCommand();
14572
- function readShebang2(command2) {
14573
- const size = 150;
14574
- const buffer = Buffer.alloc(size);
14575
- let fd;
14576
- try {
14577
- fd = fs2.openSync(command2, "r");
14578
- fs2.readSync(fd, buffer, 0, size, 0);
14579
- fs2.closeSync(fd);
14580
- } catch (e) {
14581
- }
14582
- return shebangCommand2(buffer.toString());
14583
- }
14584
- readShebang_1 = readShebang2;
14585
- return readShebang_1;
14586
- }
14587
- var parse_1;
14588
- var hasRequiredParse;
14589
- function requireParse() {
14590
- if (hasRequiredParse) return parse_1;
14591
- hasRequiredParse = 1;
14592
- const path2 = require$$0$1;
14593
- const resolveCommand = requireResolveCommand();
14594
- const escape = require_escape();
14595
- const readShebang2 = requireReadShebang();
14596
- const isWin = process.platform === "win32";
14597
- const isExecutableRegExp = /\.(?:com|exe)$/i;
14598
- const isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
14599
- function detectShebang(parsed) {
14600
- parsed.file = resolveCommand(parsed);
14601
- const shebang = parsed.file && readShebang2(parsed.file);
14602
- if (shebang) {
14603
- parsed.args.unshift(parsed.file);
14604
- parsed.command = shebang;
14605
- return resolveCommand(parsed);
14606
- }
14607
- return parsed.file;
14608
- }
14609
- function parseNonShell(parsed) {
14610
- if (!isWin) {
14611
- return parsed;
14612
- }
14613
- const commandFile = detectShebang(parsed);
14614
- const needsShell = !isExecutableRegExp.test(commandFile);
14615
- if (parsed.options.forceShell || needsShell) {
14616
- const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
14617
- parsed.command = path2.normalize(parsed.command);
14618
- parsed.command = escape.command(parsed.command);
14619
- parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
14620
- const shellCommand = [parsed.command].concat(parsed.args).join(" ");
14621
- parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`];
14622
- parsed.command = process.env.comspec || "cmd.exe";
14623
- parsed.options.windowsVerbatimArguments = true;
14624
- }
14625
- return parsed;
14626
- }
14627
- function parse2(command2, args, options) {
14628
- if (args && !Array.isArray(args)) {
14629
- options = args;
14630
- args = null;
14631
- }
14632
- args = args ? args.slice(0) : [];
14633
- options = Object.assign({}, options);
14634
- const parsed = {
14635
- command: command2,
14636
- args,
14637
- options,
14638
- file: void 0,
14639
- original: {
14640
- command: command2,
14641
- args
14642
- }
14643
- };
14644
- return options.shell ? parsed : parseNonShell(parsed);
14645
- }
14646
- parse_1 = parse2;
14647
- return parse_1;
14648
- }
14649
- var enoent;
14650
- var hasRequiredEnoent;
14651
- function requireEnoent() {
14652
- if (hasRequiredEnoent) return enoent;
14653
- hasRequiredEnoent = 1;
14654
- const isWin = process.platform === "win32";
14655
- function notFoundError(original, syscall) {
14656
- return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
14657
- code: "ENOENT",
14658
- errno: "ENOENT",
14659
- syscall: `${syscall} ${original.command}`,
14660
- path: original.command,
14661
- spawnargs: original.args
14662
- });
14663
- }
14664
- function hookChildProcess(cp2, parsed) {
14665
- if (!isWin) {
14666
- return;
14667
- }
14668
- const originalEmit = cp2.emit;
14669
- cp2.emit = function(name, arg1) {
14670
- if (name === "exit") {
14671
- const err = verifyENOENT(arg1, parsed);
14672
- if (err) {
14673
- return originalEmit.call(cp2, "error", err);
14674
- }
14675
- }
14676
- return originalEmit.apply(cp2, arguments);
14677
- };
14678
- }
14679
- function verifyENOENT(status, parsed) {
14680
- if (isWin && status === 1 && !parsed.file) {
14681
- return notFoundError(parsed.original, "spawn");
14682
- }
14683
- return null;
14684
- }
14685
- function verifyENOENTSync(status, parsed) {
14686
- if (isWin && status === 1 && !parsed.file) {
14687
- return notFoundError(parsed.original, "spawnSync");
14688
- }
14689
- return null;
14690
- }
14691
- enoent = {
14692
- hookChildProcess,
14693
- verifyENOENT,
14694
- verifyENOENTSync,
14695
- notFoundError
14696
- };
14697
- return enoent;
14698
- }
14699
- var hasRequiredCrossSpawn;
14700
- function requireCrossSpawn() {
14701
- if (hasRequiredCrossSpawn) return crossSpawn.exports;
14702
- hasRequiredCrossSpawn = 1;
14703
- const cp2 = require$$0$2;
14704
- const parse2 = requireParse();
14705
- const enoent2 = requireEnoent();
14706
- function spawn2(command2, args, options) {
14707
- const parsed = parse2(command2, args, options);
14708
- const spawned = cp2.spawn(parsed.command, parsed.args, parsed.options);
14709
- enoent2.hookChildProcess(spawned, parsed);
14710
- return spawned;
14711
- }
14712
- function spawnSync2(command2, args, options) {
14713
- const parsed = parse2(command2, args, options);
14714
- const result = cp2.spawnSync(parsed.command, parsed.args, parsed.options);
14715
- result.error = result.error || enoent2.verifyENOENTSync(result.status, parsed);
14716
- return result;
14717
- }
14718
- crossSpawn.exports = spawn2;
14719
- crossSpawn.exports.spawn = spawn2;
14720
- crossSpawn.exports.sync = spawnSync2;
14721
- crossSpawn.exports._parse = parse2;
14722
- crossSpawn.exports._enoent = enoent2;
14723
- return crossSpawn.exports;
14724
- }
14725
- var crossSpawnExports = requireCrossSpawn();
14726
- const launch = /* @__PURE__ */ getDefaultExportFromCjs(crossSpawnExports);
14727
- function stop(proc) {
14728
- if (proc.exitCode !== null || proc.signalCode !== null)
14729
- return;
14730
- if (process.platform === "win32" && proc.pid) {
14731
- const out = spawnSync("taskkill", ["/pid", String(proc.pid), "/T", "/F"], { windowsHide: true });
14732
- if (!out.error && out.status === 0)
14733
- return;
14734
- }
14735
- proc.kill();
14736
- }
14737
- function bindAbort$1(proc, signal, onAbort) {
14738
- if (!signal)
14739
- return () => {
14740
- };
14741
- const abort = () => {
14742
- clear();
14743
- stop(proc);
14744
- onAbort?.();
14745
- };
14746
- const clear = () => {
14747
- signal.removeEventListener("abort", abort);
14748
- proc.off("exit", clear);
14749
- proc.off("error", clear);
14750
- };
14751
- signal.addEventListener("abort", abort, { once: true });
14752
- proc.on("exit", clear);
14753
- proc.on("error", clear);
14754
- if (signal.aborted)
14755
- abort();
14756
- return clear;
14757
- }
14758
- async function createOpencodeServer(options) {
14759
- options = Object.assign({
14760
- hostname: "127.0.0.1",
14761
- port: 4096,
14762
- timeout: 5e3
14763
- }, options ?? {});
14764
- const args = [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`];
14765
- if (options.config?.logLevel)
14766
- args.push(`--log-level=${options.config.logLevel}`);
14767
- const proc = launch(`opencode`, args, {
14768
- env: {
14769
- ...process.env,
14770
- OPENCODE_CONFIG_CONTENT: JSON.stringify(options.config ?? {})
14771
- }
14772
- });
14773
- let clear = () => {
14774
- };
14775
- const url = await new Promise((resolve2, reject) => {
14776
- const id = setTimeout(() => {
14777
- clear();
14778
- stop(proc);
14779
- reject(new Error(`Timeout waiting for server to start after ${options.timeout}ms`));
14780
- }, options.timeout);
14781
- let output = "";
14782
- let resolved = false;
14783
- proc.stdout?.on("data", (chunk) => {
14784
- if (resolved)
14785
- return;
14786
- output += chunk.toString();
14787
- const lines = output.split("\n");
14788
- for (const line of lines) {
14789
- if (line.startsWith("opencode server listening")) {
14790
- const match = line.match(/on\s+(https?:\/\/[^\s]+)/);
14791
- if (!match) {
14792
- clear();
14793
- stop(proc);
14794
- clearTimeout(id);
14795
- reject(new Error(`Failed to parse server url from output: ${line}`));
14796
- return;
14797
- }
14798
- clearTimeout(id);
14799
- resolved = true;
14800
- resolve2(match[1]);
14801
- return;
14802
- }
14803
- }
14804
- });
14805
- proc.stderr?.on("data", (chunk) => {
14806
- output += chunk.toString();
14807
- });
14808
- proc.on("exit", (code) => {
14809
- clearTimeout(id);
14810
- let msg = `Server exited with code ${code}`;
14811
- if (output.trim()) {
14812
- msg += `
14813
- Server output: ${output}`;
14814
- }
14815
- reject(new Error(msg));
14816
- });
14817
- proc.on("error", (error) => {
14818
- clearTimeout(id);
14819
- reject(error);
14820
- });
14821
- clear = bindAbort$1(proc, options.signal, () => {
14822
- clearTimeout(id);
14823
- reject(options.signal?.reason);
14824
- });
14825
- });
14826
- return {
14827
- url,
14828
- close() {
14829
- clear();
14830
- stop(proc);
14831
- }
14832
- };
12958
+ function failure(code, message) {
12959
+ return new AiOperationError({ code, operation: "grok-generate", harness: "grok", message });
14833
12960
  }
14834
12961
  function openCodeCliName(executable) {
14835
12962
  return path.parse(executable).name.toLowerCase() === "opencode2" ? "opencode2" : "opencode";
14836
12963
  }
14837
- function isOpenCodeV2(executable) {
14838
- return openCodeCliName(executable) === "opencode2";
12964
+ function isOpenCodeV2Version(raw) {
12965
+ return /^(?:opencode2?\s+)?v?2\.\d+\.\d+(?:[-+][\w.-]+)?$/.test(stripAnsi(raw).trim());
14839
12966
  }
14840
12967
  function openCodeLoginCommand(cliName) {
14841
12968
  return cliName === "opencode2" ? "opencode2 auth login" : "opencode auth login";
14842
12969
  }
14843
12970
  function parseOpenCodeAuthList(raw, exitCode) {
14844
12971
  if (exitCode !== 0) return "unknown";
14845
- const text2 = stripAnsi(raw);
14846
- if (/no authenticated/i.test(text2)) return "unauthenticated";
14847
- if (/credential/i.test(text2)) return "authenticated";
14848
- const lines = text2.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
14849
- if (lines.some((line) => /^[A-Za-z0-9._-]+$/.test(line) && !/^(providers?|credentials?|integrations?)$/i.test(line))) {
14850
- return "authenticated";
12972
+ try {
12973
+ const integrations = JSON.parse(stripAnsi(raw).trim());
12974
+ if (!Array.isArray(integrations) || integrations.some((item) => !item || typeof item !== "object" || !Array.isArray(item.connections))) return "unknown";
12975
+ return integrations.some((item) => item.connections.length > 0) ? "authenticated" : "unauthenticated";
12976
+ } catch {
14851
12977
  }
14852
12978
  return "unknown";
14853
12979
  }
14854
12980
  function parseOpenCodeModels(raw) {
14855
12981
  const seen = /* @__PURE__ */ new Set();
14856
- const models = stripAnsi(raw).split(/\r?\n/).map((line) => line.trim()).filter((line) => /^[A-Za-z0-9._-]+\/[A-Za-z0-9._:/-]+$/.test(line) && !seen.has(line) && seen.add(line)).map((id) => ({ id, label: id }));
14857
- return [DEFAULT_MODEL, ...models];
14858
- }
14859
- function parseOpenCodeV1Model(value) {
14860
- const slash = value.indexOf("/");
14861
- if (slash <= 0 || slash === value.length - 1) throw invalidModel();
14862
- return { providerID: value.slice(0, slash), modelID: value.slice(slash + 1) };
12982
+ const models = stripAnsi(raw).split(/\r?\n/).map((line) => line.trim()).filter((line) => /^[A-Za-z0-9._-]+\/[A-Za-z0-9._:/-]+(?:#[A-Za-z0-9._-]+)?$/.test(line) && !seen.has(line) && seen.add(line)).map((id) => ({ id, label: id }));
12983
+ return [DEFAULT_MODEL$1, ...models];
14863
12984
  }
14864
12985
  function parseOpenCodeV2ModelRef(value) {
14865
- const parsed = parseOpenCodeV1Model(value);
14866
- const hash = parsed.modelID.lastIndexOf("#");
14867
- if (hash > 0 && hash < parsed.modelID.length - 1) {
14868
- return { providerID: parsed.providerID, id: parsed.modelID.slice(0, hash), variant: parsed.modelID.slice(hash + 1) };
14869
- }
14870
- return { providerID: parsed.providerID, id: parsed.modelID };
12986
+ const match = /^([^/#\s]+)\/([^#\s]+)(?:#([^#\s]+))?$/.exec(value);
12987
+ if (!match?.[1] || !match[2]) throw invalidModel();
12988
+ return { providerID: match[1], id: match[2], ...match[3] ? { variant: match[3] } : {} };
14871
12989
  }
14872
12990
  function parseOpenCodeV2GenerateText(payload) {
14873
12991
  if (!payload || typeof payload !== "object") throw invalidOutput$1();
@@ -14921,12 +13039,12 @@ async function startOpenCodeV2Server(options) {
14921
13039
  });
14922
13040
  void subprocess.catch(() => void 0);
14923
13041
  let settled = false;
14924
- const stop2 = () => {
13042
+ const stop = () => {
14925
13043
  if (settled) return;
14926
13044
  settled = true;
14927
13045
  stopProcess(subprocess);
14928
13046
  };
14929
- const unbind = bindAbort(options.signal, stop2);
13047
+ const unbind = bindAbort(options.signal, stop);
14930
13048
  try {
14931
13049
  const url = await waitForListenUrl(subprocess, timeoutMs, options.signal);
14932
13050
  return {
@@ -14934,12 +13052,12 @@ async function startOpenCodeV2Server(options) {
14934
13052
  password,
14935
13053
  close() {
14936
13054
  unbind();
14937
- stop2();
13055
+ stop();
14938
13056
  }
14939
13057
  };
14940
13058
  } catch (error) {
14941
13059
  unbind();
14942
- stop2();
13060
+ stop();
14943
13061
  if (options.signal?.aborted) {
14944
13062
  throw new AiOperationError({ code: "AI_CANCELLED", operation: "opencode-server", harness: "opencode", message: "Generation canceled." });
14945
13063
  }
@@ -14952,8 +13070,9 @@ async function generateOpenCodeV2Text(server, input) {
14952
13070
  const created = await v2Request(server, "/api/session", {
14953
13071
  method: "POST",
14954
13072
  body: {
14955
- title: "OpenTig commit message",
13073
+ title: "OpenTig text generation",
14956
13074
  location: { directory: input.cwd },
13075
+ permissions: [{ action: "*", resource: "*", effect: "deny" }],
14957
13076
  ...model ? { model } : {}
14958
13077
  },
14959
13078
  signal
@@ -15006,7 +13125,7 @@ function throwIfV2Failed(status, payload, signal) {
15006
13125
  if (status === 401 || /not logged|login required|unauth|authentication|sign in/.test(raw)) {
15007
13126
  throw new AiOperationError({ code: "AI_AUTH_REQUIRED", operation: "opencode-generate", harness: "opencode", message: "Sign in to OpenCode to generate the message." });
15008
13127
  }
15009
- if (/rate.?limit|quota|usage limit|too many requests|credit/.test(raw)) {
13128
+ if (status === 429 || /rate.?limit|quota|usage limit|too many requests|credit/.test(raw)) {
15010
13129
  throw new AiOperationError({ code: "AI_RATE_LIMITED", operation: "opencode-generate", harness: "opencode", message: "OpenCode rejected the request because of a usage limit.", retryable: true });
15011
13130
  }
15012
13131
  if (/model.*(not found|unavailable|invalid|access)|unknown model|no model specified/.test(raw)) {
@@ -15089,7 +13208,7 @@ function freePort() {
15089
13208
  server.on("error", reject);
15090
13209
  });
15091
13210
  }
15092
- const DISABLED_TOOLS = { bash: false, edit: false, write: false, read: false, glob: false, grep: false, webfetch: false, websearch: false, task: false };
13211
+ const UNSUPPORTED_MESSAGE = "OpenCode 2.x is required. Upgrade the installed CLI; OpenCode 1 and legacy beta builds are not supported.";
15093
13212
  class OpenCodeProvider {
15094
13213
  constructor(resolver, runner) {
15095
13214
  this.resolver = resolver;
@@ -15101,18 +13220,17 @@ class OpenCodeProvider {
15101
13220
  servers = /* @__PURE__ */ new Set();
15102
13221
  async status(forceRefresh = false) {
15103
13222
  const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
15104
- const executable = await this.resolver.resolve("opencode", forceRefresh);
15105
- if (!executable) return { id: this.id, label: "OpenCode", availability: "error", installed: false, authStatus: "unknown", message: "Install OpenCode to use this harness.", models: [DEFAULT_MODEL], checkedAt };
13223
+ const detected = await this.detect(forceRefresh);
13224
+ if (!detected) return { id: this.id, label: "OpenCode", availability: "error", installed: false, authStatus: "unknown", message: "Install OpenCode 2 to use this harness.", models: [DEFAULT_MODEL$1], checkedAt };
13225
+ const { executable, version: version2, compatible } = detected;
15106
13226
  const cliName = openCodeCliName(executable);
15107
- const catalogArgs = cliName === "opencode2" ? ["models", "--standalone"] : ["models"];
15108
- const [version2, auth, catalog] = await Promise.all([
15109
- this.runner.run(executable, ["--version"]),
15110
- this.runner.run(executable, ["auth", "list"]),
15111
- this.runner.run(executable, catalogArgs, cliName === "opencode2" ? { timeoutMs: 3e4 } : {})
13227
+ if (!compatible) return { id: this.id, label: "OpenCode", availability: "error", installed: true, authStatus: "unknown", message: UNSUPPORTED_MESSAGE, cliName, version: version2, models: [DEFAULT_MODEL$1], checkedAt };
13228
+ const [auth, catalog] = await Promise.all([
13229
+ this.runner.run(executable, ["auth", "list", "--format", "json", "--standalone"]),
13230
+ this.runner.run(executable, ["models", "--standalone"], { timeoutMs: 3e4 })
15112
13231
  ]);
15113
- const models = catalog.exitCode === 0 ? parseOpenCodeModels(catalog.stdout) : [DEFAULT_MODEL];
15114
- let authStatus = parseOpenCodeAuthList(`${auth.stdout}
15115
- ${auth.stderr}`, auth.exitCode);
13232
+ const models = catalog.exitCode === 0 ? parseOpenCodeModels(catalog.stdout) : [DEFAULT_MODEL$1];
13233
+ let authStatus = parseOpenCodeAuthList(auth.stdout, auth.exitCode);
15116
13234
  if (authStatus === "unauthenticated" && models.length > 1) authStatus = "unknown";
15117
13235
  const confirmed = authStatus === "authenticated";
15118
13236
  return {
@@ -15122,19 +13240,21 @@ ${auth.stderr}`, auth.exitCode);
15122
13240
  installed: true,
15123
13241
  authStatus,
15124
13242
  cliName,
15125
- version: version2.stdout.trim() || version2.stderr.trim(),
13243
+ version: version2,
15126
13244
  models,
15127
13245
  checkedAt,
15128
13246
  ...authStatus === "unauthenticated" ? { message: `Run ${openCodeLoginCommand(cliName)}.` } : !confirmed ? { message: "Could not confirm authentication for the selected provider." } : {}
15129
13247
  };
15130
13248
  }
15131
13249
  async generate(input) {
15132
- const executable = await this.resolver.resolve("opencode");
15133
- if (!executable) throw new AiOperationError({ code: "AI_CLI_NOT_FOUND", operation: "opencode-generate", harness: this.id, message: "OpenCode is not installed." });
13250
+ const detected = await this.detect(false, input.signal);
13251
+ if (!detected) throw new AiOperationError({ code: "AI_CLI_NOT_FOUND", operation: "opencode-generate", harness: this.id, message: "OpenCode is not installed." });
13252
+ if (!detected.compatible) throw new AiOperationError({ code: "AI_PROCESS_FAILED", operation: "opencode-generate", harness: this.id, message: UNSUPPORTED_MESSAGE });
13253
+ const executable = detected.executable;
15134
13254
  const timeoutSignal = AbortSignal.timeout(AI_PROVIDER_TIMEOUT_MS);
15135
13255
  const boundedInput = { ...input, signal: AbortSignal.any([input.signal, timeoutSignal]) };
15136
13256
  try {
15137
- return await (isOpenCodeV2(executable) ? this.generateV2(executable, boundedInput) : this.generateV1(boundedInput));
13257
+ return await this.generateV2(executable, boundedInput);
15138
13258
  } catch (error) {
15139
13259
  if (timeoutSignal.aborted && !input.signal.aborted) {
15140
13260
  throw new AiOperationError({ code: "AI_TIMEOUT", operation: "opencode-generate", harness: this.id, message: "Generation took too long.", retryable: true });
@@ -15149,7 +13269,10 @@ ${auth.stderr}`, auth.exitCode);
15149
13269
  });
15150
13270
  this.servers.add(server);
15151
13271
  try {
15152
- const text2 = await generateOpenCodeV2Text(server, { prompt: input.prompt, model: input.model, cwd: input.repositoryPath, signal: input.signal });
13272
+ const text2 = await generateOpenCodeV2Text(server, { prompt: `Reply with a single JSON object satisfying this JSON Schema:
13273
+ ${JSON.stringify(input.schema)}
13274
+
13275
+ ${input.prompt}`, model: input.model, cwd: input.repositoryPath, signal: input.signal });
15153
13276
  return { output: parseJsonPayload(text2), usage: { ...EMPTY_AI_USAGE } };
15154
13277
  } catch (error) {
15155
13278
  if (input.signal.aborted) throw new AiOperationError({ code: "AI_CANCELLED", operation: "opencode-generate", harness: this.id, message: "Generation canceled." });
@@ -15162,53 +13285,22 @@ ${auth.stderr}`, auth.exitCode);
15162
13285
  this.servers.delete(server);
15163
13286
  }
15164
13287
  }
15165
- async generateV1(input) {
15166
- const server = await createOpencodeServer({
15167
- hostname: "127.0.0.1",
15168
- port: 0,
15169
- timeout: 15e3,
15170
- signal: input.signal,
15171
- config: { share: "disabled", autoupdate: false, plugin: [], instructions: [], tools: DISABLED_TOOLS, permission: { edit: "deny", bash: "deny", webfetch: "deny", external_directory: "deny" } }
15172
- }).catch(() => {
15173
- throw new AiOperationError({ code: "AI_PROCESS_FAILED", operation: "opencode-server", harness: this.id, message: "Could not start the local OpenCode server.", retryable: true });
15174
- });
15175
- this.servers.add(server);
15176
- const client2 = createOpencodeClient({ baseUrl: server.url, directory: input.repositoryPath });
15177
- let sessionId = null;
15178
- try {
15179
- const created = await client2.session.create({ body: { title: "OpenTig commit message" }, query: { directory: input.repositoryPath } });
15180
- if (!created.data?.id) throw new Error("missing session");
15181
- sessionId = created.data.id;
15182
- const model = input.model === "default" ? void 0 : parseOpenCodeV1Model(input.model);
15183
- const response = await client2.session.prompt({
15184
- path: { id: sessionId },
15185
- query: { directory: input.repositoryPath },
15186
- body: {
15187
- parts: [{ type: "text", text: input.prompt }],
15188
- tools: DISABLED_TOOLS,
15189
- // The server API takes no schema, unlike the Codex and Claude CLIs, so
15190
- // the only way to hold this harness to the contract is the system
15191
- // prompt. Without it the model answers in whatever shape it likes.
15192
- system: `Reply with a single JSON object and nothing else. It must satisfy this JSON Schema:
15193
- ${JSON.stringify(input.schema)}`,
15194
- ...model ? { model } : {}
15195
- }
15196
- });
15197
- const infoError = response.data?.info && "error" in response.data.info ? response.data.info.error : void 0;
15198
- if (infoError) throw new Error("provider rejected request");
15199
- const text2 = (response.data?.parts ?? []).filter((part) => part.type === "text" && "text" in part && typeof part.text === "string").map((part) => part.text).join("").trim();
15200
- return { output: parseJsonPayload(text2), usage: openCodeUsage(response.data?.info) };
15201
- } catch (error) {
15202
- if (input.signal?.aborted) throw new AiOperationError({ code: "AI_CANCELLED", operation: "opencode-generate", harness: this.id, message: "Generation canceled." });
15203
- if (error instanceof AiOperationError) throw error;
15204
- const synthetic = { exitCode: 1, stdout: "", stderr: error instanceof Error ? error.message : "" };
15205
- requireSuccess(synthetic, this.id, "opencode-generate");
15206
- throw error;
15207
- } finally {
15208
- if (sessionId) await client2.session.delete({ path: { id: sessionId }, query: { directory: input.repositoryPath } }).catch(() => void 0);
15209
- server.close();
15210
- this.servers.delete(server);
13288
+ async detect(forceRefresh = false, signal) {
13289
+ const candidates = await this.resolver.resolveAll("opencode", forceRefresh);
13290
+ let first = null;
13291
+ for (const executable of candidates) {
13292
+ try {
13293
+ const result = await this.runner.run(executable, ["--version"], signal ? { signal } : {});
13294
+ const version2 = result.stdout.trim() || result.stderr.trim();
13295
+ const detected = { executable, version: version2, compatible: result.exitCode === 0 && isOpenCodeV2Version(version2) };
13296
+ if (detected.compatible) return detected;
13297
+ first ??= detected;
13298
+ } catch (error) {
13299
+ if (signal?.aborted) throw error;
13300
+ first ??= { executable, version: "", compatible: false };
13301
+ }
15211
13302
  }
13303
+ return first;
15212
13304
  }
15213
13305
  close() {
15214
13306
  for (const server of this.servers) server.close();
@@ -16472,9 +14564,9 @@ function parseNumstat$1(output) {
16472
14564
  const stats = /* @__PURE__ */ new Map();
16473
14565
  const tokens = output.split("\0");
16474
14566
  for (let index = 0; index < tokens.length; index += 1) {
16475
- const record = tokens[index];
16476
- if (!record) continue;
16477
- const match = /^(\d+|-)\t(\d+|-)\t(.*)$/s.exec(record);
14567
+ const record2 = tokens[index];
14568
+ if (!record2) continue;
14569
+ const match = /^(\d+|-)\t(\d+|-)\t(.*)$/s.exec(record2);
16478
14570
  if (!match) continue;
16479
14571
  const binary = match[1] === "-" || match[2] === "-";
16480
14572
  const entry = {
@@ -16495,8 +14587,8 @@ const FIELD = "";
16495
14587
  const RECORD = "";
16496
14588
  const LOG_FORMAT = `%H${FIELD}%h${FIELD}%s${FIELD}%b${FIELD}%an${FIELD}%ae${FIELD}%aI${FIELD}%D${FIELD}%P${RECORD}`;
16497
14589
  function parseLog(output) {
16498
- return output.split(RECORD).map((record) => record.trim()).filter(Boolean).flatMap((record) => {
16499
- const fields = record.split(FIELD);
14590
+ return output.split(RECORD).map((record2) => record2.trim()).filter(Boolean).flatMap((record2) => {
14591
+ const fields = record2.split(FIELD);
16500
14592
  if (fields.length < 9) return [];
16501
14593
  const oid = fields[0] ?? "";
16502
14594
  if (!/^[0-9a-f]{40,64}$/i.test(oid)) return [];
@@ -16517,6 +14609,21 @@ function parseLog(output) {
16517
14609
  }];
16518
14610
  });
16519
14611
  }
14612
+ function selectHistoryBase(output, upstream) {
14613
+ const refs = output.trim().split("\n").map((line) => {
14614
+ const [ref = "", oid = "", target = ""] = line.split("\0");
14615
+ return { ref, oid, target };
14616
+ }).filter((ref) => /^[a-f0-9]{40,64}$/i.test(ref.oid));
14617
+ const remoteDefaults = refs.filter((ref) => ref.ref.startsWith("refs/remotes/") && ref.ref.endsWith("/HEAD") && ref.target);
14618
+ const preferred = remoteDefaults.filter((ref) => upstream?.startsWith(ref.ref.slice("refs/remotes/".length, -4))).sort((a2, b) => b.ref.length - a2.ref.length)[0] ?? remoteDefaults.find((ref) => ref.ref === "refs/remotes/origin/HEAD");
14619
+ if (preferred) return { ref: preferred.target.replace(/^refs\/(heads|remotes)\//, ""), oid: preferred.oid };
14620
+ const remotePrefix = upstream?.split("/")[0] ?? "origin";
14621
+ for (const name of [`refs/remotes/${remotePrefix}/main`, `refs/remotes/${remotePrefix}/master`, "refs/heads/main", "refs/heads/master"]) {
14622
+ const ref = refs.find((candidate) => candidate.ref === name);
14623
+ if (ref) return { ref: name.replace(/^refs\/(heads|remotes)\//, ""), oid: ref.oid };
14624
+ }
14625
+ return null;
14626
+ }
16520
14627
  const REF_FORMAT = "%(refname)%00%(refname:short)%00%(HEAD)%00%(upstream:short)%00%(upstream:track)%00%(worktreepath)%00%(objectname)%00%(objectname:short)%00%(subject)%00%(authorname)%00%(committerdate:iso-strict)%00";
16521
14628
  const FIELDS_PER_REF = 11;
16522
14629
  function parseRefs(buffer) {
@@ -16618,25 +14725,25 @@ function parseStatus(buffer) {
16618
14725
  };
16619
14726
  const chunks = splitNul(buffer).map((chunk) => chunk.toString("utf8"));
16620
14727
  for (let index = 0; index < chunks.length; index += 1) {
16621
- const record = chunks[index] ?? "";
16622
- if (!record) continue;
16623
- if (record.startsWith("# ")) {
16624
- parseHeader(record, status);
14728
+ const record2 = chunks[index] ?? "";
14729
+ if (!record2) continue;
14730
+ if (record2.startsWith("# ")) {
14731
+ parseHeader(record2, status);
16625
14732
  continue;
16626
14733
  }
16627
- if (record.startsWith("? ")) {
16628
- status.changes.push(makeChange(record.slice(2), "?", "?"));
14734
+ if (record2.startsWith("? ")) {
14735
+ status.changes.push(makeChange(record2.slice(2), "?", "?"));
16629
14736
  continue;
16630
14737
  }
16631
- if (record.startsWith("1 ") || record.startsWith("u ")) {
16632
- const fields = record.split(" ");
14738
+ if (record2.startsWith("1 ") || record2.startsWith("u ")) {
14739
+ const fields = record2.split(" ");
16633
14740
  const xy = fields[1] ?? "..";
16634
- const pathIndex = record.startsWith("1 ") ? 8 : 10;
14741
+ const pathIndex = record2.startsWith("1 ") ? 8 : 10;
16635
14742
  status.changes.push(makeChange(fields.slice(pathIndex).join(" "), xy[0] ?? ".", xy[1] ?? ".", fields[2] ?? ""));
16636
14743
  continue;
16637
14744
  }
16638
- if (record.startsWith("2 ")) {
16639
- const fields = record.split(" ");
14745
+ if (record2.startsWith("2 ")) {
14746
+ const fields = record2.split(" ");
16640
14747
  const xy = fields[1] ?? "..";
16641
14748
  const next = chunks[index + 1] ?? "";
16642
14749
  const pathValue = fields.slice(9).join(" ");
@@ -16984,14 +15091,18 @@ ${base}
16984
15091
  if (cursor && commits[0]?.oid === cursor) commits = commits.slice(1);
16985
15092
  const hasMore = commits.length > 100;
16986
15093
  commits = commits.slice(0, 100);
16987
- const localOids = await this.localOnlyOids(repository.path, status.upstream, status.detached || status.unborn);
15094
+ const [localOids, base] = await Promise.all([
15095
+ this.localOnlyOids(repository.path, status.upstream, status.detached || status.unborn),
15096
+ this.historyBase(repository.path, revision2, status.upstream)
15097
+ ]);
16988
15098
  commits = commits.map((commit) => ({
16989
15099
  ...commit,
16990
15100
  isHead: commit.oid === status.oid,
16991
- upstreamState: localOids === null ? "unknown" : localOids.has(commit.oid) ? "local-only" : "published"
15101
+ upstreamState: localOids === null ? "unknown" : localOids.has(commit.oid) ? "local-only" : "published",
15102
+ baseState: base === null ? "unknown" : base.outside.has(commit.oid) ? "outside" : "included"
16992
15103
  }));
16993
15104
  for (const commit of commits) this.rememberOid(repositoryId, commit.oid);
16994
- return { commits, nextCursor: hasMore ? commits.at(-1)?.oid ?? null : null };
15105
+ return { commits, nextCursor: hasMore ? commits.at(-1)?.oid ?? null : null, baseRef: base?.ref ?? null };
16995
15106
  } catch (error) {
16996
15107
  if (!cursor && error instanceof GitOperationError && /does not have any commits|unknown revision|bad revision/i.test(error.message)) return { commits: [], nextCursor: null };
16997
15108
  throw error;
@@ -17564,6 +15675,18 @@ ${body}
17564
15675
  const status = await this.repositories.status(repositoryId, false);
17565
15676
  if (status.readOnly) throw new GitOperationError({ code: "INVALID_ARGUMENT", operation: "write", message: `The repository is in the middle of ${status.operation}; OpenTig keeps it read-only.` });
17566
15677
  }
15678
+ async historyBase(repositoryPath, revision2, upstream) {
15679
+ try {
15680
+ const options = { operation: "history-base", readOnly: true, maxOutputBytes: 8 * 1024 * 1024 };
15681
+ const refs = await this.git.run(repositoryPath, ["for-each-ref", "--format=%(refname)%00%(objectname)%00%(symref)", "refs/heads/main", "refs/heads/master", "refs/remotes"], options);
15682
+ const base = selectHistoryBase(refs.stdout.toString("utf8"), upstream);
15683
+ if (!base) return null;
15684
+ const output = await this.git.run(repositoryPath, ["rev-list", revision2, `^${base.oid}`, "--"], options);
15685
+ return { ref: base.ref, outside: new Set(output.stdout.toString("utf8").trim().split("\n").filter(Boolean)) };
15686
+ } catch {
15687
+ return null;
15688
+ }
15689
+ }
17567
15690
  async localOnlyOids(repositoryPath, upstream, unavailable) {
17568
15691
  if (!upstream || unavailable) return null;
17569
15692
  try {
@@ -18253,6 +16376,73 @@ function revision(bytes) {
18253
16376
  function invalidReplacement(message) {
18254
16377
  return new GitOperationError({ code: "INVALID_ARGUMENT", operation: "replace-search", message });
18255
16378
  }
16379
+ const positive = number().int().positive().safe();
16380
+ const membershipSchema = object({
16381
+ stack: object({ number: positive, size: positive, baseRefName: string().min(1) }).nullable(),
16382
+ stackEntry: object({ position: positive }).nullable()
16383
+ });
16384
+ const stackSchema = object({
16385
+ number: positive,
16386
+ base: union([string().min(1), object({ ref: string().min(1) })]),
16387
+ pull_requests: array(object({
16388
+ number: positive,
16389
+ title: string().optional(),
16390
+ draft: boolean().optional(),
16391
+ head: object({ ref: string().min(1) }),
16392
+ state: _enum(["open", "closed", "merged"]),
16393
+ merged_at: string().nullable().optional()
16394
+ })).min(1)
16395
+ });
16396
+ function invalid() {
16397
+ return new GhOperationError({ code: "GH_INVALID_OUTPUT", operation: "gh-pr-stack", message: "GitHub returned unreadable stack information." });
16398
+ }
16399
+ function json(raw) {
16400
+ try {
16401
+ return JSON.parse(raw);
16402
+ } catch {
16403
+ throw invalid();
16404
+ }
16405
+ }
16406
+ function stackMembershipQuery(numbers) {
16407
+ if (!numbers.length || numbers.some((number2) => !positive.safeParse(number2).success)) throw invalid();
16408
+ return `query($owner:String!,$name:String!){repository(owner:$owner,name:$name){${numbers.map((number2) => `pr${number2}:pullRequest(number:${number2}){stack{number size baseRefName} stackEntry{position}}`).join(" ")}}}`;
16409
+ }
16410
+ function parseStackMemberships(raw, numbers) {
16411
+ const envelope = object({ data: object({ repository: record(string(), membershipSchema.nullable()) }), errors: array(unknown()).optional() }).safeParse(json(raw));
16412
+ if (!envelope.success || envelope.data.errors?.length) throw invalid();
16413
+ const result = /* @__PURE__ */ new Map();
16414
+ for (const number2 of numbers) {
16415
+ const entry = envelope.data.data.repository[`pr${number2}`];
16416
+ if (entry === void 0) throw invalid();
16417
+ if (!entry?.stack && !entry?.stackEntry) continue;
16418
+ if (!entry?.stack || !entry.stackEntry || entry.stackEntry.position > entry.stack.size) throw invalid();
16419
+ result.set(number2, { number: entry.stack.number, size: entry.stack.size, position: entry.stackEntry.position, base: entry.stack.baseRefName });
16420
+ }
16421
+ return result;
16422
+ }
16423
+ function parsePullRequestStack(raw, prNumber, listing = false) {
16424
+ let value = json(raw);
16425
+ if (listing) {
16426
+ if (!Array.isArray(value) || value.length > 1) throw invalid();
16427
+ if (!value.length) return null;
16428
+ value = value[0];
16429
+ }
16430
+ const parsed = stackSchema.safeParse(value);
16431
+ if (!parsed.success) throw invalid();
16432
+ const stack = parsed.data;
16433
+ if (!stack.pull_requests.some((pr) => pr.number === prNumber) || new Set(stack.pull_requests.map((pr) => pr.number)).size !== stack.pull_requests.length) throw invalid();
16434
+ return {
16435
+ number: stack.number,
16436
+ base: typeof stack.base === "string" ? stack.base : stack.base.ref,
16437
+ layers: stack.pull_requests.map((pr) => ({
16438
+ number: pr.number,
16439
+ title: pr.title || pr.head.ref,
16440
+ headRefName: pr.head.ref,
16441
+ state: pr.merged_at || pr.state === "merged" ? "MERGED" : pr.state === "closed" ? "CLOSED" : "OPEN",
16442
+ isDraft: pr.draft ?? false
16443
+ }))
16444
+ };
16445
+ }
18256
16446
  const OWNER_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?$/;
18257
16447
  const REPO_PATTERN = /^[A-Za-z0-9._-]+$/;
18258
16448
  function parseGitHubRemote(url) {
@@ -18292,13 +16482,13 @@ function parsePullRequestList(raw) {
18292
16482
  function parsePullRequestDetails(raw) {
18293
16483
  const item = parseJson(raw, "gh-pr-view");
18294
16484
  const summary = parseSummary(item, "gh-pr-view");
18295
- const record = item;
16485
+ const record2 = item;
18296
16486
  return {
18297
16487
  ...summary,
18298
- body: typeof record.body === "string" ? record.body : "",
18299
- changedFiles: numberOrZero(record.changedFiles),
18300
- labels: parseLabels(record.labels),
18301
- commits: parseCommits(record.commits)
16488
+ body: typeof record2.body === "string" ? record2.body : "",
16489
+ changedFiles: numberOrZero(record2.changedFiles),
16490
+ labels: parseLabels(record2.labels),
16491
+ commits: parseCommits(record2.commits)
18302
16492
  };
18303
16493
  }
18304
16494
  function sortPullRequestsNewestFirst(pulls) {
@@ -18325,27 +16515,27 @@ function parseCreatedPullRequestUrl(stdout) {
18325
16515
  function parseSummary(item, operation) {
18326
16516
  const parsed = summaryRecordSchema.safeParse(item);
18327
16517
  if (!parsed.success) throw invalidOutput(operation);
18328
- const record = parsed.data;
16518
+ const record2 = parsed.data;
18329
16519
  const { number: number2, state } = parsed.data;
18330
- const parsedAuthor = tolerantRecordSchema.safeParse(record.author);
16520
+ const parsedAuthor = tolerantRecordSchema.safeParse(record2.author);
18331
16521
  const authorRecord = parsedAuthor.success ? parsedAuthor.data : null;
18332
16522
  const author = authorRecord?.login;
18333
16523
  const authorLogin = typeof author === "string" ? author : "unknown";
18334
16524
  return {
18335
16525
  number: number2,
18336
- title: typeof record.title === "string" ? record.title : "",
16526
+ title: typeof record2.title === "string" ? record2.title : "",
18337
16527
  state,
18338
- isDraft: record.isDraft === true,
16528
+ isDraft: record2.isDraft === true,
18339
16529
  author: authorLogin,
18340
16530
  authorAvatarUrl: avatarUrl(authorLogin, authorRecord?.is_bot === true),
18341
- headRefName: typeof record.headRefName === "string" ? record.headRefName : "",
18342
- baseRefName: typeof record.baseRefName === "string" ? record.baseRefName : "",
18343
- updatedAt: typeof record.updatedAt === "string" ? record.updatedAt : "",
18344
- url: typeof record.url === "string" ? record.url : "",
18345
- reviewDecision: typeof record.reviewDecision === "string" && record.reviewDecision ? record.reviewDecision : null,
18346
- additions: numberOrZero(record.additions),
18347
- deletions: numberOrZero(record.deletions),
18348
- checksState: parseChecksState(record.statusCheckRollup)
16531
+ headRefName: typeof record2.headRefName === "string" ? record2.headRefName : "",
16532
+ baseRefName: typeof record2.baseRefName === "string" ? record2.baseRefName : "",
16533
+ updatedAt: typeof record2.updatedAt === "string" ? record2.updatedAt : "",
16534
+ url: typeof record2.url === "string" ? record2.url : "",
16535
+ reviewDecision: typeof record2.reviewDecision === "string" && record2.reviewDecision ? record2.reviewDecision : null,
16536
+ additions: numberOrZero(record2.additions),
16537
+ deletions: numberOrZero(record2.deletions),
16538
+ checksState: parseChecksState(record2.statusCheckRollup)
18349
16539
  };
18350
16540
  }
18351
16541
  function parseLabels(value) {
@@ -18354,10 +16544,10 @@ function parseLabels(value) {
18354
16544
  return parsed.data.flatMap((item) => {
18355
16545
  const candidate = tolerantRecordSchema.safeParse(item);
18356
16546
  if (!candidate.success) return [];
18357
- const record = candidate.data;
18358
- if (typeof record.name !== "string" || !record.name) return [];
18359
- const color = typeof record.color === "string" && /^[0-9a-f]{6}$/i.test(record.color) ? record.color : "6e7781";
18360
- return [{ name: record.name, color }];
16547
+ const record2 = candidate.data;
16548
+ if (typeof record2.name !== "string" || !record2.name) return [];
16549
+ const color = typeof record2.color === "string" && /^[0-9a-f]{6}$/i.test(record2.color) ? record2.color : "6e7781";
16550
+ return [{ name: record2.name, color }];
18361
16551
  });
18362
16552
  }
18363
16553
  function parseCommits(value) {
@@ -18366,16 +16556,16 @@ function parseCommits(value) {
18366
16556
  return parsed.data.flatMap((item) => {
18367
16557
  const candidate = tolerantRecordSchema.safeParse(item);
18368
16558
  if (!candidate.success) return [];
18369
- const record = candidate.data;
18370
- if (typeof record.oid !== "string" || !record.oid) return [];
18371
- const authors = Array.isArray(record.authors) ? record.authors : [];
16559
+ const record2 = candidate.data;
16560
+ if (typeof record2.oid !== "string" || !record2.oid) return [];
16561
+ const authors = Array.isArray(record2.authors) ? record2.authors : [];
18372
16562
  const authorRecord = authors.map((author) => tolerantRecordSchema.safeParse(author)).find((author) => author.success)?.data;
18373
16563
  const login = typeof authorRecord?.login === "string" ? authorRecord.login : null;
18374
16564
  const name = typeof authorRecord?.name === "string" && authorRecord.name ? authorRecord.name : login ?? "unknown";
18375
16565
  return [{
18376
- oid: record.oid,
18377
- messageHeadline: typeof record.messageHeadline === "string" ? record.messageHeadline : "",
18378
- authoredAt: typeof record.authoredDate === "string" ? record.authoredDate : "",
16566
+ oid: record2.oid,
16567
+ messageHeadline: typeof record2.messageHeadline === "string" ? record2.messageHeadline : "",
16568
+ authoredAt: typeof record2.authoredDate === "string" ? record2.authoredDate : "",
18379
16569
  author: name,
18380
16570
  authorAvatarUrl: login ? avatarUrl(login, login.endsWith("[bot]")) : null
18381
16571
  }];
@@ -18387,11 +16577,11 @@ function parseChecksState(value) {
18387
16577
  for (const item of value) {
18388
16578
  const parsed = tolerantRecordSchema.safeParse(item);
18389
16579
  if (!parsed.success) continue;
18390
- const record = parsed.data;
18391
- const conclusion = typeof record.conclusion === "string" ? record.conclusion.toUpperCase() : "";
18392
- const state = typeof record.state === "string" ? record.state.toUpperCase() : "";
16580
+ const record2 = parsed.data;
16581
+ const conclusion = typeof record2.conclusion === "string" ? record2.conclusion.toUpperCase() : "";
16582
+ const state = typeof record2.state === "string" ? record2.state.toUpperCase() : "";
18393
16583
  if (["FAILURE", "ERROR", "TIMED_OUT", "CANCELLED", "ACTION_REQUIRED", "STARTUP_FAILURE"].includes(conclusion || state)) return "FAILING";
18394
- const status = typeof record.status === "string" ? record.status.toUpperCase() : "";
16584
+ const status = typeof record2.status === "string" ? record2.status.toUpperCase() : "";
18395
16585
  if (status && status !== "COMPLETED" || ["PENDING", "EXPECTED"].includes(state)) pending = true;
18396
16586
  }
18397
16587
  return pending ? "PENDING" : "PASSING";
@@ -18456,7 +16646,7 @@ class GitHubService {
18456
16646
  ["pr", "list", "-R", nameWithOwner, "--state", state.toLowerCase(), "--json", PR_SUMMARY_FIELDS, "--limit", "50"],
18457
16647
  { cwd: repository.path, operation: "gh-pr-list", timeoutMs: NETWORK_TIMEOUT_MS, maxOutputBytes: 4 * 1024 * 1024 }
18458
16648
  )));
18459
- return selectPullRequestsNewestFirst(results.flatMap((result) => parsePullRequestList(result.stdout)), states);
16649
+ return this.withStackMembership(repository.path, nameWithOwner, selectPullRequestsNewestFirst(results.flatMap((result) => parsePullRequestList(result.stdout)), states));
18460
16650
  }
18461
16651
  async findPullRequestForBranch(repositoryId, branchName) {
18462
16652
  const operation = "gh-pr-for-branch";
@@ -18474,7 +16664,51 @@ class GitHubService {
18474
16664
  ["pr", "view", String(prNumber), "-R", nameWithOwner, "--json", PR_DETAIL_FIELDS],
18475
16665
  { cwd: repository.path, operation: "gh-pr-view", timeoutMs: NETWORK_TIMEOUT_MS, maxOutputBytes: 4 * 1024 * 1024 }
18476
16666
  );
18477
- return parsePullRequestDetails(result.stdout);
16667
+ const details = parsePullRequestDetails(result.stdout);
16668
+ return (await this.withStackMembership(repository.path, nameWithOwner, [details]))[0];
16669
+ }
16670
+ async withStackMembership(cwd, nameWithOwner, pulls) {
16671
+ const [owner, name] = nameWithOwner.split("/");
16672
+ const enriched = [];
16673
+ for (let start = 0; start < pulls.length; start += 25) {
16674
+ const batch = pulls.slice(start, start + 25);
16675
+ try {
16676
+ const numbers = batch.map((pr) => pr.number);
16677
+ const result = await this.runGh(["api", "graphql", "-f", `owner=${owner}`, "-f", `name=${name}`, "-f", `query=${stackMembershipQuery(numbers)}`], {
16678
+ cwd,
16679
+ operation: "gh-pr-stack-membership",
16680
+ timeoutMs: 1e4,
16681
+ maxOutputBytes: 1024 * 1024
16682
+ });
16683
+ const memberships = parseStackMemberships(result.stdout, numbers);
16684
+ enriched.push(...batch.map((pr) => {
16685
+ const stack = memberships.get(pr.number);
16686
+ return stack ? { ...pr, stack } : pr;
16687
+ }));
16688
+ } catch {
16689
+ enriched.push(...batch);
16690
+ }
16691
+ }
16692
+ return enriched;
16693
+ }
16694
+ async getPullRequestStack(repositoryId, prNumber) {
16695
+ const operation = "gh-pr-stack";
16696
+ const { repository, nameWithOwner } = await this.requireGitHub(repositoryId, operation);
16697
+ const options = { cwd: repository.path, operation, timeoutMs: NETWORK_TIMEOUT_MS, maxOutputBytes: 4 * 1024 * 1024 };
16698
+ const read = async (endpoint) => this.runGh(["api", endpoint], options);
16699
+ let listing;
16700
+ try {
16701
+ listing = await read(`repos/${nameWithOwner}/stacks?pull_request=${prNumber}`);
16702
+ } catch (error) {
16703
+ if (error instanceof GhOperationError && error.detail.code === "GH_PROCESS_FAILED" && /HTTP 404/.test(error.message)) return null;
16704
+ throw error;
16705
+ }
16706
+ const stack = parsePullRequestStack(listing.stdout, prNumber, true);
16707
+ if (!stack) return null;
16708
+ const details = await read(`repos/${nameWithOwner}/stacks/${stack.number}`);
16709
+ const complete = parsePullRequestStack(details.stdout, prNumber);
16710
+ if (complete?.number !== stack.number) throw new GhOperationError({ code: "GH_INVALID_OUTPUT", operation, message: "The stack changed while loading. Refresh to try again." });
16711
+ return complete;
18478
16712
  }
18479
16713
  async getPullRequestDiff(repositoryId, prNumber) {
18480
16714
  const { repository, nameWithOwner } = await this.requireGitHub(repositoryId, "gh-pr-diff");
@@ -18718,7 +16952,7 @@ class ProblemsLogStore {
18718
16952
  this.loaded = true;
18719
16953
  }
18720
16954
  record(entry) {
18721
- const record = {
16955
+ const record2 = {
18722
16956
  id: randomUUID(),
18723
16957
  at: (/* @__PURE__ */ new Date()).toISOString(),
18724
16958
  level: entry.level ?? "error",
@@ -18728,7 +16962,7 @@ class ProblemsLogStore {
18728
16962
  message: entry.message,
18729
16963
  repositoryId: entry.repositoryId ?? null
18730
16964
  };
18731
- const normalized = normalizeProblemLogEntry(record);
16965
+ const normalized = normalizeProblemLogEntry(record2);
18732
16966
  if (!normalized) return;
18733
16967
  this.pending = this.pending.then(async () => {
18734
16968
  await mkdir(path.dirname(this.filePath), { recursive: true });
@@ -18827,10 +17061,10 @@ resolveShortcuts();
18827
17061
  function sanitizeShortcutOverrides(value) {
18828
17062
  const result = {};
18829
17063
  if (!value || typeof value !== "object") return result;
18830
- const record = value;
17064
+ const record2 = value;
18831
17065
  const usedCombos = /* @__PURE__ */ new Set();
18832
17066
  for (const def of SHORTCUT_DEFINITIONS) {
18833
- const combo = record[def.id];
17067
+ const combo = record2[def.id];
18834
17068
  if (typeof combo !== "string" || combo === def.defaultCombo) continue;
18835
17069
  if (!isValidCombo(combo, def.allowBare)) continue;
18836
17070
  if (RESERVED_COMBOS.has(combo) || usedCombos.has(combo)) continue;
@@ -19028,7 +17262,7 @@ const defaults = {
19028
17262
  uiFont: "plus-jakarta-sans",
19029
17263
  monoFont: "jetbrains-mono",
19030
17264
  commitMessageHarness: "codex",
19031
- commitMessageModels: { codex: "default", claude: "default", opencode: "default" },
17265
+ commitMessageModels: { codex: "default", claude: "default", opencode: "default", grok: "default" },
19032
17266
  shortcutOverrides: {},
19033
17267
  doubleControlShortcutEnabled: true,
19034
17268
  remoteFetchIntervalSeconds: DEFAULT_REMOTE_FETCH_INTERVAL_SECONDS
@@ -19435,7 +17669,7 @@ function projectError(message) {
19435
17669
  return new GitOperationError({ code: "INVALID_ARGUMENT", operation: "repository-projects", message });
19436
17670
  }
19437
17671
  function isHarness(value) {
19438
- return value === "codex" || value === "claude" || value === "opencode";
17672
+ return value === "codex" || value === "claude" || value === "opencode" || value === "grok";
19439
17673
  }
19440
17674
  function normalizeUiFont(value) {
19441
17675
  if (value === "cabinet-grotesk" || value === "satoshi") return "plus-jakarta-sans";
@@ -19450,9 +17684,9 @@ function normalizeSidebarWidth(value) {
19450
17684
  return Math.max(300, Math.min(680, width));
19451
17685
  }
19452
17686
  function modelPreferences(value) {
19453
- const result = { codex: "default", claude: "default", opencode: "default" };
17687
+ const result = { codex: "default", claude: "default", opencode: "default", grok: "default" };
19454
17688
  if (!value || typeof value !== "object") return result;
19455
- for (const harness of ["codex", "claude", "opencode"]) {
17689
+ for (const harness of ["codex", "claude", "opencode", "grok"]) {
19456
17690
  const model = value[harness];
19457
17691
  if (typeof model === "string" && model.length > 0 && model.length <= 200 && !hasControlCharacters$1(model)) result[harness] = model;
19458
17692
  }
@@ -19595,7 +17829,8 @@ async function createOpenTigRuntime(options) {
19595
17829
  const providers = [
19596
17830
  new CodexProvider(cliResolver, cliRunner),
19597
17831
  new ClaudeProvider(cliResolver, cliRunner),
19598
- new OpenCodeProvider(cliResolver, cliRunner)
17832
+ new OpenCodeProvider(cliResolver, cliRunner),
17833
+ new GrokProvider(cliResolver, cliRunner)
19599
17834
  ];
19600
17835
  const aiLog = new AiLogStore(options.aiLogPath);
19601
17836
  await aiLog.load();
@@ -19836,6 +18071,7 @@ const IPC = {
19836
18071
  githubPrForBranch: "github:pr-for-branch",
19837
18072
  githubPrList: "github:pr-list",
19838
18073
  githubPrView: "github:pr-view",
18074
+ githubPrStack: "github:pr-stack",
19839
18075
  githubPrDiff: "github:pr-diff",
19840
18076
  githubPrCommitDiff: "github:pr-commit-diff",
19841
18077
  githubPrCreate: "github:pr-create",
@@ -19920,6 +18156,7 @@ const OPEN_TIG_SERVER_COMMANDS = {
19920
18156
  "github.findPullRequestForBranch": command(IPC.githubPrForBranch, "gh-pr-for-branch", false),
19921
18157
  "github.listPullRequests": command(IPC.githubPrList, "gh-pr-list", false),
19922
18158
  "github.getPullRequest": command(IPC.githubPrView, "gh-pr-view", false),
18159
+ "github.getPullRequestStack": command(IPC.githubPrStack, "gh-pr-stack", false),
19923
18160
  "github.getPullRequestDiff": command(IPC.githubPrDiff, "gh-pr-diff", false),
19924
18161
  "github.getPullRequestCommitDiff": command(IPC.githubPrCommitDiff, "gh-pr-commit-diff", false),
19925
18162
  "github.createPullRequest": command(IPC.githubPrCreate, "gh-pr-create", true),
@@ -20115,7 +18352,7 @@ const searchOptionsSchema = object({
20115
18352
  includeIgnored: unknown().optional()
20116
18353
  });
20117
18354
  const openFileTabSchema = object({ path: unknown(), pinned: boolean() });
20118
- const aiHarnessSchema = _enum(["codex", "claude", "opencode"]);
18355
+ const aiHarnessSchema = _enum(["codex", "claude", "opencode", "grok"]);
20119
18356
  const pullRequestStateSchema = _enum(["OPEN", "CLOSED", "MERGED"]);
20120
18357
  function stringArg(value, operation, maxLength = 32768) {
20121
18358
  const parsed = boundedStringSchema(maxLength, { controls: false }).safeParse(value);
@@ -20169,28 +18406,28 @@ function filesTreeStateArg(repositoryId, value, operation) {
20169
18406
  return { repositoryId, expandedPaths: normalizeExpandedPaths(expandedPaths) };
20170
18407
  }
20171
18408
  function openFilesStateArg(repositoryId, tabs, activePath, previewPath, operation) {
20172
- const invalid = () => new GitOperationError({ code: "INVALID_ARGUMENT", operation, message: "Invalid open files state." });
18409
+ const invalid2 = () => new GitOperationError({ code: "INVALID_ARGUMENT", operation, message: "Invalid open files state." });
20173
18410
  const parsedTabs = array(openFileTabSchema).max(MAX_OPEN_FILE_TABS).safeParse(tabs);
20174
- if (!isOpenFilesRepositoryId(repositoryId) || !parsedTabs.success) throw invalid();
18411
+ if (!isOpenFilesRepositoryId(repositoryId) || !parsedTabs.success) throw invalid2();
20175
18412
  const normalizedTabs = [];
20176
18413
  const seen = /* @__PURE__ */ new Set();
20177
18414
  for (const input of parsedTabs.data) {
20178
18415
  const path2 = normalizeOpenFilePath(input.path);
20179
- if (!path2 || typeof input.pinned !== "boolean") throw invalid();
18416
+ if (!path2 || typeof input.pinned !== "boolean") throw invalid2();
20180
18417
  if (seen.has(path2)) continue;
20181
18418
  seen.add(path2);
20182
18419
  normalizedTabs.push({ path: path2, pinned: input.pinned });
20183
18420
  }
20184
- const active = optionalOpenFilePath(activePath, invalid);
20185
- const preview = optionalOpenFilePath(previewPath, invalid);
20186
- if (active && !seen.has(active)) throw invalid();
20187
- if (preview && !seen.has(preview)) throw invalid();
18421
+ const active = optionalOpenFilePath(activePath, invalid2);
18422
+ const preview = optionalOpenFilePath(previewPath, invalid2);
18423
+ if (active && !seen.has(active)) throw invalid2();
18424
+ if (preview && !seen.has(preview)) throw invalid2();
20188
18425
  return { repositoryId, tabs: normalizedTabs, activePath: active, previewPath: preview };
20189
18426
  }
20190
- function optionalOpenFilePath(value, invalid) {
18427
+ function optionalOpenFilePath(value, invalid2) {
20191
18428
  if (value === null || value === void 0) return null;
20192
18429
  const normalized = normalizeOpenFilePath(value);
20193
- if (!normalized) throw invalid();
18430
+ if (!normalized) throw invalid2();
20194
18431
  return normalized;
20195
18432
  }
20196
18433
  function projectNameArg(value, operation) {
@@ -20770,6 +19007,7 @@ function registerServerCommands(registry2, services, host) {
20770
19007
  pullRequestStatesArg(states, "gh-pr-list")
20771
19008
  ));
20772
19009
  handle(IPC.githubPrView, "gh-pr-view", (id, prNumber) => services.github.getPullRequest(stringArg(id, "gh-pr-view", 64), prNumberArg(prNumber, "gh-pr-view")));
19010
+ handle(IPC.githubPrStack, "gh-pr-stack", (id, prNumber) => services.github.getPullRequestStack(stringArg(id, "gh-pr-stack", 64), prNumberArg(prNumber, "gh-pr-stack")));
20773
19011
  handle(IPC.githubPrDiff, "gh-pr-diff", (id, prNumber) => services.github.getPullRequestDiff(stringArg(id, "gh-pr-diff", 64), prNumberArg(prNumber, "gh-pr-diff")));
20774
19012
  handle(IPC.githubPrCommitDiff, "gh-pr-commit-diff", (id, oid) => services.github.getPullRequestCommitDiff(stringArg(id, "gh-pr-commit-diff", 64), oidArg(oid, "gh-pr-commit-diff")));
20775
19013
  handle(IPC.githubPrCreate, "gh-pr-create", (input) => services.github.createPullRequest(createPullRequestArg(input)));
@@ -21804,12 +20042,12 @@ class OpenTigWebSocketTransport {
21804
20042
  upgradeHandler;
21805
20043
  closePromise = null;
21806
20044
  get connectedSessionCount() {
21807
- return new Set([...this.clients.values()].map((client2) => client2.sessionId)).size;
20045
+ return new Set([...this.clients.values()].map((client) => client.sessionId)).size;
21808
20046
  }
21809
20047
  connectionCount(sessionId) {
21810
20048
  let count2 = 0;
21811
- for (const client2 of this.clients.values()) {
21812
- if (client2.sessionId === sessionId) count2 += 1;
20049
+ for (const client of this.clients.values()) {
20050
+ if (client.sessionId === sessionId) count2 += 1;
21813
20051
  }
21814
20052
  return count2;
21815
20053
  }
@@ -21855,7 +20093,7 @@ class OpenTigWebSocketTransport {
21855
20093
  socket.on("close", () => {
21856
20094
  for (const controller of state.requests.values()) controller.abort();
21857
20095
  this.clients.delete(socket);
21858
- if (![...this.clients.values()].some((client2) => client2.sessionId === sessionId)) {
20096
+ if (![...this.clients.values()].some((client) => client.sessionId === sessionId)) {
21859
20097
  this.options.registry.clearSession(sessionId);
21860
20098
  }
21861
20099
  });