@opentig/cli 0.1.7 → 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 (114) hide show
  1. package/dist/bin.mjs +1 -4
  2. package/dist/chunks/{cli-DCPhUVBb.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-BUAz46Qa.js → FilesView-rT5hzb7y.js} +1 -1
  9. package/dist/client/assets/{GitHubAvatar-Depnd_JA.js → GitHubAvatar-EO1TD_1z.js} +1 -1
  10. package/dist/client/assets/{HistoryView-Dd4Kr4KN.js → HistoryView-C4c0CqMC.js} +1 -1
  11. package/dist/client/assets/{HtmlFileViewer-C3Qylr9B.js → HtmlFileViewer-bL6T57PQ.js} +1 -1
  12. package/dist/client/assets/{IconEdit-BHqlqze_.js → IconEdit-DePJMGIi.js} +1 -1
  13. package/dist/client/assets/{IconFolderPlus-BJIo1hfe.js → IconFolderPlus-ByGyA0Di.js} +1 -1
  14. package/dist/client/assets/{ImageFileViewer-BJy0ptmR.js → ImageFileViewer-DJaHH3hJ.js} +1 -1
  15. package/dist/client/assets/{LocalRefsDialog-C1MWMkv1.js → LocalRefsDialog-D9wYZWBg.js} +1 -1
  16. package/dist/client/assets/MarkdownFileViewer-BNPb9v8u.js +2 -0
  17. package/dist/client/assets/{PairingPage-DOPAXy3a.js → PairingPage-D9oguvKU.js} +1 -1
  18. package/dist/client/assets/PierreDiffViewer-8wTLYd5-.js +1 -0
  19. package/dist/client/assets/{PierreEditBoundary-mxtF7x3F.js → PierreEditBoundary-KzU3HDc2.js} +2 -2
  20. package/dist/client/assets/{PierreWorkerPool-B_NFnwU-.js → PierreWorkerPool-DH2jp9oe.js} +18 -18
  21. package/dist/client/assets/{PullRequestDiff-Bcu8Gmrf.js → PullRequestDiff-DK-m07ZP.js} +1 -1
  22. package/dist/client/assets/{PullRequestViewer-oeDoq-3g.js → PullRequestViewer-CpLwq4o2.js} +2 -2
  23. package/dist/client/assets/{PullRequestsView-DpTtagTX.js → PullRequestsView-DnvXaJ4t.js} +1 -1
  24. package/dist/client/assets/{QuickOpenDialog-rjeV0l_J.js → QuickOpenDialog-DIWjfUkt.js} +1 -1
  25. package/dist/client/assets/RepositoryProjectsDialog-BsQn5Yjr.js +1 -0
  26. package/dist/client/assets/{SearchView-C-c6oCil.js → SearchView-D-91dtSv.js} +1 -1
  27. package/dist/client/assets/SettingsDialog-dJUYk2cP.js +9 -0
  28. package/dist/client/assets/{Viewer-B6qUr83C.js → Viewer-GH-5bJW4.js} +2 -2
  29. package/dist/client/assets/{abnfDiagram-N423BO3Z-BxGW6tGd.js → abnfDiagram-N423BO3Z-CkHOGdAl.js} +1 -1
  30. package/dist/client/assets/{arc-CphVLv_F.js → arc-Dj8F8CO5.js} +1 -1
  31. package/dist/client/assets/{architectureDiagram-T3A2C74G-D9IDzZ6u.js → architectureDiagram-T3A2C74G-g87Y5LXk.js} +1 -1
  32. package/dist/client/assets/{blockDiagram-VBNYF7ZC-CzCatff9.js → blockDiagram-VBNYF7ZC-D6efB7jD.js} +1 -1
  33. package/dist/client/assets/{c4Diagram-5PPSVZJV-jvC7ACDE.js → c4Diagram-5PPSVZJV-DoZEC2xg.js} +1 -1
  34. package/dist/client/assets/channel-Dsy2VD23.js +1 -0
  35. package/dist/client/assets/{checkbox-DDpujnre.js → checkbox-DYwmgDPS.js} +1 -1
  36. package/dist/client/assets/{chunk-2GRJ4B5K-CNRn3w2y.js → chunk-2GRJ4B5K-Dr44hDNV.js} +1 -1
  37. package/dist/client/assets/{chunk-2Q5K7J3B-CnTjXDS8.js → chunk-2Q5K7J3B-YIEyVOOL.js} +1 -1
  38. package/dist/client/assets/{chunk-5RXB4S5H-8QZZSU3J.js → chunk-5RXB4S5H-gjmGBtkE.js} +1 -1
  39. package/dist/client/assets/{chunk-5VM5RSS4-B2MFN1L0.js → chunk-5VM5RSS4-DCOQko4g.js} +1 -1
  40. package/dist/client/assets/{chunk-6Q2QTUOP-BRGuFKSr.js → chunk-6Q2QTUOP-DfGlvPVm.js} +1 -1
  41. package/dist/client/assets/{chunk-GF5L2VYU-CWTKyD7U.js → chunk-GF5L2VYU-CCWOLPVL.js} +1 -1
  42. package/dist/client/assets/{chunk-JWPE2WC7-rGurufZY.js → chunk-JWPE2WC7-CFRTGh8r.js} +1 -1
  43. package/dist/client/assets/{chunk-KBJHAD2P-DOwIHyo0.js → chunk-KBJHAD2P-By3wsJVD.js} +1 -1
  44. package/dist/client/assets/{chunk-RYQCIY6F-qrVd0AV3.js → chunk-RYQCIY6F-C0wmsHmy.js} +1 -1
  45. package/dist/client/assets/{chunk-XXDRQBXY-BGvaybJK.js → chunk-XXDRQBXY-t3SnJvV_.js} +1 -1
  46. package/dist/client/assets/classDiagram-JCYQIIEL-BBQJgoWd.js +1 -0
  47. package/dist/client/assets/classDiagram-v2-OCEON4UE-BBQJgoWd.js +1 -0
  48. package/dist/client/assets/{vb-D17OF-Vu.js → cmd-BW5THilD.js} +1 -1
  49. package/dist/client/assets/{cose-bilkent-JH36ORCC-CHgOt-vq.js → cose-bilkent-JH36ORCC-D3VltoVk.js} +1 -1
  50. package/dist/client/assets/{cynefin-VYW2F7L2-DX7Kb3Ft.js → cynefin-VYW2F7L2-DwLwbeoe.js} +1 -1
  51. package/dist/client/assets/{cynefinDiagram-MW4NZA55-B4MgYgbV.js → cynefinDiagram-MW4NZA55-B23kuaQF.js} +1 -1
  52. package/dist/client/assets/{dagre-VZM6K2ZE-xG9l95NU.js → dagre-VZM6K2ZE-SgMrTr2p.js} +1 -1
  53. package/dist/client/assets/{diagram-7IWD3JNH-BQKb8ivh.js → diagram-7IWD3JNH-C7cQN4aD.js} +1 -1
  54. package/dist/client/assets/{diagram-B4RE2ZJO-CyIMrtDr.js → diagram-B4RE2ZJO-CzeI3yOw.js} +1 -1
  55. package/dist/client/assets/{diagram-LBJQPF4R-WuCMu4WW.js → diagram-LBJQPF4R-DhKm4hlI.js} +1 -1
  56. package/dist/client/assets/{diagram-Q27KOJAE--Oi1nRrR.js → diagram-Q27KOJAE-BXlU6Wp3.js} +1 -1
  57. package/dist/client/assets/{diagram-UB23O5K3-CP1DXsa_.js → diagram-UB23O5K3-BOwY_YwR.js} +1 -1
  58. package/dist/client/assets/{ebnfDiagram-BXEA7PRR-C-7jJg9C.js → ebnfDiagram-BXEA7PRR-CuIQuYPa.js} +1 -1
  59. package/dist/client/assets/{erDiagram-JOGREHBK-FSyqgO_9.js → erDiagram-JOGREHBK-d45NhKfk.js} +1 -1
  60. package/dist/client/assets/{flowDiagram-UKHOOZJN-y2e2HZHu.js → flowDiagram-UKHOOZJN-Dzq-6qo7.js} +1 -1
  61. package/dist/client/assets/{ganttDiagram-PKOTCBZU-kZ3m3wwW.js → ganttDiagram-PKOTCBZU-RVlL9mX2.js} +1 -1
  62. package/dist/client/assets/{gh-utils-DxPHIkD8.js → gh-utils-LsOSydCg.js} +1 -1
  63. package/dist/client/assets/{gitGraphDiagram-DS77QQ5N-3Z9e4WPi.js → gitGraphDiagram-DS77QQ5N-8kEJVUFH.js} +1 -1
  64. package/dist/client/assets/{index-DDbUjVD9.js → index-BzmFkR37.js} +1 -1
  65. package/dist/client/assets/{index-ChKJF4C_.js → index-CQcx9aRt.js} +4 -4
  66. package/dist/client/assets/index-DMbFAH51.css +1 -0
  67. package/dist/client/assets/{infoDiagram-6WML65LV-TfCo0Rhw.js → infoDiagram-6WML65LV-Co21Ql9M.js} +1 -1
  68. package/dist/client/assets/{ishikawaDiagram-WSZJBQD7-DaXI89rw.js → ishikawaDiagram-WSZJBQD7-BvPB_G97.js} +1 -1
  69. package/dist/client/assets/{journeyDiagram-NVQOT4AX-C4jS6BVn.js → journeyDiagram-NVQOT4AX-k7x89IE9.js} +1 -1
  70. package/dist/client/assets/{kanban-definition-27J2QSJJ-bwOtQiC8.js → kanban-definition-27J2QSJJ-BjrgN30t.js} +1 -1
  71. package/dist/client/assets/{linear-DfZM9J6Z.js → linear-m158kske.js} +1 -1
  72. package/dist/client/assets/{mermaid.core-B-iLnCqi.js → mermaid.core-C0FKucv-.js} +4 -4
  73. package/dist/client/assets/{mindmap-definition-FAOFIHXS-DAdKdypB.js → mindmap-definition-FAOFIHXS-CF8noycK.js} +1 -1
  74. package/dist/client/assets/{pegDiagram-VL7TDLO6-Bl95_ELH.js → pegDiagram-VL7TDLO6-_y7nfJFV.js} +1 -1
  75. package/dist/client/assets/{pieDiagram-7S7Q4E2Y-DXf4GTLI.js → pieDiagram-7S7Q4E2Y-DhdWHi45.js} +1 -1
  76. package/dist/client/assets/{platform-BMNQ8V5r.js → platform-Bqt97_Jr.js} +2 -2
  77. package/dist/client/assets/{quadrantDiagram-CIZ2JOQS-CDiwouFY.js → quadrantDiagram-CIZ2JOQS-BRvEIECQ.js} +1 -1
  78. package/dist/client/assets/{railroadDiagram-AXF67PYL-CZAR7rja.js → railroadDiagram-AXF67PYL-BgLZ8XU1.js} +1 -1
  79. package/dist/client/assets/render-markdown-2GjhuGA-.js +280 -0
  80. package/dist/client/assets/repository-grammars-ixqpb0uW.js +1 -0
  81. package/dist/client/assets/{requirementDiagram-LRYGKXZP-BklWtcnl.js → requirementDiagram-LRYGKXZP-CX-gxyGF.js} +1 -1
  82. package/dist/client/assets/{sankeyDiagram-W5VNT64P-CpD7cM5j.js → sankeyDiagram-W5VNT64P-CLSjSU_X.js} +1 -1
  83. package/dist/client/assets/{sequenceDiagram-SI44F4Z6-BnHPNl9l.js → sequenceDiagram-SI44F4Z6-dGlHyZRB.js} +1 -1
  84. package/dist/client/assets/{sizeCapture-X5ZJPWSS-D1eo0r-2.js → sizeCapture-X5ZJPWSS-BH3qO9T3.js} +1 -1
  85. package/dist/client/assets/{stateDiagram-OKZ733FA-ClTacl-d.js → stateDiagram-OKZ733FA-FXxo1iIM.js} +1 -1
  86. package/dist/client/assets/{stateDiagram-v2-UEYNNEHI-DAo7Tfh9.js → stateDiagram-v2-UEYNNEHI-DqxQ14yP.js} +1 -1
  87. package/dist/client/assets/{swimlanes-SLNWSIFB-_PLbkM5u.js → swimlanes-SLNWSIFB-VJGIuM4S.js} +2 -2
  88. package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-No0dCAkd.js +8 -0
  89. package/dist/client/assets/{timeline-definition-Z64GVDOM-C9U6VikV.js → timeline-definition-Z64GVDOM-BXNTAanY.js} +1 -1
  90. package/dist/client/assets/{vennDiagram-T6HMQDX7-Desj7KFU.js → vennDiagram-T6HMQDX7-D9nXAts5.js} +1 -1
  91. package/dist/client/assets/{viewer-tabs-BwMhis6Q.js → viewer-tabs-DkLmDzFg.js} +1 -1
  92. package/dist/client/assets/{wardleyDiagram-T6FBY63Y-rlMEd5tV.js → wardleyDiagram-T6FBY63Y-D89EaEfa.js} +1 -1
  93. package/dist/client/assets/{xychartDiagram-ELKLHX3M-CzFgA0NM.js → xychartDiagram-ELKLHX3M-B_xFDiIh.js} +1 -1
  94. package/dist/client/index.html +2 -2
  95. package/dist/dev.mjs +1 -4
  96. package/dist/manifest.json +1 -1
  97. package/dist/server.mjs +295 -2351
  98. package/dist/utility.mjs +0 -3
  99. package/package.json +1 -1
  100. package/dist/client/assets/App-CGiS2z40.js +0 -74
  101. package/dist/client/assets/CreatePullRequestDialog-dNbTTo9i.js +0 -2
  102. package/dist/client/assets/DiffWorkspace-XS025gbZ.js +0 -26
  103. package/dist/client/assets/EditableFileViewer-Cve4V9RS.js +0 -1
  104. package/dist/client/assets/File-BJuBDans.js +0 -1
  105. package/dist/client/assets/MarkdownFileViewer-pagMxv2y.js +0 -2
  106. package/dist/client/assets/PierreDiffViewer-FmgbHdls.js +0 -1
  107. package/dist/client/assets/RepositoryProjectsDialog-QYXEt7Lg.js +0 -1
  108. package/dist/client/assets/SettingsDialog-DHmWkKYV.js +0 -9
  109. package/dist/client/assets/channel-BGbncBYv.js +0 -1
  110. package/dist/client/assets/classDiagram-JCYQIIEL-BoYriqPM.js +0 -1
  111. package/dist/client/assets/classDiagram-v2-OCEON4UE-BoYriqPM.js +0 -1
  112. package/dist/client/assets/index-WwGOu_aM.css +0 -1
  113. package/dist/client/assets/render-markdown-BiKX2Zdv.js +0 -280
  114. package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-DHeOpgR_.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;
