@opentig/cli 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +3 -1
- package/dist/bin.mjs +2 -5
- package/dist/chunks/{cli-DCPhUVBb.mjs → cli-Bi6ET5UT.mjs} +15 -2
- package/dist/client/assets/App-BXZLGT86.js +74 -0
- package/dist/client/assets/CreatePullRequestDialog-DFonMYEx.js +2 -0
- package/dist/client/assets/DiffWorkspace-RDG_Y70N.js +26 -0
- package/dist/client/assets/EditableFileViewer-CsbifqBO.js +1 -0
- package/dist/client/assets/File-CHjvYpb2.js +1 -0
- package/dist/client/assets/FilesView-Dl8QFbFA.js +1 -0
- package/dist/client/assets/GitHubAvatar-CnBaloV0.js +1 -0
- package/dist/client/assets/HistoryView-BgCZU2JO.js +1 -0
- package/dist/client/assets/{HtmlFileViewer-C3Qylr9B.js → HtmlFileViewer-h8ULU8Gy.js} +1 -1
- package/dist/client/assets/{IconEdit-BHqlqze_.js → IconEdit-Cg8S2wqW.js} +1 -1
- package/dist/client/assets/IconFolderSymlink-BZSLX1ez.js +1 -0
- package/dist/client/assets/{ImageFileViewer-BJy0ptmR.js → ImageFileViewer-Cjw58ckv.js} +1 -1
- package/dist/client/assets/LocalRefsDialog-DNgrd7Qp.js +1 -0
- package/dist/client/assets/MarkdownFileViewer-kLiduag6.js +2 -0
- package/dist/client/assets/{PairingPage-DOPAXy3a.js → PairingPage-C97sv-8s.js} +1 -1
- package/dist/client/assets/PierreDiffViewer-eAcugmoF.js +1 -0
- package/dist/client/assets/{PierreEditBoundary-mxtF7x3F.js → PierreEditBoundary-DlGd1pqO.js} +2 -2
- package/dist/client/assets/{PierreWorkerPool-B_NFnwU-.js → PierreWorkerPool-Col4k7qz.js} +18 -18
- package/dist/client/assets/{PullRequestDiff-Bcu8Gmrf.js → PullRequestDiff-DhKTXyIF.js} +1 -1
- package/dist/client/assets/PullRequestViewer-BgI8HFMe.js +2 -0
- package/dist/client/assets/PullRequestsView-PYWLy8We.js +1 -0
- package/dist/client/assets/QuickOpenDialog-BFDDZVCL.js +1 -0
- package/dist/client/assets/RepositoryProjectsDialog-CvB8KcFp.js +1 -0
- package/dist/client/assets/SearchView-BwF_MsxK.js +1 -0
- package/dist/client/assets/SettingsDialog-DIcLmXSE.js +9 -0
- package/dist/client/assets/Viewer-o1hDU33O.js +3 -0
- package/dist/client/assets/{abnfDiagram-N423BO3Z-BxGW6tGd.js → abnfDiagram-N423BO3Z-BvrnK_R-.js} +1 -1
- package/dist/client/assets/{arc-CphVLv_F.js → arc-DLa3_7ua.js} +1 -1
- package/dist/client/assets/{architectureDiagram-T3A2C74G-D9IDzZ6u.js → architectureDiagram-T3A2C74G-BexwhnyX.js} +1 -1
- package/dist/client/assets/base-ui-CJ8ZIx3d.js +1 -0
- package/dist/client/assets/{blockDiagram-VBNYF7ZC-CzCatff9.js → blockDiagram-VBNYF7ZC-CoOttUUo.js} +1 -1
- package/dist/client/assets/{c4Diagram-5PPSVZJV-jvC7ACDE.js → c4Diagram-5PPSVZJV-Bgp6ppUh.js} +1 -1
- package/dist/client/assets/channel-1k1AYpyV.js +1 -0
- package/dist/client/assets/{checkbox-DDpujnre.js → checkbox-BRH0ZNIC.js} +1 -1
- package/dist/client/assets/{chunk-2GRJ4B5K-CNRn3w2y.js → chunk-2GRJ4B5K-C_kzp38w.js} +1 -1
- package/dist/client/assets/{chunk-2Q5K7J3B-CnTjXDS8.js → chunk-2Q5K7J3B-CysYnRkJ.js} +1 -1
- package/dist/client/assets/{chunk-5RXB4S5H-8QZZSU3J.js → chunk-5RXB4S5H-oMS6x_ag.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-B2MFN1L0.js → chunk-5VM5RSS4-C5-dW5wf.js} +1 -1
- package/dist/client/assets/{chunk-6Q2QTUOP-BRGuFKSr.js → chunk-6Q2QTUOP-DxahInnA.js} +1 -1
- package/dist/client/assets/{chunk-GF5L2VYU-CWTKyD7U.js → chunk-GF5L2VYU-D7V-3eRg.js} +1 -1
- package/dist/client/assets/{chunk-JWPE2WC7-rGurufZY.js → chunk-JWPE2WC7-BrLmjbVP.js} +1 -1
- package/dist/client/assets/{chunk-KBJHAD2P-DOwIHyo0.js → chunk-KBJHAD2P-CyOvijwM.js} +1 -1
- package/dist/client/assets/{chunk-RYQCIY6F-qrVd0AV3.js → chunk-RYQCIY6F-BvEjVjQs.js} +1 -1
- package/dist/client/assets/{chunk-XXDRQBXY-BGvaybJK.js → chunk-XXDRQBXY-C_IY9A64.js} +1 -1
- package/dist/client/assets/classDiagram-JCYQIIEL-ChyNFpay.js +1 -0
- package/dist/client/assets/classDiagram-v2-OCEON4UE-ChyNFpay.js +1 -0
- package/dist/client/assets/{vb-D17OF-Vu.js → cmd-BW5THilD.js} +1 -1
- package/dist/client/assets/{cose-bilkent-JH36ORCC-CHgOt-vq.js → cose-bilkent-JH36ORCC-Cu7qZi7h.js} +1 -1
- package/dist/client/assets/{cynefin-VYW2F7L2-DX7Kb3Ft.js → cynefin-VYW2F7L2-B4M1t9lL.js} +1 -1
- package/dist/client/assets/{cynefinDiagram-MW4NZA55-B4MgYgbV.js → cynefinDiagram-MW4NZA55-CAosOLmT.js} +1 -1
- package/dist/client/assets/{dagre-VZM6K2ZE-xG9l95NU.js → dagre-VZM6K2ZE-q354V538.js} +1 -1
- package/dist/client/assets/{diagram-7IWD3JNH-BQKb8ivh.js → diagram-7IWD3JNH-C_CzkBPt.js} +1 -1
- package/dist/client/assets/{diagram-B4RE2ZJO-CyIMrtDr.js → diagram-B4RE2ZJO-VvvYHE9c.js} +1 -1
- package/dist/client/assets/{diagram-LBJQPF4R-WuCMu4WW.js → diagram-LBJQPF4R-D8vRQwb5.js} +1 -1
- package/dist/client/assets/{diagram-Q27KOJAE--Oi1nRrR.js → diagram-Q27KOJAE-Bul4aDKg.js} +1 -1
- package/dist/client/assets/{diagram-UB23O5K3-CP1DXsa_.js → diagram-UB23O5K3-DNadEE58.js} +1 -1
- package/dist/client/assets/{ebnfDiagram-BXEA7PRR-C-7jJg9C.js → ebnfDiagram-BXEA7PRR-Bf-68MMZ.js} +1 -1
- package/dist/client/assets/{erDiagram-JOGREHBK-FSyqgO_9.js → erDiagram-JOGREHBK-CJ-jHFsf.js} +1 -1
- package/dist/client/assets/{flowDiagram-UKHOOZJN-y2e2HZHu.js → flowDiagram-UKHOOZJN-DMOdinBU.js} +1 -1
- package/dist/client/assets/{ganttDiagram-PKOTCBZU-kZ3m3wwW.js → ganttDiagram-PKOTCBZU-DzezS3Zy.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-DS77QQ5N-3Z9e4WPi.js → gitGraphDiagram-DS77QQ5N-Dftpvns8.js} +1 -1
- package/dist/client/assets/index-BfA4tAc1.css +1 -0
- package/dist/client/assets/{index-DDbUjVD9.js → index-BzmFkR37.js} +1 -1
- package/dist/client/assets/{index-ChKJF4C_.js → index-DAUK3rnz.js} +4 -4
- package/dist/client/assets/{infoDiagram-6WML65LV-TfCo0Rhw.js → infoDiagram-6WML65LV-DmgUBq17.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-WSZJBQD7-DaXI89rw.js → ishikawaDiagram-WSZJBQD7-CL0PQhpQ.js} +1 -1
- package/dist/client/assets/{journeyDiagram-NVQOT4AX-C4jS6BVn.js → journeyDiagram-NVQOT4AX-Ck4pQx_A.js} +1 -1
- package/dist/client/assets/{kanban-definition-27J2QSJJ-bwOtQiC8.js → kanban-definition-27J2QSJJ-DuRZxBql.js} +1 -1
- package/dist/client/assets/{linear-DfZM9J6Z.js → linear-C2JDCaz4.js} +1 -1
- package/dist/client/assets/{mermaid.core-B-iLnCqi.js → mermaid.core-9dt2ugQA.js} +4 -4
- package/dist/client/assets/{mindmap-definition-FAOFIHXS-DAdKdypB.js → mindmap-definition-FAOFIHXS-vy0fdDF0.js} +1 -1
- package/dist/client/assets/{pegDiagram-VL7TDLO6-Bl95_ELH.js → pegDiagram-VL7TDLO6-DjVJy-Gm.js} +1 -1
- package/dist/client/assets/{pieDiagram-7S7Q4E2Y-DXf4GTLI.js → pieDiagram-7S7Q4E2Y-ATbd_8vw.js} +1 -1
- package/dist/client/assets/{platform-BMNQ8V5r.js → platform-Bqt97_Jr.js} +2 -2
- package/dist/client/assets/{quadrantDiagram-CIZ2JOQS-CDiwouFY.js → quadrantDiagram-CIZ2JOQS-C8o6ofcl.js} +1 -1
- package/dist/client/assets/{railroadDiagram-AXF67PYL-CZAR7rja.js → railroadDiagram-AXF67PYL-Qvij9Ubo.js} +1 -1
- package/dist/client/assets/render-markdown-BtCybfvQ.js +280 -0
- package/dist/client/assets/repository-grammars-ixqpb0uW.js +1 -0
- package/dist/client/assets/{requirementDiagram-LRYGKXZP-BklWtcnl.js → requirementDiagram-LRYGKXZP-yLfrba2h.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-W5VNT64P-CpD7cM5j.js → sankeyDiagram-W5VNT64P-BTXRtTyG.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-SI44F4Z6-BnHPNl9l.js → sequenceDiagram-SI44F4Z6-BN1CCZIX.js} +1 -1
- package/dist/client/assets/{sizeCapture-X5ZJPWSS-D1eo0r-2.js → sizeCapture-X5ZJPWSS-BfXjBBYo.js} +1 -1
- package/dist/client/assets/{stateDiagram-OKZ733FA-ClTacl-d.js → stateDiagram-OKZ733FA-DMAWiBsP.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-UEYNNEHI-D_ofZeaa.js +1 -0
- package/dist/client/assets/{swimlanes-SLNWSIFB-_PLbkM5u.js → swimlanes-SLNWSIFB-BD20m5cw.js} +2 -2
- package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-CF9m5JSB.js +8 -0
- package/dist/client/assets/{tanstack-CtfgE41X.js → tanstack-B0Sf7wNU.js} +1 -1
- package/dist/client/assets/{timeline-definition-Z64GVDOM-C9U6VikV.js → timeline-definition-Z64GVDOM-gtc0-AHB.js} +1 -1
- package/dist/client/assets/{vennDiagram-T6HMQDX7-Desj7KFU.js → vennDiagram-T6HMQDX7-Cdr4AXTp.js} +1 -1
- package/dist/client/assets/viewer-tabs-D-T0xQaq.js +1 -0
- package/dist/client/assets/{wardleyDiagram-T6FBY63Y-rlMEd5tV.js → wardleyDiagram-T6FBY63Y-BcU4vxO8.js} +1 -1
- package/dist/client/assets/{xychartDiagram-ELKLHX3M-CzFgA0NM.js → xychartDiagram-ELKLHX3M-B3Zuadj8.js} +1 -1
- package/dist/client/index.html +4 -4
- package/dist/dev.mjs +1 -4
- package/dist/manifest.json +1 -1
- package/dist/server.mjs +779 -2436
- package/dist/utility.mjs +1 -4
- package/package.json +2 -2
- package/dist/client/assets/App-CGiS2z40.js +0 -74
- package/dist/client/assets/CreatePullRequestDialog-dNbTTo9i.js +0 -2
- package/dist/client/assets/DiffWorkspace-XS025gbZ.js +0 -26
- package/dist/client/assets/EditableFileViewer-Cve4V9RS.js +0 -1
- package/dist/client/assets/File-BJuBDans.js +0 -1
- package/dist/client/assets/FilesView-BUAz46Qa.js +0 -1
- package/dist/client/assets/GitHubAvatar-Depnd_JA.js +0 -1
- package/dist/client/assets/HistoryView-Dd4Kr4KN.js +0 -1
- package/dist/client/assets/IconFolderPlus-BJIo1hfe.js +0 -1
- package/dist/client/assets/LocalRefsDialog-C1MWMkv1.js +0 -1
- package/dist/client/assets/MarkdownFileViewer-pagMxv2y.js +0 -2
- package/dist/client/assets/PierreDiffViewer-FmgbHdls.js +0 -1
- package/dist/client/assets/PullRequestViewer-oeDoq-3g.js +0 -2
- package/dist/client/assets/PullRequestsView-DpTtagTX.js +0 -1
- package/dist/client/assets/QuickOpenDialog-rjeV0l_J.js +0 -1
- package/dist/client/assets/RepositoryProjectsDialog-QYXEt7Lg.js +0 -1
- package/dist/client/assets/SearchView-C-c6oCil.js +0 -1
- package/dist/client/assets/SettingsDialog-DHmWkKYV.js +0 -9
- package/dist/client/assets/Viewer-B6qUr83C.js +0 -3
- package/dist/client/assets/base-ui-DT3JsyND.js +0 -1
- package/dist/client/assets/channel-BGbncBYv.js +0 -1
- package/dist/client/assets/classDiagram-JCYQIIEL-BoYriqPM.js +0 -1
- package/dist/client/assets/classDiagram-v2-OCEON4UE-BoYriqPM.js +0 -1
- package/dist/client/assets/gh-utils-DxPHIkD8.js +0 -1
- package/dist/client/assets/index-WwGOu_aM.css +0 -1
- package/dist/client/assets/render-markdown-BiKX2Zdv.js +0 -280
- package/dist/client/assets/stateDiagram-v2-UEYNNEHI-DAo7Tfh9.js +0 -1
- package/dist/client/assets/swimlanesDiagram-ULZ7WXOC-DHeOpgR_.js +0 -8
- package/dist/client/assets/viewer-tabs-BwMhis6Q.js +0 -1
package/dist/server.mjs
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
2
2
|
import path, { extname, delimiter, resolve, join, isAbsolute, dirname } from "node:path";
|
|
3
3
|
import { randomUUID, randomBytes, createHash, createHmac, timingSafeEqual } from "node:crypto";
|
|
4
|
-
import { access, mkdir, open, rename, chmod, rm, appendFile, readFile, mkdtemp, writeFile, lstat, readdir,
|
|
4
|
+
import { stat, access, realpath, mkdir, open, rename, chmod, rm, appendFile, readFile, mkdtemp, writeFile, lstat, readdir, cp } from "node:fs/promises";
|
|
5
|
+
import os, { constants, homedir, networkInterfaces } from "node:os";
|
|
5
6
|
import { ChildProcess, execFile, spawnSync, spawn } from "node:child_process";
|
|
6
7
|
import { StringDecoder } from "node:string_decoder";
|
|
7
8
|
import { debuglog, stripVTControlCharacters, inspect, promisify, callbackify, aborted as aborted$1 } from "node:util";
|
|
8
9
|
import process$3, { platform, hrtime, execPath, execArgv } from "node:process";
|
|
9
10
|
import tty from "node:tty";
|
|
10
11
|
import { setTimeout as setTimeout$1, scheduler, setImmediate } from "node:timers/promises";
|
|
11
|
-
import os, { constants, homedir, networkInterfaces } from "node:os";
|
|
12
12
|
import { once, addAbortListener, EventEmitter, on, setMaxListeners } from "node:events";
|
|
13
13
|
import { serialize } from "node:v8";
|
|
14
|
-
import fs, { openSync, readSync, closeSync, statSync, readFileSync, appendFileSync, writeFileSync, createWriteStream, createReadStream, watch } from "node:fs";
|
|
14
|
+
import fs, { openSync, readSync, closeSync, statSync, readFileSync, appendFileSync, writeFileSync, createWriteStream, createReadStream, constants as constants$1, watch } from "node:fs";
|
|
15
15
|
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$
|
|
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$
|
|
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$
|
|
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
|
|
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
|
|
5280
|
-
return global
|
|
5276
|
+
if (global[kExitEmitter]) {
|
|
5277
|
+
return global[kExitEmitter];
|
|
5281
5278
|
}
|
|
5282
|
-
ObjectDefineProperty(global
|
|
5279
|
+
ObjectDefineProperty(global, kExitEmitter, {
|
|
5283
5280
|
value: this,
|
|
5284
5281
|
writable: false,
|
|
5285
5282
|
enumerable: false,
|
|
@@ -6875,6 +6872,153 @@ createExeca(() => ({ isSync: true }));
|
|
|
6875
6872
|
createExeca(mapNode);
|
|
6876
6873
|
createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
|
|
6877
6874
|
getIpcExport();
|
|
6875
|
+
const LOCATION_KEYS = ["PATH", "CODEX_INSTALL_DIR", "GROK_BIN_DIR", "BUN_INSTALL", "PNPM_HOME", "VOLTA_HOME", "NPM_CONFIG_PREFIX", "npm_config_prefix", "NVM_BIN", "FNM_MULTISHELL_PATH", "ASDF_DATA_DIR", "MISE_DATA_DIR", "XDG_DATA_HOME", "APPDATA", "LOCALAPPDATA"];
|
|
6876
|
+
function currentCliHost() {
|
|
6877
|
+
let shell;
|
|
6878
|
+
try {
|
|
6879
|
+
shell = os.userInfo().shell ?? void 0;
|
|
6880
|
+
} catch {
|
|
6881
|
+
}
|
|
6882
|
+
return { platform: process.platform, home: os.homedir(), env: cleanEnvironment(process.env), shell: process.env.SHELL || shell };
|
|
6883
|
+
}
|
|
6884
|
+
function cleanEnvironment(input, platform2 = process.platform) {
|
|
6885
|
+
const result = {};
|
|
6886
|
+
for (const [key, value] of Object.entries(input)) {
|
|
6887
|
+
if (value !== void 0) result[platform2 === "win32" && key.toUpperCase() === "PATH" ? "PATH" : key] = value;
|
|
6888
|
+
}
|
|
6889
|
+
return result;
|
|
6890
|
+
}
|
|
6891
|
+
function pathDirectories(value, platform2) {
|
|
6892
|
+
const p = platform2 === "win32" ? path.win32 : path.posix;
|
|
6893
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6894
|
+
return (value ?? "").split(platform2 === "win32" ? ";" : ":").map((item) => item.replace(/^"(.*)"$/, "$1")).filter((item) => {
|
|
6895
|
+
if (!p.isAbsolute(item)) return false;
|
|
6896
|
+
const key = platform2 === "win32" ? p.normalize(item).toLowerCase() : p.normalize(item);
|
|
6897
|
+
if (seen.has(key)) return false;
|
|
6898
|
+
seen.add(key);
|
|
6899
|
+
return true;
|
|
6900
|
+
});
|
|
6901
|
+
}
|
|
6902
|
+
class CliEnvironment {
|
|
6903
|
+
constructor(host = currentCliHost(), read = readUserEnvironment) {
|
|
6904
|
+
this.host = host;
|
|
6905
|
+
this.read = read;
|
|
6906
|
+
}
|
|
6907
|
+
host;
|
|
6908
|
+
read;
|
|
6909
|
+
cached;
|
|
6910
|
+
pending;
|
|
6911
|
+
generation = 0;
|
|
6912
|
+
invalidate() {
|
|
6913
|
+
this.generation++;
|
|
6914
|
+
this.cached = void 0;
|
|
6915
|
+
this.pending = void 0;
|
|
6916
|
+
}
|
|
6917
|
+
async get(force = false) {
|
|
6918
|
+
const env = cleanEnvironment(this.host.env, this.host.platform);
|
|
6919
|
+
const inheritedPath = pathDirectories(env.PATH, this.host.platform);
|
|
6920
|
+
if (this.pending) return this.pending;
|
|
6921
|
+
if (!force && this.cached && Date.now() - this.cached.at < 3e4) return this.cached.value;
|
|
6922
|
+
const generation = this.generation;
|
|
6923
|
+
const pending = (async () => {
|
|
6924
|
+
let locations = {};
|
|
6925
|
+
let warning;
|
|
6926
|
+
try {
|
|
6927
|
+
locations = await this.read(this.host);
|
|
6928
|
+
} catch {
|
|
6929
|
+
warning = "Could not refresh the user environment. Using the inherited environment and known installation locations. Check your shell configuration or set an executable path.";
|
|
6930
|
+
}
|
|
6931
|
+
const refreshedPath = pathDirectories(locations.PATH, this.host.platform);
|
|
6932
|
+
const value = { env: { ...env, ...locations }, inheritedPath, refreshedPath, ...warning ? { warning } : {} };
|
|
6933
|
+
if (generation === this.generation) this.cached = { at: Date.now(), value };
|
|
6934
|
+
return value;
|
|
6935
|
+
})();
|
|
6936
|
+
this.pending = pending;
|
|
6937
|
+
try {
|
|
6938
|
+
return await pending;
|
|
6939
|
+
} finally {
|
|
6940
|
+
if (this.pending === pending) this.pending = void 0;
|
|
6941
|
+
}
|
|
6942
|
+
}
|
|
6943
|
+
}
|
|
6944
|
+
async function readUserEnvironment(host) {
|
|
6945
|
+
const options = {
|
|
6946
|
+
cwd: host.home,
|
|
6947
|
+
env: host.env,
|
|
6948
|
+
extendEnv: false,
|
|
6949
|
+
input: "",
|
|
6950
|
+
timeout: 5e3,
|
|
6951
|
+
maxBuffer: 128 * 1024,
|
|
6952
|
+
cleanup: true,
|
|
6953
|
+
killDescendants: true,
|
|
6954
|
+
windowsHide: true,
|
|
6955
|
+
reject: false,
|
|
6956
|
+
stripFinalNewline: false
|
|
6957
|
+
};
|
|
6958
|
+
if (host.platform === "win32") {
|
|
6959
|
+
const root = host.env.SystemRoot || host.env.SYSTEMROOT;
|
|
6960
|
+
if (!root || !path.win32.isAbsolute(root)) throw new Error("SystemRoot unavailable");
|
|
6961
|
+
const shell2 = path.win32.join(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
6962
|
+
const script = '$ErrorActionPreference="Stop"; $r=@{}; foreach($scope in @("Machine","User")){ $r[$scope]=[Environment]::GetEnvironmentVariables($scope) }; ConvertTo-Json -InputObject $r -Compress';
|
|
6963
|
+
const result = await execa(shell2, ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", script], options);
|
|
6964
|
+
if (result.exitCode !== 0 || result.timedOut || result.isMaxBuffer) throw new Error("Environment query failed");
|
|
6965
|
+
return windowsLocations(JSON.parse(result.stdout), host.env);
|
|
6966
|
+
}
|
|
6967
|
+
const shell = host.shell;
|
|
6968
|
+
if (!shell || !path.posix.isAbsolute(shell)) throw new Error("User shell unavailable");
|
|
6969
|
+
const kind = path.posix.basename(shell);
|
|
6970
|
+
if (!["bash", "zsh", "fish"].includes(kind)) throw new Error("Unsupported user shell");
|
|
6971
|
+
const started = Date.now();
|
|
6972
|
+
const modes = kind === "bash" ? ["-lic", "-ic"] : ["-lic"];
|
|
6973
|
+
let merged = {};
|
|
6974
|
+
let succeeded = false;
|
|
6975
|
+
for (const mode of modes) {
|
|
6976
|
+
const timeout = 5e3 - (Date.now() - started);
|
|
6977
|
+
if (timeout <= 0) break;
|
|
6978
|
+
const script = LOCATION_KEYS.map((key) => kind === "fish" ? `printf '\\0OPENTIG_ENV_${key}\\0%s\\0' (string join ':' -- $${key})` : `printf '\\0OPENTIG_ENV_${key}\\0%s\\0' "$${key}"`).join("; ");
|
|
6979
|
+
const result = await execa(shell, [mode, script], { ...options, timeout });
|
|
6980
|
+
if (result.exitCode !== 0 || result.timedOut || result.isMaxBuffer) continue;
|
|
6981
|
+
const locations = parseShellLocations(result.stdout);
|
|
6982
|
+
if (!locations.PATH) continue;
|
|
6983
|
+
succeeded = true;
|
|
6984
|
+
merged = { ...merged, ...locations, PATH: [locations.PATH, merged.PATH].filter(Boolean).join(":") };
|
|
6985
|
+
}
|
|
6986
|
+
if (!succeeded) throw new Error("Shell environment query failed");
|
|
6987
|
+
return merged;
|
|
6988
|
+
}
|
|
6989
|
+
function parseShellLocations(output) {
|
|
6990
|
+
const locations = {};
|
|
6991
|
+
for (const key of LOCATION_KEYS) {
|
|
6992
|
+
const marker = `\0OPENTIG_ENV_${key}\0`;
|
|
6993
|
+
const start = output.lastIndexOf(marker);
|
|
6994
|
+
if (start < 0) continue;
|
|
6995
|
+
const end = output.indexOf("\0", start + marker.length);
|
|
6996
|
+
if (end < 0) continue;
|
|
6997
|
+
const value = output.slice(start + marker.length, end);
|
|
6998
|
+
if (value && !/[\r\n]/.test(value)) locations[key] = value;
|
|
6999
|
+
}
|
|
7000
|
+
return locations;
|
|
7001
|
+
}
|
|
7002
|
+
function windowsLocations(raw, inherited) {
|
|
7003
|
+
const data = raw;
|
|
7004
|
+
if (!data || typeof data !== "object" || !data.Machine || !data.User) throw new Error("Invalid environment response");
|
|
7005
|
+
const upper = (input) => Object.fromEntries(Object.entries(input).filter(([, v]) => typeof v === "string").map(([k, v]) => [k.toUpperCase(), v]));
|
|
7006
|
+
const machine = upper(data.Machine), user = upper(data.User);
|
|
7007
|
+
const variables = { ...upper(inherited), ...machine, ...user };
|
|
7008
|
+
const expand = (input) => {
|
|
7009
|
+
let value = input;
|
|
7010
|
+
for (let i2 = 0; i2 < 10; i2++) {
|
|
7011
|
+
const next = value.replace(/%([^%]+)%/g, (match, key) => variables[key.toUpperCase()] ?? match);
|
|
7012
|
+
if (next === value) break;
|
|
7013
|
+
value = next;
|
|
7014
|
+
}
|
|
7015
|
+
return value;
|
|
7016
|
+
};
|
|
7017
|
+
const result = {};
|
|
7018
|
+
for (const key of LOCATION_KEYS) if (key !== "PATH" && variables[key.toUpperCase()]) result[key] = expand(variables[key.toUpperCase()]);
|
|
7019
|
+
result.PATH = [machine.PATH, user.PATH].filter((value) => !!value).map(expand).join(";");
|
|
7020
|
+
return result;
|
|
7021
|
+
}
|
|
6878
7022
|
class GitOperationError extends Error {
|
|
6879
7023
|
detail;
|
|
6880
7024
|
constructor(detail) {
|
|
@@ -6942,17 +7086,18 @@ class CliProcessRunner {
|
|
|
6942
7086
|
async run(command2, args, options = {}) {
|
|
6943
7087
|
const timeoutMs = options.timeoutMs ?? 15e3;
|
|
6944
7088
|
const maxOutputBytes = options.maxOutputBytes ?? 2 * 1024 * 1024;
|
|
6945
|
-
const environment = Object.fromEntries(
|
|
7089
|
+
const environment = cleanEnvironment(Object.fromEntries(
|
|
6946
7090
|
Object.entries({ ...process.env, ...options.env }).filter((entry) => entry[1] !== void 0)
|
|
6947
|
-
);
|
|
7091
|
+
));
|
|
6948
7092
|
for (const key of options.removeEnv ?? []) delete environment[key];
|
|
6949
7093
|
if (this.closePromise || options.signal?.aborted) throw cancelled();
|
|
6950
7094
|
const lifecycle = new AbortController();
|
|
6951
7095
|
this.active.add(lifecycle);
|
|
6952
7096
|
const signal = options.signal ? AbortSignal.any([options.signal, lifecycle.signal]) : lifecycle.signal;
|
|
6953
|
-
|
|
7097
|
+
let resolvedCommand;
|
|
6954
7098
|
let result;
|
|
6955
7099
|
try {
|
|
7100
|
+
resolvedCommand = resolveProcessCommand(command2, options.cwd ?? process.cwd(), environment);
|
|
6956
7101
|
result = await execa(resolvedCommand.file, args, {
|
|
6957
7102
|
...options.cwd ? { cwd: options.cwd } : {},
|
|
6958
7103
|
cancelSignal: signal,
|
|
@@ -6967,9 +7112,9 @@ class CliProcessRunner {
|
|
|
6967
7112
|
input: options.stdin ?? "",
|
|
6968
7113
|
stripFinalNewline: false,
|
|
6969
7114
|
reject: false
|
|
6970
|
-
}).catch(() => {
|
|
7115
|
+
}).catch((error) => {
|
|
6971
7116
|
if (signal.aborted) throw cancelled();
|
|
6972
|
-
throw processFailed();
|
|
7117
|
+
throw processFailed(error);
|
|
6973
7118
|
});
|
|
6974
7119
|
} finally {
|
|
6975
7120
|
this.active.delete(lifecycle);
|
|
@@ -6986,7 +7131,7 @@ class CliProcessRunner {
|
|
|
6986
7131
|
throw new AiOperationError({ code: "AI_CONTEXT_TOO_LARGE", operation: "ai-process", message: "The AI tool produced too much output." });
|
|
6987
7132
|
}
|
|
6988
7133
|
if (result.exitCode === void 0 || !resolvedCommand.found) {
|
|
6989
|
-
throw processFailed();
|
|
7134
|
+
throw processFailed(result);
|
|
6990
7135
|
}
|
|
6991
7136
|
return { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr };
|
|
6992
7137
|
}
|
|
@@ -7011,45 +7156,143 @@ class CliProcessRunner {
|
|
|
7011
7156
|
function cancelled() {
|
|
7012
7157
|
return new AiOperationError({ code: "AI_CANCELLED", operation: "ai-process", message: "Generation canceled." });
|
|
7013
7158
|
}
|
|
7014
|
-
|
|
7015
|
-
|
|
7159
|
+
class CliLaunchError extends AiOperationError {
|
|
7160
|
+
constructor(reason) {
|
|
7161
|
+
super({ code: "AI_PROCESS_FAILED", operation: "ai-process", message: "Could not start the AI tool." });
|
|
7162
|
+
this.reason = reason;
|
|
7163
|
+
}
|
|
7164
|
+
reason;
|
|
7165
|
+
}
|
|
7166
|
+
function processFailed(error) {
|
|
7167
|
+
const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
|
|
7168
|
+
return new CliLaunchError(code === "ENOENT" ? "missing" : code === "EACCES" || code === "EPERM" ? "permission" : code === "ENOEXEC" ? "format" : "unknown");
|
|
7016
7169
|
}
|
|
7017
|
-
const ALLOWED = /* @__PURE__ */ new Set(["codex", "claude", "opencode", "gh"]);
|
|
7018
7170
|
const ALIASES = {
|
|
7019
7171
|
codex: ["codex"],
|
|
7020
7172
|
claude: ["claude"],
|
|
7021
|
-
// OpenCode 2 installs as opencode2 and does not replace OpenCode 1's opencode binary.
|
|
7022
7173
|
opencode: ["opencode", "opencode2"],
|
|
7174
|
+
grok: ["grok"],
|
|
7023
7175
|
gh: ["gh"]
|
|
7024
7176
|
};
|
|
7025
7177
|
class CliResolver {
|
|
7178
|
+
constructor(environment = new CliEnvironment(), preferences = () => ({ aiExecutablePaths: {} })) {
|
|
7179
|
+
this.environment = environment;
|
|
7180
|
+
this.preferences = preferences;
|
|
7181
|
+
}
|
|
7182
|
+
environment;
|
|
7183
|
+
preferences;
|
|
7026
7184
|
cache = /* @__PURE__ */ new Map();
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
if (resolved) break;
|
|
7034
|
-
}
|
|
7035
|
-
this.cache.set(name, resolved);
|
|
7036
|
-
return resolved;
|
|
7185
|
+
settingsKey = "";
|
|
7186
|
+
generation = 0;
|
|
7187
|
+
invalidate() {
|
|
7188
|
+
this.generation++;
|
|
7189
|
+
this.cache.clear();
|
|
7190
|
+
this.environment.invalidate();
|
|
7037
7191
|
}
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7192
|
+
async resolve(name, forceRefresh = false) {
|
|
7193
|
+
return (await this.resolveAll(name, forceRefresh))[0] ?? null;
|
|
7194
|
+
}
|
|
7195
|
+
async resolveAll(name, forceRefresh = false) {
|
|
7196
|
+
return (await this.discover(name, forceRefresh)).filter((item) => !item.problem).map((item) => item.executable);
|
|
7197
|
+
}
|
|
7198
|
+
async discover(name, forceRefresh = false) {
|
|
7199
|
+
if (!Object.hasOwn(ALIASES, name)) return [];
|
|
7200
|
+
const preferences = this.preferences();
|
|
7201
|
+
const settingsKey = JSON.stringify(preferences.aiExecutablePaths);
|
|
7202
|
+
if (settingsKey !== this.settingsKey) {
|
|
7203
|
+
this.settingsKey = settingsKey;
|
|
7204
|
+
this.invalidate();
|
|
7205
|
+
}
|
|
7206
|
+
const key = name;
|
|
7207
|
+
if (forceRefresh) {
|
|
7208
|
+
this.generation++;
|
|
7209
|
+
this.cache.delete(key);
|
|
7210
|
+
}
|
|
7211
|
+
const generation = this.generation;
|
|
7212
|
+
const cached2 = this.cache.get(key);
|
|
7213
|
+
if (!forceRefresh && cached2 && Date.now() - cached2.at < 3e4) {
|
|
7214
|
+
if ((await Promise.all(cached2.candidates.map((item) => this.problem(item.executable)))).every((problem, index) => problem === cached2.candidates[index]?.problem)) {
|
|
7215
|
+
return structuredClone(cached2.candidates);
|
|
7216
|
+
}
|
|
7217
|
+
}
|
|
7218
|
+
const snapshot = await this.environment.get(forceRefresh);
|
|
7219
|
+
const host = this.environment.host;
|
|
7220
|
+
const p = host.platform === "win32" ? path.win32 : path.posix;
|
|
7221
|
+
const known = knownCliDirectories(name, host.home, host.platform, snapshot.env);
|
|
7222
|
+
const allKnown = [...new Set(Object.keys(ALIASES).flatMap((id) => knownCliDirectories(id, host.home, host.platform, snapshot.env)))];
|
|
7223
|
+
const runtimePath = host.platform === "win32" ? [...snapshot.inheritedPath, ...snapshot.refreshedPath] : [...snapshot.refreshedPath, ...snapshot.inheritedPath];
|
|
7224
|
+
const env = { ...snapshot.env, PATH: pathDirectories([...runtimePath, ...allKnown].join(p.delimiter), host.platform).join(p.delimiter) };
|
|
7225
|
+
if (host.env.XDG_DATA_HOME === void 0) delete env.XDG_DATA_HOME;
|
|
7226
|
+
else env.XDG_DATA_HOME = host.env.XDG_DATA_HOME;
|
|
7227
|
+
const configured = name === "gh" ? void 0 : preferences.aiExecutablePaths[name];
|
|
7228
|
+
const candidates = [];
|
|
7229
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7230
|
+
const add = async (executable, alias, source) => {
|
|
7231
|
+
const problem = await this.problem(executable);
|
|
7232
|
+
if (problem === "not-found" && source !== "configured") return;
|
|
7233
|
+
const canonical = await realpath(executable).catch(() => executable);
|
|
7234
|
+
const identity2 = host.platform === "win32" ? canonical.toLowerCase() : canonical;
|
|
7235
|
+
if (seen.has(identity2)) return;
|
|
7236
|
+
seen.add(identity2);
|
|
7237
|
+
candidates.push({ executable, alias, source, env, ...problem ? { problem } : {}, ...snapshot.warning ? { warning: snapshot.warning } : {} });
|
|
7238
|
+
};
|
|
7239
|
+
if (configured) {
|
|
7240
|
+
await add(configured, p.basename(configured), "configured");
|
|
7241
|
+
} else {
|
|
7242
|
+
for (const [directories, source] of [[snapshot.inheritedPath, "process-path"], [snapshot.refreshedPath, "user-path"], [known, "known-location"]]) {
|
|
7243
|
+
for (const directory of directories) {
|
|
7244
|
+
for (const alias of ALIASES[name]) {
|
|
7245
|
+
for (const extension of executableExtensions(host.platform, snapshot.env)) await add(p.join(directory, `${alias}${extension}`), alias, source);
|
|
7246
|
+
}
|
|
7247
|
+
}
|
|
7049
7248
|
}
|
|
7050
7249
|
}
|
|
7250
|
+
if (generation === this.generation) this.cache.set(key, { at: Date.now(), candidates });
|
|
7251
|
+
return structuredClone(candidates);
|
|
7051
7252
|
}
|
|
7052
|
-
|
|
7253
|
+
async warning() {
|
|
7254
|
+
return (await this.environment.get()).warning;
|
|
7255
|
+
}
|
|
7256
|
+
async problem(executable) {
|
|
7257
|
+
try {
|
|
7258
|
+
if (!(await stat(executable)).isFile()) return "not-executable";
|
|
7259
|
+
if (this.environment.host.platform === "win32") {
|
|
7260
|
+
if (![".exe", ".com", ".cmd", ".bat"].includes(path.win32.extname(executable).toLowerCase())) return "not-executable";
|
|
7261
|
+
} else await access(executable, constants$1.X_OK);
|
|
7262
|
+
return void 0;
|
|
7263
|
+
} catch (error) {
|
|
7264
|
+
return error.code === "EACCES" ? "not-executable" : "not-found";
|
|
7265
|
+
}
|
|
7266
|
+
}
|
|
7267
|
+
}
|
|
7268
|
+
function executableExtensions(platform2, env) {
|
|
7269
|
+
if (platform2 !== "win32") return [""];
|
|
7270
|
+
const value = Object.entries(env).find(([key]) => key.toUpperCase() === "PATHEXT")?.[1] ?? ".COM;.EXE;.BAT;.CMD";
|
|
7271
|
+
return [...new Set(value.split(";").map((item) => item.toLowerCase()).filter((item) => [".exe", ".com", ".cmd", ".bat"].includes(item)))];
|
|
7272
|
+
}
|
|
7273
|
+
function knownCliDirectories(name, home, platform2, env) {
|
|
7274
|
+
const p = platform2 === "win32" ? path.win32 : path.posix;
|
|
7275
|
+
const dirs = [p.join(home, ".local", "bin")];
|
|
7276
|
+
if (name === "opencode") dirs.push(p.join(home, ".opencode", "bin"));
|
|
7277
|
+
if (name === "grok") dirs.push(env.GROK_BIN_DIR, p.join(home, ".grok", "bin"));
|
|
7278
|
+
if (name === "codex") dirs.push(env.CODEX_INSTALL_DIR);
|
|
7279
|
+
dirs.push(env.PNPM_HOME, env.NVM_BIN, p.join(env.BUN_INSTALL || p.join(home, ".bun"), "bin"));
|
|
7280
|
+
if (env.FNM_MULTISHELL_PATH) dirs.push(platform2 === "win32" ? env.FNM_MULTISHELL_PATH : p.join(env.FNM_MULTISHELL_PATH, "bin"));
|
|
7281
|
+
const prefix = env.npm_config_prefix || env.NPM_CONFIG_PREFIX;
|
|
7282
|
+
if (prefix) dirs.push(platform2 === "win32" ? prefix : p.join(prefix, "bin"));
|
|
7283
|
+
if (platform2 === "win32") {
|
|
7284
|
+
if (env.APPDATA) dirs.push(p.join(env.APPDATA, "npm"));
|
|
7285
|
+
if (env.LOCALAPPDATA) {
|
|
7286
|
+
dirs.push(p.join(env.LOCALAPPDATA, "Volta", "bin"), p.join(env.LOCALAPPDATA, "pnpm"), p.join(env.LOCALAPPDATA, "Microsoft", "WinGet", "Links"));
|
|
7287
|
+
if (name === "codex") dirs.push(p.join(env.LOCALAPPDATA, "Programs", "OpenAI", "Codex", "bin"));
|
|
7288
|
+
}
|
|
7289
|
+
if (env.VOLTA_HOME) dirs.push(p.join(env.VOLTA_HOME, "bin"));
|
|
7290
|
+
} else {
|
|
7291
|
+
dirs.push(p.join(env.VOLTA_HOME || p.join(home, ".volta"), "bin"), p.join(home, ".npm-global", "bin"), p.join(home, ".yarn", "bin"));
|
|
7292
|
+
dirs.push(p.join(env.XDG_DATA_HOME || p.join(home, ".local", "share"), "pnpm"));
|
|
7293
|
+
dirs.push("/usr/local/bin", "/usr/bin", "/bin", platform2 === "darwin" ? "/opt/homebrew/bin" : "/home/linuxbrew/.linuxbrew/bin");
|
|
7294
|
+
}
|
|
7295
|
+
return [...new Set(dirs.filter((item) => !!item && p.isAbsolute(item)))];
|
|
7053
7296
|
}
|
|
7054
7297
|
var _a$1;
|
|
7055
7298
|
function $constructor(name, initializer2, params) {
|
|
@@ -7286,7 +7529,7 @@ const NUMBER_FORMAT_RANGES = {
|
|
|
7286
7529
|
float32: [-34028234663852886e22, 34028234663852886e22],
|
|
7287
7530
|
float64: [-Number.MAX_VALUE, Number.MAX_VALUE]
|
|
7288
7531
|
};
|
|
7289
|
-
function pick
|
|
7532
|
+
function pick(schema, mask) {
|
|
7290
7533
|
const currDef = schema._zod.def;
|
|
7291
7534
|
const checks = currDef.checks;
|
|
7292
7535
|
const hasChecks = checks && checks.length > 0;
|
|
@@ -11529,7 +11772,7 @@ const ZodObject = /* @__PURE__ */ $constructor("ZodObject", (inst, def) => {
|
|
|
11529
11772
|
return merge(this, other);
|
|
11530
11773
|
},
|
|
11531
11774
|
pick(mask) {
|
|
11532
|
-
return pick
|
|
11775
|
+
return pick(this, mask);
|
|
11533
11776
|
},
|
|
11534
11777
|
omit(mask) {
|
|
11535
11778
|
return omit(this, mask);
|
|
@@ -11854,7 +12097,7 @@ const EMPTY_AI_USAGE = {
|
|
|
11854
12097
|
};
|
|
11855
12098
|
const OPERATIONS = ["commit-message", "pull-request-draft"];
|
|
11856
12099
|
const STATUSES = ["success", "failed", "cancelled"];
|
|
11857
|
-
const HARNESSES = ["codex", "claude", "opencode"];
|
|
12100
|
+
const HARNESSES = ["codex", "claude", "opencode", "grok"];
|
|
11858
12101
|
const MAX_TEXT$1 = 200;
|
|
11859
12102
|
const MAX_ERROR_TEXT = 400;
|
|
11860
12103
|
const aiUsageRecordSchema = looseObject({
|
|
@@ -12134,7 +12377,7 @@ function parseGeneratedParts(value) {
|
|
|
12134
12377
|
const parsed = generatedPartsSchema.safeParse(value);
|
|
12135
12378
|
if (!parsed.success || `${parsed.data.subject}
|
|
12136
12379
|
|
|
12137
|
-
${parsed.data.body}`.length > 1e4) throw invalidOutput$
|
|
12380
|
+
${parsed.data.body}`.length > 1e4) throw invalidOutput$4();
|
|
12138
12381
|
return parsed.data;
|
|
12139
12382
|
}
|
|
12140
12383
|
function parseCommitSplitProposal(value, stagedPaths) {
|
|
@@ -12194,14 +12437,14 @@ function parseJsonPayload(raw) {
|
|
|
12194
12437
|
if (nested instanceof AiOperationError) throw nested;
|
|
12195
12438
|
}
|
|
12196
12439
|
}
|
|
12197
|
-
throw invalidOutput$
|
|
12440
|
+
throw invalidOutput$4();
|
|
12198
12441
|
}
|
|
12199
12442
|
}
|
|
12200
12443
|
function asRecord(value) {
|
|
12201
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) throw invalidOutput$
|
|
12444
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw invalidOutput$4();
|
|
12202
12445
|
return value;
|
|
12203
12446
|
}
|
|
12204
|
-
function invalidOutput$
|
|
12447
|
+
function invalidOutput$4() {
|
|
12205
12448
|
return new AiOperationError({ code: "AI_INVALID_OUTPUT", operation: "ai-parse-output", message: "The AI returned a message with an invalid format.", retryable: true });
|
|
12206
12449
|
}
|
|
12207
12450
|
function hasControlCharacters$6(value, allowWhitespace) {
|
|
@@ -12215,22 +12458,58 @@ function cleanText(value, maxLength) {
|
|
|
12215
12458
|
const text2 = value.trim();
|
|
12216
12459
|
return !text2 || text2.length > maxLength || hasControlCharacters$6(text2, true) ? null : text2;
|
|
12217
12460
|
}
|
|
12461
|
+
const DEFAULT_MODEL$1 = { id: "default", label: "Default (CLI)" };
|
|
12218
12462
|
class CommitMessageService {
|
|
12219
|
-
constructor(operations, providers, log) {
|
|
12463
|
+
constructor(operations, providers, log, invalidateDiscovery) {
|
|
12220
12464
|
this.operations = operations;
|
|
12221
12465
|
this.log = log;
|
|
12466
|
+
this.invalidateDiscovery = invalidateDiscovery;
|
|
12222
12467
|
for (const provider of providers) this.providers.set(provider.id, provider);
|
|
12223
12468
|
}
|
|
12224
12469
|
operations;
|
|
12225
12470
|
log;
|
|
12471
|
+
invalidateDiscovery;
|
|
12226
12472
|
providers = /* @__PURE__ */ new Map();
|
|
12227
12473
|
active = /* @__PURE__ */ new Map();
|
|
12228
12474
|
statusCache = null;
|
|
12475
|
+
statusGeneration = 0;
|
|
12476
|
+
pendingStatus;
|
|
12477
|
+
invalidateStatuses() {
|
|
12478
|
+
this.statusGeneration++;
|
|
12479
|
+
this.statusCache = null;
|
|
12480
|
+
this.pendingStatus = void 0;
|
|
12481
|
+
this.invalidateDiscovery?.();
|
|
12482
|
+
}
|
|
12229
12483
|
async statuses(forceRefresh = false) {
|
|
12230
12484
|
if (!forceRefresh && this.statusCache && Date.now() - this.statusCache.at < 3e4) return this.statusCache.value;
|
|
12231
|
-
|
|
12232
|
-
|
|
12233
|
-
|
|
12485
|
+
if (this.pendingStatus && (!forceRefresh || this.pendingStatus.force)) return this.pendingStatus.promise;
|
|
12486
|
+
const generation = ++this.statusGeneration;
|
|
12487
|
+
const promise = Promise.all([...this.providers.values()].map(async (provider) => {
|
|
12488
|
+
try {
|
|
12489
|
+
return await provider.status(forceRefresh);
|
|
12490
|
+
} catch {
|
|
12491
|
+
return {
|
|
12492
|
+
id: provider.id,
|
|
12493
|
+
label: { codex: "Codex", claude: "Claude Code", opencode: "OpenCode", grok: "Grok Build" }[provider.id],
|
|
12494
|
+
installed: false,
|
|
12495
|
+
availability: "error",
|
|
12496
|
+
authStatus: "unknown",
|
|
12497
|
+
installationStatus: "inspection-failed",
|
|
12498
|
+
message: "Could not inspect this CLI. Check again or review its executable path.",
|
|
12499
|
+
models: [DEFAULT_MODEL$1],
|
|
12500
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12501
|
+
};
|
|
12502
|
+
}
|
|
12503
|
+
})).then((value) => {
|
|
12504
|
+
if (generation === this.statusGeneration) this.statusCache = { at: Date.now(), value };
|
|
12505
|
+
return value;
|
|
12506
|
+
});
|
|
12507
|
+
this.pendingStatus = { force: forceRefresh, promise };
|
|
12508
|
+
try {
|
|
12509
|
+
return await promise;
|
|
12510
|
+
} finally {
|
|
12511
|
+
if (this.pendingStatus?.promise === promise) this.pendingStatus = void 0;
|
|
12512
|
+
}
|
|
12234
12513
|
}
|
|
12235
12514
|
async generate(input, externalSignal) {
|
|
12236
12515
|
if (this.active.has(input.requestId) || [...this.active.values()].some((entry) => entry.repositoryId === input.repositoryId) || this.active.size >= 3) {
|
|
@@ -12293,7 +12572,7 @@ ${parts.body}` : parts.subject,
|
|
|
12293
12572
|
splitBlockedReason: context.splitBlockedReason
|
|
12294
12573
|
};
|
|
12295
12574
|
} catch (error) {
|
|
12296
|
-
const
|
|
12575
|
+
const failure2 = failureLogFields(error);
|
|
12297
12576
|
recordSafely(this.log, {
|
|
12298
12577
|
operation: "commit-message",
|
|
12299
12578
|
harness: input.harness,
|
|
@@ -12301,10 +12580,10 @@ ${parts.body}` : parts.subject,
|
|
|
12301
12580
|
repositoryId: input.repositoryId,
|
|
12302
12581
|
// A cancellation is a decision, not a failure; merging the two would
|
|
12303
12582
|
// poison any reliability figure taken from this log.
|
|
12304
|
-
status:
|
|
12583
|
+
status: failure2.status,
|
|
12305
12584
|
durationMs: Date.now() - startedAt,
|
|
12306
|
-
errorCode:
|
|
12307
|
-
errorMessage:
|
|
12585
|
+
errorCode: failure2.errorCode,
|
|
12586
|
+
errorMessage: failure2.errorMessage,
|
|
12308
12587
|
usage,
|
|
12309
12588
|
stagedFileCount,
|
|
12310
12589
|
contextTruncated,
|
|
@@ -12375,10 +12654,10 @@ ${context.patch}`;
|
|
|
12375
12654
|
}
|
|
12376
12655
|
function parsePullRequestDraft(value) {
|
|
12377
12656
|
const parsed = pullRequestDraftSchema.safeParse(value);
|
|
12378
|
-
if (!parsed.success) throw invalidOutput$
|
|
12657
|
+
if (!parsed.success) throw invalidOutput$3();
|
|
12379
12658
|
return parsed.data;
|
|
12380
12659
|
}
|
|
12381
|
-
function invalidOutput$
|
|
12660
|
+
function invalidOutput$3() {
|
|
12382
12661
|
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
12662
|
}
|
|
12384
12663
|
function hasControlCharacters$5(value, allowWhitespace) {
|
|
@@ -12428,8 +12707,8 @@ class PullRequestDraftService {
|
|
|
12428
12707
|
this.record(input, "success", null, null, usage, contextTruncated, Date.now() - startedAt);
|
|
12429
12708
|
return { ...parts, harness: input.harness, model: input.model, contextWasTruncated: context.truncated };
|
|
12430
12709
|
} catch (error) {
|
|
12431
|
-
const
|
|
12432
|
-
this.record(input,
|
|
12710
|
+
const failure2 = failureLogFields(error);
|
|
12711
|
+
this.record(input, failure2.status, failure2.errorCode, failure2.errorMessage, usage, contextTruncated, Date.now() - startedAt);
|
|
12433
12712
|
throw error;
|
|
12434
12713
|
} finally {
|
|
12435
12714
|
this.active.delete(input.requestId);
|
|
@@ -12467,9 +12746,66 @@ function throwIfCancelled(signal, harness) {
|
|
|
12467
12746
|
if (!signal?.aborted) return;
|
|
12468
12747
|
throw new AiOperationError({ code: "AI_CANCELLED", operation: "ai-pr-draft", harness, message: "Generation canceled." });
|
|
12469
12748
|
}
|
|
12749
|
+
function runCandidate(runner, candidate, args, options = {}) {
|
|
12750
|
+
return runner.run(candidate.executable, args, { ...options, env: { ...candidate.env, ...options.env } });
|
|
12751
|
+
}
|
|
12752
|
+
async function selectCli(resolver, runner, name, options = {}) {
|
|
12753
|
+
let first;
|
|
12754
|
+
const candidates = await resolver.discover(name, options.forceRefresh);
|
|
12755
|
+
for (const candidate of candidates) {
|
|
12756
|
+
if (options.runOptions?.signal?.aborted) throw new AiOperationError({ code: "AI_CANCELLED", operation: "cli-discovery", message: "Generation canceled." });
|
|
12757
|
+
if (candidate.problem) {
|
|
12758
|
+
first ??= { candidate, state: candidate.problem };
|
|
12759
|
+
continue;
|
|
12760
|
+
}
|
|
12761
|
+
try {
|
|
12762
|
+
const result = await runCandidate(runner, candidate, ["--version"], options.runOptions);
|
|
12763
|
+
const raw = result.stdout.trim() || result.stderr.trim();
|
|
12764
|
+
const version2 = (raw.split(/\r?\n/)[0] ?? "").slice(0, 200);
|
|
12765
|
+
if (result.exitCode !== 0 || !version2) {
|
|
12766
|
+
first ??= { candidate, state: "not-executable" };
|
|
12767
|
+
continue;
|
|
12768
|
+
}
|
|
12769
|
+
if (options.compatible && !options.compatible(raw)) {
|
|
12770
|
+
first ??= { candidate, version: version2, state: "incompatible" };
|
|
12771
|
+
continue;
|
|
12772
|
+
}
|
|
12773
|
+
return { candidate, version: version2, state: "available", warning: candidate.warning };
|
|
12774
|
+
} catch (error) {
|
|
12775
|
+
if (options.runOptions?.signal?.aborted) throw error;
|
|
12776
|
+
first ??= { candidate, state: "not-executable" };
|
|
12777
|
+
}
|
|
12778
|
+
}
|
|
12779
|
+
const warning = await resolver.warning();
|
|
12780
|
+
return first ? { ...first, warning } : { state: warning ? "inspection-failed" : "not-found", warning };
|
|
12781
|
+
}
|
|
12782
|
+
function detectionFields(detected) {
|
|
12783
|
+
return { installationStatus: detected.state, ...detected.candidate ? { executablePath: detected.candidate.executable, executableSource: detected.candidate.source } : {}, ...detected.warning ? { discoveryWarning: detected.warning } : {} };
|
|
12784
|
+
}
|
|
12785
|
+
function detectionFailure(detected, base, unsupported) {
|
|
12786
|
+
if (detected.state === "available") return null;
|
|
12787
|
+
const message = detected.state === "not-found" ? detected.candidate?.source === "configured" ? "The configured executable was not found. Correct the path or reset it to Automatic." : `Install ${base.label} and check again, or set its executable path.` : detected.state === "incompatible" ? unsupported ?? "The installed CLI version is not supported." : detected.state === "inspection-failed" ? "Could not inspect the CLI installation. Check again or set its executable path." : "The CLI was found but could not run. Check executable permissions, runtime dependencies, and system compatibility.";
|
|
12788
|
+
return { ...base, ...detectionFields(detected), installed: !!detected.candidate && detected.state !== "not-found", availability: "error", authStatus: "unknown", ...detected.version ? { version: detected.version } : {}, message };
|
|
12789
|
+
}
|
|
12790
|
+
function requireCandidate(detected, name) {
|
|
12791
|
+
if (detected.state !== "available" || !detected.candidate) throw new AiOperationError({ code: detected.state === "not-found" ? "AI_CLI_NOT_FOUND" : "AI_PROCESS_FAILED", operation: "cli-discovery", message: `${name} could not be started. Check its status in Settings → AI assistance.` });
|
|
12792
|
+
return detected.candidate;
|
|
12793
|
+
}
|
|
12470
12794
|
const AI_PROVIDER_TIMEOUT_MS = 9 * 6e4;
|
|
12471
12795
|
const AI_SERVER_TIMEOUT_MS = AI_PROVIDER_TIMEOUT_MS + 3e4;
|
|
12472
|
-
|
|
12796
|
+
function grokUsage(envelope) {
|
|
12797
|
+
if (!envelope || typeof envelope !== "object") return { ...EMPTY_AI_USAGE };
|
|
12798
|
+
const record2 = envelope;
|
|
12799
|
+
const usage = record2.usage && typeof record2.usage === "object" ? record2.usage : {};
|
|
12800
|
+
return {
|
|
12801
|
+
inputTokens: count(usage.input_tokens),
|
|
12802
|
+
outputTokens: count(usage.output_tokens),
|
|
12803
|
+
reasoningTokens: count(usage.reasoning_tokens),
|
|
12804
|
+
cacheReadTokens: count(usage.cache_read_input_tokens),
|
|
12805
|
+
cacheWriteTokens: count(usage.cache_creation_input_tokens),
|
|
12806
|
+
costUsd: count(record2.total_cost_usd, true)
|
|
12807
|
+
};
|
|
12808
|
+
}
|
|
12473
12809
|
function claudeUsage(envelope) {
|
|
12474
12810
|
if (!envelope || typeof envelope !== "object") return { ...EMPTY_AI_USAGE };
|
|
12475
12811
|
const record2 = envelope;
|
|
@@ -12507,20 +12843,6 @@ function codexUsage(stdout) {
|
|
|
12507
12843
|
costUsd: null
|
|
12508
12844
|
};
|
|
12509
12845
|
}
|
|
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
12846
|
function count(value, fractional = false) {
|
|
12525
12847
|
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return null;
|
|
12526
12848
|
return fractional ? value : Math.round(value);
|
|
@@ -12569,7 +12891,7 @@ ${diagnostic ?? ""}`.toLowerCase();
|
|
|
12569
12891
|
});
|
|
12570
12892
|
}
|
|
12571
12893
|
function label(harness) {
|
|
12572
|
-
return harness === "codex" ? "Codex" : harness === "claude" ? "Claude Code" : "OpenCode";
|
|
12894
|
+
return harness === "codex" ? "Codex" : harness === "claude" ? "Claude Code" : harness === "grok" ? "Grok Build" : "OpenCode";
|
|
12573
12895
|
}
|
|
12574
12896
|
function stripAnsi(value) {
|
|
12575
12897
|
return value.replace(new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g"), "");
|
|
@@ -12663,7 +12985,7 @@ function flattenWhitespace(value) {
|
|
|
12663
12985
|
}
|
|
12664
12986
|
return flattened.replace(/ {2,}/g, " ").trim();
|
|
12665
12987
|
}
|
|
12666
|
-
const MODELS = [DEFAULT_MODEL, { id: "sonnet", label: "Sonnet" }, { id: "opus", label: "Opus" }, { id: "haiku", label: "Haiku" }];
|
|
12988
|
+
const MODELS = [DEFAULT_MODEL$1, { id: "sonnet", label: "Sonnet" }, { id: "opus", label: "Opus" }, { id: "haiku", label: "Haiku" }];
|
|
12667
12989
|
class ClaudeProvider {
|
|
12668
12990
|
constructor(resolver, runner) {
|
|
12669
12991
|
this.resolver = resolver;
|
|
@@ -12674,10 +12996,11 @@ class ClaudeProvider {
|
|
|
12674
12996
|
id = "claude";
|
|
12675
12997
|
async status(forceRefresh = false) {
|
|
12676
12998
|
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
12677
|
-
const
|
|
12678
|
-
|
|
12679
|
-
|
|
12680
|
-
const
|
|
12999
|
+
const detected = await selectCli(this.resolver, this.runner, "claude", { forceRefresh });
|
|
13000
|
+
const failure2 = detectionFailure(detected, { id: this.id, label: "Claude Code", models: MODELS, checkedAt });
|
|
13001
|
+
if (failure2) return failure2;
|
|
13002
|
+
const executable = requireCandidate(detected, this.id);
|
|
13003
|
+
const auth = await runCandidate(this.runner, executable, ["auth", "status", "--json"]);
|
|
12681
13004
|
let loggedIn;
|
|
12682
13005
|
try {
|
|
12683
13006
|
loggedIn = auth.exitCode === 0 && JSON.parse(auth.stdout).loggedIn === true;
|
|
@@ -12685,23 +13008,23 @@ class ClaudeProvider {
|
|
|
12685
13008
|
loggedIn = false;
|
|
12686
13009
|
}
|
|
12687
13010
|
return {
|
|
13011
|
+
...detectionFields(detected),
|
|
12688
13012
|
id: this.id,
|
|
12689
13013
|
label: "Claude Code",
|
|
12690
13014
|
availability: loggedIn ? "ready" : "error",
|
|
12691
13015
|
installed: true,
|
|
12692
13016
|
authStatus: loggedIn ? "authenticated" : "unauthenticated",
|
|
12693
|
-
version:
|
|
13017
|
+
version: detected.version ?? "",
|
|
12694
13018
|
...!loggedIn ? { message: "Run claude auth login." } : {},
|
|
12695
13019
|
models: MODELS,
|
|
12696
13020
|
checkedAt
|
|
12697
13021
|
};
|
|
12698
13022
|
}
|
|
12699
13023
|
async generate(input) {
|
|
12700
|
-
const executable = await this.resolver.
|
|
12701
|
-
if (!executable) throw new AiOperationError({ code: "AI_CLI_NOT_FOUND", operation: "claude-generate", harness: this.id, message: "Claude Code is not installed." });
|
|
13024
|
+
const executable = requireCandidate(await selectCli(this.resolver, this.runner, "claude", { runOptions: { signal: input.signal } }), this.id);
|
|
12702
13025
|
const args = ["-p", "--output-format", "json", "--json-schema", JSON.stringify(input.schema), "--tools", "", "--no-session-persistence", "--safe-mode"];
|
|
12703
13026
|
if (input.model !== "default") args.push("--model", input.model);
|
|
12704
|
-
const result = await this.runner
|
|
13027
|
+
const result = await runCandidate(this.runner, executable, args, { cwd: input.repositoryPath, stdin: input.prompt, timeoutMs: AI_PROVIDER_TIMEOUT_MS, signal: input.signal, removeEnv: ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN"] });
|
|
12705
13028
|
requireSuccess(result, this.id, "claude-generate");
|
|
12706
13029
|
try {
|
|
12707
13030
|
const envelope = JSON.parse(result.stdout);
|
|
@@ -12724,31 +13047,32 @@ class CodexProvider {
|
|
|
12724
13047
|
id = "codex";
|
|
12725
13048
|
async status(forceRefresh = false) {
|
|
12726
13049
|
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
12727
|
-
const
|
|
12728
|
-
|
|
12729
|
-
|
|
12730
|
-
const
|
|
13050
|
+
const detected = await selectCli(this.resolver, this.runner, "codex", { forceRefresh });
|
|
13051
|
+
const failure2 = detectionFailure(detected, { id: this.id, label: "Codex", models: [DEFAULT_MODEL$1], checkedAt });
|
|
13052
|
+
if (failure2) return failure2;
|
|
13053
|
+
const executable = requireCandidate(detected, this.id);
|
|
13054
|
+
const login = await runCandidate(this.runner, executable, ["login", "status"]);
|
|
12731
13055
|
if (login.exitCode !== 0 || !/logged in/i.test(`${login.stdout}
|
|
12732
13056
|
${login.stderr}`)) {
|
|
12733
|
-
return { id: this.id, label: "Codex", availability: "error", installed: true, authStatus: "unauthenticated", version:
|
|
13057
|
+
return { ...detectionFields(detected), id: this.id, label: "Codex", availability: "error", installed: true, authStatus: "unauthenticated", version: detected.version ?? "", message: "Run codex login.", models: [DEFAULT_MODEL$1], checkedAt };
|
|
12734
13058
|
}
|
|
12735
|
-
const catalog = await this.runner
|
|
12736
|
-
const models = catalog.exitCode === 0 ? parseCodexModels(catalog.stdout) : [DEFAULT_MODEL];
|
|
13059
|
+
const catalog = await runCandidate(this.runner, executable, ["debug", "models", "--bundled"]);
|
|
13060
|
+
const models = catalog.exitCode === 0 ? parseCodexModels(catalog.stdout) : [DEFAULT_MODEL$1];
|
|
12737
13061
|
return {
|
|
13062
|
+
...detectionFields(detected),
|
|
12738
13063
|
id: this.id,
|
|
12739
13064
|
label: "Codex",
|
|
12740
13065
|
availability: models.length > 1 ? "ready" : "warning",
|
|
12741
13066
|
installed: true,
|
|
12742
13067
|
authStatus: "authenticated",
|
|
12743
|
-
version:
|
|
13068
|
+
version: detected.version ?? "",
|
|
12744
13069
|
...models.length > 1 ? {} : { message: "Available; the model catalog could not be verified." },
|
|
12745
13070
|
models,
|
|
12746
13071
|
checkedAt
|
|
12747
13072
|
};
|
|
12748
13073
|
}
|
|
12749
13074
|
async generate(input) {
|
|
12750
|
-
const executable = await this.resolver.
|
|
12751
|
-
if (!executable) throw new AiOperationError({ code: "AI_CLI_NOT_FOUND", operation: "codex-generate", harness: this.id, message: "Codex is not installed." });
|
|
13075
|
+
const executable = requireCandidate(await selectCli(this.resolver, this.runner, "codex", { runOptions: { signal: input.signal } }), this.id);
|
|
12752
13076
|
const temporary = await mkdtemp(path.join(os.tmpdir(), "opentig-codex-"));
|
|
12753
13077
|
const schemaPath = path.join(temporary, "schema.json");
|
|
12754
13078
|
const outputPath = path.join(temporary, "output.json");
|
|
@@ -12757,7 +13081,7 @@ ${login.stderr}`)) {
|
|
|
12757
13081
|
const args = ["exec", "--json", "--ephemeral", "--skip-git-repo-check", "-s", "read-only"];
|
|
12758
13082
|
if (input.model !== "default") args.push("--model", input.model);
|
|
12759
13083
|
args.push("--config", 'model_reasoning_effort="low"', "--output-schema", schemaPath, "--output-last-message", outputPath, "-");
|
|
12760
|
-
const result = await this.runner
|
|
13084
|
+
const result = await runCandidate(this.runner, executable, args, { cwd: input.repositoryPath, stdin: input.prompt, timeoutMs: AI_PROVIDER_TIMEOUT_MS, signal: input.signal, removeEnv: ["OPENAI_API_KEY"] });
|
|
12761
13085
|
requireSuccess(result, this.id, "codex-generate");
|
|
12762
13086
|
return { output: parseJsonPayload(await readFile(outputPath, "utf8")), usage: codexUsage(result.stdout) };
|
|
12763
13087
|
} finally {
|
|
@@ -12769,2254 +13093,219 @@ function parseCodexModels(raw) {
|
|
|
12769
13093
|
try {
|
|
12770
13094
|
const parsed = JSON.parse(raw);
|
|
12771
13095
|
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];
|
|
13096
|
+
return [DEFAULT_MODEL$1, ...options];
|
|
12773
13097
|
} 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()}`;
|
|
13098
|
+
return [DEFAULT_MODEL$1];
|
|
12972
13099
|
}
|
|
12973
|
-
|
|
12974
|
-
|
|
12975
|
-
|
|
12976
|
-
|
|
12977
|
-
|
|
12978
|
-
|
|
12979
|
-
|
|
12980
|
-
|
|
12981
|
-
|
|
12982
|
-
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
|
|
12986
|
-
|
|
12987
|
-
|
|
12988
|
-
|
|
12989
|
-
|
|
12990
|
-
|
|
12991
|
-
|
|
12992
|
-
|
|
12993
|
-
|
|
12994
|
-
|
|
12995
|
-
|
|
12996
|
-
|
|
12997
|
-
|
|
12998
|
-
|
|
12999
|
-
|
|
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
|
-
}
|
|
13100
|
+
}
|
|
13101
|
+
function isSupportedGrokVersion(raw) {
|
|
13102
|
+
const match = /^grok (\d+)\.(\d+)\.(\d+)\b/i.exec(stripAnsi(raw).trim());
|
|
13103
|
+
return !!match && Number(match[1]) === 1 && (Number(match[2]) > 0 || Number(match[3]) >= 46);
|
|
13104
|
+
}
|
|
13105
|
+
function parseGrokModels(raw) {
|
|
13106
|
+
const text2 = stripAnsi(raw);
|
|
13107
|
+
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";
|
|
13108
|
+
const models = [{ id: "default", label: "Default (Grok)" }];
|
|
13109
|
+
const seen = /* @__PURE__ */ new Set(["default"]);
|
|
13110
|
+
const catalog = text2.split("Available models:")[1] ?? "";
|
|
13111
|
+
for (const line of catalog.split(/\r?\n/)) {
|
|
13112
|
+
const match = /^\s+[*-]\s+([^\s]+?)(?:\s+\(default\))?\s*$/.exec(line);
|
|
13113
|
+
const id = match?.[1];
|
|
13114
|
+
if (id && id.length <= 200 && /^[\w.:/#-]+$/.test(id) && !seen.has(id)) {
|
|
13115
|
+
seen.add(id);
|
|
13116
|
+
models.push({ id, label: id });
|
|
13117
|
+
}
|
|
13118
|
+
}
|
|
13119
|
+
return { authStatus, models };
|
|
13120
|
+
}
|
|
13121
|
+
function parseGrokOutput(raw) {
|
|
13122
|
+
let envelope;
|
|
13123
|
+
try {
|
|
13124
|
+
envelope = parseJsonPayload(stripAnsi(raw));
|
|
13125
|
+
} catch {
|
|
13126
|
+
throw invalidOutput$2();
|
|
13046
13127
|
}
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
if (path2) {
|
|
13053
|
-
url = defaultPathSerializer({ path: path2, url });
|
|
13128
|
+
if (envelope.type === "error" || envelope.structuredOutputError || envelope.stopReason !== "end_turn") throw invalidOutput$2();
|
|
13129
|
+
const structured = envelope.structuredOutput;
|
|
13130
|
+
if (structured !== void 0) {
|
|
13131
|
+
if (!structured || typeof structured !== "object" || Array.isArray(structured)) throw invalidOutput$2();
|
|
13132
|
+
return { envelope, output: structured };
|
|
13054
13133
|
}
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13134
|
+
if (typeof envelope.text !== "string") throw invalidOutput$2();
|
|
13135
|
+
try {
|
|
13136
|
+
return { envelope, output: parseJsonPayload(envelope.text) };
|
|
13137
|
+
} catch {
|
|
13138
|
+
throw invalidOutput$2();
|
|
13058
13139
|
}
|
|
13059
|
-
|
|
13060
|
-
|
|
13140
|
+
}
|
|
13141
|
+
function invalidOutput$2() {
|
|
13142
|
+
return new AiOperationError({ code: "AI_INVALID_OUTPUT", operation: "grok-generate", harness: "grok", message: "Grok returned an incomplete or invalid structured response.", retryable: true });
|
|
13143
|
+
}
|
|
13144
|
+
const DEFAULT_MODEL = { id: "default", label: "Default (Grok)" };
|
|
13145
|
+
const UNSUPPORTED = "Grok Build 1.0.46 or later in the 1.x series is required, with headless JSON and tool controls.";
|
|
13146
|
+
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";
|
|
13147
|
+
const REQUIRED_FLAGS = ["--prompt-file", "--json-schema", "--output-format", "--tools", "--disallowed-tools", "--deny", "--disable-web-search", "--max-turns", "--permission-mode", "--verbatim"];
|
|
13148
|
+
class GrokProvider {
|
|
13149
|
+
constructor(resolver, runner) {
|
|
13150
|
+
this.resolver = resolver;
|
|
13151
|
+
this.runner = runner;
|
|
13061
13152
|
}
|
|
13062
|
-
|
|
13063
|
-
|
|
13064
|
-
|
|
13065
|
-
|
|
13066
|
-
const
|
|
13067
|
-
|
|
13068
|
-
|
|
13069
|
-
|
|
13070
|
-
|
|
13071
|
-
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
|
|
13075
|
-
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13086
|
-
|
|
13087
|
-
|
|
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
|
-
}
|
|
13153
|
+
resolver;
|
|
13154
|
+
runner;
|
|
13155
|
+
id = "grok";
|
|
13156
|
+
async status(forceRefresh = false) {
|
|
13157
|
+
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13158
|
+
const base = { id: this.id, label: "Grok Build", checkedAt, models: [DEFAULT_MODEL] };
|
|
13159
|
+
return this.withEnvironment(async (options) => {
|
|
13160
|
+
const detected = await selectCli(this.resolver, this.runner, this.id, { forceRefresh, compatible: isSupportedGrokVersion, runOptions: options });
|
|
13161
|
+
const failure2 = detectionFailure(detected, base, UNSUPPORTED);
|
|
13162
|
+
if (failure2) return failure2;
|
|
13163
|
+
const executable = requireCandidate(detected, this.id);
|
|
13164
|
+
const installed = { ...base, ...detectionFields(detected), installed: true, version: detected.version ?? "" };
|
|
13165
|
+
try {
|
|
13166
|
+
await this.checkControls(executable, options);
|
|
13167
|
+
const result = await runCandidate(this.runner, executable, ["models"], options);
|
|
13168
|
+
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." };
|
|
13169
|
+
const { authStatus, models } = parseGrokModels(result.stdout);
|
|
13170
|
+
return {
|
|
13171
|
+
...installed,
|
|
13172
|
+
models,
|
|
13173
|
+
authStatus,
|
|
13174
|
+
availability: authStatus === "unauthenticated" ? "error" : authStatus === "authenticated" && models.length > 1 ? "ready" : "warning",
|
|
13175
|
+
...authStatus === "unauthenticated" ? { message: "Run grok login, or provide XAI_API_KEY to the OpenTig process." } : authStatus === "unknown" ? { message: "Could not confirm Grok authentication." } : {}
|
|
13176
|
+
};
|
|
13177
|
+
} catch (error) {
|
|
13178
|
+
return { ...installed, availability: "error", authStatus: "unknown", message: error instanceof AiOperationError ? error.message : "Could not verify Grok execution controls." };
|
|
13104
13179
|
}
|
|
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;
|
|
13180
|
+
});
|
|
13138
13181
|
}
|
|
13139
|
-
|
|
13140
|
-
|
|
13141
|
-
const
|
|
13142
|
-
|
|
13143
|
-
|
|
13144
|
-
|
|
13145
|
-
|
|
13146
|
-
|
|
13147
|
-
|
|
13148
|
-
|
|
13149
|
-
|
|
13150
|
-
|
|
13151
|
-
|
|
13152
|
-
|
|
13153
|
-
|
|
13154
|
-
|
|
13155
|
-
|
|
13156
|
-
|
|
13157
|
-
|
|
13158
|
-
|
|
13159
|
-
|
|
13160
|
-
|
|
13161
|
-
|
|
13162
|
-
|
|
13163
|
-
|
|
13164
|
-
|
|
13165
|
-
|
|
13166
|
-
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
13170
|
-
|
|
13171
|
-
|
|
13172
|
-
|
|
13173
|
-
|
|
13174
|
-
}
|
|
13175
|
-
|
|
13176
|
-
|
|
13177
|
-
|
|
13178
|
-
|
|
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
|
-
}
|
|
13182
|
+
async generate(input) {
|
|
13183
|
+
const timeout = AbortSignal.timeout(AI_PROVIDER_TIMEOUT_MS);
|
|
13184
|
+
const signal = AbortSignal.any([input.signal, timeout]);
|
|
13185
|
+
try {
|
|
13186
|
+
return await this.withEnvironment(async (options) => {
|
|
13187
|
+
const controlled = { ...options, signal };
|
|
13188
|
+
const executable = requireCandidate(await selectCli(this.resolver, this.runner, this.id, { compatible: isSupportedGrokVersion, runOptions: controlled }), this.id);
|
|
13189
|
+
await this.checkControls(executable, controlled);
|
|
13190
|
+
const promptFile = path.join(options.cwd, "prompt.txt");
|
|
13191
|
+
await writeFile(promptFile, input.prompt, { encoding: "utf8", mode: 384 });
|
|
13192
|
+
const args = [
|
|
13193
|
+
"--prompt-file",
|
|
13194
|
+
promptFile,
|
|
13195
|
+
"--output-format",
|
|
13196
|
+
"json",
|
|
13197
|
+
"--json-schema",
|
|
13198
|
+
JSON.stringify(input.schema),
|
|
13199
|
+
"--verbatim",
|
|
13200
|
+
"--tools",
|
|
13201
|
+
"read_file",
|
|
13202
|
+
"--disallowed-tools",
|
|
13203
|
+
"read_file,search_tool,use_tool,Agent",
|
|
13204
|
+
"--deny",
|
|
13205
|
+
"MCPTool",
|
|
13206
|
+
"--disable-web-search",
|
|
13207
|
+
"--max-turns",
|
|
13208
|
+
"1",
|
|
13209
|
+
"--permission-mode",
|
|
13210
|
+
"dontAsk",
|
|
13211
|
+
"--no-memory"
|
|
13212
|
+
];
|
|
13213
|
+
if (input.model !== "default") args.push("--model", input.model);
|
|
13214
|
+
const result = await runCandidate(this.runner, executable, args, { ...controlled, timeoutMs: AI_PROVIDER_TIMEOUT_MS });
|
|
13215
|
+
requireGrokSuccess(result);
|
|
13216
|
+
const parsed = parseGrokOutput(result.stdout);
|
|
13217
|
+
return { output: parsed.output, usage: grokUsage(parsed.envelope) };
|
|
13218
|
+
});
|
|
13219
|
+
} catch (error) {
|
|
13220
|
+
if (input.signal.aborted) throw failure("AI_CANCELLED", "Generation canceled.");
|
|
13221
|
+
if (timeout.aborted) throw failure("AI_TIMEOUT", "Generation took too long.");
|
|
13222
|
+
throw error;
|
|
13200
13223
|
}
|
|
13201
13224
|
}
|
|
13202
|
-
|
|
13203
|
-
|
|
13204
|
-
|
|
13205
|
-
|
|
13206
|
-
|
|
13207
|
-
|
|
13208
|
-
|
|
13209
|
-
|
|
13210
|
-
|
|
13211
|
-
}
|
|
13212
|
-
getInterceptorIndex(id) {
|
|
13213
|
-
if (typeof id === "number") {
|
|
13214
|
-
return this._fns[id] ? id : -1;
|
|
13215
|
-
} else {
|
|
13216
|
-
return this._fns.indexOf(id);
|
|
13225
|
+
async checkControls(executable, options) {
|
|
13226
|
+
const help = await runCandidate(this.runner, executable, ["--help"], options);
|
|
13227
|
+
if (help.exitCode !== 0 || REQUIRED_FLAGS.some((flag2) => !help.stdout.includes(flag2))) throw failure("AI_PROCESS_FAILED", UNSUPPORTED);
|
|
13228
|
+
const result = await runCandidate(this.runner, executable, ["inspect", "--json"], options);
|
|
13229
|
+
let report;
|
|
13230
|
+
try {
|
|
13231
|
+
report = JSON.parse(result.stdout);
|
|
13232
|
+
} catch {
|
|
13233
|
+
throw failure("AI_PROCESS_FAILED", "Could not verify the isolated Grok configuration.");
|
|
13217
13234
|
}
|
|
13218
|
-
|
|
13219
|
-
|
|
13220
|
-
|
|
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;
|
|
13235
|
+
const surfaces = ["hooks", "plugins", "mcpServers", "projectInstructions"];
|
|
13236
|
+
if (result.exitCode !== 0 || !report || surfaces.some((key) => !Array.isArray(report[key]) || report[key].length > 0)) {
|
|
13237
|
+
throw failure("AI_PROCESS_FAILED", "Grok configuration includes hooks, plugins, MCP servers or instructions. OpenTig requires an isolated text-only configuration.");
|
|
13227
13238
|
}
|
|
13228
13239
|
}
|
|
13229
|
-
|
|
13230
|
-
const
|
|
13231
|
-
|
|
13232
|
-
|
|
13233
|
-
|
|
13234
|
-
|
|
13235
|
-
|
|
13240
|
+
async withEnvironment(run) {
|
|
13241
|
+
const temporary = await mkdtemp(path.join(os.tmpdir(), "opentig-grok-"));
|
|
13242
|
+
const userGrokHome = process.env.GROK_HOME || path.join(os.homedir(), ".grok");
|
|
13243
|
+
const authPath = path.resolve(process.env.GROK_AUTH_PATH || path.join(userGrokHome, "auth.json"));
|
|
13244
|
+
const privateGrokHome = path.join(temporary, ".grok");
|
|
13245
|
+
try {
|
|
13246
|
+
await mkdir(privateGrokHome, { mode: 448 });
|
|
13247
|
+
await writeFile(path.join(privateGrokHome, "config.toml"), CONFIG, { encoding: "utf8", mode: 384 });
|
|
13248
|
+
const env = {
|
|
13249
|
+
HOME: temporary,
|
|
13250
|
+
USERPROFILE: temporary,
|
|
13251
|
+
GROK_HOME: privateGrokHome,
|
|
13252
|
+
GROK_AUTH_PATH: authPath,
|
|
13253
|
+
XDG_CONFIG_HOME: path.join(temporary, "config"),
|
|
13254
|
+
XDG_DATA_HOME: path.join(temporary, "data"),
|
|
13255
|
+
XDG_CACHE_HOME: path.join(temporary, "cache"),
|
|
13256
|
+
GROK_SUBAGENTS: "0",
|
|
13257
|
+
GROK_MANAGED_MCPS_ENABLED: "0",
|
|
13258
|
+
GROK_MANAGED_MCP_GATEWAY_TOOLS_ENABLED: "0",
|
|
13259
|
+
GROK_TITLE_REFRESH: "0"
|
|
13260
|
+
};
|
|
13261
|
+
const preserved = /* @__PURE__ */ new Set([...Object.keys(env), "GROK_AUTH", "GROK_CODE_XAI_API_KEY"]);
|
|
13262
|
+
const removeEnv = Object.keys(process.env).filter((key) => key.startsWith("GROK_") && !preserved.has(key));
|
|
13263
|
+
return await run({ cwd: temporary, env, removeEnv });
|
|
13264
|
+
} finally {
|
|
13265
|
+
await rm(temporary, { recursive: true, force: true, maxRetries: 3 });
|
|
13236
13266
|
}
|
|
13237
13267
|
}
|
|
13238
|
-
use(fn) {
|
|
13239
|
-
this._fns = [...this._fns, fn];
|
|
13240
|
-
return this._fns.length - 1;
|
|
13241
|
-
}
|
|
13242
13268
|
}
|
|
13243
|
-
|
|
13244
|
-
|
|
13245
|
-
|
|
13246
|
-
|
|
13247
|
-
|
|
13248
|
-
|
|
13249
|
-
|
|
13250
|
-
|
|
13251
|
-
|
|
13252
|
-
|
|
13253
|
-
}
|
|
13254
|
-
|
|
13255
|
-
|
|
13256
|
-
|
|
13257
|
-
|
|
13258
|
-
|
|
13259
|
-
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
|
|
13265
|
-
|
|
13266
|
-
|
|
13267
|
-
|
|
13268
|
-
|
|
13269
|
-
|
|
13270
|
-
|
|
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
|
|
13332
|
-
};
|
|
13333
|
-
}
|
|
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
|
-
};
|
|
13362
|
-
}
|
|
13363
|
-
const textError = await response.text();
|
|
13364
|
-
let jsonError;
|
|
13365
|
-
try {
|
|
13366
|
-
jsonError = JSON.parse(textError);
|
|
13367
|
-
} catch {
|
|
13368
|
-
}
|
|
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;
|
|
13379
|
-
}
|
|
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;
|
|
13424
|
-
}
|
|
13425
|
-
}
|
|
13426
|
-
}
|
|
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
|
-
}
|
|
13437
|
-
}
|
|
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
|
-
}
|
|
13457
|
-
}
|
|
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
|
-
}
|
|
13521
|
-
}
|
|
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
|
-
}
|
|
13554
|
-
}
|
|
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
|
-
}
|
|
13574
|
-
}
|
|
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
|
-
});
|
|
13584
|
-
}
|
|
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";
|
|
13269
|
+
function requireGrokSuccess(result) {
|
|
13270
|
+
if (result.exitCode === 0) return;
|
|
13271
|
+
const diagnostic = `${result.stdout}
|
|
13272
|
+
${result.stderr}`.toLowerCase();
|
|
13273
|
+
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.");
|
|
13274
|
+
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.");
|
|
13275
|
+
if (/model.*(not found|unavailable|invalid|access|not supported)|unknown model/.test(diagnostic)) throw failure("AI_MODEL_UNAVAILABLE", "The selected Grok model is unavailable.");
|
|
13276
|
+
throw failure("AI_PROCESS_FAILED", "Grok could not generate content.");
|
|
13277
|
+
}
|
|
13278
|
+
function failure(code, message) {
|
|
13279
|
+
return new AiOperationError({ code, operation: "grok-generate", harness: "grok", message });
|
|
13280
|
+
}
|
|
13281
|
+
function openCodeCliName(executable) {
|
|
13282
|
+
return path.parse(executable).name.toLowerCase() === "opencode2" ? "opencode2" : "opencode";
|
|
13283
|
+
}
|
|
13284
|
+
function isOpenCodeV2Version(raw) {
|
|
13285
|
+
return /^(?:opencode2?\s+)?v?2\.\d+\.\d+(?:[-+][\w.-]+)?$/.test(stripAnsi(raw).trim());
|
|
13286
|
+
}
|
|
13287
|
+
function openCodeLoginCommand(cliName) {
|
|
13288
|
+
return cliName === "opencode2" ? "opencode2 auth login" : "opencode auth login";
|
|
13289
|
+
}
|
|
13290
|
+
function parseOpenCodeAuthList(raw, exitCode) {
|
|
13291
|
+
if (exitCode !== 0) return "unknown";
|
|
13292
|
+
try {
|
|
13293
|
+
const integrations = JSON.parse(stripAnsi(raw).trim());
|
|
13294
|
+
if (!Array.isArray(integrations) || integrations.some((item) => !item || typeof item !== "object" || !Array.isArray(item.connections))) return "unknown";
|
|
13295
|
+
return integrations.some((item) => item.connections.length > 0) ? "authenticated" : "unauthenticated";
|
|
13296
|
+
} catch {
|
|
15000
13297
|
}
|
|
15001
13298
|
return "unknown";
|
|
15002
13299
|
}
|
|
15003
13300
|
function parseOpenCodeModels(raw) {
|
|
15004
13301
|
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._:/-]
|
|
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) };
|
|
13302
|
+
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 }));
|
|
13303
|
+
return [DEFAULT_MODEL$1, ...models];
|
|
15012
13304
|
}
|
|
15013
13305
|
function parseOpenCodeV2ModelRef(value) {
|
|
15014
|
-
const
|
|
15015
|
-
|
|
15016
|
-
|
|
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 };
|
|
13306
|
+
const match = /^([^/#\s]+)\/([^#\s]+)(?:#([^#\s]+))?$/.exec(value);
|
|
13307
|
+
if (!match?.[1] || !match[2]) throw invalidModel();
|
|
13308
|
+
return { providerID: match[1], id: match[2], ...match[3] ? { variant: match[3] } : {} };
|
|
15020
13309
|
}
|
|
15021
13310
|
function parseOpenCodeV2GenerateText(payload) {
|
|
15022
13311
|
if (!payload || typeof payload !== "object") throw invalidOutput$1();
|
|
@@ -15046,13 +13335,14 @@ async function startOpenCodeV2Server(options) {
|
|
|
15046
13335
|
const timeoutMs = options.timeoutMs;
|
|
15047
13336
|
const password = randomBytes(24).toString("base64url");
|
|
15048
13337
|
const port = await freePort();
|
|
15049
|
-
const environment = Object.fromEntries(
|
|
13338
|
+
const environment = cleanEnvironment(Object.fromEntries(
|
|
15050
13339
|
Object.entries({
|
|
15051
13340
|
...process.env,
|
|
13341
|
+
...options.env,
|
|
15052
13342
|
OPENCODE_SERVER_USERNAME: SERVER_USERNAME,
|
|
15053
13343
|
OPENCODE_SERVER_PASSWORD: password
|
|
15054
13344
|
}).filter((entry) => entry[1] !== void 0)
|
|
15055
|
-
);
|
|
13345
|
+
));
|
|
15056
13346
|
const resolved = resolveProcessCommand(options.executable, options.cwd ?? process.cwd(), environment);
|
|
15057
13347
|
if (!resolved.found) {
|
|
15058
13348
|
throw new AiOperationError({ code: "AI_PROCESS_FAILED", operation: "opencode-server", harness: "opencode", message: "Could not start the local OpenCode server.", retryable: true });
|
|
@@ -15070,12 +13360,12 @@ async function startOpenCodeV2Server(options) {
|
|
|
15070
13360
|
});
|
|
15071
13361
|
void subprocess.catch(() => void 0);
|
|
15072
13362
|
let settled = false;
|
|
15073
|
-
const
|
|
13363
|
+
const stop = () => {
|
|
15074
13364
|
if (settled) return;
|
|
15075
13365
|
settled = true;
|
|
15076
13366
|
stopProcess(subprocess);
|
|
15077
13367
|
};
|
|
15078
|
-
const unbind = bindAbort(options.signal,
|
|
13368
|
+
const unbind = bindAbort(options.signal, stop);
|
|
15079
13369
|
try {
|
|
15080
13370
|
const url = await waitForListenUrl(subprocess, timeoutMs, options.signal);
|
|
15081
13371
|
return {
|
|
@@ -15083,12 +13373,12 @@ async function startOpenCodeV2Server(options) {
|
|
|
15083
13373
|
password,
|
|
15084
13374
|
close() {
|
|
15085
13375
|
unbind();
|
|
15086
|
-
|
|
13376
|
+
stop();
|
|
15087
13377
|
}
|
|
15088
13378
|
};
|
|
15089
13379
|
} catch (error) {
|
|
15090
13380
|
unbind();
|
|
15091
|
-
|
|
13381
|
+
stop();
|
|
15092
13382
|
if (options.signal?.aborted) {
|
|
15093
13383
|
throw new AiOperationError({ code: "AI_CANCELLED", operation: "opencode-server", harness: "opencode", message: "Generation canceled." });
|
|
15094
13384
|
}
|
|
@@ -15101,8 +13391,9 @@ async function generateOpenCodeV2Text(server, input) {
|
|
|
15101
13391
|
const created = await v2Request(server, "/api/session", {
|
|
15102
13392
|
method: "POST",
|
|
15103
13393
|
body: {
|
|
15104
|
-
title: "OpenTig
|
|
13394
|
+
title: "OpenTig text generation",
|
|
15105
13395
|
location: { directory: input.cwd },
|
|
13396
|
+
permissions: [{ action: "*", resource: "*", effect: "deny" }],
|
|
15106
13397
|
...model ? { model } : {}
|
|
15107
13398
|
},
|
|
15108
13399
|
signal
|
|
@@ -15155,7 +13446,7 @@ function throwIfV2Failed(status, payload, signal) {
|
|
|
15155
13446
|
if (status === 401 || /not logged|login required|unauth|authentication|sign in/.test(raw)) {
|
|
15156
13447
|
throw new AiOperationError({ code: "AI_AUTH_REQUIRED", operation: "opencode-generate", harness: "opencode", message: "Sign in to OpenCode to generate the message." });
|
|
15157
13448
|
}
|
|
15158
|
-
if (/rate.?limit|quota|usage limit|too many requests|credit/.test(raw)) {
|
|
13449
|
+
if (status === 429 || /rate.?limit|quota|usage limit|too many requests|credit/.test(raw)) {
|
|
15159
13450
|
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
13451
|
}
|
|
15161
13452
|
if (/model.*(not found|unavailable|invalid|access)|unknown model|no model specified/.test(raw)) {
|
|
@@ -15238,7 +13529,7 @@ function freePort() {
|
|
|
15238
13529
|
server.on("error", reject);
|
|
15239
13530
|
});
|
|
15240
13531
|
}
|
|
15241
|
-
const
|
|
13532
|
+
const UNSUPPORTED_MESSAGE = "OpenCode 2.x is required. Upgrade the installed CLI; OpenCode 1 and legacy beta builds are not supported.";
|
|
15242
13533
|
class OpenCodeProvider {
|
|
15243
13534
|
constructor(resolver, runner) {
|
|
15244
13535
|
this.resolver = resolver;
|
|
@@ -15250,40 +13541,41 @@ class OpenCodeProvider {
|
|
|
15250
13541
|
servers = /* @__PURE__ */ new Set();
|
|
15251
13542
|
async status(forceRefresh = false) {
|
|
15252
13543
|
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15253
|
-
const
|
|
15254
|
-
|
|
15255
|
-
|
|
15256
|
-
const
|
|
15257
|
-
const
|
|
15258
|
-
|
|
15259
|
-
|
|
15260
|
-
this.runner
|
|
13544
|
+
const detected = await this.detect(forceRefresh);
|
|
13545
|
+
const failure2 = detectionFailure(detected, { id: this.id, label: "OpenCode", models: [DEFAULT_MODEL$1], checkedAt }, UNSUPPORTED_MESSAGE);
|
|
13546
|
+
if (failure2) return failure2;
|
|
13547
|
+
const executable = requireCandidate(detected, this.id);
|
|
13548
|
+
const version2 = detected.version ?? "";
|
|
13549
|
+
const cliName = openCodeCliName(executable.executable);
|
|
13550
|
+
const [auth, catalog] = await Promise.all([
|
|
13551
|
+
runCandidate(this.runner, executable, ["auth", "list", "--format", "json", "--standalone"]),
|
|
13552
|
+
runCandidate(this.runner, executable, ["models", "--standalone"], { timeoutMs: 3e4 })
|
|
15261
13553
|
]);
|
|
15262
|
-
const models = catalog.exitCode === 0 ? parseOpenCodeModels(catalog.stdout) : [DEFAULT_MODEL];
|
|
15263
|
-
let authStatus = parseOpenCodeAuthList(
|
|
15264
|
-
${auth.stderr}`, auth.exitCode);
|
|
13554
|
+
const models = catalog.exitCode === 0 ? parseOpenCodeModels(catalog.stdout) : [DEFAULT_MODEL$1];
|
|
13555
|
+
let authStatus = parseOpenCodeAuthList(auth.stdout, auth.exitCode);
|
|
15265
13556
|
if (authStatus === "unauthenticated" && models.length > 1) authStatus = "unknown";
|
|
15266
13557
|
const confirmed = authStatus === "authenticated";
|
|
15267
13558
|
return {
|
|
15268
13559
|
id: this.id,
|
|
15269
13560
|
label: "OpenCode",
|
|
15270
13561
|
availability: models.length > 1 ? confirmed ? "ready" : "warning" : authStatus === "unauthenticated" ? "error" : "warning",
|
|
13562
|
+
...detectionFields(detected),
|
|
15271
13563
|
installed: true,
|
|
15272
13564
|
authStatus,
|
|
15273
13565
|
cliName,
|
|
15274
|
-
version: version2
|
|
13566
|
+
version: version2,
|
|
15275
13567
|
models,
|
|
15276
13568
|
checkedAt,
|
|
15277
13569
|
...authStatus === "unauthenticated" ? { message: `Run ${openCodeLoginCommand(cliName)}.` } : !confirmed ? { message: "Could not confirm authentication for the selected provider." } : {}
|
|
15278
13570
|
};
|
|
15279
13571
|
}
|
|
15280
13572
|
async generate(input) {
|
|
15281
|
-
const
|
|
15282
|
-
|
|
13573
|
+
const detected = await this.detect(false, input.signal);
|
|
13574
|
+
const executable = requireCandidate(detected, this.id);
|
|
15283
13575
|
const timeoutSignal = AbortSignal.timeout(AI_PROVIDER_TIMEOUT_MS);
|
|
15284
13576
|
const boundedInput = { ...input, signal: AbortSignal.any([input.signal, timeoutSignal]) };
|
|
15285
13577
|
try {
|
|
15286
|
-
return await
|
|
13578
|
+
return await this.generateV2(executable, boundedInput);
|
|
15287
13579
|
} catch (error) {
|
|
15288
13580
|
if (timeoutSignal.aborted && !input.signal.aborted) {
|
|
15289
13581
|
throw new AiOperationError({ code: "AI_TIMEOUT", operation: "opencode-generate", harness: this.id, message: "Generation took too long.", retryable: true });
|
|
@@ -15292,13 +13584,16 @@ ${auth.stderr}`, auth.exitCode);
|
|
|
15292
13584
|
}
|
|
15293
13585
|
}
|
|
15294
13586
|
async generateV2(executable, input) {
|
|
15295
|
-
const server = await startOpenCodeV2Server({ executable, cwd: input.repositoryPath, timeoutMs: 15e3, signal: input.signal }).catch((error) => {
|
|
13587
|
+
const server = await startOpenCodeV2Server({ executable: executable.executable, env: executable.env, cwd: input.repositoryPath, timeoutMs: 15e3, signal: input.signal }).catch((error) => {
|
|
15296
13588
|
if (error instanceof AiOperationError) throw error;
|
|
15297
13589
|
throw new AiOperationError({ code: "AI_PROCESS_FAILED", operation: "opencode-server", harness: this.id, message: "Could not start the local OpenCode server.", retryable: true });
|
|
15298
13590
|
});
|
|
15299
13591
|
this.servers.add(server);
|
|
15300
13592
|
try {
|
|
15301
|
-
const text2 = await generateOpenCodeV2Text(server, { prompt:
|
|
13593
|
+
const text2 = await generateOpenCodeV2Text(server, { prompt: `Reply with a single JSON object satisfying this JSON Schema:
|
|
13594
|
+
${JSON.stringify(input.schema)}
|
|
13595
|
+
|
|
13596
|
+
${input.prompt}`, model: input.model, cwd: input.repositoryPath, signal: input.signal });
|
|
15302
13597
|
return { output: parseJsonPayload(text2), usage: { ...EMPTY_AI_USAGE } };
|
|
15303
13598
|
} catch (error) {
|
|
15304
13599
|
if (input.signal.aborted) throw new AiOperationError({ code: "AI_CANCELLED", operation: "opencode-generate", harness: this.id, message: "Generation canceled." });
|
|
@@ -15311,53 +13606,8 @@ ${auth.stderr}`, auth.exitCode);
|
|
|
15311
13606
|
this.servers.delete(server);
|
|
15312
13607
|
}
|
|
15313
13608
|
}
|
|
15314
|
-
async
|
|
15315
|
-
|
|
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);
|
|
15360
|
-
}
|
|
13609
|
+
async detect(forceRefresh = false, signal) {
|
|
13610
|
+
return selectCli(this.resolver, this.runner, this.id, { forceRefresh, compatible: isOpenCodeV2Version, runOptions: signal ? { signal } : {} });
|
|
15361
13611
|
}
|
|
15362
13612
|
close() {
|
|
15363
13613
|
for (const server of this.servers) server.close();
|
|
@@ -15646,7 +13896,7 @@ class FileService {
|
|
|
15646
13896
|
// UI pulls its children through here instead of paying for them at startup.
|
|
15647
13897
|
async listDirectory(repositoryId, relativePath) {
|
|
15648
13898
|
const repository = this.repositories.get(repositoryId);
|
|
15649
|
-
const directory = this.repositories.resolvePath(repositoryId, relativePath);
|
|
13899
|
+
const directory = relativePath === "" ? repository.path : this.repositories.resolvePath(repositoryId, relativePath);
|
|
15650
13900
|
const parent = normalizeGitPath(relativePath).replace(/\/+$/, "");
|
|
15651
13901
|
let dirents;
|
|
15652
13902
|
try {
|
|
@@ -15656,13 +13906,12 @@ class FileService {
|
|
|
15656
13906
|
if (code === "ENOENT" || code === "ENOTDIR") return [];
|
|
15657
13907
|
throw error;
|
|
15658
13908
|
}
|
|
15659
|
-
const ignored = (await this.findIgnoredDirectories(repository.path, [parent])).has(parent);
|
|
15660
13909
|
const entries = [];
|
|
15661
13910
|
for (const dirent of dirents) {
|
|
15662
13911
|
if (dirent.name === ".git") continue;
|
|
15663
13912
|
const entryPath = parent ? `${parent}/${dirent.name}` : dirent.name;
|
|
15664
13913
|
if (dirent.isDirectory() && !dirent.isSymbolicLink()) {
|
|
15665
|
-
entries.push({ path: entryPath, name: dirent.name, type: "directory",
|
|
13914
|
+
entries.push({ path: entryPath, name: dirent.name, type: "directory", children: [] });
|
|
15666
13915
|
continue;
|
|
15667
13916
|
}
|
|
15668
13917
|
if (!dirent.isFile() && !dirent.isSymbolicLink()) continue;
|
|
@@ -15673,15 +13922,25 @@ class FileService {
|
|
|
15673
13922
|
name: dirent.name,
|
|
15674
13923
|
type: "file",
|
|
15675
13924
|
size: metadata.size,
|
|
15676
|
-
mtimeMs: metadata.mtimeMs
|
|
15677
|
-
...ignored ? { ignored: true } : {}
|
|
13925
|
+
mtimeMs: metadata.mtimeMs
|
|
15678
13926
|
});
|
|
15679
13927
|
} catch (error) {
|
|
15680
13928
|
const code = error.code;
|
|
15681
13929
|
if (code !== "ENOENT" && code !== "ENOTDIR") throw error;
|
|
15682
13930
|
}
|
|
15683
13931
|
}
|
|
15684
|
-
|
|
13932
|
+
const ignoredChildren = await this.findIgnoredDirectories(repository.path, entries.map((entry) => entry.path));
|
|
13933
|
+
const ignoredFolders = entries.filter((entry) => entry.type === "directory" && ignoredChildren.has(entry.path));
|
|
13934
|
+
if (ignoredFolders.length > 0) {
|
|
13935
|
+
const tracked = await this.git.run(repository.path, ["ls-files", "-z", "--", ...ignoredFolders.map((entry) => entry.path)], {
|
|
13936
|
+
operation: "list-tracked-folder-children",
|
|
13937
|
+
readOnly: true,
|
|
13938
|
+
maxOutputBytes: 64 * 1024 * 1024
|
|
13939
|
+
});
|
|
13940
|
+
const ancestors = directoryAncestors(tracked.stdout.toString("utf8").split("\0").filter(Boolean).map(normalizeGitPath));
|
|
13941
|
+
for (const folder of ignoredFolders) if (ancestors.has(folder.path)) ignoredChildren.delete(folder.path);
|
|
13942
|
+
}
|
|
13943
|
+
return entries.map((entry) => ignoredChildren.has(entry.path) ? { ...entry, ignored: true } : entry).sort((a2, b) => a2.type === b.type ? a2.name.localeCompare(b.name) : a2.type === "directory" ? -1 : 1);
|
|
15685
13944
|
}
|
|
15686
13945
|
async findIgnoredDirectories(repositoryPath, directories) {
|
|
15687
13946
|
const ignored = /* @__PURE__ */ new Set();
|
|
@@ -18709,6 +16968,12 @@ class GitHubService {
|
|
|
18709
16968
|
const operation = "gh-pr-for-branch";
|
|
18710
16969
|
const { repository, nameWithOwner } = await this.requireGitHub(repositoryId, operation);
|
|
18711
16970
|
const branch = validateRef(branchName, operation);
|
|
16971
|
+
const openResult = await this.runGh(
|
|
16972
|
+
["pr", "list", "-R", nameWithOwner, "--head", branch, "--state", "open", "--json", PR_SUMMARY_FIELDS, "--limit", "10"],
|
|
16973
|
+
{ cwd: repository.path, operation, timeoutMs: NETWORK_TIMEOUT_MS, maxOutputBytes: 1024 * 1024 }
|
|
16974
|
+
);
|
|
16975
|
+
const openPull = sortPullRequestsNewestFirst(parsePullRequestList(openResult.stdout)).find((pull) => pull.state === "OPEN");
|
|
16976
|
+
if (openPull) return openPull;
|
|
18712
16977
|
const result = await this.runGh(
|
|
18713
16978
|
["pr", "list", "-R", nameWithOwner, "--head", branch, "--state", "all", "--json", PR_SUMMARY_FIELDS, "--limit", "10"],
|
|
18714
16979
|
{ cwd: repository.path, operation, timeoutMs: NETWORK_TIMEOUT_MS, maxOutputBytes: 1024 * 1024 }
|
|
@@ -18821,12 +17086,13 @@ class GitHubService {
|
|
|
18821
17086
|
}
|
|
18822
17087
|
async checkStatus(forceRefresh) {
|
|
18823
17088
|
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
18824
|
-
const
|
|
17089
|
+
const detected = await selectCli(this.resolver, this.runner, "gh", { forceRefresh, runOptions: { cwd: os.tmpdir(), env: { ...GH_ENV } } });
|
|
17090
|
+
const executable = detected.candidate;
|
|
18825
17091
|
if (!executable) {
|
|
18826
17092
|
return { installed: false, availability: "error", authStatus: "unknown", message: "Install GitHub CLI (cli.github.com) to work with pull requests.", checkedAt };
|
|
18827
17093
|
}
|
|
18828
|
-
|
|
18829
|
-
const versionLabel =
|
|
17094
|
+
if (detected.state !== "available") return { installed: true, availability: "error", authStatus: "unknown", message: "GitHub CLI was found but could not run. Check its installation and dependencies.", checkedAt };
|
|
17095
|
+
const versionLabel = detected.version ?? "";
|
|
18830
17096
|
const auth = await this.run(executable, ["auth", "status", "--hostname", "github.com", "--active"], { cwd: os.tmpdir(), operation: "gh-auth-status" });
|
|
18831
17097
|
if (auth.exitCode !== 0) {
|
|
18832
17098
|
return { installed: true, availability: "error", authStatus: "unauthenticated", version: versionLabel, message: "Run gh auth login.", checkedAt };
|
|
@@ -18845,7 +17111,8 @@ class GitHubService {
|
|
|
18845
17111
|
return { repository, nameWithOwner: info.nameWithOwner };
|
|
18846
17112
|
}
|
|
18847
17113
|
async runGh(args, options) {
|
|
18848
|
-
const
|
|
17114
|
+
const detected = await selectCli(this.resolver, this.runner, "gh", { runOptions: { cwd: options.cwd, env: { ...GH_ENV } } });
|
|
17115
|
+
const executable = detected.state === "available" ? detected.candidate : void 0;
|
|
18849
17116
|
if (!executable) throw new GhOperationError({ code: "GH_CLI_NOT_FOUND", operation: options.operation, message: "GitHub CLI is not installed." });
|
|
18850
17117
|
const result = await this.run(executable, args, options);
|
|
18851
17118
|
if (result.exitCode !== 0) throw classifyFailure(result, options.operation);
|
|
@@ -18853,9 +17120,9 @@ class GitHubService {
|
|
|
18853
17120
|
}
|
|
18854
17121
|
async run(executable, args, options) {
|
|
18855
17122
|
try {
|
|
18856
|
-
return await this.runner.run(executable, args, {
|
|
17123
|
+
return await this.runner.run(executable.executable, args, {
|
|
18857
17124
|
cwd: options.cwd,
|
|
18858
|
-
env: { ...GH_ENV },
|
|
17125
|
+
env: { ...executable.env, ...GH_ENV },
|
|
18859
17126
|
...options.timeoutMs !== void 0 ? { timeoutMs: options.timeoutMs } : {},
|
|
18860
17127
|
...options.maxOutputBytes !== void 0 ? { maxOutputBytes: options.maxOutputBytes } : {},
|
|
18861
17128
|
...options.stdin !== void 0 ? { stdin: options.stdin } : {}
|
|
@@ -19319,7 +17586,8 @@ const defaults = {
|
|
|
19319
17586
|
uiFont: "plus-jakarta-sans",
|
|
19320
17587
|
monoFont: "jetbrains-mono",
|
|
19321
17588
|
commitMessageHarness: "codex",
|
|
19322
|
-
commitMessageModels: { codex: "default", claude: "default", opencode: "default" },
|
|
17589
|
+
commitMessageModels: { codex: "default", claude: "default", opencode: "default", grok: "default" },
|
|
17590
|
+
aiExecutablePaths: {},
|
|
19323
17591
|
shortcutOverrides: {},
|
|
19324
17592
|
doubleControlShortcutEnabled: true,
|
|
19325
17593
|
remoteFetchIntervalSeconds: DEFAULT_REMOTE_FETCH_INTERVAL_SECONDS
|
|
@@ -19399,7 +17667,7 @@ class SettingsStore {
|
|
|
19399
17667
|
return this.data.activeRepositoryId;
|
|
19400
17668
|
}
|
|
19401
17669
|
get preferences() {
|
|
19402
|
-
return { ...this.data.preferences, commitMessageModels: { ...this.data.preferences.commitMessageModels }, shortcutOverrides: { ...this.data.preferences.shortcutOverrides } };
|
|
17670
|
+
return { ...this.data.preferences, aiExecutablePaths: { ...this.data.preferences.aiExecutablePaths }, commitMessageModels: { ...this.data.preferences.commitMessageModels }, shortcutOverrides: { ...this.data.preferences.shortcutOverrides } };
|
|
19403
17671
|
}
|
|
19404
17672
|
get windowBounds() {
|
|
19405
17673
|
return { ...this.data.windowBounds };
|
|
@@ -19528,6 +17796,8 @@ class SettingsStore {
|
|
|
19528
17796
|
next.monoFont = isMonoFont(next.monoFont) ? next.monoFont : "jetbrains-mono";
|
|
19529
17797
|
next.commitMessageHarness = isHarness(next.commitMessageHarness) ? next.commitMessageHarness : "codex";
|
|
19530
17798
|
next.commitMessageModels = modelPreferences(next.commitMessageModels);
|
|
17799
|
+
next.aiExecutablePaths = executablePaths(next.aiExecutablePaths, true);
|
|
17800
|
+
delete next.aiShellEnvironment;
|
|
19531
17801
|
next.shortcutOverrides = sanitizeShortcutOverrides(next.shortcutOverrides);
|
|
19532
17802
|
next.doubleControlShortcutEnabled = typeof next.doubleControlShortcutEnabled === "boolean" ? next.doubleControlShortcutEnabled : this.defaultDoubleControlShortcutEnabled;
|
|
19533
17803
|
next.remoteFetchIntervalSeconds = normalizeRemoteFetchIntervalSeconds(next.remoteFetchIntervalSeconds);
|
|
@@ -19656,6 +17926,7 @@ function validate(value, defaultDoubleControlShortcutEnabled) {
|
|
|
19656
17926
|
monoFont: isMonoFont(parsedPreferences.data.monoFont) ? parsedPreferences.data.monoFont : "jetbrains-mono",
|
|
19657
17927
|
commitMessageHarness: isHarness(parsedPreferences.data.commitMessageHarness) ? parsedPreferences.data.commitMessageHarness : "codex",
|
|
19658
17928
|
commitMessageModels: modelPreferences(parsedPreferences.data.commitMessageModels),
|
|
17929
|
+
aiExecutablePaths: executablePaths(parsedPreferences.data.aiExecutablePaths),
|
|
19659
17930
|
shortcutOverrides: sanitizeShortcutOverrides(parsedPreferences.data.shortcutOverrides),
|
|
19660
17931
|
doubleControlShortcutEnabled: typeof parsedPreferences.data.doubleControlShortcutEnabled === "boolean" ? parsedPreferences.data.doubleControlShortcutEnabled : defaultDoubleControlShortcutEnabled,
|
|
19661
17932
|
remoteFetchIntervalSeconds: normalizeRemoteFetchIntervalSeconds(
|
|
@@ -19726,7 +17997,7 @@ function projectError(message) {
|
|
|
19726
17997
|
return new GitOperationError({ code: "INVALID_ARGUMENT", operation: "repository-projects", message });
|
|
19727
17998
|
}
|
|
19728
17999
|
function isHarness(value) {
|
|
19729
|
-
return value === "codex" || value === "claude" || value === "opencode";
|
|
18000
|
+
return value === "codex" || value === "claude" || value === "opencode" || value === "grok";
|
|
19730
18001
|
}
|
|
19731
18002
|
function normalizeUiFont(value) {
|
|
19732
18003
|
if (value === "cabinet-grotesk" || value === "satoshi") return "plus-jakarta-sans";
|
|
@@ -19741,9 +18012,9 @@ function normalizeSidebarWidth(value) {
|
|
|
19741
18012
|
return Math.max(300, Math.min(680, width));
|
|
19742
18013
|
}
|
|
19743
18014
|
function modelPreferences(value) {
|
|
19744
|
-
const result = { codex: "default", claude: "default", opencode: "default" };
|
|
18015
|
+
const result = { codex: "default", claude: "default", opencode: "default", grok: "default" };
|
|
19745
18016
|
if (!value || typeof value !== "object") return result;
|
|
19746
|
-
for (const harness of ["codex", "claude", "opencode"]) {
|
|
18017
|
+
for (const harness of ["codex", "claude", "opencode", "grok"]) {
|
|
19747
18018
|
const model = value[harness];
|
|
19748
18019
|
if (typeof model === "string" && model.length > 0 && model.length <= 200 && !hasControlCharacters$1(model)) result[harness] = model;
|
|
19749
18020
|
}
|
|
@@ -19763,6 +18034,31 @@ function normalizeRecent(item) {
|
|
|
19763
18034
|
repositoryName: typeof item.repositoryName === "string" && item.repositoryName ? item.repositoryName : path.basename(path.dirname(commonDir))
|
|
19764
18035
|
};
|
|
19765
18036
|
}
|
|
18037
|
+
function executablePaths(value, strict = false, platform2 = process.platform, home = os.homedir()) {
|
|
18038
|
+
const result = {};
|
|
18039
|
+
const invalid2 = () => {
|
|
18040
|
+
if (strict) throw projectError("CLI executable paths must be absolute paths on the backend host, without arguments or control characters.");
|
|
18041
|
+
};
|
|
18042
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
18043
|
+
invalid2();
|
|
18044
|
+
return result;
|
|
18045
|
+
}
|
|
18046
|
+
const p = platform2 === "win32" ? path.win32 : path.posix;
|
|
18047
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
18048
|
+
if (!isHarness(key) || typeof raw !== "string") {
|
|
18049
|
+
invalid2();
|
|
18050
|
+
continue;
|
|
18051
|
+
}
|
|
18052
|
+
if (!raw.trim()) continue;
|
|
18053
|
+
const expanded = raw.startsWith("~/") ? p.join(home, raw.slice(2)) : raw;
|
|
18054
|
+
if (raw.length > 4096 || hasControlCharacters$1(raw) || !p.isAbsolute(expanded) || platform2 === "win32" && !/^(?:[a-z]:[\\/]|\\\\)/i.test(expanded)) {
|
|
18055
|
+
invalid2();
|
|
18056
|
+
continue;
|
|
18057
|
+
}
|
|
18058
|
+
result[key] = expanded;
|
|
18059
|
+
}
|
|
18060
|
+
return result;
|
|
18061
|
+
}
|
|
19766
18062
|
class SystemTrash {
|
|
19767
18063
|
available;
|
|
19768
18064
|
operation;
|
|
@@ -19881,16 +18177,17 @@ async function createOpenTigRuntime(options) {
|
|
|
19881
18177
|
const fileHistory = new FileOperationHistory(files, trash);
|
|
19882
18178
|
const search = new SearchService(git, repositories, files, fileHistory);
|
|
19883
18179
|
const operations = new GitRepositoryOperations(git, repositories, files);
|
|
19884
|
-
const cliResolver = new CliResolver();
|
|
18180
|
+
const cliResolver = new CliResolver(void 0, () => settings.preferences);
|
|
19885
18181
|
const cliRunner = new CliProcessRunner();
|
|
19886
18182
|
const providers = [
|
|
19887
18183
|
new CodexProvider(cliResolver, cliRunner),
|
|
19888
18184
|
new ClaudeProvider(cliResolver, cliRunner),
|
|
19889
|
-
new OpenCodeProvider(cliResolver, cliRunner)
|
|
18185
|
+
new OpenCodeProvider(cliResolver, cliRunner),
|
|
18186
|
+
new GrokProvider(cliResolver, cliRunner)
|
|
19890
18187
|
];
|
|
19891
18188
|
const aiLog = new AiLogStore(options.aiLogPath);
|
|
19892
18189
|
await aiLog.load();
|
|
19893
|
-
const ai = new CommitMessageService(operations, providers, aiLog);
|
|
18190
|
+
const ai = new CommitMessageService(operations, providers, aiLog, () => cliResolver.invalidate());
|
|
19894
18191
|
const prDrafts = new PullRequestDraftService(operations, providers, aiLog);
|
|
19895
18192
|
const github = new GitHubService(cliResolver, cliRunner, git, repositories);
|
|
19896
18193
|
let runtime = null;
|
|
@@ -20370,22 +18667,66 @@ function mimeTypeOf(relativePath, bytes) {
|
|
|
20370
18667
|
if (fromPath === "image/svg+xml") return fromPath;
|
|
20371
18668
|
return detectRasterImageMime(bytes) ?? fromPath;
|
|
20372
18669
|
}
|
|
20373
|
-
async function browseServerDirectories(requestedPath) {
|
|
20374
|
-
const
|
|
20375
|
-
const
|
|
20376
|
-
|
|
18670
|
+
async function browseServerDirectories(requestedPath, git = new GitProcess()) {
|
|
18671
|
+
const home = homedir();
|
|
18672
|
+
const input = requestedPath ?? home;
|
|
18673
|
+
const expanded = input === "~" ? home : /^~[/\\]/.test(input) ? join(home, input.slice(2)) : input;
|
|
18674
|
+
if (!isAbsolute(expanded)) throw new Error("Enter an absolute folder path.");
|
|
20377
18675
|
const path2 = resolve(expanded);
|
|
20378
|
-
|
|
18676
|
+
let entries;
|
|
18677
|
+
try {
|
|
18678
|
+
entries = await readdir(path2, { withFileTypes: true });
|
|
18679
|
+
} catch (error) {
|
|
18680
|
+
const code = error.code;
|
|
18681
|
+
if (code === "EACCES" || code === "EPERM") throw new Error("You do not have permission to browse this folder.", { cause: error });
|
|
18682
|
+
if (code === "ENOENT") throw new Error("That folder was not found. Check the path and try again.", { cause: error });
|
|
18683
|
+
if (code === "ENOTDIR") throw new Error("This path points to a file. Choose a folder instead.", { cause: error });
|
|
18684
|
+
throw new Error("Could not read this folder. Try another location.", { cause: error });
|
|
18685
|
+
}
|
|
20379
18686
|
const directories = [];
|
|
20380
|
-
|
|
20381
|
-
|
|
20382
|
-
|
|
20383
|
-
|
|
18687
|
+
let index = 0;
|
|
18688
|
+
await Promise.all(Array.from({ length: Math.min(6, entries.length) }, async () => {
|
|
18689
|
+
while (index < entries.length) {
|
|
18690
|
+
const entry = entries[index++];
|
|
18691
|
+
const entryPath = join(path2, entry.name);
|
|
18692
|
+
if (entry.isDirectory() || entry.isSymbolicLink() && await stat(entryPath).then((value) => value.isDirectory(), () => false)) {
|
|
18693
|
+
directories.push({ name: entry.name, path: entryPath, repository: await inspectRepository(entryPath, git) });
|
|
18694
|
+
}
|
|
20384
18695
|
}
|
|
20385
|
-
}
|
|
18696
|
+
}));
|
|
20386
18697
|
directories.sort((a2, b) => a2.name.localeCompare(b.name, void 0, { numeric: true, sensitivity: "base" }));
|
|
18698
|
+
const locations = [{ name: "Home", path: home, kind: "home" }];
|
|
18699
|
+
for (const [name, kind] of [["Documents", "documents"], ["Downloads", "downloads"]]) {
|
|
18700
|
+
const location = join(home, name);
|
|
18701
|
+
if (await stat(location).then((value) => value.isDirectory(), () => false)) locations.push({ name, path: location, kind });
|
|
18702
|
+
}
|
|
20387
18703
|
const parentPath = dirname(path2);
|
|
20388
|
-
return { path: path2, parentPath: parentPath === path2 ? null : parentPath, directories };
|
|
18704
|
+
return { path: path2, parentPath: parentPath === path2 ? null : parentPath, repository: await inspectRepository(path2, git), locations, directories };
|
|
18705
|
+
}
|
|
18706
|
+
async function inspectRepository(path2, git) {
|
|
18707
|
+
if (!await stat(join(path2, ".git")).then((value) => value.isDirectory() || value.isFile(), () => false)) return null;
|
|
18708
|
+
try {
|
|
18709
|
+
const result = await git.run(path2, ["rev-parse", "--is-inside-work-tree", "--absolute-git-dir"], {
|
|
18710
|
+
operation: "browse-repository",
|
|
18711
|
+
readOnly: true,
|
|
18712
|
+
timeoutMs: 2e3,
|
|
18713
|
+
maxOutputBytes: 32768
|
|
18714
|
+
});
|
|
18715
|
+
const [inside, gitDir] = result.stdout.toString("utf8").trim().split(/\r?\n/);
|
|
18716
|
+
if (inside !== "true" || !gitDir || !isAbsolute(gitDir)) return null;
|
|
18717
|
+
const headFile = await open(join(gitDir, "HEAD"), "r");
|
|
18718
|
+
let head;
|
|
18719
|
+
try {
|
|
18720
|
+
const buffer = Buffer.alloc(4096);
|
|
18721
|
+
const { bytesRead } = await headFile.read(buffer, 0, buffer.length, 0);
|
|
18722
|
+
head = buffer.subarray(0, bytesRead).toString("utf8").trim();
|
|
18723
|
+
} finally {
|
|
18724
|
+
await headFile.close();
|
|
18725
|
+
}
|
|
18726
|
+
return { branch: head.startsWith("ref: refs/heads/") ? head.slice("ref: refs/heads/".length) : null };
|
|
18727
|
+
} catch {
|
|
18728
|
+
return null;
|
|
18729
|
+
}
|
|
20389
18730
|
}
|
|
20390
18731
|
const requestRecordSchema = looseObject({});
|
|
20391
18732
|
function boundedStringSchema(maxLength, options = {}) {
|
|
@@ -20408,7 +18749,7 @@ const searchOptionsSchema = object({
|
|
|
20408
18749
|
includeIgnored: unknown().optional()
|
|
20409
18750
|
});
|
|
20410
18751
|
const openFileTabSchema = object({ path: unknown(), pinned: boolean() });
|
|
20411
|
-
const aiHarnessSchema = _enum(["codex", "claude", "opencode"]);
|
|
18752
|
+
const aiHarnessSchema = _enum(["codex", "claude", "opencode", "grok"]);
|
|
20412
18753
|
const pullRequestStateSchema = _enum(["OPEN", "CLOSED", "MERGED"]);
|
|
20413
18754
|
function stringArg(value, operation, maxLength = 32768) {
|
|
20414
18755
|
const parsed = boundedStringSchema(maxLength, { controls: false }).safeParse(value);
|
|
@@ -20729,6 +19070,7 @@ function registerServerCommands(registry2, services, host) {
|
|
|
20729
19070
|
});
|
|
20730
19071
|
handle(IPC.preferences, "preferences", async (partial2) => {
|
|
20731
19072
|
const preferences = await services.settings.setPreferences(partial2 ?? {});
|
|
19073
|
+
if (partial2 && typeof partial2 === "object" && "aiExecutablePaths" in partial2) services.ai.invalidateStatuses();
|
|
20732
19074
|
return preferences;
|
|
20733
19075
|
});
|
|
20734
19076
|
handle(IPC.filesTreeStateUpdate, "files-tree-state", (repositoryId, expandedPaths) => {
|
|
@@ -20748,7 +19090,8 @@ function registerServerCommands(registry2, services, host) {
|
|
|
20748
19090
|
context
|
|
20749
19091
|
));
|
|
20750
19092
|
handle(IPC.repositoryBrowseDirectories, "browse-directories", (path2) => browseServerDirectories(
|
|
20751
|
-
path2 === void 0 ? void 0 : stringArg(path2, "browse-directories", 32768)
|
|
19093
|
+
path2 === void 0 ? void 0 : stringArg(path2, "browse-directories", 32768),
|
|
19094
|
+
services.git
|
|
20752
19095
|
));
|
|
20753
19096
|
handleWithContext(IPC.repositoryOpenRecent, "open-recent", async (context, id) => {
|
|
20754
19097
|
const repositoryId = stringArg(id, "open-recent", 64);
|
|
@@ -20786,7 +19129,7 @@ function registerServerCommands(registry2, services, host) {
|
|
|
20786
19129
|
));
|
|
20787
19130
|
handle(IPC.repositoryDirectoryEntries, "directory-entries", (id, directoryPath) => services.files.listDirectory(
|
|
20788
19131
|
stringArg(id, "directory-entries", 64),
|
|
20789
|
-
stringArg(directoryPath, "directory-entries")
|
|
19132
|
+
directoryPath === "" ? "" : stringArg(directoryPath, "directory-entries")
|
|
20790
19133
|
));
|
|
20791
19134
|
handle(IPC.repositoryReadFile, "read-file", (id, filePath, allowLarge) => services.files.read(stringArg(id, "read-file", 64), stringArg(filePath, "read-file"), allowLarge === true));
|
|
20792
19135
|
handle(IPC.repositoryReadImage, "read-image", (id, filePath) => services.files.readImage(
|
|
@@ -22098,12 +20441,12 @@ class OpenTigWebSocketTransport {
|
|
|
22098
20441
|
upgradeHandler;
|
|
22099
20442
|
closePromise = null;
|
|
22100
20443
|
get connectedSessionCount() {
|
|
22101
|
-
return new Set([...this.clients.values()].map((
|
|
20444
|
+
return new Set([...this.clients.values()].map((client) => client.sessionId)).size;
|
|
22102
20445
|
}
|
|
22103
20446
|
connectionCount(sessionId) {
|
|
22104
20447
|
let count2 = 0;
|
|
22105
|
-
for (const
|
|
22106
|
-
if (
|
|
20448
|
+
for (const client of this.clients.values()) {
|
|
20449
|
+
if (client.sessionId === sessionId) count2 += 1;
|
|
22107
20450
|
}
|
|
22108
20451
|
return count2;
|
|
22109
20452
|
}
|
|
@@ -22149,7 +20492,7 @@ class OpenTigWebSocketTransport {
|
|
|
22149
20492
|
socket.on("close", () => {
|
|
22150
20493
|
for (const controller of state.requests.values()) controller.abort();
|
|
22151
20494
|
this.clients.delete(socket);
|
|
22152
|
-
if (![...this.clients.values()].some((
|
|
20495
|
+
if (![...this.clients.values()].some((client) => client.sessionId === sessionId)) {
|
|
22153
20496
|
this.options.registry.clearSession(sessionId);
|
|
22154
20497
|
}
|
|
22155
20498
|
});
|