@@ -11529,7 +11530,7 @@ const ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => {
11529
11530
  return merge(this, other);
11530
11531
  },
11531
11532
  pick(mask) {
11532
- return pick$1(this, mask);
11533
+ return pick(this, mask);
11533
11534
  },
11534
11535
  omit(mask) {
11535
11536
  return omit(this, mask);
@@ -11854,7 +11855,7 @@ const EMPTY_AI_USAGE = {
11854
11855
  };
11855
11856
  const OPERATIONS = ["commit-message", "pull-request-draft"];
11856
11857
  const STATUSES = ["success", "failed", "cancelled"];
11857
- const HARNESSES = ["codex", "claude", "opencode"];
11858
+ const HARNESSES = ["codex", "claude", "opencode", "grok"];
11858
11859
  const MAX_TEXT$1 = 200;
11859
11860
  const MAX_ERROR_TEXT = 400;
11860
11861
  const aiUsageRecordSchema = looseObject({
@@ -12134,7 +12135,7 @@ function parseGeneratedParts(value) {
12134
12135
  const parsed = generatedPartsSchema.safeParse(value);
12135
12136
  if (!parsed.success || `${parsed.data.subject}
12136
12137
 
12137
- ${parsed.data.body}`.length > 1e4) throw invalidOutput$3();
12138
+ ${parsed.data.body}`.length > 1e4) throw invalidOutput$4();
12138
12139
  return parsed.data;
12139
12140
  }
12140
12141
  function parseCommitSplitProposal(value, stagedPaths) {
@@ -12194,14 +12195,14 @@ function parseJsonPayload(raw) {
12194
12195
  if (nested instanceof AiOperationError) throw nested;
12195
12196
  }
12196
12197
  }
12197
- throw invalidOutput$3();
12198
+ throw invalidOutput$4();
12198
12199
  }
12199
12200
  }
12200
12201
  function asRecord(value) {
12201
- if (!value || typeof value !== "object" || Array.isArray(value)) throw invalidOutput$3();
12202
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw invalidOutput$4();
12202
12203
  return value;
12203
12204
  }
12204
- function invalidOutput$3() {
12205
+ function invalidOutput$4() {
12205
12206
  return new AiOperationError({ code: "AI_INVALID_OUTPUT", operation: "ai-parse-output", message: "The AI returned a message with an invalid format.", retryable: true });
12206
12207
  }
12207
12208
  function hasControlCharacters$6(value, allowWhitespace) {
@@ -12293,7 +12294,7 @@ ${parts.body}` : parts.subject,
12293
12294
  splitBlockedReason: context.splitBlockedReason
12294
12295
  };
12295
12296
  } catch (error) {
12296
- const failure = failureLogFields(error);
12297
+ const failure2 = failureLogFields(error);
12297
12298
  recordSafely(this.log, {
12298
12299
  operation: "commit-message",
12299
12300
  harness: input.harness,
@@ -12301,10 +12302,10 @@ ${parts.body}` : parts.subject,
12301
12302
  repositoryId: input.repositoryId,
12302
12303
  // A cancellation is a decision, not a failure; merging the two would
12303
12304
  // poison any reliability figure taken from this log.
12304
- status: failure.status,
12305
+ status: failure2.status,
12305
12306
  durationMs: Date.now() - startedAt,
12306
- errorCode: failure.errorCode,
12307
- errorMessage: failure.errorMessage,
12307
+ errorCode: failure2.errorCode,
12308
+ errorMessage: failure2.errorMessage,
12308
12309
  usage,
12309
12310
  stagedFileCount,
12310
12311
  contextTruncated,
@@ -12375,10 +12376,10 @@ ${context.patch}`;
12375
12376
  }
12376
12377
  function parsePullRequestDraft(value) {
12377
12378
  const parsed = pullRequestDraftSchema.safeParse(value);
12378
- if (!parsed.success) throw invalidOutput$2();
12379
+ if (!parsed.success) throw invalidOutput$3();
12379
12380
  return parsed.data;
12380
12381
  }
12381
- function invalidOutput$2() {
12382
+ function invalidOutput$3() {
12382
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 });
12383
12384
  }
12384
12385
  function hasControlCharacters$5(value, allowWhitespace) {
@@ -12428,8 +12429,8 @@ class PullRequestDraftService {
12428
12429
  this.record(input, "success", null, null, usage, contextTruncated, Date.now() - startedAt);
12429
12430
  return { ...parts, harness: input.harness, model: input.model, contextWasTruncated: context.truncated };
12430
12431
  } catch (error) {
12431
- const failure = failureLogFields(error);
12432
- 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);
12433
12434
  throw error;
12434
12435
  } finally {
12435
12436
  this.active.delete(input.requestId);
@@ -12469,7 +12470,20 @@ function throwIfCancelled(signal, harness) {
12469
12470
  }
12470
12471
  const AI_PROVIDER_TIMEOUT_MS = 9 * 6e4;
12471
12472
  const AI_SERVER_TIMEOUT_MS = AI_PROVIDER_TIMEOUT_MS + 3e4;
12472
- 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
+ }
12473
12487
  function claudeUsage(envelope) {
12474
12488
  if (!envelope || typeof envelope !== "object") return { ...EMPTY_AI_USAGE };
12475
12489
  const record2 = envelope;
@@ -12507,20 +12521,6 @@ function codexUsage(stdout) {
12507
12521
  costUsd: null
12508
12522
  };
12509
12523
  }
12510
- function openCodeUsage(info) {
12511
- if (!info || typeof info !== "object") return { ...EMPTY_AI_USAGE };
12512
- const record2 = info;
12513
- const tokens = record2.tokens ?? {};
12514
- const cache = tokens.cache ?? {};
12515
- return {
12516
- inputTokens: count(tokens.input),
12517
- outputTokens: count(tokens.output),
12518
- reasoningTokens: count(tokens.reasoning),
12519
- cacheReadTokens: count(cache.read),
12520
- cacheWriteTokens: count(cache.write),
12521
- costUsd: count(record2.cost, true)
12522
- };
12523
- }
12524
12524
  function count(value, fractional = false) {
12525
12525
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return null;
12526
12526
  return fractional ? value : Math.round(value);
@@ -12569,7 +12569,7 @@ ${diagnostic ?? ""}`.toLowerCase();
12569
12569
  });
12570
12570
  }
12571
12571
  function label(harness) {
12572
- return harness === "codex" ? "Codex" : harness === "claude" ? "Claude Code" : "OpenCode";
12572
+ return harness === "codex" ? "Codex" : harness === "claude" ? "Claude Code" : harness === "grok" ? "Grok Build" : "OpenCode";
12573
12573
  }
12574
12574
  function stripAnsi(value) {
12575
12575
  return value.replace(new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g"), "");
@@ -12663,7 +12663,7 @@ function flattenWhitespace(value) {
12663
12663
  }
12664
12664
  return flattened.replace(/ {2,}/g, " ").trim();
12665
12665
  }
12666
- 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" }];
12667
12667
  class ClaudeProvider {
12668
12668
  constructor(resolver, runner) {
12669
12669
  this.resolver = resolver;
@@ -12725,15 +12725,15 @@ class CodexProvider {
12725
12725
  async status(forceRefresh = false) {
12726
12726
  const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
12727
12727
  const executable = await this.resolver.resolve("codex", forceRefresh);
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], 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 };
12729
12729
  const version2 = await this.runner.run(executable, ["--version"]);
12730
12730
  const login = await this.runner.run(executable, ["login", "status"]);
12731
12731
  if (login.exitCode !== 0 || !/logged in/i.test(`${login.stdout}
12732
12732
  ${login.stderr}`)) {
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], 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 };
12734
12734
  }
12735
12735
  const catalog = await this.runner.run(executable, ["debug", "models", "--bundled"]);
12736
- const models = catalog.exitCode === 0 ? parseCodexModels(catalog.stdout) : [DEFAULT_MODEL];
12736
+ const models = catalog.exitCode === 0 ? parseCodexModels(catalog.stdout) : [DEFAULT_MODEL$1];
12737
12737
  return {
12738
12738
  id: this.id,
12739
12739
  label: "Codex",
@@ -12769,2254 +12769,223 @@ function parseCodexModels(raw) {
12769
12769
  try {
12770
12770
  const parsed = JSON.parse(raw);
12771
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 }));
12772
- return [DEFAULT_MODEL, ...options];
12772
+ return [DEFAULT_MODEL$1, ...options];
12773
12773
  } catch {
12774
- return [DEFAULT_MODEL];
12775
- }
12776
- }
12777
- const createSseClient = ({ onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url, ...options }) => {
12778
- let lastEventId;
12779
- const sleep = sseSleepFn ?? ((ms) => new Promise((resolve2) => setTimeout(resolve2, ms)));
12780
- const createStream = async function* () {
12781
- let retryDelay = sseDefaultRetryDelay ?? 3e3;
12782
- let attempt = 0;
12783
- const signal = options.signal ?? new AbortController().signal;
12784
- while (true) {
12785
- if (signal.aborted)
12786
- break;
12787
- attempt++;
12788
- const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
12789
- if (lastEventId !== void 0) {
12790
- headers.set("Last-Event-ID", lastEventId);
12791
- }
12792
- try {
12793
- const response = await fetch(url, { ...options, headers, signal });
12794
- if (!response.ok)
12795
- throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
12796
- if (!response.body)
12797
- throw new Error("No body in SSE response");
12798
- const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
12799
- let buffer = "";
12800
- const abortHandler = () => {
12801
- try {
12802
- void reader.cancel();
12803
- } catch {
12804
- }
12805
- };
12806
- signal.addEventListener("abort", abortHandler);
12807
- try {
12808
- while (true) {
12809
- const { done, value } = await reader.read();
12810
- if (done)
12811
- break;
12812
- buffer += value;
12813
- const chunks = buffer.split("\n\n");
12814
- buffer = chunks.pop() ?? "";
12815
- for (const chunk of chunks) {
12816
- const lines = chunk.split("\n");
12817
- const dataLines = [];
12818
- let eventName;
12819
- for (const line of lines) {
12820
- if (line.startsWith("data:")) {
12821
- dataLines.push(line.replace(/^data:\s*/, ""));
12822
- } else if (line.startsWith("event:")) {
12823
- eventName = line.replace(/^event:\s*/, "");
12824
- } else if (line.startsWith("id:")) {
12825
- lastEventId = line.replace(/^id:\s*/, "");
12826
- } else if (line.startsWith("retry:")) {
12827
- const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10);
12828
- if (!Number.isNaN(parsed)) {
12829
- retryDelay = parsed;
12830
- }
12831
- }
12832
- }
12833
- let data;
12834
- let parsedJson = false;
12835
- if (dataLines.length) {
12836
- const rawData = dataLines.join("\n");
12837
- try {
12838
- data = JSON.parse(rawData);
12839
- parsedJson = true;
12840
- } catch {
12841
- data = rawData;
12842
- }
12843
- }
12844
- if (parsedJson) {
12845
- if (responseValidator) {
12846
- await responseValidator(data);
12847
- }
12848
- if (responseTransformer) {
12849
- data = await responseTransformer(data);
12850
- }
12851
- }
12852
- onSseEvent?.({
12853
- data,
12854
- event: eventName,
12855
- id: lastEventId,
12856
- retry: retryDelay
12857
- });
12858
- if (dataLines.length) {
12859
- yield data;
12860
- }
12861
- }
12862
- }
12863
- } finally {
12864
- signal.removeEventListener("abort", abortHandler);
12865
- reader.releaseLock();
12866
- }
12867
- break;
12868
- } catch (error) {
12869
- onSseError?.(error);
12870
- if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
12871
- break;
12872
- }
12873
- const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 3e4);
12874
- await sleep(backoff);
12875
- }
12876
- }
12877
- };
12878
- const stream = createStream();
12879
- return { stream };
12880
- };
12881
- const getAuthToken = async (auth, callback) => {
12882
- const token = typeof callback === "function" ? await callback(auth) : callback;
12883
- if (!token) {
12884
- return;
12885
- }
12886
- if (auth.scheme === "bearer") {
12887
- return `Bearer ${token}`;
12888
- }
12889
- if (auth.scheme === "basic") {
12890
- return `Basic ${btoa(token)}`;
12891
- }
12892
- return token;
12893
- };
12894
- const jsonBodySerializer = {
12895
- bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value)
12896
- };
12897
- const separatorArrayExplode = (style) => {
12898
- switch (style) {
12899
- case "label":
12900
- return ".";
12901
- case "matrix":
12902
- return ";";
12903
- case "simple":
12904
- return ",";
12905
- default:
12906
- return "&";
12907
- }
12908
- };
12909
- const separatorArrayNoExplode = (style) => {
12910
- switch (style) {
12911
- case "form":
12912
- return ",";
12913
- case "pipeDelimited":
12914
- return "|";
12915
- case "spaceDelimited":
12916
- return "%20";
12917
- default:
12918
- return ",";
12919
- }
12920
- };
12921
- const separatorObjectExplode = (style) => {
12922
- switch (style) {
12923
- case "label":
12924
- return ".";
12925
- case "matrix":
12926
- return ";";
12927
- case "simple":
12928
- return ",";
12929
- default:
12930
- return "&";
12931
- }
12932
- };
12933
- const serializeArrayParam = ({ allowReserved, explode, name, style, value }) => {
12934
- if (!explode) {
12935
- const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
12936
- switch (style) {
12937
- case "label":
12938
- return `.${joinedValues2}`;
12939
- case "matrix":
12940
- return `;${name}=${joinedValues2}`;
12941
- case "simple":
12942
- return joinedValues2;
12943
- default:
12944
- return `${name}=${joinedValues2}`;
12945
- }
12946
- }
12947
- const separator = separatorArrayExplode(style);
12948
- const joinedValues = value.map((v) => {
12949
- if (style === "label" || style === "simple") {
12950
- return allowReserved ? v : encodeURIComponent(v);
12951
- }
12952
- return serializePrimitiveParam({
12953
- allowReserved,
12954
- name,
12955
- value: v
12956
- });
12957
- }).join(separator);
12958
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
12959
- };
12960
- const serializePrimitiveParam = ({ allowReserved, name, value }) => {
12961
- if (value === void 0 || value === null) {
12962
- return "";
12963
- }
12964
- if (typeof value === "object") {
12965
- throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");
12966
- }
12967
- return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
12968
- };
12969
- const serializeObjectParam = ({ allowReserved, explode, name, style, value, valueOnly }) => {
12970
- if (value instanceof Date) {
12971
- return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
12972
- }
12973
- if (style !== "deepObject" && !explode) {
12974
- let values = [];
12975
- Object.entries(value).forEach(([key, v]) => {
12976
- values = [...values, key, allowReserved ? v : encodeURIComponent(v)];
12977
- });
12978
- const joinedValues2 = values.join(",");
12979
- switch (style) {
12980
- case "form":
12981
- return `${name}=${joinedValues2}`;
12982
- case "label":
12983
- return `.${joinedValues2}`;
12984
- case "matrix":
12985
- return `;${name}=${joinedValues2}`;
12986
- default:
12987
- return joinedValues2;
12988
- }
12989
- }
12990
- const separator = separatorObjectExplode(style);
12991
- const joinedValues = Object.entries(value).map(([key, v]) => serializePrimitiveParam({
12992
- allowReserved,
12993
- name: style === "deepObject" ? `${name}[${key}]` : key,
12994
- value: v
12995
- })).join(separator);
12996
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
12997
- };
12998
- const PATH_PARAM_RE = /\{[^{}]+\}/g;
12999
- const defaultPathSerializer = ({ path: path2, url: _url2 }) => {
13000
- let url = _url2;
13001
- const matches = _url2.match(PATH_PARAM_RE);
13002
- if (matches) {
13003
- for (const match of matches) {
13004
- let explode = false;
13005
- let name = match.substring(1, match.length - 1);
13006
- let style = "simple";
13007
- if (name.endsWith("*")) {
13008
- explode = true;
13009
- name = name.substring(0, name.length - 1);
13010
- }
13011
- if (name.startsWith(".")) {
13012
- name = name.substring(1);
13013
- style = "label";
13014
- } else if (name.startsWith(";")) {
13015
- name = name.substring(1);
13016
- style = "matrix";
13017
- }
13018
- const value = path2[name];
13019
- if (value === void 0 || value === null) {
13020
- continue;
13021
- }
13022
- if (Array.isArray(value)) {
13023
- url = url.replace(match, serializeArrayParam({ explode, name, style, value }));
13024
- continue;
13025
- }
13026
- if (typeof value === "object") {
13027
- url = url.replace(match, serializeObjectParam({
13028
- explode,
13029
- name,
13030
- style,
13031
- value,
13032
- valueOnly: true
13033
- }));
13034
- continue;
13035
- }
13036
- if (style === "matrix") {
13037
- url = url.replace(match, `;${serializePrimitiveParam({
13038
- name,
13039
- value
13040
- })}`);
13041
- continue;
13042
- }
13043
- const replaceValue = encodeURIComponent(style === "label" ? `.${value}` : value);
13044
- url = url.replace(match, replaceValue);
13045
- }
13046
- }
13047
- return url;
13048
- };
13049
- const getUrl = ({ baseUrl, path: path2, query, querySerializer, url: _url2 }) => {
13050
- const pathUrl = _url2.startsWith("/") ? _url2 : `/${_url2}`;
13051
- let url = (baseUrl ?? "") + pathUrl;
13052
- if (path2) {
13053
- url = defaultPathSerializer({ path: path2, url });
13054
- }
13055
- let search = query ? querySerializer(query) : "";
13056
- if (search.startsWith("?")) {
13057
- search = search.substring(1);
13058
- }
13059
- if (search) {
13060
- url += `?${search}`;
12774
+ return [DEFAULT_MODEL$1];
13061
12775
  }
13062
- return url;
13063
- };
13064
- const createQuerySerializer = ({ allowReserved, array: array2, object: object2 } = {}) => {
13065
- const querySerializer = (queryParams) => {
13066
- const search = [];
13067
- if (queryParams && typeof queryParams === "object") {
13068
- for (const name in queryParams) {
13069
- const value = queryParams[name];
13070
- if (value === void 0 || value === null) {
13071
- continue;
13072
- }
13073
- if (Array.isArray(value)) {
13074
- const serializedArray = serializeArrayParam({
13075
- allowReserved,
13076
- explode: true,
13077
- name,
13078
- style: "form",
13079
- value,
13080
- ...array2
13081
- });
13082
- if (serializedArray)
13083
- search.push(serializedArray);
13084
- } else if (typeof value === "object") {
13085
- const serializedObject = serializeObjectParam({
13086
- allowReserved,
13087
- explode: true,
13088
- name,
13089
- style: "deepObject",
13090
- value,
13091
- ...object2
13092
- });
13093
- if (serializedObject)
13094
- search.push(serializedObject);
13095
- } else {
13096
- const serializedPrimitive = serializePrimitiveParam({
13097
- allowReserved,
13098
- name,
13099
- value
13100
- });
13101
- if (serializedPrimitive)
13102
- search.push(serializedPrimitive);
13103
- }
13104
- }
13105
- }
13106
- return search.join("&");
13107
- };
13108
- return querySerializer;
13109
- };
13110
- const getParseAs = (contentType) => {
13111
- if (!contentType) {
13112
- return "stream";
13113
- }
13114
- const cleanContent = contentType.split(";")[0]?.trim();
13115
- if (!cleanContent) {
13116
- return;
13117
- }
13118
- if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
13119
- return "json";
13120
- }
13121
- if (cleanContent === "multipart/form-data") {
13122
- return "formData";
13123
- }
13124
- if (["application/", "audio/", "image/", "video/"].some((type) => cleanContent.startsWith(type))) {
13125
- return "blob";
13126
- }
13127
- if (cleanContent.startsWith("text/")) {
13128
- return "text";
13129
- }
13130
- return;
13131
- };
13132
- const checkForExistence = (options, name) => {
13133
- if (!name) {
13134
- return false;
13135
- }
13136
- if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) {
13137
- return true;
13138
- }
13139
- return false;
13140
- };
13141
- const setAuthParams = async ({ security, ...options }) => {
13142
- for (const auth of security) {
13143
- if (checkForExistence(options, auth.name)) {
13144
- continue;
13145
- }
13146
- const token = await getAuthToken(auth, options.auth);
13147
- if (!token) {
13148
- continue;
13149
- }
13150
- const name = auth.name ?? "Authorization";
13151
- switch (auth.in) {
13152
- case "query":
13153
- if (!options.query) {
13154
- options.query = {};
13155
- }
13156
- options.query[name] = token;
13157
- break;
13158
- case "cookie":
13159
- options.headers.append("Cookie", `${name}=${token}`);
13160
- break;
13161
- case "header":
13162
- default:
13163
- options.headers.set(name, token);
13164
- break;
13165
- }
13166
- }
13167
- };
13168
- const buildUrl = (options) => getUrl({
13169
- baseUrl: options.baseUrl,
13170
- path: options.path,
13171
- query: options.query,
13172
- querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
13173
- url: options.url
13174
- });
13175
- const mergeConfigs = (a2, b) => {
13176
- const config2 = { ...a2, ...b };
13177
- if (config2.baseUrl?.endsWith("/")) {
13178
- config2.baseUrl = config2.baseUrl.substring(0, config2.baseUrl.length - 1);
13179
- }
13180
- config2.headers = mergeHeaders(a2.headers, b.headers);
13181
- return config2;
13182
- };
13183
- const mergeHeaders = (...headers) => {
13184
- const mergedHeaders = new Headers();
13185
- for (const header of headers) {
13186
- if (!header || typeof header !== "object") {
13187
- continue;
13188
- }
13189
- const iterator = header instanceof Headers ? header.entries() : Object.entries(header);
13190
- for (const [key, value] of iterator) {
13191
- if (value === null) {
13192
- mergedHeaders.delete(key);
13193
- } else if (Array.isArray(value)) {
13194
- for (const v of value) {
13195
- mergedHeaders.append(key, v);
13196
- }
13197
- } else if (value !== void 0) {
13198
- mergedHeaders.set(key, typeof value === "object" ? JSON.stringify(value) : value);
13199
- }
13200
- }
13201
- }
13202
- return mergedHeaders;
13203
- };
13204
- class Interceptors {
13205
- _fns;
13206
- constructor() {
13207
- this._fns = [];
13208
- }
13209
- clear() {
13210
- this._fns = [];
13211
- }
13212
- getInterceptorIndex(id) {
13213
- if (typeof id === "number") {
13214
- return this._fns[id] ? id : -1;
13215
- } else {
13216
- return this._fns.indexOf(id);
13217
- }
13218
- }
13219
- exists(id) {
13220
- const index = this.getInterceptorIndex(id);
13221
- return !!this._fns[index];
13222
- }
13223
- eject(id) {
13224
- const index = this.getInterceptorIndex(id);
13225
- if (this._fns[index]) {
13226
- this._fns[index] = null;
13227
- }
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();
13228
12803
  }
13229
- update(id, fn) {
13230
- const index = this.getInterceptorIndex(id);
13231
- if (this._fns[index]) {
13232
- this._fns[index] = fn;
13233
- return id;
13234
- } else {
13235
- return false;
13236
- }
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 };
13237
12809
  }
13238
- use(fn) {
13239
- this._fns = [...this._fns, fn];
13240
- 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();
13241
12815
  }
13242
12816
  }
13243
- const createInterceptors = () => ({
13244
- error: new Interceptors(),
13245
- request: new Interceptors(),
13246
- response: new Interceptors()
13247
- });
13248
- const defaultQuerySerializer = createQuerySerializer({
13249
- allowReserved: false,
13250
- array: {
13251
- explode: true,
13252
- style: "form"
13253
- },
13254
- object: {
13255
- explode: true,
13256
- 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;
13257
12828
  }
13258
- });
13259
- const defaultHeaders = {
13260
- "Content-Type": "application/json"
13261
- };
13262
- const createConfig = (override = {}) => ({
13263
- ...jsonBodySerializer,
13264
- headers: defaultHeaders,
13265
- parseAs: "auto",
13266
- querySerializer: defaultQuerySerializer,
13267
- ...override
13268
- });
13269
- const createClient = (config2 = {}) => {
13270
- let _config = mergeConfigs(createConfig(), config2);
13271
- const getConfig = () => ({ ..._config });
13272
- const setConfig = (config3) => {
13273
- _config = mergeConfigs(_config, config3);
13274
- return getConfig();
13275
- };
13276
- const interceptors = createInterceptors();
13277
- const beforeRequest = async (options) => {
13278
- const opts = {
13279
- ..._config,
13280
- ...options,
13281
- fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
13282
- headers: mergeHeaders(_config.headers, options.headers),
13283
- serializedBody: void 0
13284
- };
13285
- if (opts.security) {
13286
- await setAuthParams({
13287
- ...opts,
13288
- security: opts.security
13289
- });
13290
- }
13291
- if (opts.requestValidator) {
13292
- await opts.requestValidator(opts);
13293
- }
13294
- if (opts.body && opts.bodySerializer) {
13295
- opts.serializedBody = opts.bodySerializer(opts.body);
13296
- }
13297
- if (opts.serializedBody === void 0 || opts.serializedBody === "") {
13298
- opts.headers.delete("Content-Type");
13299
- }
13300
- const url = buildUrl(opts);
13301
- return { opts, url };
13302
- };
13303
- const request = async (options) => {
13304
- const { opts, url } = await beforeRequest(options);
13305
- const requestInit = {
13306
- redirect: "follow",
13307
- ...opts,
13308
- body: opts.serializedBody
13309
- };
13310
- let request2 = new Request(url, requestInit);
13311
- for (const fn of interceptors.request._fns) {
13312
- if (fn) {
13313
- request2 = await fn(request2, opts);
13314
- }
13315
- }
13316
- const _fetch = opts.fetch;
13317
- let response = await _fetch(request2);
13318
- for (const fn of interceptors.response._fns) {
13319
- if (fn) {
13320
- response = await fn(response, request2, opts);
13321
- }
13322
- }
13323
- const result = {
13324
- request: request2,
13325
- response
13326
- };
13327
- if (response.ok) {
13328
- if (response.status === 204 || response.headers.get("Content-Length") === "0") {
13329
- return opts.responseStyle === "data" ? {} : {
13330
- data: {},
13331
- ...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." } : {}
13332
12853
  };
12854
+ } catch (error) {
12855
+ return { ...installed, availability: "error", authStatus: "unknown", message: error instanceof AiOperationError ? error.message : "Could not verify Grok execution controls." };
13333
12856
  }
13334
- const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
13335
- let data;
13336
- switch (parseAs) {
13337
- case "arrayBuffer":
13338
- case "blob":
13339
- case "formData":
13340
- case "json":
13341
- case "text":
13342
- data = await response[parseAs]();
13343
- break;
13344
- case "stream":
13345
- return opts.responseStyle === "data" ? response.body : {
13346
- data: response.body,
13347
- ...result
13348
- };
13349
- }
13350
- if (parseAs === "json") {
13351
- if (opts.responseValidator) {
13352
- await opts.responseValidator(data);
13353
- }
13354
- if (opts.responseTransformer) {
13355
- data = await opts.responseTransformer(data);
13356
- }
13357
- }
13358
- return opts.responseStyle === "data" ? data : {
13359
- data,
13360
- ...result
13361
- };
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;
13362
12903
  }
13363
- const textError = await response.text();
13364
- 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;
13365
12910
  try {
13366
- jsonError = JSON.parse(textError);
12911
+ report = JSON.parse(result.stdout);
13367
12912
  } catch {
12913
+ throw failure("AI_PROCESS_FAILED", "Could not verify the isolated Grok configuration.");
13368
12914
  }
13369
- const error = jsonError ?? textError;
13370
- let finalError = error;
13371
- for (const fn of interceptors.error._fns) {
13372
- if (fn) {
13373
- finalError = await fn(error, response, request2, opts);
13374
- }
13375
- }
13376
- finalError = finalError || {};
13377
- if (opts.throwOnError) {
13378
- 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.");
13379
12918
  }
13380
- return opts.responseStyle === "data" ? void 0 : {
13381
- error: finalError,
13382
- ...result
13383
- };
13384
- };
13385
- const makeMethod = (method) => {
13386
- const fn = (options) => request({ ...options, method });
13387
- fn.sse = async (options) => {
13388
- const { opts, url } = await beforeRequest(options);
13389
- return createSseClient({
13390
- ...opts,
13391
- body: opts.body,
13392
- headers: opts.headers,
13393
- method,
13394
- url
13395
- });
13396
- };
13397
- return fn;
13398
- };
13399
- return {
13400
- buildUrl,
13401
- connect: makeMethod("CONNECT"),
13402
- delete: makeMethod("DELETE"),
13403
- get: makeMethod("GET"),
13404
- getConfig,
13405
- head: makeMethod("HEAD"),
13406
- interceptors,
13407
- options: makeMethod("OPTIONS"),
13408
- patch: makeMethod("PATCH"),
13409
- post: makeMethod("POST"),
13410
- put: makeMethod("PUT"),
13411
- request,
13412
- setConfig,
13413
- trace: makeMethod("TRACE")
13414
- };
13415
- };
13416
- const client = createClient(createConfig({
13417
- baseUrl: "http://localhost:4096"
13418
- }));
13419
- class _HeyApiClient {
13420
- _client = client;
13421
- constructor(args) {
13422
- if (args?.client) {
13423
- 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 });
13424
12946
  }
13425
12947
  }
13426
12948
  }
13427
- class Global extends _HeyApiClient {
13428
- /**
13429
- * Get events
13430
- */
13431
- event(options) {
13432
- return (options?.client ?? this._client).get.sse({
13433
- url: "/global/event",
13434
- ...options
13435
- });
13436
- }
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.");
13437
12957
  }
13438
- class Project extends _HeyApiClient {
13439
- /**
13440
- * List all projects
13441
- */
13442
- list(options) {
13443
- return (options?.client ?? this._client).get({
13444
- url: "/project",
13445
- ...options
13446
- });
13447
- }
13448
- /**
13449
- * Get the current project
13450
- */
13451
- current(options) {
13452
- return (options?.client ?? this._client).get({
13453
- url: "/project/current",
13454
- ...options
13455
- });
13456
- }
12958
+ function failure(code, message) {
12959
+ return new AiOperationError({ code, operation: "grok-generate", harness: "grok", message });
13457
12960
  }
13458
- class Pty extends _HeyApiClient {
13459
- /**
13460
- * List all PTY sessions
13461
- */
13462
- list(options) {
13463
- return (options?.client ?? this._client).get({
13464
- url: "/pty",
13465
- ...options
13466
- });
13467
- }
13468
- /**
13469
- * Create a new PTY session
13470
- */
13471
- create(options) {
13472
- return (options?.client ?? this._client).post({
13473
- url: "/pty",
13474
- ...options,
13475
- headers: {
13476
- "Content-Type": "application/json",
13477
- ...options?.headers
13478
- }
13479
- });
13480
- }
13481
- /**
13482
- * Remove a PTY session
13483
- */
13484
- remove(options) {
13485
- return (options.client ?? this._client).delete({
13486
- url: "/pty/{id}",
13487
- ...options
13488
- });
13489
- }
13490
- /**
13491
- * Get PTY session info
13492
- */
13493
- get(options) {
13494
- return (options.client ?? this._client).get({
13495
- url: "/pty/{id}",
13496
- ...options
13497
- });
13498
- }
13499
- /**
13500
- * Update PTY session
13501
- */
13502
- update(options) {
13503
- return (options.client ?? this._client).put({
13504
- url: "/pty/{id}",
13505
- ...options,
13506
- headers: {
13507
- "Content-Type": "application/json",
13508
- ...options.headers
13509
- }
13510
- });
13511
- }
13512
- /**
13513
- * Connect to a PTY session
13514
- */
13515
- connect(options) {
13516
- return (options.client ?? this._client).get({
13517
- url: "/pty/{id}/connect",
13518
- ...options
13519
- });
13520
- }
12961
+ function openCodeCliName(executable) {
12962
+ return path.parse(executable).name.toLowerCase() === "opencode2" ? "opencode2" : "opencode";
13521
12963
  }
13522
- class Config extends _HeyApiClient {
13523
- /**
13524
- * Get config info
13525
- */
13526
- get(options) {
13527
- return (options?.client ?? this._client).get({
13528
- url: "/config",
13529
- ...options
13530
- });
13531
- }
13532
- /**
13533
- * Update config
13534
- */
13535
- update(options) {
13536
- return (options?.client ?? this._client).patch({
13537
- url: "/config",
13538
- ...options,
13539
- headers: {
13540
- "Content-Type": "application/json",
13541
- ...options?.headers
13542
- }
13543
- });
13544
- }
13545
- /**
13546
- * List all providers
13547
- */
13548
- providers(options) {
13549
- return (options?.client ?? this._client).get({
13550
- url: "/config/providers",
13551
- ...options
13552
- });
13553
- }
12964
+ function isOpenCodeV2Version(raw) {
12965
+ return /^(?:opencode2?\s+)?v?2\.\d+\.\d+(?:[-+][\w.-]+)?$/.test(stripAnsi(raw).trim());
13554
12966
  }
13555
- class Tool extends _HeyApiClient {
13556
- /**
13557
- * List all tool IDs (including built-in and dynamically registered)
13558
- */
13559
- ids(options) {
13560
- return (options?.client ?? this._client).get({
13561
- url: "/experimental/tool/ids",
13562
- ...options
13563
- });
13564
- }
13565
- /**
13566
- * List tools with JSON schema parameters for a provider/model
13567
- */
13568
- list(options) {
13569
- return (options.client ?? this._client).get({
13570
- url: "/experimental/tool",
13571
- ...options
13572
- });
13573
- }
12967
+ function openCodeLoginCommand(cliName) {
12968
+ return cliName === "opencode2" ? "opencode2 auth login" : "opencode auth login";
13574
12969
  }
13575
- class Instance extends _HeyApiClient {
13576
- /**
13577
- * Dispose the current instance
13578
- */
13579
- dispose(options) {
13580
- return (options?.client ?? this._client).post({
13581
- url: "/instance/dispose",
13582
- ...options
13583
- });
12970
+ function parseOpenCodeAuthList(raw, exitCode) {
12971
+ if (exitCode !== 0) return "unknown";
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 {
13584
12977
  }
13585
- }
13586
- class Path extends _HeyApiClient {
13587
- /**
13588
- * Get the current path
13589
- */
13590
- get(options) {
13591
- return (options?.client ?? this._client).get({
13592
- url: "/path",
13593
- ...options
13594
- });
13595
- }
13596
- }
13597
- class Vcs extends _HeyApiClient {
13598
- /**
13599
- * Get VCS info for the current instance
13600
- */
13601
- get(options) {
13602
- return (options?.client ?? this._client).get({
13603
- url: "/vcs",
13604
- ...options
13605
- });
13606
- }
13607
- }
13608
- class Session extends _HeyApiClient {
13609
- /**
13610
- * List all sessions
13611
- */
13612
- list(options) {
13613
- return (options?.client ?? this._client).get({
13614
- url: "/session",
13615
- ...options
13616
- });
13617
- }
13618
- /**
13619
- * Create a new session
13620
- */
13621
- create(options) {
13622
- return (options?.client ?? this._client).post({
13623
- url: "/session",
13624
- ...options,
13625
- headers: {
13626
- "Content-Type": "application/json",
13627
- ...options?.headers
13628
- }
13629
- });
13630
- }
13631
- /**
13632
- * Get session status
13633
- */
13634
- status(options) {
13635
- return (options?.client ?? this._client).get({
13636
- url: "/session/status",
13637
- ...options
13638
- });
13639
- }
13640
- /**
13641
- * Delete a session and all its data
13642
- */
13643
- delete(options) {
13644
- return (options.client ?? this._client).delete({
13645
- url: "/session/{id}",
13646
- ...options
13647
- });
13648
- }
13649
- /**
13650
- * Get session
13651
- */
13652
- get(options) {
13653
- return (options.client ?? this._client).get({
13654
- url: "/session/{id}",
13655
- ...options
13656
- });
13657
- }
13658
- /**
13659
- * Update session properties
13660
- */
13661
- update(options) {
13662
- return (options.client ?? this._client).patch({
13663
- url: "/session/{id}",
13664
- ...options,
13665
- headers: {
13666
- "Content-Type": "application/json",
13667
- ...options.headers
13668
- }
13669
- });
13670
- }
13671
- /**
13672
- * Get a session's children
13673
- */
13674
- children(options) {
13675
- return (options.client ?? this._client).get({
13676
- url: "/session/{id}/children",
13677
- ...options
13678
- });
13679
- }
13680
- /**
13681
- * Get the todo list for a session
13682
- */
13683
- todo(options) {
13684
- return (options.client ?? this._client).get({
13685
- url: "/session/{id}/todo",
13686
- ...options
13687
- });
13688
- }
13689
- /**
13690
- * Analyze the app and create an AGENTS.md file
13691
- */
13692
- init(options) {
13693
- return (options.client ?? this._client).post({
13694
- url: "/session/{id}/init",
13695
- ...options,
13696
- headers: {
13697
- "Content-Type": "application/json",
13698
- ...options.headers
13699
- }
13700
- });
13701
- }
13702
- /**
13703
- * Fork an existing session at a specific message
13704
- */
13705
- fork(options) {
13706
- return (options.client ?? this._client).post({
13707
- url: "/session/{id}/fork",
13708
- ...options,
13709
- headers: {
13710
- "Content-Type": "application/json",
13711
- ...options.headers
13712
- }
13713
- });
13714
- }
13715
- /**
13716
- * Abort a session
13717
- */
13718
- abort(options) {
13719
- return (options.client ?? this._client).post({
13720
- url: "/session/{id}/abort",
13721
- ...options
13722
- });
13723
- }
13724
- /**
13725
- * Unshare the session
13726
- */
13727
- unshare(options) {
13728
- return (options.client ?? this._client).delete({
13729
- url: "/session/{id}/share",
13730
- ...options
13731
- });
13732
- }
13733
- /**
13734
- * Share a session
13735
- */
13736
- share(options) {
13737
- return (options.client ?? this._client).post({
13738
- url: "/session/{id}/share",
13739
- ...options
13740
- });
13741
- }
13742
- /**
13743
- * Get the diff for this session
13744
- */
13745
- diff(options) {
13746
- return (options.client ?? this._client).get({
13747
- url: "/session/{id}/diff",
13748
- ...options
13749
- });
13750
- }
13751
- /**
13752
- * Summarize the session
13753
- */
13754
- summarize(options) {
13755
- return (options.client ?? this._client).post({
13756
- url: "/session/{id}/summarize",
13757
- ...options,
13758
- headers: {
13759
- "Content-Type": "application/json",
13760
- ...options.headers
13761
- }
13762
- });
13763
- }
13764
- /**
13765
- * List messages for a session
13766
- */
13767
- messages(options) {
13768
- return (options.client ?? this._client).get({
13769
- url: "/session/{id}/message",
13770
- ...options
13771
- });
13772
- }
13773
- /**
13774
- * Create and send a new message to a session
13775
- */
13776
- prompt(options) {
13777
- return (options.client ?? this._client).post({
13778
- url: "/session/{id}/message",
13779
- ...options,
13780
- headers: {
13781
- "Content-Type": "application/json",
13782
- ...options.headers
13783
- }
13784
- });
13785
- }
13786
- /**
13787
- * Get a message from a session
13788
- */
13789
- message(options) {
13790
- return (options.client ?? this._client).get({
13791
- url: "/session/{id}/message/{messageID}",
13792
- ...options
13793
- });
13794
- }
13795
- /**
13796
- * Create and send a new message to a session, start if needed and return immediately
13797
- */
13798
- promptAsync(options) {
13799
- return (options.client ?? this._client).post({
13800
- url: "/session/{id}/prompt_async",
13801
- ...options,
13802
- headers: {
13803
- "Content-Type": "application/json",
13804
- ...options.headers
13805
- }
13806
- });
13807
- }
13808
- /**
13809
- * Send a new command to a session
13810
- */
13811
- command(options) {
13812
- return (options.client ?? this._client).post({
13813
- url: "/session/{id}/command",
13814
- ...options,
13815
- headers: {
13816
- "Content-Type": "application/json",
13817
- ...options.headers
13818
- }
13819
- });
13820
- }
13821
- /**
13822
- * Run a shell command
13823
- */
13824
- shell(options) {
13825
- return (options.client ?? this._client).post({
13826
- url: "/session/{id}/shell",
13827
- ...options,
13828
- headers: {
13829
- "Content-Type": "application/json",
13830
- ...options.headers
13831
- }
13832
- });
13833
- }
13834
- /**
13835
- * Revert a message
13836
- */
13837
- revert(options) {
13838
- return (options.client ?? this._client).post({
13839
- url: "/session/{id}/revert",
13840
- ...options,
13841
- headers: {
13842
- "Content-Type": "application/json",
13843
- ...options.headers
13844
- }
13845
- });
13846
- }
13847
- /**
13848
- * Restore all reverted messages
13849
- */
13850
- unrevert(options) {
13851
- return (options.client ?? this._client).post({
13852
- url: "/session/{id}/unrevert",
13853
- ...options
13854
- });
13855
- }
13856
- }
13857
- class Command extends _HeyApiClient {
13858
- /**
13859
- * List all commands
13860
- */
13861
- list(options) {
13862
- return (options?.client ?? this._client).get({
13863
- url: "/command",
13864
- ...options
13865
- });
13866
- }
13867
- }
13868
- class Oauth extends _HeyApiClient {
13869
- /**
13870
- * Authorize a provider using OAuth
13871
- */
13872
- authorize(options) {
13873
- return (options.client ?? this._client).post({
13874
- url: "/provider/{id}/oauth/authorize",
13875
- ...options,
13876
- headers: {
13877
- "Content-Type": "application/json",
13878
- ...options.headers
13879
- }
13880
- });
13881
- }
13882
- /**
13883
- * Handle OAuth callback for a provider
13884
- */
13885
- callback(options) {
13886
- return (options.client ?? this._client).post({
13887
- url: "/provider/{id}/oauth/callback",
13888
- ...options,
13889
- headers: {
13890
- "Content-Type": "application/json",
13891
- ...options.headers
13892
- }
13893
- });
13894
- }
13895
- }
13896
- class Provider extends _HeyApiClient {
13897
- /**
13898
- * List all providers
13899
- */
13900
- list(options) {
13901
- return (options?.client ?? this._client).get({
13902
- url: "/provider",
13903
- ...options
13904
- });
13905
- }
13906
- /**
13907
- * Get provider authentication methods
13908
- */
13909
- auth(options) {
13910
- return (options?.client ?? this._client).get({
13911
- url: "/provider/auth",
13912
- ...options
13913
- });
13914
- }
13915
- oauth = new Oauth({ client: this._client });
13916
- }
13917
- class Find extends _HeyApiClient {
13918
- /**
13919
- * Find text in files
13920
- */
13921
- text(options) {
13922
- return (options.client ?? this._client).get({
13923
- url: "/find",
13924
- ...options
13925
- });
13926
- }
13927
- /**
13928
- * Find files
13929
- */
13930
- files(options) {
13931
- return (options.client ?? this._client).get({
13932
- url: "/find/file",
13933
- ...options
13934
- });
13935
- }
13936
- /**
13937
- * Find workspace symbols
13938
- */
13939
- symbols(options) {
13940
- return (options.client ?? this._client).get({
13941
- url: "/find/symbol",
13942
- ...options
13943
- });
13944
- }
13945
- }
13946
- class File extends _HeyApiClient {
13947
- /**
13948
- * List files and directories
13949
- */
13950
- list(options) {
13951
- return (options.client ?? this._client).get({
13952
- url: "/file",
13953
- ...options
13954
- });
13955
- }
13956
- /**
13957
- * Read a file
13958
- */
13959
- read(options) {
13960
- return (options.client ?? this._client).get({
13961
- url: "/file/content",
13962
- ...options
13963
- });
13964
- }
13965
- /**
13966
- * Get file status
13967
- */
13968
- status(options) {
13969
- return (options?.client ?? this._client).get({
13970
- url: "/file/status",
13971
- ...options
13972
- });
13973
- }
13974
- }
13975
- class App extends _HeyApiClient {
13976
- /**
13977
- * Write a log entry to the server logs
13978
- */
13979
- log(options) {
13980
- return (options?.client ?? this._client).post({
13981
- url: "/log",
13982
- ...options,
13983
- headers: {
13984
- "Content-Type": "application/json",
13985
- ...options?.headers
13986
- }
13987
- });
13988
- }
13989
- /**
13990
- * List all agents
13991
- */
13992
- agents(options) {
13993
- return (options?.client ?? this._client).get({
13994
- url: "/agent",
13995
- ...options
13996
- });
13997
- }
13998
- }
13999
- class Auth extends _HeyApiClient {
14000
- /**
14001
- * Remove OAuth credentials for an MCP server
14002
- */
14003
- remove(options) {
14004
- return (options.client ?? this._client).delete({
14005
- url: "/mcp/{name}/auth",
14006
- ...options
14007
- });
14008
- }
14009
- /**
14010
- * Start OAuth authentication flow for an MCP server
14011
- */
14012
- start(options) {
14013
- return (options.client ?? this._client).post({
14014
- url: "/mcp/{name}/auth",
14015
- ...options
14016
- });
14017
- }
14018
- /**
14019
- * Complete OAuth authentication with authorization code
14020
- */
14021
- callback(options) {
14022
- return (options.client ?? this._client).post({
14023
- url: "/mcp/{name}/auth/callback",
14024
- ...options,
14025
- headers: {
14026
- "Content-Type": "application/json",
14027
- ...options.headers
14028
- }
14029
- });
14030
- }
14031
- /**
14032
- * Start OAuth flow and wait for callback (opens browser)
14033
- */
14034
- authenticate(options) {
14035
- return (options.client ?? this._client).post({
14036
- url: "/mcp/{name}/auth/authenticate",
14037
- ...options
14038
- });
14039
- }
14040
- /**
14041
- * Set authentication credentials
14042
- */
14043
- set(options) {
14044
- return (options.client ?? this._client).put({
14045
- url: "/auth/{id}",
14046
- ...options,
14047
- headers: {
14048
- "Content-Type": "application/json",
14049
- ...options.headers
14050
- }
14051
- });
14052
- }
14053
- }
14054
- class Mcp extends _HeyApiClient {
14055
- /**
14056
- * Get MCP server status
14057
- */
14058
- status(options) {
14059
- return (options?.client ?? this._client).get({
14060
- url: "/mcp",
14061
- ...options
14062
- });
14063
- }
14064
- /**
14065
- * Add MCP server dynamically
14066
- */
14067
- add(options) {
14068
- return (options?.client ?? this._client).post({
14069
- url: "/mcp",
14070
- ...options,
14071
- headers: {
14072
- "Content-Type": "application/json",
14073
- ...options?.headers
14074
- }
14075
- });
14076
- }
14077
- /**
14078
- * Connect an MCP server
14079
- */
14080
- connect(options) {
14081
- return (options.client ?? this._client).post({
14082
- url: "/mcp/{name}/connect",
14083
- ...options
14084
- });
14085
- }
14086
- /**
14087
- * Disconnect an MCP server
14088
- */
14089
- disconnect(options) {
14090
- return (options.client ?? this._client).post({
14091
- url: "/mcp/{name}/disconnect",
14092
- ...options
14093
- });
14094
- }
14095
- auth = new Auth({ client: this._client });
14096
- }
14097
- class Lsp extends _HeyApiClient {
14098
- /**
14099
- * Get LSP server status
14100
- */
14101
- status(options) {
14102
- return (options?.client ?? this._client).get({
14103
- url: "/lsp",
14104
- ...options
14105
- });
14106
- }
14107
- }
14108
- class Formatter extends _HeyApiClient {
14109
- /**
14110
- * Get formatter status
14111
- */
14112
- status(options) {
14113
- return (options?.client ?? this._client).get({
14114
- url: "/formatter",
14115
- ...options
14116
- });
14117
- }
14118
- }
14119
- class Control extends _HeyApiClient {
14120
- /**
14121
- * Get the next TUI request from the queue
14122
- */
14123
- next(options) {
14124
- return (options?.client ?? this._client).get({
14125
- url: "/tui/control/next",
14126
- ...options
14127
- });
14128
- }
14129
- /**
14130
- * Submit a response to the TUI request queue
14131
- */
14132
- response(options) {
14133
- return (options?.client ?? this._client).post({
14134
- url: "/tui/control/response",
14135
- ...options,
14136
- headers: {
14137
- "Content-Type": "application/json",
14138
- ...options?.headers
14139
- }
14140
- });
14141
- }
14142
- }
14143
- class Tui extends _HeyApiClient {
14144
- /**
14145
- * Append prompt to the TUI
14146
- */
14147
- appendPrompt(options) {
14148
- return (options?.client ?? this._client).post({
14149
- url: "/tui/append-prompt",
14150
- ...options,
14151
- headers: {
14152
- "Content-Type": "application/json",
14153
- ...options?.headers
14154
- }
14155
- });
14156
- }
14157
- /**
14158
- * Open the help dialog
14159
- */
14160
- openHelp(options) {
14161
- return (options?.client ?? this._client).post({
14162
- url: "/tui/open-help",
14163
- ...options
14164
- });
14165
- }
14166
- /**
14167
- * Open the session dialog
14168
- */
14169
- openSessions(options) {
14170
- return (options?.client ?? this._client).post({
14171
- url: "/tui/open-sessions",
14172
- ...options
14173
- });
14174
- }
14175
- /**
14176
- * Open the theme dialog
14177
- */
14178
- openThemes(options) {
14179
- return (options?.client ?? this._client).post({
14180
- url: "/tui/open-themes",
14181
- ...options
14182
- });
14183
- }
14184
- /**
14185
- * Open the model dialog
14186
- */
14187
- openModels(options) {
14188
- return (options?.client ?? this._client).post({
14189
- url: "/tui/open-models",
14190
- ...options
14191
- });
14192
- }
14193
- /**
14194
- * Submit the prompt
14195
- */
14196
- submitPrompt(options) {
14197
- return (options?.client ?? this._client).post({
14198
- url: "/tui/submit-prompt",
14199
- ...options
14200
- });
14201
- }
14202
- /**
14203
- * Clear the prompt
14204
- */
14205
- clearPrompt(options) {
14206
- return (options?.client ?? this._client).post({
14207
- url: "/tui/clear-prompt",
14208
- ...options
14209
- });
14210
- }
14211
- /**
14212
- * Execute a TUI command (e.g. agent_cycle)
14213
- */
14214
- executeCommand(options) {
14215
- return (options?.client ?? this._client).post({
14216
- url: "/tui/execute-command",
14217
- ...options,
14218
- headers: {
14219
- "Content-Type": "application/json",
14220
- ...options?.headers
14221
- }
14222
- });
14223
- }
14224
- /**
14225
- * Show a toast notification in the TUI
14226
- */
14227
- showToast(options) {
14228
- return (options?.client ?? this._client).post({
14229
- url: "/tui/show-toast",
14230
- ...options,
14231
- headers: {
14232
- "Content-Type": "application/json",
14233
- ...options?.headers
14234
- }
14235
- });
14236
- }
14237
- /**
14238
- * Publish a TUI event
14239
- */
14240
- publish(options) {
14241
- return (options?.client ?? this._client).post({
14242
- url: "/tui/publish",
14243
- ...options,
14244
- headers: {
14245
- "Content-Type": "application/json",
14246
- ...options?.headers
14247
- }
14248
- });
14249
- }
14250
- control = new Control({ client: this._client });
14251
- }
14252
- class Event extends _HeyApiClient {
14253
- /**
14254
- * Get events
14255
- */
14256
- subscribe(options) {
14257
- return (options?.client ?? this._client).get.sse({
14258
- url: "/event",
14259
- ...options
14260
- });
14261
- }
14262
- }
14263
- class OpencodeClient extends _HeyApiClient {
14264
- /**
14265
- * Respond to a permission request
14266
- */
14267
- postSessionIdPermissionsPermissionId(options) {
14268
- return (options.client ?? this._client).post({
14269
- url: "/session/{id}/permissions/{permissionID}",
14270
- ...options,
14271
- headers: {
14272
- "Content-Type": "application/json",
14273
- ...options.headers
14274
- }
14275
- });
14276
- }
14277
- global = new Global({ client: this._client });
14278
- project = new Project({ client: this._client });
14279
- pty = new Pty({ client: this._client });
14280
- config = new Config({ client: this._client });
14281
- tool = new Tool({ client: this._client });
14282
- instance = new Instance({ client: this._client });
14283
- path = new Path({ client: this._client });
14284
- vcs = new Vcs({ client: this._client });
14285
- session = new Session({ client: this._client });
14286
- command = new Command({ client: this._client });
14287
- provider = new Provider({ client: this._client });
14288
- find = new Find({ client: this._client });
14289
- file = new File({ client: this._client });
14290
- app = new App({ client: this._client });
14291
- mcp = new Mcp({ client: this._client });
14292
- lsp = new Lsp({ client: this._client });
14293
- formatter = new Formatter({ client: this._client });
14294
- tui = new Tui({ client: this._client });
14295
- auth = new Auth({ client: this._client });
14296
- event = new Event({ client: this._client });
14297
- }
14298
- function wrapClientError(error, response, request, opts) {
14299
- if (!opts?.throwOnError)
14300
- return error;
14301
- if (error instanceof Error)
14302
- return error;
14303
- if (typeof error === "object" && error !== null && Object.keys(error).length > 0) {
14304
- const obj = error;
14305
- 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);
14306
- return new Error(message, { cause: { body: error, status: response?.status } });
14307
- }
14308
- if (typeof error === "string" && error.length > 0) {
14309
- return new Error(error, { cause: { body: error, status: response?.status } });
14310
- }
14311
- const reason = response ? "(empty response body)" : "network error (no response)";
14312
- return new Error(`opencode server ${describe(request, response)}: ${reason}`, {
14313
- cause: { body: error, status: response?.status }
14314
- });
14315
- }
14316
- function describe(request, response) {
14317
- const method = request?.method ?? "?";
14318
- const url = request?.url ?? "?";
14319
- const status = response?.status;
14320
- const statusText = response?.statusText;
14321
- return `${method} ${url}${status ? " → " + status : ""}${statusText ? " " + statusText : ""}`;
14322
- }
14323
- function pick(value, fallback) {
14324
- if (!value)
14325
- return;
14326
- if (!fallback)
14327
- return value;
14328
- if (value === fallback)
14329
- return fallback;
14330
- if (value === encodeURIComponent(fallback))
14331
- return fallback;
14332
- return value;
14333
- }
14334
- function rewrite(request, directory) {
14335
- if (request.method !== "GET" && request.method !== "HEAD")
14336
- return request;
14337
- const value = pick(request.headers.get("x-opencode-directory"), directory);
14338
- if (!value)
14339
- return request;
14340
- const url = new URL(request.url);
14341
- if (!url.searchParams.has("directory")) {
14342
- url.searchParams.set("directory", value);
14343
- }
14344
- const next = new Request(url, request);
14345
- next.headers.delete("x-opencode-directory");
14346
- return next;
14347
- }
14348
- function createOpencodeClient(config2) {
14349
- if (!config2?.fetch) {
14350
- const customFetch = (req) => {
14351
- req.timeout = false;
14352
- return fetch(req);
14353
- };
14354
- config2 = {
14355
- ...config2,
14356
- fetch: customFetch
14357
- };
14358
- }
14359
- if (config2?.directory) {
14360
- config2.headers = {
14361
- ...config2.headers,
14362
- "x-opencode-directory": encodeURIComponent(config2.directory)
14363
- };
14364
- }
14365
- const client2 = createClient(config2);
14366
- client2.interceptors.request.use((request) => rewrite(request, config2?.directory));
14367
- client2.interceptors.error.use(wrapClientError);
14368
- return new OpencodeClient({ client: client2 });
14369
- }
14370
- var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
14371
- function getDefaultExportFromCjs(x) {
14372
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
14373
- }
14374
- var crossSpawn = { exports: {} };
14375
- var windows;
14376
- var hasRequiredWindows;
14377
- function requireWindows() {
14378
- if (hasRequiredWindows) return windows;
14379
- hasRequiredWindows = 1;
14380
- windows = isexe;
14381
- isexe.sync = sync;
14382
- var fs2 = require$$0;
14383
- function checkPathExt(path2, options) {
14384
- var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
14385
- if (!pathext) {
14386
- return true;
14387
- }
14388
- pathext = pathext.split(";");
14389
- if (pathext.indexOf("") !== -1) {
14390
- return true;
14391
- }
14392
- for (var i2 = 0; i2 < pathext.length; i2++) {
14393
- var p = pathext[i2].toLowerCase();
14394
- if (p && path2.substr(-p.length).toLowerCase() === p) {
14395
- return true;
14396
- }
14397
- }
14398
- return false;
14399
- }
14400
- function checkStat(stat2, path2, options) {
14401
- if (!stat2.isSymbolicLink() && !stat2.isFile()) {
14402
- return false;
14403
- }
14404
- return checkPathExt(path2, options);
14405
- }
14406
- function isexe(path2, options, cb) {
14407
- fs2.stat(path2, function(er, stat2) {
14408
- cb(er, er ? false : checkStat(stat2, path2, options));
14409
- });
14410
- }
14411
- function sync(path2, options) {
14412
- return checkStat(fs2.statSync(path2), path2, options);
14413
- }
14414
- return windows;
14415
- }
14416
- var mode;
14417
- var hasRequiredMode;
14418
- function requireMode() {
14419
- if (hasRequiredMode) return mode;
14420
- hasRequiredMode = 1;
14421
- mode = isexe;
14422
- isexe.sync = sync;
14423
- var fs2 = require$$0;
14424
- function isexe(path2, options, cb) {
14425
- fs2.stat(path2, function(er, stat2) {
14426
- cb(er, er ? false : checkStat(stat2, options));
14427
- });
14428
- }
14429
- function sync(path2, options) {
14430
- return checkStat(fs2.statSync(path2), options);
14431
- }
14432
- function checkStat(stat2, options) {
14433
- return stat2.isFile() && checkMode(stat2, options);
14434
- }
14435
- function checkMode(stat2, options) {
14436
- var mod = stat2.mode;
14437
- var uid = stat2.uid;
14438
- var gid = stat2.gid;
14439
- var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
14440
- var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
14441
- var u2 = parseInt("100", 8);
14442
- var g = parseInt("010", 8);
14443
- var o2 = parseInt("001", 8);
14444
- var ug = u2 | g;
14445
- var ret = mod & o2 || mod & g && gid === myGid || mod & u2 && uid === myUid || mod & ug && myUid === 0;
14446
- return ret;
14447
- }
14448
- return mode;
14449
- }
14450
- var isexe_1;
14451
- var hasRequiredIsexe;
14452
- function requireIsexe() {
14453
- if (hasRequiredIsexe) return isexe_1;
14454
- hasRequiredIsexe = 1;
14455
- var core;
14456
- if (process.platform === "win32" || commonjsGlobal.TESTING_WINDOWS) {
14457
- core = requireWindows();
14458
- } else {
14459
- core = requireMode();
14460
- }
14461
- isexe_1 = isexe;
14462
- isexe.sync = sync;
14463
- function isexe(path2, options, cb) {
14464
- if (typeof options === "function") {
14465
- cb = options;
14466
- options = {};
14467
- }
14468
- if (!cb) {
14469
- if (typeof Promise !== "function") {
14470
- throw new TypeError("callback not provided");
14471
- }
14472
- return new Promise(function(resolve2, reject) {
14473
- isexe(path2, options || {}, function(er, is) {
14474
- if (er) {
14475
- reject(er);
14476
- } else {
14477
- resolve2(is);
14478
- }
14479
- });
14480
- });
14481
- }
14482
- core(path2, options || {}, function(er, is) {
14483
- if (er) {
14484
- if (er.code === "EACCES" || options && options.ignoreErrors) {
14485
- er = null;
14486
- is = false;
14487
- }
14488
- }
14489
- cb(er, is);
14490
- });
14491
- }
14492
- function sync(path2, options) {
14493
- try {
14494
- return core.sync(path2, options || {});
14495
- } catch (er) {
14496
- if (options && options.ignoreErrors || er.code === "EACCES") {
14497
- return false;
14498
- } else {
14499
- throw er;
14500
- }
14501
- }
14502
- }
14503
- return isexe_1;
14504
- }
14505
- var which_1;
14506
- var hasRequiredWhich;
14507
- function requireWhich() {
14508
- if (hasRequiredWhich) return which_1;
14509
- hasRequiredWhich = 1;
14510
- const isWindows2 = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
14511
- const path2 = require$$0$1;
14512
- const COLON = isWindows2 ? ";" : ":";
14513
- const isexe = requireIsexe();
14514
- const getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
14515
- const getPathInfo = (cmd, opt) => {
14516
- const colon = opt.colon || COLON;
14517
- const pathEnv = cmd.match(/\//) || isWindows2 && cmd.match(/\\/) ? [""] : [
14518
- // windows always checks the cwd first
14519
- ...isWindows2 ? [process.cwd()] : [],
14520
- ...(opt.path || process.env.PATH || /* istanbul ignore next: very unusual */
14521
- "").split(colon)
14522
- ];
14523
- const pathExtExe = isWindows2 ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : "";
14524
- const pathExt = isWindows2 ? pathExtExe.split(colon) : [""];
14525
- if (isWindows2) {
14526
- if (cmd.indexOf(".") !== -1 && pathExt[0] !== "")
14527
- pathExt.unshift("");
14528
- }
14529
- return {
14530
- pathEnv,
14531
- pathExt,
14532
- pathExtExe
14533
- };
14534
- };
14535
- const which = (cmd, opt, cb) => {
14536
- if (typeof opt === "function") {
14537
- cb = opt;
14538
- opt = {};
14539
- }
14540
- if (!opt)
14541
- opt = {};
14542
- const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
14543
- const found = [];
14544
- const step = (i2) => new Promise((resolve2, reject) => {
14545
- if (i2 === pathEnv.length)
14546
- return opt.all && found.length ? resolve2(found) : reject(getNotFoundError(cmd));
14547
- const ppRaw = pathEnv[i2];
14548
- const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
14549
- const pCmd = path2.join(pathPart, cmd);
14550
- const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
14551
- resolve2(subStep(p, i2, 0));
14552
- });
14553
- const subStep = (p, i2, ii) => new Promise((resolve2, reject) => {
14554
- if (ii === pathExt.length)
14555
- return resolve2(step(i2 + 1));
14556
- const ext = pathExt[ii];
14557
- isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
14558
- if (!er && is) {
14559
- if (opt.all)
14560
- found.push(p + ext);
14561
- else
14562
- return resolve2(p + ext);
14563
- }
14564
- return resolve2(subStep(p, i2, ii + 1));
14565
- });
14566
- });
14567
- return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
14568
- };
14569
- const whichSync = (cmd, opt) => {
14570
- opt = opt || {};
14571
- const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
14572
- const found = [];
14573
- for (let i2 = 0; i2 < pathEnv.length; i2++) {
14574
- const ppRaw = pathEnv[i2];
14575
- const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
14576
- const pCmd = path2.join(pathPart, cmd);
14577
- const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
14578
- for (let j = 0; j < pathExt.length; j++) {
14579
- const cur = p + pathExt[j];
14580
- try {
14581
- const is = isexe.sync(cur, { pathExt: pathExtExe });
14582
- if (is) {
14583
- if (opt.all)
14584
- found.push(cur);
14585
- else
14586
- return cur;
14587
- }
14588
- } catch (ex) {
14589
- }
14590
- }
14591
- }
14592
- if (opt.all && found.length)
14593
- return found;
14594
- if (opt.nothrow)
14595
- return null;
14596
- throw getNotFoundError(cmd);
14597
- };
14598
- which_1 = which;
14599
- which.sync = whichSync;
14600
- return which_1;
14601
- }
14602
- var pathKey$1 = { exports: {} };
14603
- var hasRequiredPathKey;
14604
- function requirePathKey() {
14605
- if (hasRequiredPathKey) return pathKey$1.exports;
14606
- hasRequiredPathKey = 1;
14607
- const pathKey2 = (options = {}) => {
14608
- const environment = options.env || process.env;
14609
- const platform2 = options.platform || process.platform;
14610
- if (platform2 !== "win32") {
14611
- return "PATH";
14612
- }
14613
- return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path";
14614
- };
14615
- pathKey$1.exports = pathKey2;
14616
- pathKey$1.exports.default = pathKey2;
14617
- return pathKey$1.exports;
14618
- }
14619
- var resolveCommand_1;
14620
- var hasRequiredResolveCommand;
14621
- function requireResolveCommand() {
14622
- if (hasRequiredResolveCommand) return resolveCommand_1;
14623
- hasRequiredResolveCommand = 1;
14624
- const path2 = require$$0$1;
14625
- const which = requireWhich();
14626
- const getPathKey = requirePathKey();
14627
- function resolveCommandAttempt(parsed, withoutPathExt) {
14628
- const env = parsed.options.env || process.env;
14629
- const cwd = process.cwd();
14630
- const hasCustomCwd = parsed.options.cwd != null;
14631
- const shouldSwitchCwd = hasCustomCwd && process.chdir !== void 0 && !process.chdir.disabled;
14632
- if (shouldSwitchCwd) {
14633
- try {
14634
- process.chdir(parsed.options.cwd);
14635
- } catch (err) {
14636
- }
14637
- }
14638
- let resolved;
14639
- try {
14640
- resolved = which.sync(parsed.command, {
14641
- path: env[getPathKey({ env })],
14642
- pathExt: withoutPathExt ? path2.delimiter : void 0
14643
- });
14644
- } catch (e) {
14645
- } finally {
14646
- if (shouldSwitchCwd) {
14647
- process.chdir(cwd);
14648
- }
14649
- }
14650
- if (resolved) {
14651
- resolved = path2.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
14652
- }
14653
- return resolved;
14654
- }
14655
- function resolveCommand(parsed) {
14656
- return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true);
14657
- }
14658
- resolveCommand_1 = resolveCommand;
14659
- return resolveCommand_1;
14660
- }
14661
- var _escape = {};
14662
- var hasRequired_escape;
14663
- function require_escape() {
14664
- if (hasRequired_escape) return _escape;
14665
- hasRequired_escape = 1;
14666
- const metaCharsRegExp2 = /([()\][%!^"`<>&|;, *?])/g;
14667
- function escapeCommand(arg) {
14668
- arg = arg.replace(metaCharsRegExp2, "^$1");
14669
- return arg;
14670
- }
14671
- function escapeArgument2(arg, doubleEscapeMetaChars) {
14672
- arg = `${arg}`;
14673
- arg = arg.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"');
14674
- arg = arg.replace(/(?=(\\+?)?)\1$/, "$1$1");
14675
- arg = `"${arg}"`;
14676
- arg = arg.replace(metaCharsRegExp2, "^$1");
14677
- if (doubleEscapeMetaChars) {
14678
- arg = arg.replace(metaCharsRegExp2, "^$1");
14679
- }
14680
- return arg;
14681
- }
14682
- _escape.command = escapeCommand;
14683
- _escape.argument = escapeArgument2;
14684
- return _escape;
14685
- }
14686
- var shebangRegex;
14687
- var hasRequiredShebangRegex;
14688
- function requireShebangRegex() {
14689
- if (hasRequiredShebangRegex) return shebangRegex;
14690
- hasRequiredShebangRegex = 1;
14691
- shebangRegex = /^#!(.*)/;
14692
- return shebangRegex;
14693
- }
14694
- var shebangCommand;
14695
- var hasRequiredShebangCommand;
14696
- function requireShebangCommand() {
14697
- if (hasRequiredShebangCommand) return shebangCommand;
14698
- hasRequiredShebangCommand = 1;
14699
- const shebangRegex2 = requireShebangRegex();
14700
- shebangCommand = (string2 = "") => {
14701
- const match = string2.match(shebangRegex2);
14702
- if (!match) {
14703
- return null;
14704
- }
14705
- const [path2, argument] = match[0].replace(/#! ?/, "").split(" ");
14706
- const binary = path2.split("/").pop();
14707
- if (binary === "env") {
14708
- return argument;
14709
- }
14710
- return argument ? `${binary} ${argument}` : binary;
14711
- };
14712
- return shebangCommand;
14713
- }
14714
- var readShebang_1;
14715
- var hasRequiredReadShebang;
14716
- function requireReadShebang() {
14717
- if (hasRequiredReadShebang) return readShebang_1;
14718
- hasRequiredReadShebang = 1;
14719
- const fs2 = require$$0;
14720
- const shebangCommand2 = requireShebangCommand();
14721
- function readShebang2(command2) {
14722
- const size = 150;
14723
- const buffer = Buffer.alloc(size);
14724
- let fd;
14725
- try {
14726
- fd = fs2.openSync(command2, "r");
14727
- fs2.readSync(fd, buffer, 0, size, 0);
14728
- fs2.closeSync(fd);
14729
- } catch (e) {
14730
- }
14731
- return shebangCommand2(buffer.toString());
14732
- }
14733
- readShebang_1 = readShebang2;
14734
- return readShebang_1;
14735
- }
14736
- var parse_1;
14737
- var hasRequiredParse;
14738
- function requireParse() {
14739
- if (hasRequiredParse) return parse_1;
14740
- hasRequiredParse = 1;
14741
- const path2 = require$$0$1;
14742
- const resolveCommand = requireResolveCommand();
14743
- const escape = require_escape();
14744
- const readShebang2 = requireReadShebang();
14745
- const isWin = process.platform === "win32";
14746
- const isExecutableRegExp = /\.(?:com|exe)$/i;
14747
- const isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
14748
- function detectShebang(parsed) {
14749
- parsed.file = resolveCommand(parsed);
14750
- const shebang = parsed.file && readShebang2(parsed.file);
14751
- if (shebang) {
14752
- parsed.args.unshift(parsed.file);
14753
- parsed.command = shebang;
14754
- return resolveCommand(parsed);
14755
- }
14756
- return parsed.file;
14757
- }
14758
- function parseNonShell(parsed) {
14759
- if (!isWin) {
14760
- return parsed;
14761
- }
14762
- const commandFile = detectShebang(parsed);
14763
- const needsShell = !isExecutableRegExp.test(commandFile);
14764
- if (parsed.options.forceShell || needsShell) {
14765
- const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
14766
- parsed.command = path2.normalize(parsed.command);
14767
- parsed.command = escape.command(parsed.command);
14768
- parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
14769
- const shellCommand = [parsed.command].concat(parsed.args).join(" ");
14770
- parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`];
14771
- parsed.command = process.env.comspec || "cmd.exe";
14772
- parsed.options.windowsVerbatimArguments = true;
14773
- }
14774
- return parsed;
14775
- }
14776
- function parse2(command2, args, options) {
14777
- if (args && !Array.isArray(args)) {
14778
- options = args;
14779
- args = null;
14780
- }
14781
- args = args ? args.slice(0) : [];
14782
- options = Object.assign({}, options);
14783
- const parsed = {
14784
- command: command2,
14785
- args,
14786
- options,
14787
- file: void 0,
14788
- original: {
14789
- command: command2,
14790
- args
14791
- }
14792
- };
14793
- return options.shell ? parsed : parseNonShell(parsed);
14794
- }
14795
- parse_1 = parse2;
14796
- return parse_1;
14797
- }
14798
- var enoent;
14799
- var hasRequiredEnoent;
14800
- function requireEnoent() {
14801
- if (hasRequiredEnoent) return enoent;
14802
- hasRequiredEnoent = 1;
14803
- const isWin = process.platform === "win32";
14804
- function notFoundError(original, syscall) {
14805
- return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
14806
- code: "ENOENT",
14807
- errno: "ENOENT",
14808
- syscall: `${syscall} ${original.command}`,
14809
- path: original.command,
14810
- spawnargs: original.args
14811
- });
14812
- }
14813
- function hookChildProcess(cp2, parsed) {
14814
- if (!isWin) {
14815
- return;
14816
- }
14817
- const originalEmit = cp2.emit;
14818
- cp2.emit = function(name, arg1) {
14819
- if (name === "exit") {
14820
- const err = verifyENOENT(arg1, parsed);
14821
- if (err) {
14822
- return originalEmit.call(cp2, "error", err);
14823
- }
14824
- }
14825
- return originalEmit.apply(cp2, arguments);
14826
- };
14827
- }
14828
- function verifyENOENT(status, parsed) {
14829
- if (isWin && status === 1 && !parsed.file) {
14830
- return notFoundError(parsed.original, "spawn");
14831
- }
14832
- return null;
14833
- }
14834
- function verifyENOENTSync(status, parsed) {
14835
- if (isWin && status === 1 && !parsed.file) {
14836
- return notFoundError(parsed.original, "spawnSync");
14837
- }
14838
- return null;
14839
- }
14840
- enoent = {
14841
- hookChildProcess,
14842
- verifyENOENT,
14843
- verifyENOENTSync,
14844
- notFoundError
14845
- };
14846
- return enoent;
14847
- }
14848
- var hasRequiredCrossSpawn;
14849
- function requireCrossSpawn() {
14850
- if (hasRequiredCrossSpawn) return crossSpawn.exports;
14851
- hasRequiredCrossSpawn = 1;
14852
- const cp2 = require$$0$2;
14853
- const parse2 = requireParse();
14854
- const enoent2 = requireEnoent();
14855
- function spawn2(command2, args, options) {
14856
- const parsed = parse2(command2, args, options);
14857
- const spawned = cp2.spawn(parsed.command, parsed.args, parsed.options);
14858
- enoent2.hookChildProcess(spawned, parsed);
14859
- return spawned;
14860
- }
14861
- function spawnSync2(command2, args, options) {
14862
- const parsed = parse2(command2, args, options);
14863
- const result = cp2.spawnSync(parsed.command, parsed.args, parsed.options);
14864
- result.error = result.error || enoent2.verifyENOENTSync(result.status, parsed);
14865
- return result;
14866
- }
14867
- crossSpawn.exports = spawn2;
14868
- crossSpawn.exports.spawn = spawn2;
14869
- crossSpawn.exports.sync = spawnSync2;
14870
- crossSpawn.exports._parse = parse2;
14871
- crossSpawn.exports._enoent = enoent2;
14872
- return crossSpawn.exports;
14873
- }
14874
- var crossSpawnExports = requireCrossSpawn();
14875
- const launch = /* @__PURE__ */ getDefaultExportFromCjs(crossSpawnExports);
14876
- function stop(proc) {
14877
- if (proc.exitCode !== null || proc.signalCode !== null)
14878
- return;
14879
- if (process.platform === "win32" && proc.pid) {
14880
- const out = spawnSync("taskkill", ["/pid", String(proc.pid), "/T", "/F"], { windowsHide: true });
14881
- if (!out.error && out.status === 0)
14882
- return;
14883
- }
14884
- proc.kill();
14885
- }
14886
- function bindAbort$1(proc, signal, onAbort) {
14887
- if (!signal)
14888
- return () => {
14889
- };
14890
- const abort = () => {
14891
- clear();
14892
- stop(proc);
14893
- onAbort?.();
14894
- };
14895
- const clear = () => {
14896
- signal.removeEventListener("abort", abort);
14897
- proc.off("exit", clear);
14898
- proc.off("error", clear);
14899
- };
14900
- signal.addEventListener("abort", abort, { once: true });
14901
- proc.on("exit", clear);
14902
- proc.on("error", clear);
14903
- if (signal.aborted)
14904
- abort();
14905
- return clear;
14906
- }
14907
- async function createOpencodeServer(options) {
14908
- options = Object.assign({
14909
- hostname: "127.0.0.1",
14910
- port: 4096,
14911
- timeout: 5e3
14912
- }, options ?? {});
14913
- const args = [`serve`, `--hostname=${options.hostname}`, `--port=${options.port}`];
14914
- if (options.config?.logLevel)
14915
- args.push(`--log-level=${options.config.logLevel}`);
14916
- const proc = launch(`opencode`, args, {
14917
- env: {
14918
- ...process.env,
14919
- OPENCODE_CONFIG_CONTENT: JSON.stringify(options.config ?? {})
14920
- }
14921
- });
14922
- let clear = () => {
14923
- };
14924
- const url = await new Promise((resolve2, reject) => {
14925
- const id = setTimeout(() => {
14926
- clear();
14927
- stop(proc);
14928
- reject(new Error(`Timeout waiting for server to start after ${options.timeout}ms`));
14929
- }, options.timeout);
14930
- let output = "";
14931
- let resolved = false;
14932
- proc.stdout?.on("data", (chunk) => {
14933
- if (resolved)
14934
- return;
14935
- output += chunk.toString();
14936
- const lines = output.split("\n");
14937
- for (const line of lines) {
14938
- if (line.startsWith("opencode server listening")) {
14939
- const match = line.match(/on\s+(https?:\/\/[^\s]+)/);
14940
- if (!match) {
14941
- clear();
14942
- stop(proc);
14943
- clearTimeout(id);
14944
- reject(new Error(`Failed to parse server url from output: ${line}`));
14945
- return;
14946
- }
14947
- clearTimeout(id);
14948
- resolved = true;
14949
- resolve2(match[1]);
14950
- return;
14951
- }
14952
- }
14953
- });
14954
- proc.stderr?.on("data", (chunk) => {
14955
- output += chunk.toString();
14956
- });
14957
- proc.on("exit", (code) => {
14958
- clearTimeout(id);
14959
- let msg = `Server exited with code ${code}`;
14960
- if (output.trim()) {
14961
- msg += `
14962
- Server output: ${output}`;
14963
- }
14964
- reject(new Error(msg));
14965
- });
14966
- proc.on("error", (error) => {
14967
- clearTimeout(id);
14968
- reject(error);
14969
- });
14970
- clear = bindAbort$1(proc, options.signal, () => {
14971
- clearTimeout(id);
14972
- reject(options.signal?.reason);
14973
- });
14974
- });
14975
- return {
14976
- url,
14977
- close() {
14978
- clear();
14979
- stop(proc);
14980
- }
14981
- };
14982
- }
14983
- function openCodeCliName(executable) {
14984
- return path.parse(executable).name.toLowerCase() === "opencode2" ? "opencode2" : "opencode";
14985
- }
14986
- function isOpenCodeV2(executable) {
14987
- return openCodeCliName(executable) === "opencode2";
14988
- }
14989
- function openCodeLoginCommand(cliName) {
14990
- return cliName === "opencode2" ? "opencode2 auth login" : "opencode auth login";
14991
- }
14992
- function parseOpenCodeAuthList(raw, exitCode) {
14993
- if (exitCode !== 0) return "unknown";
14994
- const text2 = stripAnsi(raw);
14995
- if (/no authenticated/i.test(text2)) return "unauthenticated";
14996
- if (/credential/i.test(text2)) return "authenticated";
14997
- const lines = text2.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
14998
- if (lines.some((line) => /^[A-Za-z0-9._-]+$/.test(line) && !/^(providers?|credentials?|integrations?)$/i.test(line))) {
14999
- return "authenticated";
15000
- }
15001
- return "unknown";
12978
+ return "unknown";
15002
12979
  }
15003
12980
  function parseOpenCodeModels(raw) {
15004
12981
  const seen = /* @__PURE__ */ new Set();
15005
- 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 }));
15006
- return [DEFAULT_MODEL, ...models];
15007
- }
15008
- function parseOpenCodeV1Model(value) {
15009
- const slash = value.indexOf("/");
15010
- if (slash <= 0 || slash === value.length - 1) throw invalidModel();
15011
- 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];
15012
12984
  }
15013
12985
  function parseOpenCodeV2ModelRef(value) {
15014
- const parsed = parseOpenCodeV1Model(value);
15015
- const hash = parsed.modelID.lastIndexOf("#");
15016
- if (hash > 0 && hash < parsed.modelID.length - 1) {
15017
- return { providerID: parsed.providerID, id: parsed.modelID.slice(0, hash), variant: parsed.modelID.slice(hash + 1) };
15018
- }
15019
- 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] } : {} };
15020
12989
  }
15021
12990
  function parseOpenCodeV2GenerateText(payload) {
15022
12991
  if (!payload || typeof payload !== "object") throw invalidOutput$1();
@@ -15070,12 +13039,12 @@ async function startOpenCodeV2Server(options) {
15070
13039
  });
15071
13040
  void subprocess.catch(() => void 0);
15072
13041
  let settled = false;
15073
- const stop2 = () => {
13042
+ const stop = () => {
15074
13043
  if (settled) return;
15075
13044
  settled = true;
15076
13045
  stopProcess(subprocess);
15077
13046
  };
15078
- const unbind = bindAbort(options.signal, stop2);
13047
+ const unbind = bindAbort(options.signal, stop);
15079
13048
  try {
15080
13049
  const url = await waitForListenUrl(subprocess, timeoutMs, options.signal);
15081
13050
  return {
@@ -15083,12 +13052,12 @@ async function startOpenCodeV2Server(options) {
15083
13052
  password,
15084
13053
  close() {
15085
13054
  unbind();
15086
- stop2();
13055
+ stop();
15087
13056
  }
15088
13057
  };
15089
13058
  } catch (error) {
15090
13059
  unbind();
15091
- stop2();
13060
+ stop();
15092
13061
  if (options.signal?.aborted) {
15093
13062
  throw new AiOperationError({ code: "AI_CANCELLED", operation: "opencode-server", harness: "opencode", message: "Generation canceled." });
15094
13063
  }
@@ -15101,8 +13070,9 @@ async function generateOpenCodeV2Text(server, input) {
15101
13070
  const created = await v2Request(server, "/api/session", {
15102
13071
  method: "POST",
15103
13072
  body: {
15104
- title: "OpenTig commit message",
13073
+ title: "OpenTig text generation",
15105
13074
  location: { directory: input.cwd },
13075
+ permissions: [{ action: "*", resource: "*", effect: "deny" }],
15106
13076
  ...model ? { model } : {}
15107
13077
  },
15108
13078
  signal
@@ -15155,7 +13125,7 @@ function throwIfV2Failed(status, payload, signal) {
15155
13125
  if (status === 401 || /not logged|login required|unauth|authentication|sign in/.test(raw)) {
15156
13126
  throw new AiOperationError({ code: "AI_AUTH_REQUIRED", operation: "opencode-generate", harness: "opencode", message: "Sign in to OpenCode to generate the message." });
15157
13127
  }
15158
- 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)) {
15159
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 });
15160
13130
  }
15161
13131
  if (/model.*(not found|unavailable|invalid|access)|unknown model|no model specified/.test(raw)) {
@@ -15238,7 +13208,7 @@ function freePort() {
15238
13208
  server.on("error", reject);
15239
13209
  });
15240
13210
  }
15241
- 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.";
15242
13212
  class OpenCodeProvider {
15243
13213
  constructor(resolver, runner) {
15244
13214
  this.resolver = resolver;
@@ -15250,18 +13220,17 @@ class OpenCodeProvider {
15250
13220
  servers = /* @__PURE__ */ new Set();
15251
13221
  async status(forceRefresh = false) {
15252
13222
  const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
15253
- const executable = await this.resolver.resolve("opencode", forceRefresh);
15254
- 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;
15255
13226
  const cliName = openCodeCliName(executable);
15256
- const catalogArgs = cliName === "opencode2" ? ["models", "--standalone"] : ["models"];
15257
- const [version2, auth, catalog] = await Promise.all([
15258
- this.runner.run(executable, ["--version"]),
15259
- this.runner.run(executable, ["auth", "list"]),
15260
- 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 })
15261
13231
  ]);
15262
- const models = catalog.exitCode === 0 ? parseOpenCodeModels(catalog.stdout) : [DEFAULT_MODEL];
15263
- let authStatus = parseOpenCodeAuthList(`${auth.stdout}
15264
- ${auth.stderr}`, auth.exitCode);
13232
+ const models = catalog.exitCode === 0 ? parseOpenCodeModels(catalog.stdout) : [DEFAULT_MODEL$1];
13233
+ let authStatus = parseOpenCodeAuthList(auth.stdout, auth.exitCode);
15265
13234
  if (authStatus === "unauthenticated" && models.length > 1) authStatus = "unknown";
15266
13235
  const confirmed = authStatus === "authenticated";
15267
13236
  return {
@@ -15271,19 +13240,21 @@ ${auth.stderr}`, auth.exitCode);
15271
13240
  installed: true,
15272
13241
  authStatus,
15273
13242
  cliName,
15274
- version: version2.stdout.trim() || version2.stderr.trim(),
13243
+ version: version2,
15275
13244
  models,
15276
13245
  checkedAt,
15277
13246
  ...authStatus === "unauthenticated" ? { message: `Run ${openCodeLoginCommand(cliName)}.` } : !confirmed ? { message: "Could not confirm authentication for the selected provider." } : {}
15278
13247
  };
15279
13248
  }
15280
13249
  async generate(input) {
15281
- const executable = await this.resolver.resolve("opencode");
15282
- 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;
15283
13254
  const timeoutSignal = AbortSignal.timeout(AI_PROVIDER_TIMEOUT_MS);
15284
13255
  const boundedInput = { ...input, signal: AbortSignal.any([input.signal, timeoutSignal]) };
15285
13256
  try {
15286
- return await (isOpenCodeV2(executable) ? this.generateV2(executable, boundedInput) : this.generateV1(boundedInput));
13257
+ return await this.generateV2(executable, boundedInput);
15287
13258
  } catch (error) {
15288
13259
  if (timeoutSignal.aborted && !input.signal.aborted) {
15289
13260
  throw new AiOperationError({ code: "AI_TIMEOUT", operation: "opencode-generate", harness: this.id, message: "Generation took too long.", retryable: true });
@@ -15298,7 +13269,10 @@ ${auth.stderr}`, auth.exitCode);
15298
13269
  });
15299
13270
  this.servers.add(server);
15300
13271
  try {
15301
- 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 });
15302
13276
  return { output: parseJsonPayload(text2), usage: { ...EMPTY_AI_USAGE } };
15303
13277
  } catch (error) {
15304
13278
  if (input.signal.aborted) throw new AiOperationError({ code: "AI_CANCELLED", operation: "opencode-generate", harness: this.id, message: "Generation canceled." });
@@ -15311,53 +13285,22 @@ ${auth.stderr}`, auth.exitCode);
15311
13285
  this.servers.delete(server);
15312
13286
  }
15313
13287
  }
15314
- async generateV1(input) {
15315
- const server = await createOpencodeServer({
15316
- hostname: "127.0.0.1",
15317
- port: 0,
15318
- timeout: 15e3,
15319
- signal: input.signal,
15320
- config: { share: "disabled", autoupdate: false, plugin: [], instructions: [], tools: DISABLED_TOOLS, permission: { edit: "deny", bash: "deny", webfetch: "deny", external_directory: "deny" } }
15321
- }).catch(() => {
15322
- throw new AiOperationError({ code: "AI_PROCESS_FAILED", operation: "opencode-server", harness: this.id, message: "Could not start the local OpenCode server.", retryable: true });
15323
- });
15324
- this.servers.add(server);
15325
- const client2 = createOpencodeClient({ baseUrl: server.url, directory: input.repositoryPath });
15326
- let sessionId = null;
15327
- try {
15328
- const created = await client2.session.create({ body: { title: "OpenTig commit message" }, query: { directory: input.repositoryPath } });
15329
- if (!created.data?.id) throw new Error("missing session");
15330
- sessionId = created.data.id;
15331
- const model = input.model === "default" ? void 0 : parseOpenCodeV1Model(input.model);
15332
- const response = await client2.session.prompt({
15333
- path: { id: sessionId },
15334
- query: { directory: input.repositoryPath },
15335
- body: {
15336
- parts: [{ type: "text", text: input.prompt }],
15337
- tools: DISABLED_TOOLS,
15338
- // The server API takes no schema, unlike the Codex and Claude CLIs, so
15339
- // the only way to hold this harness to the contract is the system
15340
- // prompt. Without it the model answers in whatever shape it likes.
15341
- system: `Reply with a single JSON object and nothing else. It must satisfy this JSON Schema:
15342
- ${JSON.stringify(input.schema)}`,
15343
- ...model ? { model } : {}
15344
- }
15345
- });
15346
- const infoError = response.data?.info && "error" in response.data.info ? response.data.info.error : void 0;
15347
- if (infoError) throw new Error("provider rejected request");
15348
- const text2 = (response.data?.parts ?? []).filter((part) => part.type === "text" && "text" in part && typeof part.text === "string").map((part) => part.text).join("").trim();
15349
- return { output: parseJsonPayload(text2), usage: openCodeUsage(response.data?.info) };
15350
- } catch (error) {
15351
- if (input.signal?.aborted) throw new AiOperationError({ code: "AI_CANCELLED", operation: "opencode-generate", harness: this.id, message: "Generation canceled." });
15352
- if (error instanceof AiOperationError) throw error;
15353
- const synthetic = { exitCode: 1, stdout: "", stderr: error instanceof Error ? error.message : "" };
15354
- requireSuccess(synthetic, this.id, "opencode-generate");
15355
- throw error;
15356
- } finally {
15357
- if (sessionId) await client2.session.delete({ path: { id: sessionId }, query: { directory: input.repositoryPath } }).catch(() => void 0);
15358
- server.close();
15359
- 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
+ }
15360
13302
  }
13303
+ return first;
15361
13304
  }
15362
13305
  close() {
15363
13306
  for (const server of this.servers) server.close();
@@ -19319,7 +17262,7 @@ const defaults = {
19319
17262
  uiFont: "plus-jakarta-sans",
19320
17263
  monoFont: "jetbrains-mono",
19321
17264
  commitMessageHarness: "codex",
19322
- commitMessageModels: { codex: "default", claude: "default", opencode: "default" },
17265
+ commitMessageModels: { codex: "default", claude: "default", opencode: "default", grok: "default" },
19323
17266
  shortcutOverrides: {},
19324
17267
  doubleControlShortcutEnabled: true,
19325
17268
  remoteFetchIntervalSeconds: DEFAULT_REMOTE_FETCH_INTERVAL_SECONDS
@@ -19726,7 +17669,7 @@ function projectError(message) {
19726
17669
  return new GitOperationError({ code: "INVALID_ARGUMENT", operation: "repository-projects", message });
19727
17670
  }
19728
17671
  function isHarness(value) {
19729
- return value === "codex" || value === "claude" || value === "opencode";
17672
+ return value === "codex" || value === "claude" || value === "opencode" || value === "grok";
19730
17673
  }
19731
17674
  function normalizeUiFont(value) {
19732
17675
  if (value === "cabinet-grotesk" || value === "satoshi") return "plus-jakarta-sans";
@@ -19741,9 +17684,9 @@ function normalizeSidebarWidth(value) {
19741
17684
  return Math.max(300, Math.min(680, width));
19742
17685
  }
19743
17686
  function modelPreferences(value) {
19744
- const result = { codex: "default", claude: "default", opencode: "default" };
17687
+ const result = { codex: "default", claude: "default", opencode: "default", grok: "default" };
19745
17688
  if (!value || typeof value !== "object") return result;
19746
- for (const harness of ["codex", "claude", "opencode"]) {
17689
+ for (const harness of ["codex", "claude", "opencode", "grok"]) {
19747
17690
  const model = value[harness];
19748
17691
  if (typeof model === "string" && model.length > 0 && model.length <= 200 && !hasControlCharacters$1(model)) result[harness] = model;
19749
17692
  }
@@ -19886,7 +17829,8 @@ async function createOpenTigRuntime(options) {
19886
17829
  const providers = [
19887
17830
  new CodexProvider(cliResolver, cliRunner),
19888
17831
  new ClaudeProvider(cliResolver, cliRunner),
19889
- new OpenCodeProvider(cliResolver, cliRunner)
17832
+ new OpenCodeProvider(cliResolver, cliRunner),
17833
+ new GrokProvider(cliResolver, cliRunner)
19890
17834
  ];
19891
17835
  const aiLog = new AiLogStore(options.aiLogPath);
19892
17836
  await aiLog.load();
@@ -20408,7 +18352,7 @@ const searchOptionsSchema = object({
20408
18352
  includeIgnored: unknown().optional()
20409
18353
  });
20410
18354
  const openFileTabSchema = object({ path: unknown(), pinned: boolean() });
20411
- const aiHarnessSchema = _enum(["codex", "claude", "opencode"]);
18355
+ const aiHarnessSchema = _enum(["codex", "claude", "opencode", "grok"]);
20412
18356
  const pullRequestStateSchema = _enum(["OPEN", "CLOSED", "MERGED"]);
20413
18357
  function stringArg(value, operation, maxLength = 32768) {
20414
18358
  const parsed = boundedStringSchema(maxLength, { controls: false }).safeParse(value);
@@ -22098,12 +20042,12 @@ class OpenTigWebSocketTransport {
22098
20042
  upgradeHandler;
22099
20043
  closePromise = null;
22100
20044
  get connectedSessionCount() {
22101
- return new Set([...this.clients.values()].map((client2) => client2.sessionId)).size;
20045
+ return new Set([...this.clients.values()].map((client) => client.sessionId)).size;
22102
20046
  }
22103
20047
  connectionCount(sessionId) {
22104
20048
  let count2 = 0;
22105
- for (const client2 of this.clients.values()) {
22106
- if (client2.sessionId === sessionId) count2 += 1;
20049
+ for (const client of this.clients.values()) {
20050
+ if (client.sessionId === sessionId) count2 += 1;
22107
20051
  }
22108
20052
  return count2;
22109
20053
  }
@@ -22149,7 +20093,7 @@ class OpenTigWebSocketTransport {
22149
20093
  socket.on("close", () => {
22150
20094
  for (const controller of state.requests.values()) controller.abort();
22151
20095
  this.clients.delete(socket);
22152
- if (![...this.clients.values()].some((client2) => client2.sessionId === sessionId)) {
20096
+ if (![...this.clients.values()].some((client) => client.sessionId === sessionId)) {
22153
20097
  this.options.registry.clearSession(sessionId);
22154
20098
  }
22155
20099
  });