cogpit 2.1.3 → 2.3.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.
Files changed (33) hide show
  1. package/dist/cli.js +1603 -773
  2. package/dist/web/assets/CommandPaletteHost-D-VvT_HL.js +1 -0
  3. package/dist/web/assets/ConfigBrowser-Cc2lrh85.js +1 -0
  4. package/dist/web/assets/{HighlightedEditor-qhEWgnBF.js → HighlightedEditor-DWNz1Jcz.js} +2 -2
  5. package/dist/web/assets/{KeyboardShortcutsDialog-B9nMtf5U.js → KeyboardShortcutsDialog-yOs1u5D6.js} +1 -1
  6. package/dist/web/assets/{MobileFileChanges-j9DCxvz6.js → MobileFileChanges-B1dtcdSZ.js} +1 -1
  7. package/dist/web/assets/PreviewPanel-BJwfunf9.js +1 -0
  8. package/dist/web/assets/ProjectFilesPanel-DppuIFEt.js +4 -0
  9. package/dist/web/assets/{ProjectSwitcherModal-o8NhzySH.js → ProjectSwitcherModal-DgsuH5CY.js} +1 -1
  10. package/dist/web/assets/{TerminalOutput-CcWkSv29.js → TerminalOutput-DlGDS0Wx.js} +1 -1
  11. package/dist/web/assets/ThemeSelectorModal-oI9Vm3EH.js +1 -0
  12. package/dist/web/assets/WorkflowsPanel-SKbsv_IK.js +1 -0
  13. package/dist/web/assets/WorktreePanel-CcSLupr7.js +1 -0
  14. package/dist/web/assets/{index-_0HhakEy.js → index-7FuVzOBC.js} +4 -4
  15. package/dist/web/assets/index-BVkjlOVU.js +1 -0
  16. package/dist/web/assets/index-Bw-DFQut.js +1 -0
  17. package/dist/web/assets/index-Du17HzQD.js +151 -0
  18. package/dist/web/assets/index-xdv0cIL2.css +1 -0
  19. package/dist/web/assets/{session-parser.worker-DycJL0jJ.js → session-parser.worker-RMitC4X_.js} +17 -17
  20. package/dist/web/assets/{vendor-ui-Bg9q4lA4.js → vendor-ui-CdA11Wfh.js} +162 -147
  21. package/dist/web/index.html +3 -3
  22. package/package.json +1 -1
  23. package/dist/web/assets/CommandPaletteHost-1UPdv9Nv.js +0 -1
  24. package/dist/web/assets/ConfigBrowser-B5lZsJDw.js +0 -1
  25. package/dist/web/assets/PreviewPanel-DZSVN3mt.js +0 -1
  26. package/dist/web/assets/ProjectFilesPanel-DSvO4CrB.js +0 -4
  27. package/dist/web/assets/ThemeSelectorModal-CnbSCgJj.js +0 -1
  28. package/dist/web/assets/WorkflowsPanel-CvBweQMf.js +0 -1
  29. package/dist/web/assets/WorktreePanel-DahbK2L0.js +0 -1
  30. package/dist/web/assets/index-7UiltNKa.js +0 -1
  31. package/dist/web/assets/index-BESnPMZk.js +0 -144
  32. package/dist/web/assets/index-Bif4Kdtn.css +0 -1
  33. package/dist/web/assets/index-DXTQExVH.js +0 -1
package/dist/cli.js CHANGED
@@ -73,7 +73,7 @@ var init_compression = __esm({
73
73
  import { StringDecoder } from "node:string_decoder";
74
74
  function readJsonBody(req, options = {}) {
75
75
  const maxBytes = options.maxBytes ?? DEFAULT_MAX_REQUEST_BODY_BYTES;
76
- return new Promise((resolve21, reject) => {
76
+ return new Promise((resolve22, reject) => {
77
77
  let body = "";
78
78
  let bytesRead = 0;
79
79
  let settled = false;
@@ -97,11 +97,11 @@ function readJsonBody(req, options = {}) {
97
97
  settled = true;
98
98
  body += decoder.end();
99
99
  if (!body.trim() && options.allowEmpty) {
100
- resolve21({});
100
+ resolve22({});
101
101
  return;
102
102
  }
103
103
  try {
104
- resolve21(JSON.parse(body));
104
+ resolve22(JSON.parse(body));
105
105
  } catch {
106
106
  reject(new HttpBodyError("Invalid JSON body", 400));
107
107
  }
@@ -486,8 +486,8 @@ async function mint(device, generation2) {
486
486
  if (prev?.generation === generation2 && prev.error && Date.now() - prev.at < MINT_COOLDOWN_MS) {
487
487
  throw prev.error;
488
488
  }
489
- const record2 = { at: Date.now(), generation: generation2 };
490
- lastAttempt.set(id, record2);
489
+ const record4 = { at: Date.now(), generation: generation2 };
490
+ lastAttempt.set(id, record4);
491
491
  const url = `${device.tls ? "https" : "http"}://${device.host}:${device.port}/api/auth/verify`;
492
492
  const credential = device.username ? `${device.username}:${device.password ?? ""}` : device.password ?? "";
493
493
  let res;
@@ -503,7 +503,7 @@ async function mint(device, generation2) {
503
503
  `Could not reach device "${device.name}" at ${device.host}:${device.port}`,
504
504
  { cause: err }
505
505
  );
506
- record2.error = error;
506
+ record4.error = error;
507
507
  if (generationIsCurrent(id, generation2)) {
508
508
  setDeviceRuntime(id, { lastProbe: Date.now() });
509
509
  }
@@ -511,7 +511,7 @@ async function mint(device, generation2) {
511
511
  }
512
512
  if (res.status === 401 || res.status === 403) {
513
513
  const error = new DeviceAuthError(id, `Device "${device.name}" rejected the password`, res.status);
514
- record2.error = error;
514
+ record4.error = error;
515
515
  if (generationIsCurrent(id, generation2)) {
516
516
  setDeviceRuntime(id, { authState: "bad-password", lastProbe: Date.now() });
517
517
  }
@@ -522,7 +522,7 @@ async function mint(device, generation2) {
522
522
  id,
523
523
  `Device "${device.name}" returned HTTP ${res.status} while minting a token`
524
524
  );
525
- record2.error = error;
525
+ record4.error = error;
526
526
  if (generationIsCurrent(id, generation2)) {
527
527
  setDeviceRuntime(id, { lastProbe: Date.now() });
528
528
  }
@@ -536,7 +536,7 @@ async function mint(device, generation2) {
536
536
  }
537
537
  if (!body || body.valid === false || typeof body.token !== "string" || !body.token) {
538
538
  const error = new DeviceAuthError(id, `Device "${device.name}" did not return a valid token`, res.status);
539
- record2.error = error;
539
+ record4.error = error;
540
540
  if (generationIsCurrent(id, generation2)) {
541
541
  setDeviceRuntime(id, { authState: "bad-password", lastProbe: Date.now() });
542
542
  }
@@ -779,6 +779,7 @@ var init_agent_descriptors = __esm({
779
779
  args: ["update"],
780
780
  matches: (path) => path.endsWith("/.local/bin/claude") || path.endsWith("/.local/bin/claude.exe") || path.includes("/.local/share/claude/")
781
781
  },
782
+ bundledBySdk: true,
782
783
  homeDirName: ".claude",
783
784
  homeEnvVar: null,
784
785
  installMarker: "projects",
@@ -915,6 +916,7 @@ var init_agent_descriptors = __esm({
915
916
  // Codex ships no self-updater; a hand-placed binary has to be replaced by
916
917
  // whatever put it there.
917
918
  selfUpdate: null,
919
+ bundledBySdk: false,
918
920
  homeDirName: ".codex",
919
921
  homeEnvVar: "CODEX_HOME",
920
922
  installMarker: "",
@@ -1025,6 +1027,7 @@ var init_agent_descriptors = __esm({
1025
1027
  // only do because the caller passes the realpath in as well.
1026
1028
  matches: (path) => path.endsWith("/.local/bin/copilot") || path === "/usr/local/bin/copilot"
1027
1029
  },
1030
+ bundledBySdk: false,
1028
1031
  homeDirName: ".copilot",
1029
1032
  homeEnvVar: "COPILOT_HOME",
1030
1033
  installMarker: "session-state",
@@ -1161,7 +1164,7 @@ function verifyPassword(password, stored) {
1161
1164
  async function verifyPasswordAsync(password, stored) {
1162
1165
  const scryptHash = parseScryptHash(stored);
1163
1166
  if (!scryptHash) return verifyPassword(password, stored);
1164
- const candidate = await new Promise((resolve21, reject) => {
1167
+ const candidate = await new Promise((resolve22, reject) => {
1165
1168
  scrypt(
1166
1169
  password,
1167
1170
  Buffer.from(scryptHash.salt, "hex"),
@@ -1172,7 +1175,7 @@ async function verifyPasswordAsync(password, stored) {
1172
1175
  p: SCRYPT_PARALLELISM,
1173
1176
  maxmem: SCRYPT_MAX_MEMORY
1174
1177
  },
1175
- (error, derivedKey) => error ? reject(error) : resolve21(derivedKey)
1178
+ (error, derivedKey) => error ? reject(error) : resolve22(derivedKey)
1176
1179
  );
1177
1180
  });
1178
1181
  return safeCompareBuffers(candidate, Buffer.from(scryptHash.hash, "hex"));
@@ -1236,6 +1239,9 @@ function hasExtension(binName, extensions) {
1236
1239
  function hasExecutableExtension(fileName, env = process.env) {
1237
1240
  return hasExtension(fileName, pathExtensions({ env }));
1238
1241
  }
1242
+ function isDirectlyLaunchable(fileName) {
1243
+ return DIRECT_EXTENSIONS.includes(win32.extname(fileName).toLowerCase());
1244
+ }
1239
1245
  function findExecutableOnPath(binName, options = {}) {
1240
1246
  const windows = isWindows(options);
1241
1247
  const path = windows ? win32 : posix;
@@ -1280,7 +1286,7 @@ function resolveAgentCommand(binName, args = [], options = {}) {
1280
1286
  if (!isWindows(options)) return { command: binName, args, spawnOptions: {} };
1281
1287
  const resolved = /[\\/]/.test(binName) ? binName : findExecutableOnPath(binName, options);
1282
1288
  if (!resolved) return { command: binName, args, spawnOptions: {} };
1283
- if (DIRECT_EXTENSIONS.includes(win32.extname(resolved).toLowerCase())) {
1289
+ if (isDirectlyLaunchable(resolved)) {
1284
1290
  return { command: resolved, args, spawnOptions: {} };
1285
1291
  }
1286
1292
  return throughCmdExe(resolved, args, options);
@@ -1297,6 +1303,38 @@ var init_binaryResolver = __esm({
1297
1303
  }
1298
1304
  });
1299
1305
 
1306
+ // ../../shared/contracts/agentExecutable.ts
1307
+ function isExecutableSource(value) {
1308
+ return EXECUTABLE_SOURCES.includes(value);
1309
+ }
1310
+ function parseExecutableChoice(value) {
1311
+ if (!value || typeof value !== "object") return void 0;
1312
+ const { source, path } = value;
1313
+ if (!isExecutableSource(source) || source === "auto") return void 0;
1314
+ if (source === "custom") {
1315
+ return typeof path === "string" && path.trim() ? { source, path: path.trim() } : void 0;
1316
+ }
1317
+ return { source };
1318
+ }
1319
+ var EXECUTABLE_SOURCES, DEFAULT_EXECUTABLE_CHOICE, DETECTED_EXECUTABLE_SOURCES;
1320
+ var init_agentExecutable = __esm({
1321
+ "../../shared/contracts/agentExecutable.ts"() {
1322
+ EXECUTABLE_SOURCES = [
1323
+ "auto",
1324
+ "path",
1325
+ "npm",
1326
+ "bundled",
1327
+ "custom"
1328
+ ];
1329
+ DEFAULT_EXECUTABLE_CHOICE = { source: "auto" };
1330
+ DETECTED_EXECUTABLE_SOURCES = [
1331
+ "path",
1332
+ "npm",
1333
+ "bundled"
1334
+ ];
1335
+ }
1336
+ });
1337
+
1300
1338
  // ../../server/config.ts
1301
1339
  import { readFile as readFile2, stat, readdir, chmod as chmod3 } from "node:fs/promises";
1302
1340
  import { join as join2, resolve } from "node:path";
@@ -1405,7 +1443,8 @@ async function loadConfig() {
1405
1443
  networkPassword,
1406
1444
  terminalApp: parsed.terminalApp || void 0,
1407
1445
  editorApp: parsed.editorApp || void 0,
1408
- useBuiltInEditor: !!parsed.useBuiltInEditor
1446
+ useBuiltInEditor: !!parsed.useBuiltInEditor,
1447
+ agentExecutable: parseExecutableChoice(parsed.agentExecutable)
1409
1448
  };
1410
1449
  return cachedConfig;
1411
1450
  }
@@ -1460,6 +1499,7 @@ var init_config = __esm({
1460
1499
  init_password_utils();
1461
1500
  init_atomicJsonFile();
1462
1501
  init_binaryResolver();
1502
+ init_agentExecutable();
1463
1503
  CONFIG_FILE_MODE = 384;
1464
1504
  __dirname = fileURLToPath(new URL(".", import.meta.url));
1465
1505
  PROJECT_ROOT = resolve(__dirname, "..");
@@ -3959,7 +3999,7 @@ async function createShare(input) {
3959
3999
  const passwordHash = hashPassword(passphrase);
3960
4000
  const share = await commitShareMutation((draft) => {
3961
4001
  const existing = draft.get(input.sessionId);
3962
- const record2 = {
4002
+ const record4 = {
3963
4003
  sessionId: input.sessionId,
3964
4004
  dirName: input.dirName,
3965
4005
  fileName: input.fileName,
@@ -3968,8 +4008,8 @@ async function createShare(input) {
3968
4008
  // No guest has ever used this passphrase; the UI renders 0 as "never".
3969
4009
  lastAccessAt: 0
3970
4010
  };
3971
- draft.set(record2.sessionId, record2);
3972
- return { changed: true, value: toPublicShare(record2) };
4011
+ draft.set(record4.sessionId, record4);
4012
+ return { changed: true, value: toPublicShare(record4) };
3973
4013
  });
3974
4014
  return { share, passphrase };
3975
4015
  }
@@ -4819,6 +4859,8 @@ var init_policy = __esm({
4819
4859
  "project-files": admin("/api/project-files"),
4820
4860
  "project-file": admin("/api/project-file"),
4821
4861
  "git-status": admin("/api/git-status"),
4862
+ "github-actions": admin("/api/github-actions"),
4863
+ "vercel-deployments": admin("/api/vercel-deployments"),
4822
4864
  "project-icon": admin("/api/project-icon"),
4823
4865
  "git-diff": admin("/api/git-diff"),
4824
4866
  mcp: admin("/api/mcp-servers"),
@@ -4847,6 +4889,10 @@ var init_policy = __esm({
4847
4889
  "provider-updates": [
4848
4890
  { prefix: "/api/provider-updates", methods: ["GET"], requires: "authed" },
4849
4891
  { prefix: "/api/provider-updates/run", requires: "admin" }
4892
+ ],
4893
+ // Reports which binary the server spawns; the choice itself is saved through /api/config.
4894
+ "agent-executable": [
4895
+ { prefix: "/api/agent-executable", methods: ["GET"], requires: "authed" }
4850
4896
  ]
4851
4897
  };
4852
4898
  ALL_RULES = Object.values(ROUTE_POLICIES).flat();
@@ -5619,6 +5665,274 @@ var init_subagentWatcher = __esm({
5619
5665
  }
5620
5666
  });
5621
5667
 
5668
+ // ../../shared/versions.ts
5669
+ function parseVersion(raw) {
5670
+ const match = raw.trim().replace(/^v/i, "").match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/);
5671
+ if (!match) return null;
5672
+ return {
5673
+ parts: [Number(match[1]), Number(match[2]), Number(match[3])],
5674
+ prerelease: match[4] ? match[4].split(".") : []
5675
+ };
5676
+ }
5677
+ function extractVersion(output) {
5678
+ const match = output.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/);
5679
+ return match ? match[0] : null;
5680
+ }
5681
+ function comparePrerelease(a, b) {
5682
+ if (a.length === 0 && b.length === 0) return 0;
5683
+ if (a.length === 0) return 1;
5684
+ if (b.length === 0) return -1;
5685
+ for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
5686
+ const left = a[i];
5687
+ const right = b[i];
5688
+ if (left === void 0) return -1;
5689
+ if (right === void 0) return 1;
5690
+ const leftNumeric = /^\d+$/.test(left);
5691
+ const rightNumeric = /^\d+$/.test(right);
5692
+ if (leftNumeric && rightNumeric) {
5693
+ if (Number(left) !== Number(right)) return Number(left) < Number(right) ? -1 : 1;
5694
+ continue;
5695
+ }
5696
+ if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1;
5697
+ if (left !== right) return left < right ? -1 : 1;
5698
+ }
5699
+ return 0;
5700
+ }
5701
+ function compareVersions(a, b) {
5702
+ const left = parseVersion(a);
5703
+ const right = parseVersion(b);
5704
+ if (!left || !right) return null;
5705
+ for (let i = 0; i < 3; i += 1) {
5706
+ if (left.parts[i] !== right.parts[i]) return left.parts[i] < right.parts[i] ? -1 : 1;
5707
+ }
5708
+ return comparePrerelease(left.prerelease, right.prerelease);
5709
+ }
5710
+ var init_versions = __esm({
5711
+ "../../shared/versions.ts"() {
5712
+ }
5713
+ });
5714
+
5715
+ // ../../server/lib/cliProcess.ts
5716
+ import { spawn } from "node:child_process";
5717
+ function runCli(executable, args, timeoutMs) {
5718
+ return new Promise((resolve22) => {
5719
+ const resolved = resolveAgentCommand(executable, [...args]);
5720
+ const child = spawn(resolved.command, resolved.args, {
5721
+ stdio: ["ignore", "pipe", "pipe"],
5722
+ ...resolved.spawnOptions
5723
+ });
5724
+ let stdout = "";
5725
+ let stderr = "";
5726
+ let timedOut = false;
5727
+ const timer = setTimeout(() => {
5728
+ timedOut = true;
5729
+ child.kill("SIGKILL");
5730
+ }, timeoutMs);
5731
+ const append = (buffer, chunk) => buffer.length >= CLI_OUTPUT_MAX_CHARS ? buffer : buffer + chunk.toString();
5732
+ child.stdout?.on("data", (chunk) => {
5733
+ stdout = append(stdout, chunk);
5734
+ });
5735
+ child.stderr?.on("data", (chunk) => {
5736
+ stderr = append(stderr, chunk);
5737
+ });
5738
+ child.on("error", () => {
5739
+ clearTimeout(timer);
5740
+ resolve22({ code: null, stdout, stderr, timedOut });
5741
+ });
5742
+ child.on("close", (code) => {
5743
+ clearTimeout(timer);
5744
+ resolve22({ code, stdout, stderr, timedOut });
5745
+ });
5746
+ });
5747
+ }
5748
+ async function probeCliVersion(command, versionArgs, timeoutMs = DEFAULT_PROBE_TIMEOUT_MS) {
5749
+ const probe = await runCli(command, versionArgs, timeoutMs);
5750
+ return extractVersion(`${probe.stdout}
5751
+ ${probe.stderr}`);
5752
+ }
5753
+ var DEFAULT_PROBE_TIMEOUT_MS, CLI_OUTPUT_MAX_CHARS;
5754
+ var init_cliProcess = __esm({
5755
+ "../../server/lib/cliProcess.ts"() {
5756
+ init_versions();
5757
+ init_binaryResolver();
5758
+ DEFAULT_PROBE_TIMEOUT_MS = 5e3;
5759
+ CLI_OUTPUT_MAX_CHARS = 1e4;
5760
+ }
5761
+ });
5762
+
5763
+ // ../../server/agents/claudeExecutable.ts
5764
+ import { execFileSync } from "node:child_process";
5765
+ import { readFileSync, statSync as statSync2 } from "node:fs";
5766
+ import { createRequire } from "node:module";
5767
+ import { posix as posix2, win32 as win322 } from "node:path";
5768
+ function realIsFile(path) {
5769
+ try {
5770
+ return statSync2(path).isFile();
5771
+ } catch {
5772
+ return false;
5773
+ }
5774
+ }
5775
+ function realReadFile(path) {
5776
+ try {
5777
+ return readFileSync(path, "utf-8");
5778
+ } catch {
5779
+ return void 0;
5780
+ }
5781
+ }
5782
+ function binField(manifest) {
5783
+ let bin;
5784
+ try {
5785
+ bin = JSON.parse(manifest).bin;
5786
+ } catch {
5787
+ return void 0;
5788
+ }
5789
+ if (typeof bin === "string") return bin;
5790
+ if (!bin || typeof bin !== "object") return void 0;
5791
+ const entry = bin[BIN_NAME];
5792
+ return typeof entry === "string" ? entry : void 0;
5793
+ }
5794
+ function findNpmClaude(options = {}) {
5795
+ const platform2 = options.platform ?? process.platform;
5796
+ const windows = platform2 === "win32";
5797
+ const path = windows ? win322 : posix2;
5798
+ const isFile = options.isFile ?? realIsFile;
5799
+ const readFile22 = options.readFile ?? realReadFile;
5800
+ const shim = findExecutableOnPath(BIN_NAME, { platform: platform2, env: options.env, isExecutable: isFile });
5801
+ if (!shim) return void 0;
5802
+ const shimDir = path.dirname(shim);
5803
+ const packageDirs = [
5804
+ path.join(shimDir, "node_modules", NPM_PACKAGE),
5805
+ path.join(shimDir, "..", "lib", "node_modules", NPM_PACKAGE)
5806
+ ];
5807
+ for (const packageDir of packageDirs) {
5808
+ const manifest = readFile22(path.join(packageDir, "package.json"));
5809
+ if (!manifest) continue;
5810
+ const relative11 = binField(manifest);
5811
+ if (!relative11) continue;
5812
+ const target = path.normalize(path.join(packageDir, relative11));
5813
+ if (windows && !isDirectlyLaunchable(target)) continue;
5814
+ if (isFile(target)) return target;
5815
+ }
5816
+ return void 0;
5817
+ }
5818
+ function findInstalledClaude() {
5819
+ return findExecutableOnPath(BIN_NAME, { directOnly: true });
5820
+ }
5821
+ function findBundledClaude(resolveModule2) {
5822
+ try {
5823
+ const platformPkg = `@anthropic-ai/claude-agent-sdk-${process.platform}-${process.arch}`;
5824
+ return resolveModule2(`${platformPkg}/package.json`).replace(/package\.json$/, CLI_BIN_NAME).replace(ASAR_SEGMENT, "$1app.asar.unpacked$2");
5825
+ } catch {
5826
+ return void 0;
5827
+ }
5828
+ }
5829
+ function discoverClaudeExecutables(resolveModule2, probes = {}) {
5830
+ return {
5831
+ installed: (probes.findOnPath ?? findInstalledClaude)(),
5832
+ npm: (probes.findNpm ?? findNpmClaude)(),
5833
+ bundled: findBundledClaude(resolveModule2)
5834
+ };
5835
+ }
5836
+ function readCliVersionSync(binPath) {
5837
+ try {
5838
+ const output = execFileSync(binPath, ["--version"], {
5839
+ encoding: "utf-8",
5840
+ timeout: 5e3,
5841
+ stdio: ["ignore", "pipe", "ignore"]
5842
+ });
5843
+ const match = output.match(/(\d+)\.(\d+)\.(\d+)/);
5844
+ return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : void 0;
5845
+ } catch {
5846
+ return void 0;
5847
+ }
5848
+ }
5849
+ function isAtLeast(version, floor) {
5850
+ for (let i = 0; i < 3; i += 1) {
5851
+ if (version[i] !== floor[i]) return version[i] > floor[i];
5852
+ }
5853
+ return true;
5854
+ }
5855
+ function chooseAutomatically(found, readVersion) {
5856
+ const bundled = found.bundled ? { source: "bundled", path: found.bundled } : void 0;
5857
+ if (!found.installed) return bundled;
5858
+ const installed = { source: "path", path: found.installed };
5859
+ const installedVersion = readVersion(found.installed);
5860
+ if (!installedVersion) return bundled ?? installed;
5861
+ const bundledVersion = bundled ? readVersion(bundled.path) : void 0;
5862
+ if (bundledVersion && !isAtLeast(installedVersion, bundledVersion)) return bundled;
5863
+ return installed;
5864
+ }
5865
+ function chooseClaudeExecutable(choice, found, readVersion) {
5866
+ switch (choice.source) {
5867
+ case "auto":
5868
+ return chooseAutomatically(found, readVersion);
5869
+ case "custom":
5870
+ return choice.path ? { source: "custom", path: choice.path } : void 0;
5871
+ case "path":
5872
+ return found.installed ? { source: "path", path: found.installed } : void 0;
5873
+ case "npm":
5874
+ return found.npm ? { source: "npm", path: found.npm } : void 0;
5875
+ case "bundled":
5876
+ return found.bundled ? { source: "bundled", path: found.bundled } : void 0;
5877
+ }
5878
+ }
5879
+ function configuredChoice() {
5880
+ return getConfig()?.agentExecutable ?? DEFAULT_EXECUTABLE_CHOICE;
5881
+ }
5882
+ function resolveClaudeExecutable() {
5883
+ const choice = configuredChoice();
5884
+ const key2 = JSON.stringify(choice);
5885
+ if (memo?.key !== key2) {
5886
+ memo = {
5887
+ key: key2,
5888
+ resolved: chooseClaudeExecutable(choice, discoverClaudeExecutables(resolveModule), readCliVersionSync)
5889
+ };
5890
+ }
5891
+ return memo.resolved;
5892
+ }
5893
+ function claudeCliPath() {
5894
+ return resolveClaudeExecutable()?.path;
5895
+ }
5896
+ async function describeClaudeExecutable() {
5897
+ const choice = configuredChoice();
5898
+ const found = discoverClaudeExecutables(resolveModule);
5899
+ const active = resolveClaudeExecutable();
5900
+ const pathBySource = {
5901
+ path: found.installed,
5902
+ npm: found.npm,
5903
+ bundled: found.bundled
5904
+ };
5905
+ const detected = DETECTED_EXECUTABLE_SOURCES.filter((source) => pathBySource[source] !== void 0).map((source) => ({ source, path: pathBySource[source] }));
5906
+ const paths = /* @__PURE__ */ new Set([...detected.map(({ path }) => path), ...active ? [active.path] : []]);
5907
+ const versions = new Map(
5908
+ await Promise.all(
5909
+ [...paths].map(async (path) => [path, await probeCliVersion(path, ["--version"])])
5910
+ )
5911
+ );
5912
+ return {
5913
+ choice,
5914
+ candidates: detected.map((candidate) => ({
5915
+ ...candidate,
5916
+ version: versions.get(candidate.path) ?? null
5917
+ })),
5918
+ active: active ? { ...active, version: versions.get(active.path) ?? null } : null
5919
+ };
5920
+ }
5921
+ var BIN_NAME, NPM_PACKAGE, CLI_BIN_NAME, ASAR_SEGMENT, resolveModule, memo;
5922
+ var init_claudeExecutable = __esm({
5923
+ "../../server/agents/claudeExecutable.ts"() {
5924
+ init_agentExecutable();
5925
+ init_config();
5926
+ init_binaryResolver();
5927
+ init_cliProcess();
5928
+ BIN_NAME = "claude";
5929
+ NPM_PACKAGE = "@anthropic-ai/claude-code";
5930
+ CLI_BIN_NAME = nativeBinaryName(BIN_NAME);
5931
+ ASAR_SEGMENT = /([\\/])app\.asar([\\/])/;
5932
+ resolveModule = (id) => createRequire(import.meta.url).resolve(id);
5933
+ }
5934
+ });
5935
+
5622
5936
  // ../../server/lib/streamBus.ts
5623
5937
  function getOrCreate(sessionId) {
5624
5938
  let state = sessions2.get(sessionId);
@@ -5887,58 +6201,6 @@ var init_streamBus = __esm({
5887
6201
 
5888
6202
  // ../../server/sdk-session.ts
5889
6203
  import { query } from "@anthropic-ai/claude-agent-sdk";
5890
- import { execFileSync } from "node:child_process";
5891
- import { createRequire } from "node:module";
5892
- function findClaudeOnPath() {
5893
- return findExecutableOnPath("claude", { directOnly: true });
5894
- }
5895
- function readCliVersion(binPath) {
5896
- try {
5897
- const output = execFileSync(binPath, ["--version"], {
5898
- encoding: "utf-8",
5899
- timeout: 5e3,
5900
- stdio: ["ignore", "pipe", "ignore"]
5901
- });
5902
- const match = output.match(/(\d+)\.(\d+)\.(\d+)/);
5903
- return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : void 0;
5904
- } catch {
5905
- return void 0;
5906
- }
5907
- }
5908
- function isAtLeast(version, floor) {
5909
- for (let i = 0; i < 3; i += 1) {
5910
- if (version[i] !== floor[i]) return version[i] > floor[i];
5911
- }
5912
- return true;
5913
- }
5914
- function resolveClaudeCliPath(resolveModule, probes = {}) {
5915
- const findOnPath = probes.findOnPath ?? findClaudeOnPath;
5916
- const readVersion = probes.readVersion ?? readCliVersion;
5917
- let vendored;
5918
- try {
5919
- const platformPkg = `@anthropic-ai/claude-agent-sdk-${process.platform}-${process.arch}`;
5920
- vendored = resolveModule(`${platformPkg}/package.json`).replace(/package\.json$/, CLI_BIN_NAME);
5921
- } catch {
5922
- vendored = void 0;
5923
- }
5924
- const insideAsar = vendored !== void 0 && ASAR_SEGMENT.test(vendored);
5925
- const vendoredExecutable = insideAsar ? vendored.replace(ASAR_SEGMENT, "$1app.asar.unpacked$2") : vendored;
5926
- const fallback = insideAsar ? vendoredExecutable : void 0;
5927
- const installed = findOnPath();
5928
- if (!installed) return fallback;
5929
- const installedVersion = readVersion(installed);
5930
- if (!installedVersion) return vendoredExecutable ? fallback : installed;
5931
- const vendoredVersion = vendoredExecutable ? readVersion(vendoredExecutable) : void 0;
5932
- if (vendoredVersion && !isAtLeast(installedVersion, vendoredVersion)) return fallback;
5933
- return installed;
5934
- }
5935
- function claudeCliPath() {
5936
- if (!cliPathProbed) {
5937
- cliPath = resolveClaudeCliPath((id) => createRequire(import.meta.url).resolve(id));
5938
- cliPathProbed = true;
5939
- }
5940
- return cliPath;
5941
- }
5942
6204
  function streamingEnabled() {
5943
6205
  const raw = process.env.COGPIT_STREAM_PARTIAL;
5944
6206
  if (raw === void 0) return true;
@@ -5956,16 +6218,16 @@ function makeCanUseTool(state) {
5956
6218
  return (toolName, input, options) => {
5957
6219
  if (toolName === "AskUserQuestion") {
5958
6220
  const toolUseId = options.toolUseID;
5959
- return new Promise((resolve21) => {
6221
+ return new Promise((resolve22) => {
5960
6222
  const pending = {
5961
6223
  input,
5962
6224
  askedAt: Date.now(),
5963
- resolve: resolve21
6225
+ resolve: resolve22
5964
6226
  };
5965
6227
  state.pendingUserQuestions.set(toolUseId, pending);
5966
6228
  const onAbort = () => {
5967
6229
  if (state.pendingUserQuestions.delete(toolUseId)) {
5968
- resolve21({ behavior: "deny", message: "Session aborted", interrupt: true });
6230
+ resolve22({ behavior: "deny", message: "Session aborted", interrupt: true });
5969
6231
  }
5970
6232
  };
5971
6233
  options.signal?.addEventListener("abort", onAbort, { once: true });
@@ -5978,7 +6240,7 @@ function makeCanUseTool(state) {
5978
6240
  return Promise.resolve({ behavior: "allow", updatedInput: input });
5979
6241
  }
5980
6242
  const requestId = options.toolUseID;
5981
- return new Promise((resolve21) => {
6243
+ return new Promise((resolve22) => {
5982
6244
  const pending = {
5983
6245
  requestId,
5984
6246
  toolName,
@@ -5991,12 +6253,12 @@ function makeCanUseTool(state) {
5991
6253
  blockedPath: options.blockedPath,
5992
6254
  suggestions: options.suggestions,
5993
6255
  timestamp: Date.now(),
5994
- resolve: resolve21
6256
+ resolve: resolve22
5995
6257
  };
5996
6258
  state.pendingPermissions.set(requestId, pending);
5997
6259
  const onAbort = () => {
5998
6260
  if (state.pendingPermissions.delete(requestId)) {
5999
- resolve21({ behavior: "deny", message: "Session aborted", interrupt: true });
6261
+ resolve22({ behavior: "deny", message: "Session aborted", interrupt: true });
6000
6262
  }
6001
6263
  };
6002
6264
  options.signal?.addEventListener("abort", onAbort, { once: true });
@@ -6073,16 +6335,16 @@ function makeOnElicitation(state) {
6073
6335
  );
6074
6336
  return Promise.resolve({ action: "decline" });
6075
6337
  }
6076
- return new Promise((resolve21) => {
6338
+ return new Promise((resolve22) => {
6077
6339
  const requestId = options.requestId;
6078
6340
  state.pendingElicitations.set(requestId, {
6079
6341
  request,
6080
6342
  fields: projection.fields,
6081
6343
  askedAt: Date.now(),
6082
- resolve: resolve21
6344
+ resolve: resolve22
6083
6345
  });
6084
6346
  const onAbort = () => {
6085
- if (state.pendingElicitations.delete(requestId)) resolve21({ action: "decline" });
6347
+ if (state.pendingElicitations.delete(requestId)) resolve22({ action: "decline" });
6086
6348
  };
6087
6349
  options.signal?.addEventListener("abort", onAbort, { once: true });
6088
6350
  });
@@ -6106,14 +6368,14 @@ function makeOnUserDialog(state) {
6106
6368
  if (!(request.dialogKind in DIALOG_CHOICES)) return Promise.resolve(null);
6107
6369
  const projected = projectUserDialog(request);
6108
6370
  if (!projected) return Promise.resolve({ behavior: "cancelled" });
6109
- return new Promise((resolve21) => {
6371
+ return new Promise((resolve22) => {
6110
6372
  const requestId = options.requestId;
6111
6373
  state.pendingUserDialogs.set(requestId, {
6112
6374
  dialog: { ...projected, requestId, askedAt: Date.now() },
6113
- resolve: resolve21
6375
+ resolve: resolve22
6114
6376
  });
6115
6377
  const onAbort = () => {
6116
- if (state.pendingUserDialogs.delete(requestId)) resolve21({ behavior: "cancelled" });
6378
+ if (state.pendingUserDialogs.delete(requestId)) resolve22({ behavior: "cancelled" });
6117
6379
  };
6118
6380
  options.signal?.addEventListener("abort", onAbort, { once: true });
6119
6381
  });
@@ -6824,15 +7086,12 @@ function cleanupAllSDKSessions() {
6824
7086
  sdkSessions.clear();
6825
7087
  return killed;
6826
7088
  }
6827
- var CLI_BIN_NAME, ASAR_SEGMENT, cliPathProbed, cliPath, sdkSessions, REFUSAL_FALLBACK_DIALOG, DIALOG_CHOICES, SUPPORTED_DIALOG_KINDS, SDKMessageStream, EDIT_TOOL_NAMES;
7089
+ var sdkSessions, REFUSAL_FALLBACK_DIALOG, DIALOG_CHOICES, SUPPORTED_DIALOG_KINDS, SDKMessageStream, EDIT_TOOL_NAMES;
6828
7090
  var init_sdk_session = __esm({
6829
7091
  "../../server/sdk-session.ts"() {
6830
7092
  init_subagentWatcher();
6831
- init_binaryResolver();
7093
+ init_claudeExecutable();
6832
7094
  init_streamBus();
6833
- CLI_BIN_NAME = nativeBinaryName("claude");
6834
- ASAR_SEGMENT = /([\\/])app\.asar([\\/])/;
6835
- cliPathProbed = false;
6836
7095
  sdkSessions = /* @__PURE__ */ new Map();
6837
7096
  REFUSAL_FALLBACK_DIALOG = "refusal_fallback_prompt";
6838
7097
  DIALOG_CHOICES = {
@@ -6845,8 +7104,8 @@ var init_sdk_session = __esm({
6845
7104
  closed = false;
6846
7105
  enqueue(message) {
6847
7106
  if (this.closed) return false;
6848
- const resolve21 = this.waiting.shift();
6849
- if (resolve21) resolve21({ value: message, done: false });
7107
+ const resolve22 = this.waiting.shift();
7108
+ if (resolve22) resolve22({ value: message, done: false });
6850
7109
  else this.queued.push(message);
6851
7110
  return true;
6852
7111
  }
@@ -6854,15 +7113,15 @@ var init_sdk_session = __esm({
6854
7113
  if (this.closed) return;
6855
7114
  this.closed = true;
6856
7115
  this.queued.length = 0;
6857
- for (const resolve21 of this.waiting.splice(0)) {
6858
- resolve21({ value: void 0, done: true });
7116
+ for (const resolve22 of this.waiting.splice(0)) {
7117
+ resolve22({ value: void 0, done: true });
6859
7118
  }
6860
7119
  }
6861
7120
  next() {
6862
7121
  const message = this.queued.shift();
6863
7122
  if (message) return Promise.resolve({ value: message, done: false });
6864
7123
  if (this.closed) return Promise.resolve({ value: void 0, done: true });
6865
- return new Promise((resolve21) => this.waiting.push(resolve21));
7124
+ return new Promise((resolve22) => this.waiting.push(resolve22));
6866
7125
  }
6867
7126
  return() {
6868
7127
  this.close();
@@ -6998,8 +7257,8 @@ var init_agent_prompts = __esm({
6998
7257
  function observeExit(proc) {
6999
7258
  let didExit = proc.exitCode !== null && proc.exitCode !== void 0 || proc.signalCode !== null && proc.signalCode !== void 0;
7000
7259
  let resolveExit = () => void 0;
7001
- const exited = new Promise((resolve21) => {
7002
- resolveExit = resolve21;
7260
+ const exited = new Promise((resolve22) => {
7261
+ resolveExit = resolve22;
7003
7262
  });
7004
7263
  if (didExit) resolveExit();
7005
7264
  const markExited = () => {
@@ -7025,14 +7284,14 @@ function observeExit(proc) {
7025
7284
  async function waitForExit(observers, timeoutMs, onTimeout = () => void 0) {
7026
7285
  const pending = observers.filter((observer) => !observer.hasExited());
7027
7286
  if (pending.length === 0) return;
7028
- await new Promise((resolve21) => {
7287
+ await new Promise((resolve22) => {
7029
7288
  const timer = setTimeout(() => {
7030
7289
  onTimeout();
7031
- resolve21();
7290
+ resolve22();
7032
7291
  }, timeoutMs);
7033
7292
  void Promise.all(pending.map((observer) => observer.exited)).then(() => {
7034
7293
  clearTimeout(timer);
7035
- resolve21();
7294
+ resolve22();
7036
7295
  });
7037
7296
  });
7038
7297
  }
@@ -7315,7 +7574,7 @@ async function readClaudeSessionMeta(filePath, head) {
7315
7574
  let cwd = "";
7316
7575
  let firstUserMessage = "";
7317
7576
  let lastUserMessage = "";
7318
- let timestamp = "";
7577
+ let timestamp2 = "";
7319
7578
  let lastTimestamp = "";
7320
7579
  let turnCount = 0;
7321
7580
  let aiTitle = "";
@@ -7354,8 +7613,8 @@ async function readClaudeSessionMeta(filePath, head) {
7354
7613
  if (obj.type === "assistant" && obj.message?.model && !model) {
7355
7614
  model = obj.message.model;
7356
7615
  }
7357
- if (obj.type === "user" && !obj.isMeta && !timestamp) {
7358
- timestamp = obj.timestamp || "";
7616
+ if (obj.type === "user" && !obj.isMeta && !timestamp2) {
7617
+ timestamp2 = obj.timestamp || "";
7359
7618
  }
7360
7619
  if (obj.type === "user" && !obj.isMeta) {
7361
7620
  if (obj.timestamp) lastTimestamp = obj.timestamp;
@@ -7450,8 +7709,8 @@ async function readClaudeSessionMeta(filePath, head) {
7450
7709
  cwd,
7451
7710
  firstUserMessage,
7452
7711
  lastUserMessage,
7453
- timestamp,
7454
- lastTimestamp: lastTimestamp || timestamp,
7712
+ timestamp: timestamp2,
7713
+ lastTimestamp: lastTimestamp || timestamp2,
7455
7714
  turnCount,
7456
7715
  lineCount: isPartialRead ? Math.round(head.size / (HEAD_BYTES / lines.length)) : lines.length,
7457
7716
  branchedFrom,
@@ -7740,7 +7999,7 @@ var init_sessionStats = __esm({
7740
7999
  });
7741
8000
 
7742
8001
  // ../../shared/session/turnContent.ts
7743
- function appendAssistantText(turn, text, timestamp) {
8002
+ function appendAssistantText(turn, text, timestamp2) {
7744
8003
  if (!text) return;
7745
8004
  turn.assistantText.push(text);
7746
8005
  const last = turn.contentBlocks[turn.contentBlocks.length - 1];
@@ -7748,7 +8007,7 @@ function appendAssistantText(turn, text, timestamp) {
7748
8007
  last.text.push(text);
7749
8008
  return;
7750
8009
  }
7751
- turn.contentBlocks.push({ kind: "text", text: [text], timestamp });
8010
+ turn.contentBlocks.push({ kind: "text", text: [text], timestamp: timestamp2 });
7752
8011
  }
7753
8012
  var init_turnContent = __esm({
7754
8013
  "../../shared/session/turnContent.ts"() {
@@ -8118,7 +8377,7 @@ function resolveCodexPatchPath(filePath, cwd) {
8118
8377
  const relative11 = filePath.replace(/^\.[\\/]/, "");
8119
8378
  return /^[A-Za-z]:[\\/]/.test(cwd) ? `${base}\\${relative11.replace(/\//g, "\\")}` : `${base}/${relative11}`;
8120
8379
  }
8121
- function parseApplyPatch(patchText, callId, timestamp, cwd = "") {
8380
+ function parseApplyPatch(patchText, callId, timestamp2, cwd = "") {
8122
8381
  const toolCalls = [];
8123
8382
  const filePattern = /^\*\*\*\s+(Update File|Add File|Delete File):\s*(.+)$/gm;
8124
8383
  const sections = [];
@@ -8161,7 +8420,7 @@ function parseApplyPatch(patchText, callId, timestamp, cwd = "") {
8161
8420
  input: { file_path: filePath, content: newLines.join("\n") },
8162
8421
  result: null,
8163
8422
  isError: false,
8164
- timestamp
8423
+ timestamp: timestamp2
8165
8424
  });
8166
8425
  } else if (section.action === "Delete File") {
8167
8426
  toolCalls.push({
@@ -8170,7 +8429,7 @@ function parseApplyPatch(patchText, callId, timestamp, cwd = "") {
8170
8429
  input: { file_path: filePath, old_string: oldLines.join("\n"), new_string: "" },
8171
8430
  result: null,
8172
8431
  isError: false,
8173
- timestamp
8432
+ timestamp: timestamp2
8174
8433
  });
8175
8434
  } else {
8176
8435
  toolCalls.push({
@@ -8184,18 +8443,18 @@ function parseApplyPatch(patchText, callId, timestamp, cwd = "") {
8184
8443
  },
8185
8444
  result: null,
8186
8445
  isError: false,
8187
- timestamp
8446
+ timestamp: timestamp2
8188
8447
  });
8189
8448
  }
8190
8449
  }
8191
8450
  return toolCalls;
8192
8451
  }
8193
- function parseCodexToolPatches(toolName, rawInput, callId, timestamp, cwd = "") {
8452
+ function parseCodexToolPatches(toolName, rawInput, callId, timestamp2, cwd = "") {
8194
8453
  if (toolName === "apply_patch") {
8195
- return parseApplyPatch(rawInput, callId, timestamp, cwd);
8454
+ return parseApplyPatch(rawInput, callId, timestamp2, cwd);
8196
8455
  }
8197
8456
  return extractApplyPatchInputs(rawInput).flatMap(
8198
- (patch, patchIndex) => parseApplyPatch(patch, `${callId}:patch-${patchIndex}`, timestamp, cwd)
8457
+ (patch, patchIndex) => parseApplyPatch(patch, `${callId}:patch-${patchIndex}`, timestamp2, cwd)
8199
8458
  );
8200
8459
  }
8201
8460
  function findFailedNestedPatchCallIds(output, wrapperIsError, calls) {
@@ -8320,9 +8579,9 @@ function safeParseLine(line) {
8320
8579
  function isObject2(value) {
8321
8580
  return typeof value === "object" && value !== null;
8322
8581
  }
8323
- function isCodexRecord(record2) {
8324
- if (!record2 || typeof record2.type !== "string") return false;
8325
- return record2.type === "session_meta" || record2.type === "turn_context" || record2.type === "event_msg" || record2.type === "response_item" || record2.type === "inter_agent_communication_metadata" || record2.type === "compacted" || record2.type === "world_state";
8582
+ function isCodexRecord(record4) {
8583
+ if (!record4 || typeof record4.type !== "string") return false;
8584
+ return record4.type === "session_meta" || record4.type === "turn_context" || record4.type === "event_msg" || record4.type === "response_item" || record4.type === "inter_agent_communication_metadata" || record4.type === "compacted" || record4.type === "world_state";
8326
8585
  }
8327
8586
  function extractMessageText(payload, blockType) {
8328
8587
  const content = payload?.content;
@@ -8439,7 +8698,7 @@ function parseTokenUsage(value) {
8439
8698
  cache_read_input_tokens: cacheRead
8440
8699
  };
8441
8700
  }
8442
- function appendThinking(turn, text, timestamp) {
8701
+ function appendThinking(turn, text, timestamp2) {
8443
8702
  if (!text) return;
8444
8703
  const block = { type: "thinking", thinking: text, signature: "" };
8445
8704
  turn.thinking.push(block);
@@ -8448,16 +8707,16 @@ function appendThinking(turn, text, timestamp) {
8448
8707
  last.blocks.push(block);
8449
8708
  return;
8450
8709
  }
8451
- turn.contentBlocks.push({ kind: "thinking", blocks: [block], timestamp });
8710
+ turn.contentBlocks.push({ kind: "thinking", blocks: [block], timestamp: timestamp2 });
8452
8711
  }
8453
- function appendToolCall(turn, toolCall, timestamp) {
8712
+ function appendToolCall(turn, toolCall, timestamp2) {
8454
8713
  turn.toolCalls.push(toolCall);
8455
8714
  const last = turn.contentBlocks[turn.contentBlocks.length - 1];
8456
- if (last && last.kind === "tool_calls" && last.timestamp === timestamp) {
8715
+ if (last && last.kind === "tool_calls" && last.timestamp === timestamp2) {
8457
8716
  last.toolCalls.push(toolCall);
8458
8717
  return;
8459
8718
  }
8460
- turn.contentBlocks.push({ kind: "tool_calls", toolCalls: [toolCall], timestamp });
8719
+ turn.contentBlocks.push({ kind: "tool_calls", toolCalls: [toolCall], timestamp: timestamp2 });
8461
8720
  }
8462
8721
  function finalizeTurn(turns, current, lastTimestamp) {
8463
8722
  if (!current) return null;
@@ -8508,37 +8767,37 @@ function parseMcpEventResult(value) {
8508
8767
  isError: ok.isError === true || parsedContent.isError
8509
8768
  };
8510
8769
  }
8511
- function createTurn(turnId, timestamp, model) {
8770
+ function createTurn(turnId, timestamp2, model) {
8512
8771
  return {
8513
- id: turnId ? `${turnId}@${timestamp}` : randomTurnId("codex-turn"),
8772
+ id: turnId ? `${turnId}@${timestamp2}` : randomTurnId("codex-turn"),
8514
8773
  userMessage: null,
8515
8774
  contentBlocks: [],
8516
8775
  thinking: [],
8517
8776
  assistantText: [],
8518
8777
  toolCalls: [],
8519
8778
  subAgentActivity: [],
8520
- timestamp,
8779
+ timestamp: timestamp2,
8521
8780
  durationMs: null,
8522
8781
  tokenUsage: null,
8523
8782
  model
8524
8783
  };
8525
8784
  }
8526
- function extractPromptFromRecord(record2) {
8527
- if (record2.type === "event_msg" && isObject2(record2.payload) && record2.payload.type === "user_message" && typeof record2.payload.message === "string") {
8528
- return normalizePromptText(record2.payload.message);
8785
+ function extractPromptFromRecord(record4) {
8786
+ if (record4.type === "event_msg" && isObject2(record4.payload) && record4.payload.type === "user_message" && typeof record4.payload.message === "string") {
8787
+ return normalizePromptText(record4.payload.message);
8529
8788
  }
8530
- if (record2.type === "response_item" && isObject2(record2.payload) && record2.payload.type === "message" && record2.payload.role === "user") {
8531
- return normalizePromptText(extractMessageText(record2.payload, "input_text"));
8789
+ if (record4.type === "response_item" && isObject2(record4.payload) && record4.payload.type === "message" && record4.payload.role === "user") {
8790
+ return normalizePromptText(extractMessageText(record4.payload, "input_text"));
8532
8791
  }
8533
8792
  return "";
8534
8793
  }
8535
- function recordOpensTurn(record2, payload) {
8536
- if (record2.type === "session_meta") return false;
8537
- if (record2.type === "event_msg" && payload?.type === "task_started") return false;
8538
- if (record2.type === "response_item" && payload?.type === "message") {
8794
+ function recordOpensTurn(record4, payload) {
8795
+ if (record4.type === "session_meta") return false;
8796
+ if (record4.type === "event_msg" && payload?.type === "task_started") return false;
8797
+ if (record4.type === "response_item" && payload?.type === "message") {
8539
8798
  if (payload.role === "developer" || payload.role === "system") return false;
8540
8799
  if (payload.role === "user") {
8541
- return extractPromptFromRecord(record2) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
8800
+ return extractPromptFromRecord(record4) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
8542
8801
  }
8543
8802
  }
8544
8803
  return true;
@@ -8552,29 +8811,29 @@ function extractMetadataFromRecords(records) {
8552
8811
  let branchedFrom;
8553
8812
  let firstUserMessage = "";
8554
8813
  let lastUserMessage = "";
8555
- let timestamp = "";
8814
+ let timestamp2 = "";
8556
8815
  let lastTimestamp = "";
8557
8816
  let turnCount = 0;
8558
8817
  let isSubagent = false;
8559
8818
  let parentSessionId = null;
8560
8819
  let agentPath = "/root";
8561
8820
  let previousPrompt = "";
8562
- for (const record2 of records) {
8563
- if (!isObject2(record2.payload)) continue;
8564
- if (record2.type === "session_meta") {
8565
- sessionId ||= typeof record2.payload.id === "string" ? record2.payload.id : "";
8566
- version ||= typeof record2.payload.cli_version === "string" ? record2.payload.cli_version : "";
8567
- cwd ||= typeof record2.payload.cwd === "string" ? record2.payload.cwd : "";
8568
- if (!branchedFrom && isObject2(record2.payload.branchedFrom)) {
8569
- const sourceId = typeof record2.payload.branchedFrom.sessionId === "string" ? record2.payload.branchedFrom.sessionId : "";
8821
+ for (const record4 of records) {
8822
+ if (!isObject2(record4.payload)) continue;
8823
+ if (record4.type === "session_meta") {
8824
+ sessionId ||= typeof record4.payload.id === "string" ? record4.payload.id : "";
8825
+ version ||= typeof record4.payload.cli_version === "string" ? record4.payload.cli_version : "";
8826
+ cwd ||= typeof record4.payload.cwd === "string" ? record4.payload.cwd : "";
8827
+ if (!branchedFrom && isObject2(record4.payload.branchedFrom)) {
8828
+ const sourceId = typeof record4.payload.branchedFrom.sessionId === "string" ? record4.payload.branchedFrom.sessionId : "";
8570
8829
  if (sourceId) {
8571
8830
  branchedFrom = {
8572
8831
  sessionId: sourceId,
8573
- turnIndex: typeof record2.payload.branchedFrom.turnIndex === "number" ? record2.payload.branchedFrom.turnIndex : null
8832
+ turnIndex: typeof record4.payload.branchedFrom.turnIndex === "number" ? record4.payload.branchedFrom.turnIndex : null
8574
8833
  };
8575
8834
  }
8576
8835
  }
8577
- const source = isObject2(record2.payload.source) ? record2.payload.source : null;
8836
+ const source = isObject2(record4.payload.source) ? record4.payload.source : null;
8578
8837
  if (source && isObject2(source.subagent)) {
8579
8838
  isSubagent = true;
8580
8839
  const threadSpawn = isObject2(source.subagent.thread_spawn) ? source.subagent.thread_spawn : null;
@@ -8582,27 +8841,27 @@ function extractMetadataFromRecords(records) {
8582
8841
  agentPath = threadSpawn.agent_path;
8583
8842
  }
8584
8843
  }
8585
- if (typeof record2.payload.forked_from_id === "string" && record2.payload.forked_from_id) {
8586
- parentSessionId = record2.payload.forked_from_id;
8844
+ if (typeof record4.payload.forked_from_id === "string" && record4.payload.forked_from_id) {
8845
+ parentSessionId = record4.payload.forked_from_id;
8587
8846
  }
8588
- const git = isObject2(record2.payload.git) ? record2.payload.git : null;
8847
+ const git = isObject2(record4.payload.git) ? record4.payload.git : null;
8589
8848
  gitBranch ||= git && typeof git.branch === "string" ? git.branch : "";
8590
8849
  }
8591
- if (record2.type === "turn_context") {
8592
- model ||= typeof record2.payload.model === "string" ? record2.payload.model : "";
8593
- cwd ||= typeof record2.payload.cwd === "string" ? record2.payload.cwd : "";
8850
+ if (record4.type === "turn_context") {
8851
+ model ||= typeof record4.payload.model === "string" ? record4.payload.model : "";
8852
+ cwd ||= typeof record4.payload.cwd === "string" ? record4.payload.cwd : "";
8594
8853
  }
8595
- const prompt = extractPromptFromRecord(record2);
8854
+ const prompt = extractPromptFromRecord(record4);
8596
8855
  if (!prompt) continue;
8597
8856
  if (prompt === previousPrompt) continue;
8598
8857
  if (!firstUserMessage) firstUserMessage = prompt;
8599
8858
  lastUserMessage = prompt;
8600
8859
  previousPrompt = prompt;
8601
8860
  turnCount++;
8602
- if (!timestamp) timestamp = record2.timestamp ?? "";
8603
- lastTimestamp = record2.timestamp ?? lastTimestamp;
8861
+ if (!timestamp2) timestamp2 = record4.timestamp ?? "";
8862
+ lastTimestamp = record4.timestamp ?? lastTimestamp;
8604
8863
  }
8605
- if (lastTimestamp === "") lastTimestamp = timestamp;
8864
+ if (lastTimestamp === "") lastTimestamp = timestamp2;
8606
8865
  return {
8607
8866
  sessionId,
8608
8867
  version,
@@ -8614,7 +8873,7 @@ function extractMetadataFromRecords(records) {
8614
8873
  branchedFrom,
8615
8874
  firstUserMessage,
8616
8875
  lastUserMessage,
8617
- timestamp,
8876
+ timestamp: timestamp2,
8618
8877
  lastTimestamp,
8619
8878
  turnCount,
8620
8879
  isSubagent,
@@ -8727,8 +8986,8 @@ function walkCodexRecords(records, options) {
8727
8986
  pendingTurnStart = null;
8728
8987
  return result;
8729
8988
  }
8730
- function createActiveTurn(turnId, timestamp, model) {
8731
- const turn = createTurn(turnId, timestamp, model);
8989
+ function createActiveTurn(turnId, timestamp2, model) {
8990
+ const turn = createTurn(turnId, timestamp2, model);
8732
8991
  pendingTurnStart = pendingContextIndex ?? recordIndex;
8733
8992
  pendingContextIndex = null;
8734
8993
  if (!sawTurnStart) turn.isFragment = true;
@@ -8738,7 +8997,7 @@ function walkCodexRecords(records, options) {
8738
8997
  }
8739
8998
  return turn;
8740
8999
  }
8741
- function upsertWebSearchCall(targetTurn, id, input, status, timestamp) {
9000
+ function upsertWebSearchCall(targetTurn, id, input, status, timestamp2) {
8742
9001
  const existing = webSearchCalls.get(id);
8743
9002
  if (existing) {
8744
9003
  existing.input = { ...existing.input, ...input };
@@ -8752,39 +9011,39 @@ function walkCodexRecords(records, options) {
8752
9011
  input,
8753
9012
  result: status,
8754
9013
  isError: status === "failed",
8755
- timestamp
9014
+ timestamp: timestamp2
8756
9015
  };
8757
9016
  webSearchCalls.set(id, toolCall);
8758
- appendToolCall(targetTurn, toolCall, timestamp);
9017
+ appendToolCall(targetTurn, toolCall, timestamp2);
8759
9018
  }
8760
9019
  for (let index = 0; index < records.length; index++) {
8761
- const record2 = records[index];
8762
- if (!isCodexRecord(record2)) continue;
9020
+ const record4 = records[index];
9021
+ if (!isCodexRecord(record4)) continue;
8763
9022
  recordIndex = index;
8764
- const payload = isObject2(record2.payload) ? record2.payload : void 0;
8765
- const timestamp = record2.timestamp ?? "";
8766
- if (record2.type === "compacted") {
9023
+ const payload = isObject2(record4.payload) ? record4.payload : void 0;
9024
+ const timestamp2 = record4.timestamp ?? "";
9025
+ if (record4.type === "compacted") {
8767
9026
  current = commitTurn(current);
8768
9027
  pendingCompaction = "Conversation compacted";
8769
- lastTurnTimestamp = timestamp;
9028
+ lastTurnTimestamp = timestamp2;
8770
9029
  continue;
8771
9030
  }
8772
- if (record2.type === "world_state") continue;
8773
- if (record2.type === "turn_context") {
9031
+ if (record4.type === "world_state") continue;
9032
+ if (record4.type === "turn_context") {
8774
9033
  current = commitTurn(current);
8775
9034
  pendingContextIndex = index;
8776
9035
  currentTurnId = typeof payload?.turn_id === "string" ? payload.turn_id : null;
8777
9036
  currentModel = typeof payload?.model === "string" ? payload.model : currentModel;
8778
- lastTurnTimestamp = timestamp;
9037
+ lastTurnTimestamp = timestamp2;
8779
9038
  sawTurnStart = true;
8780
9039
  continue;
8781
9040
  }
8782
- if (record2.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
9041
+ if (record4.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
8783
9042
  if (current && (current.assistantText.length > 0 || current.toolCalls.length > 0 || current.thinking.length > 0)) {
8784
9043
  current = commitTurn(current);
8785
9044
  }
8786
9045
  sawTurnStart = true;
8787
- current ??= createActiveTurn(currentTurnId, timestamp, currentModel);
9046
+ current ??= createActiveTurn(currentTurnId, timestamp2, currentModel);
8788
9047
  const localImages = (Array.isArray(payload.local_images) ? payload.local_images : []).filter(
8789
9048
  (p) => typeof p === "string" && p.length > 0
8790
9049
  );
@@ -8799,16 +9058,16 @@ function walkCodexRecords(records, options) {
8799
9058
  localAudio
8800
9059
  );
8801
9060
  current.isFragment = false;
8802
- current.timestamp = current.timestamp || timestamp;
8803
- lastTurnTimestamp = timestamp;
9061
+ current.timestamp = current.timestamp || timestamp2;
9062
+ lastTurnTimestamp = timestamp2;
8804
9063
  continue;
8805
9064
  }
8806
- if (!current && !recordOpensTurn(record2, payload)) continue;
8807
- current ??= createActiveTurn(currentTurnId, timestamp, currentModel);
9065
+ if (!current && !recordOpensTurn(record4, payload)) continue;
9066
+ current ??= createActiveTurn(currentTurnId, timestamp2, currentModel);
8808
9067
  if (!current.model && currentModel) current.model = currentModel;
8809
- if (!current.timestamp) current.timestamp = timestamp;
8810
- if (timestamp) lastTurnTimestamp = timestamp;
8811
- if (record2.type === "event_msg" && payload?.type === "token_count") {
9068
+ if (!current.timestamp) current.timestamp = timestamp2;
9069
+ if (timestamp2) lastTurnTimestamp = timestamp2;
9070
+ if (record4.type === "event_msg" && payload?.type === "token_count") {
8812
9071
  const info = isObject2(payload.info) ? payload.info : null;
8813
9072
  const lastUsage = info ? parseTokenUsage(info.last_token_usage) : null;
8814
9073
  if (lastUsage) {
@@ -8816,14 +9075,14 @@ function walkCodexRecords(records, options) {
8816
9075
  }
8817
9076
  continue;
8818
9077
  }
8819
- if (record2.type === "event_msg" && payload?.type === "web_search_end" && typeof payload.call_id === "string") {
9078
+ if (record4.type === "event_msg" && payload?.type === "web_search_end" && typeof payload.call_id === "string") {
8820
9079
  const input = {};
8821
9080
  if (typeof payload.query === "string" && payload.query) input.query = payload.query;
8822
9081
  if (isObject2(payload.action)) input.action = payload.action;
8823
- upsertWebSearchCall(current, payload.call_id, input, "completed", timestamp);
9082
+ upsertWebSearchCall(current, payload.call_id, input, "completed", timestamp2);
8824
9083
  continue;
8825
9084
  }
8826
- if (record2.type === "event_msg" && payload?.type === "mcp_tool_call_end" && typeof payload.call_id === "string" && isObject2(payload.invocation)) {
9085
+ if (record4.type === "event_msg" && payload?.type === "mcp_tool_call_end" && typeof payload.call_id === "string" && isObject2(payload.invocation)) {
8827
9086
  const invocation = payload.invocation;
8828
9087
  const server = typeof invocation.server === "string" ? invocation.server : "mcp";
8829
9088
  const tool = typeof invocation.tool === "string" ? invocation.tool : "tool";
@@ -8841,12 +9100,12 @@ function walkCodexRecords(records, options) {
8841
9100
  input,
8842
9101
  result: result.text,
8843
9102
  isError: result.isError,
8844
- timestamp
8845
- }, timestamp);
9103
+ timestamp: timestamp2
9104
+ }, timestamp2);
8846
9105
  }
8847
9106
  continue;
8848
9107
  }
8849
- if (record2.type === "event_msg" && payload?.type === "sub_agent_activity" && typeof payload.agent_thread_id === "string" && typeof payload.agent_path === "string") {
9108
+ if (record4.type === "event_msg" && payload?.type === "sub_agent_activity" && typeof payload.agent_thread_id === "string" && typeof payload.agent_path === "string") {
8850
9109
  const agentId = payload.agent_thread_id;
8851
9110
  const eventId2 = typeof payload.event_id === "string" ? payload.event_id : "";
8852
9111
  const kind = typeof payload.kind === "string" ? payload.kind : "started";
@@ -8870,24 +9129,24 @@ function walkCodexRecords(records, options) {
8870
9129
  message: existing?.message ?? spawnInfo?.message ?? "",
8871
9130
  model: existing?.model ?? spawnInfo?.model ?? null,
8872
9131
  agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
8873
- timestamp: existing?.timestamp ?? (timestamp || spawnInfo?.timestamp || ""),
9132
+ timestamp: existing?.timestamp ?? (timestamp2 || spawnInfo?.timestamp || ""),
8874
9133
  parentToolCallId: existing?.parentToolCallId ?? eventId2
8875
9134
  };
8876
9135
  agentRegistry.set(agentId, info);
8877
9136
  agentIdByPath.set(payload.agent_path, agentId);
8878
9137
  if (eventId2 && (kind === "started" || spawnInfo)) agentIdBySpawnCall.set(eventId2, agentId);
8879
9138
  const status = kind === "interrupted" ? "interrupted" : "running";
8880
- upsertAgentMessage(agentId, current, timestamp, { status });
9139
+ upsertAgentMessage(agentId, current, timestamp2, { status });
8881
9140
  continue;
8882
9141
  }
8883
- if (record2.type !== "response_item" || !payload) continue;
9142
+ if (record4.type !== "response_item" || !payload) continue;
8884
9143
  if (payload.type === "reasoning") {
8885
9144
  const summary = Array.isArray(payload.summary) ? payload.summary.filter((item) => typeof item === "string").join("\n") : "";
8886
- appendThinking(current, summary.trim(), timestamp);
9145
+ appendThinking(current, summary.trim(), timestamp2);
8887
9146
  continue;
8888
9147
  }
8889
9148
  if (payload.type === "message" && payload.role === "assistant") {
8890
- appendAssistantText(current, extractMessageText(payload, "output_text"), timestamp);
9149
+ appendAssistantText(current, extractMessageText(payload, "output_text"), timestamp2);
8891
9150
  continue;
8892
9151
  }
8893
9152
  if (payload.type === "message" && payload.role === "user" && current.userMessage === null) {
@@ -8905,7 +9164,7 @@ function walkCodexRecords(records, options) {
8905
9164
  const input = {};
8906
9165
  if (isObject2(payload.action)) input.action = payload.action;
8907
9166
  const status = typeof payload.status === "string" ? payload.status : "completed";
8908
- upsertWebSearchCall(current, payload.id, input, status, timestamp);
9167
+ upsertWebSearchCall(current, payload.id, input, status, timestamp2);
8909
9168
  continue;
8910
9169
  }
8911
9170
  if (payload.type === "tool_search_call") {
@@ -8917,10 +9176,10 @@ function walkCodexRecords(records, options) {
8917
9176
  input: isObject2(payload.arguments) ? payload.arguments : {},
8918
9177
  result: null,
8919
9178
  isError: false,
8920
- timestamp
9179
+ timestamp: timestamp2
8921
9180
  };
8922
9181
  pendingToolCalls.set(callId, toolCall);
8923
- appendToolCall(current, toolCall, timestamp);
9182
+ appendToolCall(current, toolCall, timestamp2);
8924
9183
  }
8925
9184
  continue;
8926
9185
  }
@@ -8954,7 +9213,7 @@ function walkCodexRecords(records, options) {
8954
9213
  message: "",
8955
9214
  model: null,
8956
9215
  agentType: null,
8957
- timestamp,
9216
+ timestamp: timestamp2,
8958
9217
  parentToolCallId: ""
8959
9218
  });
8960
9219
  agentIdByPath.set(author, agentId);
@@ -8964,7 +9223,7 @@ function walkCodexRecords(records, options) {
8964
9223
  else if (interAgentMessage.messageType === "ERROR" || interAgentMessage.messageType === "FAILED") status = "failed";
8965
9224
  else if (interAgentMessage.messageType === "INTERRUPTED") status = "interrupted";
8966
9225
  else if (interAgentMessage.messageType === "MESSAGE") status = "running";
8967
- upsertAgentMessage(agentId, current, timestamp, {
9226
+ upsertAgentMessage(agentId, current, timestamp2, {
8968
9227
  status,
8969
9228
  text: interAgentMessage.text || void 0
8970
9229
  });
@@ -8989,7 +9248,7 @@ function walkCodexRecords(records, options) {
8989
9248
  taskName: typeof parsedInput.task_name === "string" ? parsedInput.task_name : null,
8990
9249
  model: typeof parsedInput.model === "string" ? parsedInput.model : null,
8991
9250
  agentType: typeof parsedInput.agent_type === "string" ? parsedInput.agent_type : null,
8992
- timestamp
9251
+ timestamp: timestamp2
8993
9252
  });
8994
9253
  }
8995
9254
  const toolCall = {
@@ -8998,10 +9257,10 @@ function walkCodexRecords(records, options) {
8998
9257
  input,
8999
9258
  result: null,
9000
9259
  isError: false,
9001
- timestamp
9260
+ timestamp: timestamp2
9002
9261
  };
9003
9262
  pendingToolCalls.set(toolCall.id, toolCall);
9004
- appendToolCall(current, toolCall, timestamp);
9263
+ appendToolCall(current, toolCall, timestamp2);
9005
9264
  continue;
9006
9265
  }
9007
9266
  if (payload.type === "function_call_output" && typeof payload.call_id === "string") {
@@ -9027,13 +9286,13 @@ function walkCodexRecords(records, options) {
9027
9286
  message: existing?.message ?? spawnInfo?.message ?? "",
9028
9287
  model: existing?.model ?? spawnInfo?.model ?? null,
9029
9288
  agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
9030
- timestamp: existing?.timestamp ?? spawnInfo?.timestamp ?? timestamp,
9289
+ timestamp: existing?.timestamp ?? spawnInfo?.timestamp ?? timestamp2,
9031
9290
  parentToolCallId: existing?.parentToolCallId ?? toolCall.id
9032
9291
  };
9033
9292
  agentRegistry.set(agentId, info);
9034
9293
  agentIdBySpawnCall.set(toolCall.id, agentId);
9035
9294
  if (info.agentPath) agentIdByPath.set(info.agentPath, agentId);
9036
- upsertAgentMessage(agentId, current, timestamp, { status: "running" });
9295
+ upsertAgentMessage(agentId, current, timestamp2, { status: "running" });
9037
9296
  }
9038
9297
  } catch {
9039
9298
  }
@@ -9056,11 +9315,11 @@ function walkCodexRecords(records, options) {
9056
9315
  message: "",
9057
9316
  model: null,
9058
9317
  agentType: null,
9059
- timestamp,
9318
+ timestamp: timestamp2,
9060
9319
  parentToolCallId: ""
9061
9320
  });
9062
9321
  }
9063
- upsertAgentMessage(agentId, current, timestamp, {
9322
+ upsertAgentMessage(agentId, current, timestamp2, {
9064
9323
  status: lifecycle,
9065
9324
  text: completedText || failedText || interruptedText || void 0
9066
9325
  });
@@ -9074,7 +9333,7 @@ function walkCodexRecords(records, options) {
9074
9333
  const name = typeof payload.name === "string" ? payload.name : "tool";
9075
9334
  const rawInput = typeof payload.input === "string" ? payload.input : "";
9076
9335
  const callId = payload.call_id;
9077
- const perFileCalls = rawInput ? parseCodexToolPatches(name, rawInput, callId, timestamp, metadata.cwd) : [];
9336
+ const perFileCalls = rawInput ? parseCodexToolPatches(name, rawInput, callId, timestamp2, metadata.cwd) : [];
9078
9337
  if (name !== "apply_patch") {
9079
9338
  const toolCall = {
9080
9339
  id: callId,
@@ -9082,14 +9341,14 @@ function walkCodexRecords(records, options) {
9082
9341
  input: parseToolInput(rawInput),
9083
9342
  result: null,
9084
9343
  isError: false,
9085
- timestamp
9344
+ timestamp: timestamp2
9086
9345
  };
9087
9346
  pendingToolCalls.set(toolCall.id, toolCall);
9088
- appendToolCall(current, toolCall, timestamp);
9347
+ appendToolCall(current, toolCall, timestamp2);
9089
9348
  }
9090
9349
  for (const tc of perFileCalls) {
9091
9350
  pendingToolCalls.set(tc.id, tc);
9092
- appendToolCall(current, tc, timestamp);
9351
+ appendToolCall(current, tc, timestamp2);
9093
9352
  }
9094
9353
  if (perFileCalls.length > 0) {
9095
9354
  patchCallIds.set(callId, {
@@ -9150,7 +9409,7 @@ function parseCodexSession(jsonlText, options) {
9150
9409
  return session;
9151
9410
  }
9152
9411
  function appendCodexSession(existing, newJsonlText) {
9153
- const prefix = existing.rawMessages.map((record2) => JSON.stringify(record2)).join("\n");
9412
+ const prefix = existing.rawMessages.map((record4) => JSON.stringify(record4)).join("\n");
9154
9413
  return parseCodexSession(prefix ? `${prefix}
9155
9414
  ${newJsonlText}` : newJsonlText);
9156
9415
  }
@@ -9345,16 +9604,16 @@ async function readCodexSessionIdentity(filePath) {
9345
9604
  let parentSessionId = null;
9346
9605
  let sawSessionMeta = false;
9347
9606
  for (const line of await readHeadLines(filePath, HEAD_BYTES)) {
9348
- let record2;
9607
+ let record4;
9349
9608
  try {
9350
- record2 = JSON.parse(line);
9609
+ record4 = JSON.parse(line);
9351
9610
  } catch {
9352
9611
  continue;
9353
9612
  }
9354
- if (!isRecord2(record2) || !isRecord2(record2.payload)) continue;
9355
- if (record2.type === "session_meta") {
9613
+ if (!isRecord2(record4) || !isRecord2(record4.payload)) continue;
9614
+ if (record4.type === "session_meta") {
9356
9615
  sawSessionMeta = true;
9357
- const payload = record2.payload;
9616
+ const payload = record4.payload;
9358
9617
  if (!sessionId && typeof payload.id === "string") sessionId = payload.id;
9359
9618
  if (!cwd && typeof payload.cwd === "string") cwd = payload.cwd;
9360
9619
  if (!parentSessionId && typeof payload.forked_from_id === "string") {
@@ -9364,8 +9623,8 @@ async function readCodexSessionIdentity(filePath) {
9364
9623
  if (source && isRecord2(source.subagent)) isSubagent = true;
9365
9624
  const git = isRecord2(payload.git) ? payload.git : null;
9366
9625
  if (!gitBranch && git && typeof git.branch === "string") gitBranch = git.branch;
9367
- } else if (record2.type === "turn_context") {
9368
- if (!cwd && typeof record2.payload.cwd === "string") cwd = record2.payload.cwd;
9626
+ } else if (record4.type === "turn_context") {
9627
+ if (!cwd && typeof record4.payload.cwd === "string") cwd = record4.payload.cwd;
9369
9628
  }
9370
9629
  }
9371
9630
  if (!sawSessionMeta || !cwd) return null;
@@ -9688,8 +9947,8 @@ function extractMetadata(events) {
9688
9947
  for (const event of events) {
9689
9948
  if (!isRootEvent(event)) continue;
9690
9949
  const { data } = event;
9691
- const timestamp = eventTimestamp(event);
9692
- if (timestamp) metadata.lastTimestamp = timestamp;
9950
+ const timestamp2 = eventTimestamp(event);
9951
+ if (timestamp2) metadata.lastTimestamp = timestamp2;
9693
9952
  if (event.type === "session.start") {
9694
9953
  metadata.sessionId ||= readString(data.sessionId);
9695
9954
  metadata.version ||= readString(data.copilotVersion) || (typeof data.version === "number" ? String(data.version) : readString(data.version));
@@ -9727,7 +9986,7 @@ function extractMetadata(events) {
9727
9986
  }
9728
9987
  if (event.type !== "user.message") continue;
9729
9988
  metadata.turnCount++;
9730
- metadata.timestamp ||= timestamp;
9989
+ metadata.timestamp ||= timestamp2;
9731
9990
  const content = readString(data.content).trim();
9732
9991
  if (!content) continue;
9733
9992
  metadata.firstUserMessage ||= content;
@@ -9951,7 +10210,7 @@ function extractToolResult(data) {
9951
10210
  if (result.structuredContent !== void 0) return safeStringify2(result.structuredContent);
9952
10211
  return safeStringify2(result);
9953
10212
  }
9954
- function appendThinking2(turn, text, timestamp, signature) {
10213
+ function appendThinking2(turn, text, timestamp2, signature) {
9955
10214
  if (!text || turn.thinking.some((block2) => block2.thinking === text)) return;
9956
10215
  const block = { type: "thinking", thinking: text, signature };
9957
10216
  turn.thinking.push(block);
@@ -9960,21 +10219,21 @@ function appendThinking2(turn, text, timestamp, signature) {
9960
10219
  last.blocks.push(block);
9961
10220
  return;
9962
10221
  }
9963
- turn.contentBlocks.push({ kind: "thinking", blocks: [block], timestamp });
10222
+ turn.contentBlocks.push({ kind: "thinking", blocks: [block], timestamp: timestamp2 });
9964
10223
  }
9965
- function appendToolCall2(turn, call, timestamp) {
10224
+ function appendToolCall2(turn, call, timestamp2) {
9966
10225
  turn.toolCalls.push(call);
9967
10226
  const last = turn.contentBlocks[turn.contentBlocks.length - 1];
9968
10227
  if (last?.kind === "tool_calls") {
9969
10228
  last.toolCalls.push(call);
9970
10229
  return;
9971
10230
  }
9972
- turn.contentBlocks.push({ kind: "tool_calls", toolCalls: [call], timestamp });
10231
+ turn.contentBlocks.push({ kind: "tool_calls", toolCalls: [call], timestamp: timestamp2 });
9973
10232
  }
9974
- function newToolCall(id, name, input, timestamp) {
9975
- return { id, name, input, result: null, isError: false, timestamp };
10233
+ function newToolCall(id, name, input, timestamp2) {
10234
+ return { id, name, input, result: null, isError: false, timestamp: timestamp2 };
9976
10235
  }
9977
- function toolCallsFromRequests(value, timestamp, isPending) {
10236
+ function toolCallsFromRequests(value, timestamp2, isPending) {
9978
10237
  if (!Array.isArray(value)) return [];
9979
10238
  const calls = [];
9980
10239
  for (const request of value) {
@@ -9983,14 +10242,14 @@ function toolCallsFromRequests(value, timestamp, isPending) {
9983
10242
  const rawName = readString(request.name);
9984
10243
  if (!id || !rawName || isPending(id)) continue;
9985
10244
  const name = normalizeToolName(rawName);
9986
- calls.push(newToolCall(id, name, normalizeToolInput(name, request.arguments), timestamp));
10245
+ calls.push(newToolCall(id, name, normalizeToolInput(name, request.arguments), timestamp2));
9987
10246
  }
9988
10247
  return calls;
9989
10248
  }
9990
- function updateToolCallStart(call, name, input, timestamp) {
10249
+ function updateToolCallStart(call, name, input, timestamp2) {
9991
10250
  call.name = name;
9992
10251
  call.input = normalizeToolInput(name, input);
9993
- call.timestamp = timestamp || call.timestamp;
10252
+ call.timestamp = timestamp2 || call.timestamp;
9994
10253
  }
9995
10254
  function updateToolCallResult(call, data, binaryAssets) {
9996
10255
  call.result = extractToolResult(data);
@@ -9998,7 +10257,7 @@ function updateToolCallResult(call, data, binaryAssets) {
9998
10257
  if (resultImages.length > 0) call.resultImages = resultImages;
9999
10258
  call.isError = data.success === false || data.error !== void 0 && data.error !== null;
10000
10259
  }
10001
- function createTurn2(id, timestamp, userMessage, model, effort, isFragment) {
10260
+ function createTurn2(id, timestamp2, userMessage, model, effort, isFragment) {
10002
10261
  return {
10003
10262
  id,
10004
10263
  userMessage,
@@ -10007,7 +10266,7 @@ function createTurn2(id, timestamp, userMessage, model, effort, isFragment) {
10007
10266
  assistantText: [],
10008
10267
  toolCalls: [],
10009
10268
  subAgentActivity: [],
10010
- timestamp,
10269
+ timestamp: timestamp2,
10011
10270
  durationMs: null,
10012
10271
  tokenUsage: null,
10013
10272
  model,
@@ -10034,8 +10293,8 @@ function parseCopilotSession(jsonlText, options) {
10034
10293
  let sawAssistantUsage = false;
10035
10294
  let sawAssistantDuration = false;
10036
10295
  let shutdownUsage = null;
10037
- function noteTimestamp(turn, timestamp) {
10038
- if (timestamp) endTimestamps.set(turn, timestamp);
10296
+ function noteTimestamp(turn, timestamp2) {
10297
+ if (timestamp2) endTimestamps.set(turn, timestamp2);
10039
10298
  }
10040
10299
  function ensureTurn(event) {
10041
10300
  if (!current) {
@@ -10096,7 +10355,7 @@ function parseCopilotSession(jsonlText, options) {
10096
10355
  const message = ensureAgent(event);
10097
10356
  if (!message) return true;
10098
10357
  const { data } = event;
10099
- const timestamp = eventTimestamp(event);
10358
+ const timestamp2 = eventTimestamp(event);
10100
10359
  if (event.type === "subagent.started" || event.type === "subagent.configured") {
10101
10360
  message.parentToolUseId ||= readString(data.toolCallId) || void 0;
10102
10361
  message.agentName = readString(data.agentDisplayName, data.agentName) || message.agentName;
@@ -10135,7 +10394,7 @@ function parseCopilotSession(jsonlText, options) {
10135
10394
  if (text && !message.text.includes(text)) message.text.push(text);
10136
10395
  for (const call of toolCallsFromRequests(
10137
10396
  data.toolRequests,
10138
- timestamp,
10397
+ timestamp2,
10139
10398
  (id) => pendingAgentToolCalls.has(id)
10140
10399
  )) {
10141
10400
  message.toolCalls.push(call);
@@ -10155,13 +10414,13 @@ function parseCopilotSession(jsonlText, options) {
10155
10414
  const name = normalizeToolName(rawName);
10156
10415
  const existing = pendingAgentToolCalls.get(callId);
10157
10416
  if (existing) {
10158
- updateToolCallStart(existing.call, name, data.arguments, timestamp);
10417
+ updateToolCallStart(existing.call, name, data.arguments, timestamp2);
10159
10418
  } else {
10160
10419
  const call = newToolCall(
10161
10420
  callId,
10162
10421
  name,
10163
10422
  normalizeToolInput(name, data.arguments),
10164
- timestamp
10423
+ timestamp2
10165
10424
  );
10166
10425
  message.toolCalls.push(call);
10167
10426
  pendingAgentToolCalls.set(callId, { call, message });
@@ -10174,7 +10433,7 @@ function parseCopilotSession(jsonlText, options) {
10174
10433
  if (!pending) {
10175
10434
  const rawName = readString(data.toolName) || "Tool";
10176
10435
  const name = normalizeToolName(rawName);
10177
- const call = newToolCall(callId, name, {}, timestamp);
10436
+ const call = newToolCall(callId, name, {}, timestamp2);
10178
10437
  message.toolCalls.push(call);
10179
10438
  pending = { call, message };
10180
10439
  }
@@ -10187,7 +10446,7 @@ function parseCopilotSession(jsonlText, options) {
10187
10446
  for (const event of events) {
10188
10447
  if (applyAgentEvent(event)) continue;
10189
10448
  const { data } = event;
10190
- const timestamp = eventTimestamp(event);
10449
+ const timestamp2 = eventTimestamp(event);
10191
10450
  if (event.type === "session.start" || event.type === "session.resume") {
10192
10451
  currentModel = readString(data.selectedModel) || currentModel;
10193
10452
  currentEffort = readString(data.reasoningEffort) || currentEffort;
@@ -10220,13 +10479,13 @@ function parseCopilotSession(jsonlText, options) {
10220
10479
  finalizeCurrent();
10221
10480
  current = createTurn2(
10222
10481
  turnEventId(event),
10223
- timestamp,
10482
+ timestamp2,
10224
10483
  buildUserContent(data, binaryAssets),
10225
10484
  currentModel,
10226
10485
  currentEffort,
10227
10486
  false
10228
10487
  );
10229
- noteTimestamp(current, timestamp);
10488
+ noteTimestamp(current, timestamp2);
10230
10489
  continue;
10231
10490
  }
10232
10491
  if (event.type === "assistant.turn_start") {
@@ -10234,7 +10493,7 @@ function parseCopilotSession(jsonlText, options) {
10234
10493
  const turn = ensureTurn(event);
10235
10494
  turn.model = currentModel;
10236
10495
  if (currentEffort) turn.effort = currentEffort;
10237
- noteTimestamp(turn, timestamp);
10496
+ noteTimestamp(turn, timestamp2);
10238
10497
  continue;
10239
10498
  }
10240
10499
  if (event.type === "assistant.reasoning") {
@@ -10242,10 +10501,10 @@ function parseCopilotSession(jsonlText, options) {
10242
10501
  appendThinking2(
10243
10502
  turn,
10244
10503
  readString(data.content),
10245
- timestamp,
10504
+ timestamp2,
10246
10505
  readString(data.reasoningId) || eventId(event, "copilot-thinking")
10247
10506
  );
10248
- noteTimestamp(turn, timestamp);
10507
+ noteTimestamp(turn, timestamp2);
10249
10508
  continue;
10250
10509
  }
10251
10510
  if (event.type === "assistant.message") {
@@ -10256,19 +10515,19 @@ function parseCopilotSession(jsonlText, options) {
10256
10515
  appendThinking2(
10257
10516
  turn,
10258
10517
  readString(data.reasoningText),
10259
- timestamp,
10518
+ timestamp2,
10260
10519
  eventId(event, "copilot-thinking")
10261
10520
  );
10262
- appendAssistantText(turn, textFromValue(data.content), timestamp);
10521
+ appendAssistantText(turn, textFromValue(data.content), timestamp2);
10263
10522
  for (const call of toolCallsFromRequests(
10264
10523
  data.toolRequests,
10265
- timestamp,
10524
+ timestamp2,
10266
10525
  (id) => pendingToolCalls.has(id)
10267
10526
  )) {
10268
- appendToolCall2(turn, call, timestamp);
10527
+ appendToolCall2(turn, call, timestamp2);
10269
10528
  pendingToolCalls.set(call.id, { call, turn });
10270
10529
  }
10271
- noteTimestamp(turn, timestamp);
10530
+ noteTimestamp(turn, timestamp2);
10272
10531
  continue;
10273
10532
  }
10274
10533
  if (event.type === "assistant.usage") {
@@ -10283,7 +10542,7 @@ function parseCopilotSession(jsonlText, options) {
10283
10542
  if (currentEffort) turn.effort = currentEffort;
10284
10543
  if (usage) turn.tokenUsage = mergeTokenUsage2(turn.tokenUsage, usage);
10285
10544
  if (duration) apiDurationMs.set(turn, (apiDurationMs.get(turn) ?? 0) + duration);
10286
- noteTimestamp(turn, timestamp);
10545
+ noteTimestamp(turn, timestamp2);
10287
10546
  continue;
10288
10547
  }
10289
10548
  if (event.type === "tool.execution_start") {
@@ -10295,18 +10554,18 @@ function parseCopilotSession(jsonlText, options) {
10295
10554
  const name = normalizeToolName(rawName);
10296
10555
  const existing = pendingToolCalls.get(callId);
10297
10556
  if (existing) {
10298
- updateToolCallStart(existing.call, name, data.arguments, timestamp);
10557
+ updateToolCallStart(existing.call, name, data.arguments, timestamp2);
10299
10558
  } else {
10300
10559
  const call = newToolCall(
10301
10560
  callId,
10302
10561
  name,
10303
10562
  normalizeToolInput(name, data.arguments),
10304
- timestamp
10563
+ timestamp2
10305
10564
  );
10306
- appendToolCall2(turn, call, timestamp);
10565
+ appendToolCall2(turn, call, timestamp2);
10307
10566
  pendingToolCalls.set(callId, { call, turn });
10308
10567
  }
10309
- noteTimestamp(turn, timestamp);
10568
+ noteTimestamp(turn, timestamp2);
10310
10569
  continue;
10311
10570
  }
10312
10571
  if (event.type === "tool.execution_complete") {
@@ -10317,13 +10576,13 @@ function parseCopilotSession(jsonlText, options) {
10317
10576
  const turn = ensureTurn(event);
10318
10577
  const rawName = readString(data.toolName) || "Tool";
10319
10578
  const name = normalizeToolName(rawName);
10320
- const call = newToolCall(callId, name, {}, timestamp);
10321
- appendToolCall2(turn, call, timestamp);
10579
+ const call = newToolCall(callId, name, {}, timestamp2);
10580
+ appendToolCall2(turn, call, timestamp2);
10322
10581
  pending = { call, turn };
10323
10582
  }
10324
10583
  updateToolCallResult(pending.call, data, binaryAssets);
10325
10584
  pendingToolCalls.delete(callId);
10326
- noteTimestamp(pending.turn, timestamp);
10585
+ noteTimestamp(pending.turn, timestamp2);
10327
10586
  continue;
10328
10587
  }
10329
10588
  if (event.type === "session.error") {
@@ -10338,13 +10597,13 @@ function parseCopilotSession(jsonlText, options) {
10338
10597
  input,
10339
10598
  result: readString(data.message) || "Copilot session error",
10340
10599
  isError: true,
10341
- timestamp
10342
- }, timestamp);
10343
- noteTimestamp(turn, timestamp);
10600
+ timestamp: timestamp2
10601
+ }, timestamp2);
10602
+ noteTimestamp(turn, timestamp2);
10344
10603
  continue;
10345
10604
  }
10346
10605
  if (event.type === "assistant.turn_end" || event.type === "assistant.idle" || event.type === "session.idle") {
10347
- if (current) noteTimestamp(current, timestamp);
10606
+ if (current) noteTimestamp(current, timestamp2);
10348
10607
  }
10349
10608
  }
10350
10609
  finalizeCurrent();
@@ -10387,7 +10646,7 @@ function parseCopilotSession(jsonlText, options) {
10387
10646
  };
10388
10647
  }
10389
10648
  function appendCopilotSession(existing, newJsonlText) {
10390
- const prefix = existing.rawMessages.map((record2) => JSON.stringify(record2)).join("\n");
10649
+ const prefix = existing.rawMessages.map((record4) => JSON.stringify(record4)).join("\n");
10391
10650
  return parseCopilotSession(prefix ? `${prefix}
10392
10651
  ${newJsonlText}` : newJsonlText);
10393
10652
  }
@@ -10495,11 +10754,11 @@ function brandCopilotBranch() {
10495
10754
  function copilotTurnBoundaries(records) {
10496
10755
  const boundaries = [];
10497
10756
  for (let index = 0; index < records.length; index++) {
10498
- const record2 = records[index];
10499
- if (record2.type !== "user.message" || typeof record2.agentId === "string") continue;
10500
- const data = record2.data;
10757
+ const record4 = records[index];
10758
+ if (record4.type !== "user.message" || typeof record4.agentId === "string") continue;
10759
+ const data = record4.data;
10501
10760
  if (!data || typeof data !== "object" || Array.isArray(data)) continue;
10502
- if (typeof record2.id !== "string" || !record2.id) continue;
10761
+ if (typeof record4.id !== "string" || !record4.id) continue;
10503
10762
  boundaries.push(index);
10504
10763
  }
10505
10764
  return boundaries;
@@ -10556,14 +10815,14 @@ async function readCopilotSessionIdentity(filePath) {
10556
10815
  let cwd = "";
10557
10816
  let gitBranch = "";
10558
10817
  for (const line of await readHeadLines(filePath, HEAD_BYTES)) {
10559
- let record2;
10818
+ let record4;
10560
10819
  try {
10561
- record2 = JSON.parse(line);
10820
+ record4 = JSON.parse(line);
10562
10821
  } catch {
10563
10822
  continue;
10564
10823
  }
10565
- if (!isRecord3(record2) || record2.type !== "session.start" && record2.type !== "session.resume") continue;
10566
- const data = isRecord3(record2.data) ? record2.data : null;
10824
+ if (!isRecord3(record4) || record4.type !== "session.start" && record4.type !== "session.resume") continue;
10825
+ const data = isRecord3(record4.data) ? record4.data : null;
10567
10826
  if (!data) continue;
10568
10827
  if (typeof data.sessionId === "string" && data.sessionId) sessionId = data.sessionId;
10569
10828
  const context = isRecord3(data.context) ? data.context : null;
@@ -10883,7 +11142,7 @@ function groupPlanModeBlocks(blocks) {
10883
11142
  if (enterIdx !== -1) {
10884
11143
  const enterCall = block.toolCalls[enterIdx];
10885
11144
  const plan = String(enterCall.input.plan ?? "");
10886
- const timestamp = block.timestamp;
11145
+ const timestamp2 = block.timestamp;
10887
11146
  const before = block.toolCalls.slice(0, enterIdx);
10888
11147
  if (before.length > 0) {
10889
11148
  result.push({ kind: "tool_calls", toolCalls: before, timestamp: block.timestamp });
@@ -10899,7 +11158,7 @@ function groupPlanModeBlocks(blocks) {
10899
11158
  if (exitCall.result !== null) {
10900
11159
  status = exitCall.isError ? "rejected" : "approved";
10901
11160
  }
10902
- result.push({ kind: "plan_mode", plan, planFilePath, status, toolCalls: embedded, timestamp });
11161
+ result.push({ kind: "plan_mode", plan, planFilePath, status, toolCalls: embedded, timestamp: timestamp2 });
10903
11162
  const after = afterEnterInSameBlock.slice(exitInSameBlock + 1);
10904
11163
  if (after.length > 0) {
10905
11164
  result.push({ kind: "tool_calls", toolCalls: after, timestamp: block.timestamp });
@@ -10925,7 +11184,7 @@ function groupPlanModeBlocks(blocks) {
10925
11184
  status = exitCall.isError ? "rejected" : "approved";
10926
11185
  }
10927
11186
  const tail = next.toolCalls.slice(exitIdx + 1);
10928
- result.push({ kind: "plan_mode", plan, planFilePath, status, toolCalls: embedded, timestamp });
11187
+ result.push({ kind: "plan_mode", plan, planFilePath, status, toolCalls: embedded, timestamp: timestamp2 });
10929
11188
  result.push(...passthroughBlocks);
10930
11189
  if (tail.length > 0) {
10931
11190
  result.push({ kind: "tool_calls", toolCalls: tail, timestamp: next.timestamp });
@@ -10944,7 +11203,7 @@ function groupPlanModeBlocks(blocks) {
10944
11203
  }
10945
11204
  }
10946
11205
  if (!exitCall) {
10947
- result.push({ kind: "plan_mode", plan, planFilePath: void 0, status: "pending", toolCalls: embedded, timestamp });
11206
+ result.push({ kind: "plan_mode", plan, planFilePath: void 0, status: "pending", toolCalls: embedded, timestamp: timestamp2 });
10948
11207
  result.push(...passthroughBlocks);
10949
11208
  i = j;
10950
11209
  }
@@ -11926,9 +12185,9 @@ function nonEmpty(value) {
11926
12185
  function stripTaggedBlocks(text) {
11927
12186
  return text.replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g, "").trim();
11928
12187
  }
11929
- function effortFromRecord(record2) {
12188
+ function effortFromRecord(record4) {
11930
12189
  for (const kind of AGENT_KINDS) {
11931
- const effort = READERS[kind].effort(record2);
12190
+ const effort = READERS[kind].effort(record4);
11932
12191
  if (effort) return effort;
11933
12192
  }
11934
12193
  return null;
@@ -11938,15 +12197,15 @@ function userMessageTextFromLine(line) {
11938
12197
  (kind) => READERS[kind].userMessageMarkers.some((marker) => line.includes(marker))
11939
12198
  );
11940
12199
  if (candidates.length === 0) return null;
11941
- let record2;
12200
+ let record4;
11942
12201
  try {
11943
- record2 = JSON.parse(line);
12202
+ record4 = JSON.parse(line);
11944
12203
  } catch {
11945
12204
  return null;
11946
12205
  }
11947
- if (!isRecord4(record2)) return null;
12206
+ if (!isRecord4(record4)) return null;
11948
12207
  for (const kind of candidates) {
11949
- const text = READERS[kind].userMessageText(record2);
12208
+ const text = READERS[kind].userMessageText(record4);
11950
12209
  if (text !== null) return text;
11951
12210
  }
11952
12211
  return null;
@@ -11958,11 +12217,11 @@ var init_recordReaders = __esm({
11958
12217
  claudeReader = {
11959
12218
  kind: "claude",
11960
12219
  // Every assistant record is tagged with the effort that turn ran at.
11961
- effort: (record2) => record2.type === "assistant" ? nonEmpty(record2.effort) : null,
12220
+ effort: (record4) => record4.type === "assistant" ? nonEmpty(record4.effort) : null,
11962
12221
  userMessageMarkers: ['"user"'],
11963
- userMessageText(record2) {
11964
- if (record2.type !== "user" || record2.isMeta) return null;
11965
- const content = isRecord4(record2.message) ? record2.message.content : void 0;
12222
+ userMessageText(record4) {
12223
+ if (record4.type !== "user" || record4.isMeta) return null;
12224
+ const content = isRecord4(record4.message) ? record4.message.content : void 0;
11966
12225
  if (typeof content === "string") return stripTaggedBlocks(content);
11967
12226
  if (!Array.isArray(content)) return "";
11968
12227
  let text = "";
@@ -11977,32 +12236,32 @@ var init_recordReaders = __esm({
11977
12236
  codexReader = {
11978
12237
  kind: "codex",
11979
12238
  // Effort is recorded per turn; newer CLI versions moved it under `thread_settings`.
11980
- effort(record2) {
11981
- if (record2.type !== "turn_context" || !isRecord4(record2.payload)) return null;
11982
- const { payload } = record2;
12239
+ effort(record4) {
12240
+ if (record4.type !== "turn_context" || !isRecord4(record4.payload)) return null;
12241
+ const { payload } = record4;
11983
12242
  const direct = nonEmpty(payload.effort);
11984
12243
  if (direct) return direct;
11985
12244
  const settings = isRecord4(payload.thread_settings) ? payload.thread_settings : null;
11986
12245
  return nonEmpty(settings?.reasoning_effort);
11987
12246
  },
11988
12247
  userMessageMarkers: ['"event_msg"'],
11989
- userMessageText(record2) {
11990
- if (record2.type !== "event_msg" || !isRecord4(record2.payload)) return null;
11991
- const { payload } = record2;
12248
+ userMessageText(record4) {
12249
+ if (record4.type !== "event_msg" || !isRecord4(record4.payload)) return null;
12250
+ const { payload } = record4;
11992
12251
  return payload.type === "user_message" && typeof payload.message === "string" ? payload.message.trim() : null;
11993
12252
  }
11994
12253
  };
11995
12254
  copilotReader = {
11996
12255
  kind: "copilot",
11997
- effort(record2) {
11998
- if (record2.type !== "session.start" && record2.type !== "session.resume" && record2.type !== "session.model_change" || !isRecord4(record2.data)) return null;
11999
- return nonEmpty(record2.data.reasoningEffort ?? record2.data.effort);
12256
+ effort(record4) {
12257
+ if (record4.type !== "session.start" && record4.type !== "session.resume" && record4.type !== "session.model_change" || !isRecord4(record4.data)) return null;
12258
+ return nonEmpty(record4.data.reasoningEffort ?? record4.data.effort);
12000
12259
  },
12001
12260
  userMessageMarkers: ['"user.message"'],
12002
- userMessageText(record2) {
12003
- if (record2.type !== "user.message") return null;
12004
- if (typeof record2.agentId === "string" && record2.agentId) return null;
12005
- const data = isRecord4(record2.data) ? record2.data : null;
12261
+ userMessageText(record4) {
12262
+ if (record4.type !== "user.message") return null;
12263
+ if (typeof record4.agentId === "string" && record4.agentId) return null;
12264
+ const data = isRecord4(record4.data) ? record4.data : null;
12006
12265
  return typeof data?.content === "string" ? data.content.trim() : "";
12007
12266
  }
12008
12267
  };
@@ -12015,16 +12274,16 @@ var init_recordReaders = __esm({
12015
12274
  });
12016
12275
 
12017
12276
  // ../../server/agents/tailRecords.ts
12018
- function isSubagentLifecycle(record2) {
12019
- return record2.type.startsWith("subagent.") && typeof record2.agentId === "string" && record2.agentId.length > 0;
12277
+ function isSubagentLifecycle(record4) {
12278
+ return record4.type.startsWith("subagent.") && typeof record4.agentId === "string" && record4.agentId.length > 0;
12020
12279
  }
12021
- function isSubagentNoise(record2) {
12022
- return typeof record2.agentId === "string" && record2.agentId.length > 0;
12280
+ function isSubagentNoise(record4) {
12281
+ return typeof record4.agentId === "string" && record4.agentId.length > 0;
12023
12282
  }
12024
- function classifyTailRecord(record2) {
12283
+ function classifyTailRecord(record4) {
12025
12284
  for (const kind of AGENT_KINDS) {
12026
12285
  const format = TAIL_FORMATS[kind];
12027
- const verdict = format.classify(record2);
12286
+ const verdict = format.classify(record4);
12028
12287
  if (verdict.kind !== "ignore") return { format, verdict };
12029
12288
  }
12030
12289
  return null;
@@ -12041,31 +12300,31 @@ var init_tailRecords = __esm({
12041
12300
  // Background agent/workflow launches, task notifications and TaskStop calls
12042
12301
  // can all still change a verdict that a turn-ending line looked to settle.
12043
12302
  markers: ["async_launched", "task-notification", '"TaskStop"'],
12044
- classify(record2) {
12045
- if (record2.type === "system" && record2.subtype === "terminal_reason") {
12046
- const reason = record2.reason;
12303
+ classify(record4) {
12304
+ if (record4.type === "system" && record4.subtype === "terminal_reason") {
12305
+ const reason = record4.reason;
12047
12306
  return reason ? { kind: "final", status: { status: "completed", terminalReason: reason } } : IGNORE;
12048
12307
  }
12049
- if (record2.type === "progress") {
12050
- const data = record2.data;
12308
+ if (record4.type === "progress") {
12309
+ const data = record4.data;
12051
12310
  if (data?.type !== "hook_progress") return IGNORE;
12052
12311
  const decision = data.decision ?? data.hookSpecificOutput?.permissionDecision;
12053
12312
  return decision === "defer" ? ANSWER : IGNORE;
12054
12313
  }
12055
- if (record2.type === "attachment") return KEEP;
12056
- if (record2.type === "assistant" || record2.type === "user" || record2.type === "queue-operation") {
12057
- const stopReason = record2.message?.stop_reason;
12058
- if (record2.type === "assistant" && stopReason === "end_turn") {
12314
+ if (record4.type === "attachment") return KEEP;
12315
+ if (record4.type === "assistant" || record4.type === "user" || record4.type === "queue-operation") {
12316
+ const stopReason = record4.message?.stop_reason;
12317
+ if (record4.type === "assistant" && stopReason === "end_turn") {
12059
12318
  return { kind: "turn-end", awaitUserActivity: true };
12060
12319
  }
12061
- const canDerive = record2.type === "assistant" || record2.type === "user" && !record2.isMeta;
12320
+ const canDerive = record4.type === "assistant" || record4.type === "user" && !record4.isMeta;
12062
12321
  return canDerive ? ANSWER : KEEP;
12063
12322
  }
12064
12323
  return IGNORE;
12065
12324
  },
12066
- classifyAfterTurnEnd(record2) {
12067
- if (record2.type !== "user" && record2.type !== "assistant" && record2.type !== "queue-operation" && record2.type !== "attachment") return IGNORE;
12068
- const isRealUserTurn = record2.type === "user" && !record2.isMeta;
12325
+ classifyAfterTurnEnd(record4) {
12326
+ if (record4.type !== "user" && record4.type !== "assistant" && record4.type !== "queue-operation" && record4.type !== "attachment") return IGNORE;
12327
+ const isRealUserTurn = record4.type === "user" && !record4.isMeta;
12069
12328
  return { kind: "keep", sawUserActivity: isRealUserTurn };
12070
12329
  }
12071
12330
  };
@@ -12084,9 +12343,9 @@ var init_tailRecords = __esm({
12084
12343
  "agent_message",
12085
12344
  "function_call_output"
12086
12345
  ],
12087
- classify(record2) {
12088
- if (record2.type === "event_msg") {
12089
- const payload = record2.payload;
12346
+ classify(record4) {
12347
+ if (record4.type === "event_msg") {
12348
+ const payload = record4.payload;
12090
12349
  switch (payload?.type) {
12091
12350
  case "task_complete":
12092
12351
  return { kind: "turn-end" };
@@ -12098,32 +12357,32 @@ var init_tailRecords = __esm({
12098
12357
  return IGNORE;
12099
12358
  }
12100
12359
  }
12101
- if (record2.type === "response_item") {
12102
- const payload = record2.payload;
12360
+ if (record4.type === "response_item") {
12361
+ const payload = record4.payload;
12103
12362
  const decides = payload?.type === "function_call" || payload?.type === "message" && (payload.role === "assistant" || payload.role === "user");
12104
12363
  return decides ? ANSWER : IGNORE;
12105
12364
  }
12106
12365
  return IGNORE;
12107
12366
  },
12108
- classifyAfterTurnEnd(record2) {
12109
- return record2.type === "event_msg" || record2.type === "response_item" ? KEEP : IGNORE;
12367
+ classifyAfterTurnEnd(record4) {
12368
+ return record4.type === "event_msg" || record4.type === "response_item" ? KEEP : IGNORE;
12110
12369
  }
12111
12370
  };
12112
12371
  copilotTail = {
12113
12372
  kind: "copilot",
12114
12373
  markers: ['"abort"', '"assistant.message"', '"user.message"', '"subagent.'],
12115
- classify(record2) {
12116
- if (isSubagentLifecycle(record2)) return KEEP;
12117
- const decidable = record2.type === "abort" || record2.type === "user.message" || record2.type.startsWith("assistant.") || record2.type.startsWith("permission.") || record2.type.startsWith("session.") || record2.type.startsWith("tool.") || record2.type.startsWith("user_input.");
12118
- if (!decidable || isSubagentNoise(record2)) return IGNORE;
12119
- if (record2.type === "assistant.turn_end") return { kind: "turn-end" };
12120
- if (record2.type === "session.start" || record2.type === "session.resume") return ANSWER;
12374
+ classify(record4) {
12375
+ if (isSubagentLifecycle(record4)) return KEEP;
12376
+ const decidable = record4.type === "abort" || record4.type === "user.message" || record4.type.startsWith("assistant.") || record4.type.startsWith("permission.") || record4.type.startsWith("session.") || record4.type.startsWith("tool.") || record4.type.startsWith("user_input.");
12377
+ if (!decidable || isSubagentNoise(record4)) return IGNORE;
12378
+ if (record4.type === "assistant.turn_end") return { kind: "turn-end" };
12379
+ if (record4.type === "session.start" || record4.type === "session.resume") return ANSWER;
12121
12380
  return { kind: "answer-if-active" };
12122
12381
  },
12123
- classifyAfterTurnEnd(record2) {
12124
- if (isSubagentLifecycle(record2)) return KEEP;
12125
- if (isSubagentNoise(record2)) return IGNORE;
12126
- const decides = record2.type === "abort" || record2.type === "assistant.message" || record2.type === "user.message";
12382
+ classifyAfterTurnEnd(record4) {
12383
+ if (isSubagentLifecycle(record4)) return KEEP;
12384
+ if (isSubagentNoise(record4)) return IGNORE;
12385
+ const decides = record4.type === "abort" || record4.type === "assistant.message" || record4.type === "user.message";
12127
12386
  return decides ? ANSWER : IGNORE;
12128
12387
  }
12129
12388
  };
@@ -12178,14 +12437,14 @@ async function readTranscriptEffort(filePath) {
12178
12437
  for (let i = lines.length - 1; i >= 0; i--) {
12179
12438
  const line = lines[i];
12180
12439
  if (!line || !line.includes("effort") && !line.includes("Effort")) continue;
12181
- let record2;
12440
+ let record4;
12182
12441
  try {
12183
- record2 = JSON.parse(line);
12442
+ record4 = JSON.parse(line);
12184
12443
  } catch {
12185
12444
  continue;
12186
12445
  }
12187
- if (typeof record2 !== "object" || record2 === null) continue;
12188
- const effort = effortFromRecord(record2);
12446
+ if (typeof record4 !== "object" || record4 === null) continue;
12447
+ const effort = effortFromRecord(record4);
12189
12448
  if (effort) return effort;
12190
12449
  }
12191
12450
  }
@@ -12221,14 +12480,14 @@ async function getSessionStatus(filePath) {
12221
12480
  const line = lines[i];
12222
12481
  if (!line) continue;
12223
12482
  if (turnEnded && !isTailCandidate(line, turnEnded)) continue;
12224
- let record2;
12483
+ let record4;
12225
12484
  try {
12226
- record2 = JSON.parse(line);
12485
+ record4 = JSON.parse(line);
12227
12486
  } catch {
12228
12487
  continue;
12229
12488
  }
12230
- if (typeof record2?.type !== "string") continue;
12231
- const match = turnEnded ? { format: turnEnded, verdict: turnEnded.classifyAfterTurnEnd(record2) } : classifyTailRecord(record2);
12489
+ if (typeof record4?.type !== "string") continue;
12490
+ const match = turnEnded ? { format: turnEnded, verdict: turnEnded.classifyAfterTurnEnd(record4) } : classifyTailRecord(record4);
12232
12491
  if (!match) continue;
12233
12492
  const { verdict } = match;
12234
12493
  switch (verdict.kind) {
@@ -12237,20 +12496,20 @@ async function getSessionStatus(filePath) {
12237
12496
  case "final":
12238
12497
  return verdict.status;
12239
12498
  case "keep":
12240
- meaningful.unshift(record2);
12499
+ meaningful.unshift(record4);
12241
12500
  if (verdict.sawUserActivity) needUserActivity = false;
12242
12501
  continue;
12243
12502
  case "answer":
12244
- meaningful.unshift(record2);
12503
+ meaningful.unshift(record4);
12245
12504
  return deriveSessionStatus(meaningful);
12246
12505
  case "answer-if-active": {
12247
- meaningful.unshift(record2);
12506
+ meaningful.unshift(record4);
12248
12507
  const status = deriveSessionStatus(meaningful);
12249
12508
  if (status.status !== "idle") return status;
12250
12509
  continue;
12251
12510
  }
12252
12511
  case "turn-end":
12253
- meaningful.unshift(record2);
12512
+ meaningful.unshift(record4);
12254
12513
  turnEnded = match.format;
12255
12514
  needUserActivity = verdict.awaitUserActivity === true;
12256
12515
  continue;
@@ -12352,7 +12611,7 @@ var init_sessionPaths = __esm({
12352
12611
  });
12353
12612
 
12354
12613
  // ../../server/helpers.ts
12355
- import { spawn } from "node:child_process";
12614
+ import { spawn as spawn2 } from "node:child_process";
12356
12615
  import { homedir as homedir4 } from "node:os";
12357
12616
  import { randomUUID as randomUUID2 } from "node:crypto";
12358
12617
  import { createInterface } from "node:readline";
@@ -12395,12 +12654,12 @@ var init_modelCatalog = __esm({
12395
12654
 
12396
12655
  // ../../server/agents/timeout.ts
12397
12656
  function withTimeout(promise, ms, label) {
12398
- return new Promise((resolve21, reject) => {
12657
+ return new Promise((resolve22, reject) => {
12399
12658
  const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
12400
12659
  promise.then(
12401
12660
  (value) => {
12402
12661
  clearTimeout(timer);
12403
- resolve21(value);
12662
+ resolve22(value);
12404
12663
  },
12405
12664
  (error) => {
12406
12665
  clearTimeout(timer);
@@ -12525,7 +12784,7 @@ async function fetchClaudeModels() {
12525
12784
  }
12526
12785
  var init_claudeModels = __esm({
12527
12786
  "../../server/agents/claudeModels.ts"() {
12528
- init_sdk_session();
12787
+ init_claudeExecutable();
12529
12788
  init_modelCatalog();
12530
12789
  init_timeout();
12531
12790
  init_model_names();
@@ -12603,7 +12862,7 @@ async function awaitTranscript(filePath, isSettled) {
12603
12862
  return true;
12604
12863
  } catch {
12605
12864
  }
12606
- await new Promise((resolve21) => setTimeout(resolve21, TRANSCRIPT_POLL_INTERVAL_MS));
12865
+ await new Promise((resolve22) => setTimeout(resolve22, TRANSCRIPT_POLL_INTERVAL_MS));
12607
12866
  }
12608
12867
  return false;
12609
12868
  }
@@ -12634,7 +12893,7 @@ function startOneShot(req) {
12634
12893
  ]);
12635
12894
  const cleanEnv = { ...process.env };
12636
12895
  delete cleanEnv.CLAUDECODE;
12637
- const child = spawn(cli.command, cli.args, {
12896
+ const child = spawn2(cli.command, cli.args, {
12638
12897
  cwd: req.cwd,
12639
12898
  env: cleanEnv,
12640
12899
  stdio: ["ignore", "pipe", "pipe"],
@@ -12650,7 +12909,7 @@ function startOneShot(req) {
12650
12909
  child.on("close", () => {
12651
12910
  activeProcesses.delete(sessionId);
12652
12911
  });
12653
- return new Promise((resolve21, reject) => {
12912
+ return new Promise((resolve22, reject) => {
12654
12913
  let settled = false;
12655
12914
  const fail = (message) => {
12656
12915
  if (settled) return;
@@ -12672,7 +12931,7 @@ function startOneShot(req) {
12672
12931
  await stat7(filePath);
12673
12932
  settled = true;
12674
12933
  clearTimeout(timer);
12675
- resolve21({ sessionId, dirName: req.dirName, fileName, filePath });
12934
+ resolve22({ sessionId, dirName: req.dirName, fileName, filePath });
12676
12935
  } catch {
12677
12936
  fail(
12678
12937
  stderr.trim() || `${descriptor4.binName} exited with code ${code} before creating session`
@@ -12702,7 +12961,7 @@ function startInteractive(req) {
12702
12961
  worktreeName: req.worktreeName,
12703
12962
  mcpConfig: req.mcpConfig
12704
12963
  });
12705
- return new Promise((resolve21, reject) => {
12964
+ return new Promise((resolve22, reject) => {
12706
12965
  let settled = false;
12707
12966
  const succeed = async () => {
12708
12967
  if (settled) return;
@@ -12712,7 +12971,7 @@ function startInteractive(req) {
12712
12971
  initialContent = await readFile9(filePath, "utf-8");
12713
12972
  } catch {
12714
12973
  }
12715
- resolve21({ sessionId, dirName: req.dirName, fileName, filePath, initialContent });
12974
+ resolve22({ sessionId, dirName: req.dirName, fileName, filePath, initialContent });
12716
12975
  };
12717
12976
  const fail = (message) => {
12718
12977
  if (settled) return;
@@ -12795,6 +13054,7 @@ var init_claudeRuntime = __esm({
12795
13054
  "../../server/agents/claudeRuntime.ts"() {
12796
13055
  init_agent_descriptors();
12797
13056
  init_helpers();
13057
+ init_claudeExecutable();
12798
13058
  init_claudeModels();
12799
13059
  init_spawnError();
12800
13060
  init_binaryResolver();
@@ -12852,10 +13112,10 @@ var init_claudeRuntime = __esm({
12852
13112
  mcpConfig: req.mcpConfig
12853
13113
  });
12854
13114
  watchSubagentsFor(state, req.filePath ?? null);
12855
- const completion = new Promise((resolve21) => {
13115
+ const completion = new Promise((resolve22) => {
12856
13116
  state.onResult = (result) => {
12857
13117
  state.onResult = null;
12858
- resolve21(turnResultFrom(result));
13118
+ resolve22(turnResultFrom(result));
12859
13119
  };
12860
13120
  });
12861
13121
  return { delivery: "started", completion };
@@ -12941,7 +13201,7 @@ var init_package = __esm({
12941
13201
  package_default = {
12942
13202
  name: "cogpit",
12943
13203
  private: true,
12944
- version: "2.1.3",
13204
+ version: "2.3.0",
12945
13205
  description: "Control center for Claude Code, OpenAI Codex, and GitHub Copilot CLI sessions",
12946
13206
  license: "MIT",
12947
13207
  author: {
@@ -13051,11 +13311,11 @@ var init_package = __esm({
13051
13311
  overrides: {
13052
13312
  "@babel/core": "7.29.7",
13053
13313
  "@hono/node-server": "1.19.15",
13054
- "@xmldom/xmldom": "0.8.13",
13314
+ "@xmldom/xmldom": "0.8.15",
13055
13315
  "app-builder-lib": "26.15.3",
13056
13316
  "body-parser": "2.3.0",
13057
13317
  "builder-util-runtime": "9.7.0",
13058
- "fast-uri": "3.1.5",
13318
+ "fast-uri": "4.1.4",
13059
13319
  flatted: "3.4.2",
13060
13320
  "form-data": "4.0.6",
13061
13321
  hono: "4.13.1",
@@ -13064,7 +13324,7 @@ var init_package = __esm({
13064
13324
  lodash: "4.18.1",
13065
13325
  nanoid: "3.3.18",
13066
13326
  postcss: "8.5.26",
13067
- qs: "6.15.3",
13327
+ qs: "6.16.0",
13068
13328
  tar: "7.5.21",
13069
13329
  tmp: "0.2.7",
13070
13330
  undici: "7.29.0"
@@ -13169,109 +13429,14 @@ function forwardCodexStreamNotification(notification) {
13169
13429
  // stale overlay behind.
13170
13430
  case "turn/started":
13171
13431
  case "turn/completed":
13172
- case "thread/closed":
13173
- clear(threadId);
13174
- return;
13175
- }
13176
- }
13177
- var init_codexStreamAdapter = __esm({
13178
- "../../server/lib/codexStreamAdapter.ts"() {
13179
- init_streamBus();
13180
- }
13181
- });
13182
-
13183
- // ../../shared/versions.ts
13184
- function parseVersion(raw) {
13185
- const match = raw.trim().replace(/^v/i, "").match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/);
13186
- if (!match) return null;
13187
- return {
13188
- parts: [Number(match[1]), Number(match[2]), Number(match[3])],
13189
- prerelease: match[4] ? match[4].split(".") : []
13190
- };
13191
- }
13192
- function extractVersion(output) {
13193
- const match = output.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/);
13194
- return match ? match[0] : null;
13195
- }
13196
- function comparePrerelease(a, b) {
13197
- if (a.length === 0 && b.length === 0) return 0;
13198
- if (a.length === 0) return 1;
13199
- if (b.length === 0) return -1;
13200
- for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
13201
- const left = a[i];
13202
- const right = b[i];
13203
- if (left === void 0) return -1;
13204
- if (right === void 0) return 1;
13205
- const leftNumeric = /^\d+$/.test(left);
13206
- const rightNumeric = /^\d+$/.test(right);
13207
- if (leftNumeric && rightNumeric) {
13208
- if (Number(left) !== Number(right)) return Number(left) < Number(right) ? -1 : 1;
13209
- continue;
13210
- }
13211
- if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1;
13212
- if (left !== right) return left < right ? -1 : 1;
13213
- }
13214
- return 0;
13215
- }
13216
- function compareVersions(a, b) {
13217
- const left = parseVersion(a);
13218
- const right = parseVersion(b);
13219
- if (!left || !right) return null;
13220
- for (let i = 0; i < 3; i += 1) {
13221
- if (left.parts[i] !== right.parts[i]) return left.parts[i] < right.parts[i] ? -1 : 1;
13222
- }
13223
- return comparePrerelease(left.prerelease, right.prerelease);
13224
- }
13225
- var init_versions = __esm({
13226
- "../../shared/versions.ts"() {
13227
- }
13228
- });
13229
-
13230
- // ../../server/lib/cliProcess.ts
13231
- import { spawn as spawn2 } from "node:child_process";
13232
- function runCli(executable, args, timeoutMs) {
13233
- return new Promise((resolve21) => {
13234
- const resolved = resolveAgentCommand(executable, [...args]);
13235
- const child = spawn2(resolved.command, resolved.args, {
13236
- stdio: ["ignore", "pipe", "pipe"],
13237
- ...resolved.spawnOptions
13238
- });
13239
- let stdout = "";
13240
- let stderr = "";
13241
- let timedOut = false;
13242
- const timer = setTimeout(() => {
13243
- timedOut = true;
13244
- child.kill("SIGKILL");
13245
- }, timeoutMs);
13246
- const append = (buffer, chunk) => buffer.length >= CLI_OUTPUT_MAX_CHARS ? buffer : buffer + chunk.toString();
13247
- child.stdout?.on("data", (chunk) => {
13248
- stdout = append(stdout, chunk);
13249
- });
13250
- child.stderr?.on("data", (chunk) => {
13251
- stderr = append(stderr, chunk);
13252
- });
13253
- child.on("error", () => {
13254
- clearTimeout(timer);
13255
- resolve21({ code: null, stdout, stderr, timedOut });
13256
- });
13257
- child.on("close", (code) => {
13258
- clearTimeout(timer);
13259
- resolve21({ code, stdout, stderr, timedOut });
13260
- });
13261
- });
13262
- }
13263
- async function probeCliVersion(command, versionArgs, timeoutMs = DEFAULT_PROBE_TIMEOUT_MS) {
13264
- const probe = await runCli(command, versionArgs, timeoutMs);
13265
- return extractVersion(`${probe.stdout}
13266
- ${probe.stderr}`);
13267
- }
13268
- var DEFAULT_PROBE_TIMEOUT_MS, CLI_OUTPUT_MAX_CHARS;
13269
- var init_cliProcess = __esm({
13270
- "../../server/lib/cliProcess.ts"() {
13271
- init_versions();
13272
- init_binaryResolver();
13273
- DEFAULT_PROBE_TIMEOUT_MS = 5e3;
13274
- CLI_OUTPUT_MAX_CHARS = 1e4;
13432
+ case "thread/closed":
13433
+ clear(threadId);
13434
+ return;
13435
+ }
13436
+ }
13437
+ var init_codexStreamAdapter = __esm({
13438
+ "../../server/lib/codexStreamAdapter.ts"() {
13439
+ init_streamBus();
13275
13440
  }
13276
13441
  });
13277
13442
 
@@ -13908,7 +14073,7 @@ var init_codexAppServer = __esm({
13908
14073
  );
13909
14074
  }
13910
14075
  const id = this.nextRequestId++;
13911
- return new Promise((resolve21, reject) => {
14076
+ return new Promise((resolve22, reject) => {
13912
14077
  const timer = timeoutMs > 0 ? this.setTimer(() => {
13913
14078
  const pending = this.pendingRequests.get(id);
13914
14079
  if (!pending) return;
@@ -13921,7 +14086,7 @@ var init_codexAppServer = __esm({
13921
14086
  }, timeoutMs) : null;
13922
14087
  this.pendingRequests.set(id, {
13923
14088
  method,
13924
- resolve: (result) => resolve21(result),
14089
+ resolve: (result) => resolve22(result),
13925
14090
  reject,
13926
14091
  timer
13927
14092
  });
@@ -13947,12 +14112,12 @@ var init_codexAppServer = __esm({
13947
14112
  new CodexAppServerError("Codex app-server stdin is not writable")
13948
14113
  );
13949
14114
  }
13950
- return new Promise((resolve21, reject) => {
14115
+ return new Promise((resolve22, reject) => {
13951
14116
  try {
13952
14117
  child.stdin.write(`${JSON.stringify(message)}
13953
14118
  `, (error) => {
13954
14119
  if (error) reject(error);
13955
- else resolve21();
14120
+ else resolve22();
13956
14121
  });
13957
14122
  } catch (error) {
13958
14123
  reject(error);
@@ -14053,13 +14218,13 @@ var init_codexAppServer = __esm({
14053
14218
  }
14054
14219
  }
14055
14220
  waitForChildClose(closed, timeoutMs) {
14056
- return new Promise((resolve21) => {
14221
+ return new Promise((resolve22) => {
14057
14222
  let settled = false;
14058
14223
  const finish = (didClose) => {
14059
14224
  if (settled) return;
14060
14225
  settled = true;
14061
14226
  this.clearTimer(timer);
14062
- resolve21(didClose);
14227
+ resolve22(didClose);
14063
14228
  };
14064
14229
  const timer = this.setTimer(() => finish(false), timeoutMs);
14065
14230
  void closed.then(() => finish(true));
@@ -14068,8 +14233,8 @@ var init_codexAppServer = __esm({
14068
14233
  async terminateChild(child, error) {
14069
14234
  let didClose = false;
14070
14235
  let resolveClose = () => void 0;
14071
- const closed = new Promise((resolve21) => {
14072
- resolveClose = resolve21;
14236
+ const closed = new Promise((resolve22) => {
14237
+ resolveClose = resolve22;
14073
14238
  });
14074
14239
  child.on("close", () => {
14075
14240
  didClose = true;
@@ -14429,7 +14594,7 @@ async function waitForNewSession(cwd, knownPaths, startedAt2, timeoutMs = SESSIO
14429
14594
  while (Date.now() < deadline) {
14430
14595
  const match = await findNewestCodexSessionForCwd(cwd, knownPaths, startedAt2);
14431
14596
  if (match) return match;
14432
- await new Promise((resolve21) => setTimeout(resolve21, SESSION_DISCOVERY_INTERVAL_MS));
14597
+ await new Promise((resolve22) => setTimeout(resolve22, SESSION_DISCOVERY_INTERVAL_MS));
14433
14598
  }
14434
14599
  return null;
14435
14600
  }
@@ -14443,9 +14608,9 @@ function identityFromMetaLine(line) {
14443
14608
  const sessionId = typeof payload.id === "string" ? payload.id : "";
14444
14609
  const timestampText = typeof payload.timestamp === "string" ? payload.timestamp : typeof parsed.timestamp === "string" ? parsed.timestamp : "";
14445
14610
  if (!sessionId || !timestampText) return null;
14446
- const timestamp = new Date(timestampText);
14447
- if (Number.isNaN(timestamp.getTime())) return null;
14448
- const fileName = descriptor5.sessionFile.name(sessionId, timestamp);
14611
+ const timestamp2 = new Date(timestampText);
14612
+ if (Number.isNaN(timestamp2.getTime())) return null;
14613
+ const fileName = descriptor5.sessionFile.name(sessionId, timestamp2);
14449
14614
  return { sessionId, fileName, filePath: join11(sessionsRoot2(), fileName) };
14450
14615
  } catch {
14451
14616
  return null;
@@ -14505,7 +14670,7 @@ async function startLegacy(req, knownPaths) {
14505
14670
  ...args.turnArgs,
14506
14671
  ...args.promptArgs
14507
14672
  ]);
14508
- const child = spawn(cli.command, cli.args, {
14673
+ const child = spawn2(cli.command, cli.args, {
14509
14674
  cwd: req.cwd,
14510
14675
  env: process.env,
14511
14676
  stdio: ["ignore", "pipe", "pipe"],
@@ -14516,7 +14681,7 @@ async function startLegacy(req, knownPaths) {
14516
14681
  child.stderr?.on("data", (data) => {
14517
14682
  stderr += data.toString();
14518
14683
  });
14519
- return new Promise((resolve21, reject) => {
14684
+ return new Promise((resolve22, reject) => {
14520
14685
  let settled = false;
14521
14686
  let sessionId = null;
14522
14687
  const discovery = waitForNewSession(req.cwd, knownPaths, startedAt2);
@@ -14534,7 +14699,7 @@ async function startLegacy(req, knownPaths) {
14534
14699
  } catch {
14535
14700
  }
14536
14701
  }
14537
- resolve21({
14702
+ resolve22({
14538
14703
  sessionId: identity.sessionId,
14539
14704
  dirName: req.dirName,
14540
14705
  fileName: identity.fileName,
@@ -14597,7 +14762,7 @@ async function sendLegacy(sessionId, req) {
14597
14762
  sessionId,
14598
14763
  ...args.promptArgs
14599
14764
  ]);
14600
- const child = spawn(cli.command, cli.args, {
14765
+ const child = spawn2(cli.command, cli.args, {
14601
14766
  cwd: req.cwd,
14602
14767
  env: process.env,
14603
14768
  stdio: ["ignore", "pipe", "pipe"],
@@ -14611,10 +14776,10 @@ async function sendLegacy(sessionId, req) {
14611
14776
  child.stderr?.on("data", (data) => {
14612
14777
  stderr += data.toString();
14613
14778
  });
14614
- const completion = new Promise((resolve21) => {
14779
+ const completion = new Promise((resolve22) => {
14615
14780
  session.onResult = (result) => {
14616
14781
  session.onResult = null;
14617
- resolve21({
14782
+ resolve22({
14618
14783
  isError: result.is_error === true,
14619
14784
  message: result.result
14620
14785
  });
@@ -15652,7 +15817,7 @@ var init_copilotTransport = __esm({
15652
15817
  }
15653
15818
  waitForRequest(request, method, timeoutMs = this.transportTimeoutMs, onTimeout) {
15654
15819
  if (timeoutMs <= 0) return request;
15655
- return new Promise((resolve21, reject) => {
15820
+ return new Promise((resolve22, reject) => {
15656
15821
  const timer = setTimeout(() => {
15657
15822
  try {
15658
15823
  onTimeout?.();
@@ -15663,7 +15828,7 @@ var init_copilotTransport = __esm({
15663
15828
  request.then(
15664
15829
  (value) => {
15665
15830
  clearTimeout(timer);
15666
- resolve21(value);
15831
+ resolve22(value);
15667
15832
  },
15668
15833
  (error) => {
15669
15834
  clearTimeout(timer);
@@ -15789,10 +15954,10 @@ var init_copilotTransport = __esm({
15789
15954
  ...typeof params.allowFreeform === "boolean" ? { allowFreeform: params.allowFreeform } : {},
15790
15955
  askedAt: Date.now()
15791
15956
  };
15792
- return new Promise((resolve21, reject) => {
15957
+ return new Promise((resolve22, reject) => {
15793
15958
  this.pendingUserInputs.set(
15794
15959
  this.pendingInteractionKey(sessionId, requestId),
15795
- { value, resolve: resolve21, reject }
15960
+ { value, resolve: resolve22, reject }
15796
15961
  );
15797
15962
  });
15798
15963
  }
@@ -15812,10 +15977,10 @@ var init_copilotTransport = __esm({
15812
15977
  recommendedAction: typeof params.recommendedAction === "string" ? params.recommendedAction : actions[0] ?? "interactive",
15813
15978
  askedAt: Date.now()
15814
15979
  };
15815
- return new Promise((resolve21, reject) => {
15980
+ return new Promise((resolve22, reject) => {
15816
15981
  this.pendingExitPlans.set(
15817
15982
  this.pendingInteractionKey(sessionId, requestId),
15818
- { value, resolve: resolve21, reject }
15983
+ { value, resolve: resolve22, reject }
15819
15984
  );
15820
15985
  });
15821
15986
  }
@@ -16040,17 +16205,17 @@ function parseJsonRecord(line) {
16040
16205
  }
16041
16206
  }
16042
16207
  function parseClaudeUsageLine(line) {
16043
- const record2 = parseJsonRecord(line);
16044
- if (!record2 || record2.type !== "assistant") return null;
16045
- const message = asRecord3(record2.message);
16208
+ const record4 = parseJsonRecord(line);
16209
+ if (!record4 || record4.type !== "assistant") return null;
16210
+ const message = asRecord3(record4.message);
16046
16211
  const usage = message ? asRecord3(message.usage) : null;
16047
16212
  if (!message || !usage) return null;
16048
- const timestampMs = parseTimestampMs(record2.timestamp);
16213
+ const timestampMs = parseTimestampMs(record4.timestamp);
16049
16214
  if (timestampMs === null) return null;
16050
16215
  const model = typeof message.model === "string" ? message.model : "";
16051
16216
  if (model.length === 0) return null;
16052
16217
  const messageId = typeof message.id === "string" ? message.id : null;
16053
- const requestId = typeof record2.requestId === "string" ? record2.requestId : null;
16218
+ const requestId = typeof record4.requestId === "string" ? record4.requestId : null;
16054
16219
  const dedupeKey = messageId === null && requestId === null ? null : `${messageId ?? ""}:${requestId ?? ""}`;
16055
16220
  const cacheCreationTokens = int(usage.cache_creation_input_tokens);
16056
16221
  const byTtl = asRecord3(usage.cache_creation);
@@ -16069,12 +16234,12 @@ function parseClaudeUsageLine(line) {
16069
16234
  reasoningTokens: 0
16070
16235
  };
16071
16236
  if (totalUsageCostTokens(totals) === 0) return null;
16072
- const cost = record2.costUSD;
16237
+ const cost = record4.costUSD;
16073
16238
  return {
16074
16239
  provider: "claude",
16075
16240
  timestampMs,
16076
16241
  model,
16077
- sessionId: typeof record2.sessionId === "string" ? record2.sessionId : "",
16242
+ sessionId: typeof record4.sessionId === "string" ? record4.sessionId : "",
16078
16243
  totals,
16079
16244
  reportedCostUsd: typeof cost === "number" && Number.isFinite(cost) ? cost : null,
16080
16245
  dedupeKey
@@ -16096,30 +16261,30 @@ function isForkedSessionMeta(payload) {
16096
16261
  return typeof spawn5?.parent_thread_id === "string";
16097
16262
  }
16098
16263
  function parseCodexUsageLine(line, state) {
16099
- const record2 = parseJsonRecord(line);
16100
- if (!record2) return null;
16101
- const payload = asRecord3(record2.payload);
16264
+ const record4 = parseJsonRecord(line);
16265
+ if (!record4) return null;
16266
+ const payload = asRecord3(record4.payload);
16102
16267
  if (!payload) return null;
16103
- if (record2.type === "session_meta") {
16268
+ if (record4.type === "session_meta") {
16104
16269
  if (state.sawSessionMeta) return null;
16105
16270
  state.sawSessionMeta = true;
16106
16271
  const id = payload.id ?? payload.session_id;
16107
16272
  if (typeof id === "string") state.sessionId = id;
16108
- const metaTimestampMs = parseTimestampMs(record2.timestamp);
16273
+ const metaTimestampMs = parseTimestampMs(record4.timestamp);
16109
16274
  if (metaTimestampMs !== null && isForkedSessionMeta(payload)) {
16110
16275
  state.suppressingForkCopies = true;
16111
16276
  state.forkCopyAnchorMs = metaTimestampMs;
16112
16277
  }
16113
16278
  return null;
16114
16279
  }
16115
- if (record2.type === "turn_context") {
16280
+ if (record4.type === "turn_context") {
16116
16281
  if (typeof payload.model === "string") state.model = payload.model;
16117
16282
  return null;
16118
16283
  }
16119
16284
  if (payload.type !== "token_count") return null;
16120
16285
  const last = asRecord3(asRecord3(payload.info)?.last_token_usage);
16121
16286
  if (!last) return null;
16122
- const timestampMs = parseTimestampMs(record2.timestamp);
16287
+ const timestampMs = parseTimestampMs(record4.timestamp);
16123
16288
  if (timestampMs === null) return null;
16124
16289
  if (state.model.length === 0) return null;
16125
16290
  const signature = JSON.stringify(last);
@@ -16218,17 +16383,17 @@ function parseCopilotUsageMetrics(value, state, timestampMs) {
16218
16383
  return records;
16219
16384
  }
16220
16385
  function parseCopilotUsageLine(line, state) {
16221
- const record2 = parseJsonRecord(line);
16222
- if (!record2 || typeof record2.agentId === "string" && record2.agentId.length > 0) return [];
16223
- const data = asRecord3(record2.data);
16386
+ const record4 = parseJsonRecord(line);
16387
+ if (!record4 || typeof record4.agentId === "string" && record4.agentId.length > 0) return [];
16388
+ const data = asRecord3(record4.data);
16224
16389
  if (!data) return [];
16225
- if (record2.type === "session.start") {
16390
+ if (record4.type === "session.start") {
16226
16391
  const sessionId = data.sessionId;
16227
16392
  if (typeof sessionId === "string" && sessionId.length > 0) state.sessionId = sessionId;
16228
16393
  return [];
16229
16394
  }
16230
- if (record2.type !== "session.shutdown") return [];
16231
- const timestampMs = parseTimestampMs(record2.timestamp);
16395
+ if (record4.type !== "session.shutdown") return [];
16396
+ const timestampMs = parseTimestampMs(record4.timestamp);
16232
16397
  return timestampMs === null ? [] : parseCopilotUsageMetrics(data, state, timestampMs);
16233
16398
  }
16234
16399
  function createUsageScanner(provider, filePath) {
@@ -16245,8 +16410,8 @@ var init_usageScanners = __esm({
16245
16410
  // object, so a line is either self-contained or of no interest.
16246
16411
  wantsLine: (line) => line.includes('"usage"'),
16247
16412
  accept: (line) => {
16248
- const record2 = parseClaudeUsageLine(line);
16249
- return record2 === null ? [] : [record2];
16413
+ const record4 = parseClaudeUsageLine(line);
16414
+ return record4 === null ? [] : [record4];
16250
16415
  }
16251
16416
  }),
16252
16417
  codex: () => {
@@ -16257,8 +16422,8 @@ var init_usageScanners = __esm({
16257
16422
  // at all but still have to reach the reducer.
16258
16423
  wantsLine: (line) => line.includes('"token_count"') || line.includes('"turn_context"') || line.includes('"session_meta"'),
16259
16424
  accept: (line) => {
16260
- const record2 = parseCodexUsageLine(line, state);
16261
- return record2 === null ? [] : [record2];
16425
+ const record4 = parseCodexUsageLine(line, state);
16426
+ return record4 === null ? [] : [record4];
16262
16427
  }
16263
16428
  };
16264
16429
  },
@@ -16504,7 +16669,7 @@ var init_copilotRuntime = __esm({
16504
16669
  initialContent = await readFile9(filePath, "utf-8");
16505
16670
  break;
16506
16671
  } catch {
16507
- await new Promise((resolve21) => setTimeout(resolve21, TRANSCRIPT_POLL_INTERVAL_MS2));
16672
+ await new Promise((resolve22) => setTimeout(resolve22, TRANSCRIPT_POLL_INTERVAL_MS2));
16508
16673
  }
16509
16674
  }
16510
16675
  return { sessionId, dirName: req.dirName, fileName, filePath, initialContent };
@@ -17140,11 +17305,11 @@ function registerRunningProcessesRoute(use) {
17140
17305
  if (url.pathname.split("/").filter(Boolean).length > 0) return next();
17141
17306
  const isWindows2 = process.platform === "win32";
17142
17307
  const nameFilter = allDescriptors().map(windowsProcessNameFilter).join(" or ");
17143
- const child = isWindows2 ? spawn("powershell", [
17308
+ const child = isWindows2 ? spawn2("powershell", [
17144
17309
  "-NoProfile",
17145
17310
  "-Command",
17146
17311
  `Get-CimInstance Win32_Process -Filter "${nameFilter}" | Select-Object ProcessId, WorkingSetSize, CommandLine | ConvertTo-Json -Compress`
17147
- ]) : spawn("ps", ["aux"]);
17312
+ ]) : spawn2("ps", ["aux"]);
17148
17313
  let stdout = "";
17149
17314
  let responded = false;
17150
17315
  child.stdout?.on("data", (data) => {
@@ -17507,12 +17672,12 @@ function registerBranchSessionRoute(use) {
17507
17672
  }
17508
17673
  }
17509
17674
  const newSessionId = randomUUID2();
17510
- const { record: record2, originalId } = format.brandBranch(
17675
+ const { record: record4, originalId } = format.brandBranch(
17511
17676
  JSON.parse(lines[0]),
17512
17677
  newSessionId,
17513
17678
  turnIndex ?? null
17514
17679
  );
17515
- lines[0] = JSON.stringify(record2);
17680
+ lines[0] = JSON.stringify(record4);
17516
17681
  const target = storeForDirName(dirName).transcriptPath(dirName, newSessionId);
17517
17682
  if (!target) {
17518
17683
  res.statusCode = 500;
@@ -18055,11 +18220,11 @@ import {
18055
18220
  dirname as dirname5,
18056
18221
  isAbsolute as isAbsolute3,
18057
18222
  join as join13,
18058
- posix as posix2,
18223
+ posix as posix3,
18059
18224
  relative as relative4,
18060
18225
  resolve as resolve9,
18061
18226
  sep as sep5,
18062
- win32 as win322
18227
+ win32 as win323
18063
18228
  } from "node:path";
18064
18229
  function configuredAgentHomes() {
18065
18230
  return new Set(AGENT_KINDS.map((kind) => agentHomeDir(kind)));
@@ -18168,7 +18333,7 @@ async function resolveConfigBrowserPath(filePath, options = {}) {
18168
18333
  function isSafeConfigName(name) {
18169
18334
  if (!name || name === "." || name === ".." || name.includes("\0")) return false;
18170
18335
  if (name.includes("/") || name.includes("\\")) return false;
18171
- if (isAbsolute3(name) || posix2.parse(name).root || win322.parse(name).root) return false;
18336
+ if (isAbsolute3(name) || posix3.parse(name).root || win323.parse(name).root) return false;
18172
18337
  return true;
18173
18338
  }
18174
18339
  function isUnderDir(parentDir, dirName) {
@@ -19411,7 +19576,8 @@ function registerConfigRoutes(use) {
19411
19576
  networkPassword: config.networkPassword ? "set" : null,
19412
19577
  terminalApp: config.terminalApp || null,
19413
19578
  editorApp: config.editorApp || null,
19414
- useBuiltInEditor: config.useBuiltInEditor || false
19579
+ useBuiltInEditor: config.useBuiltInEditor || false,
19580
+ agentExecutable: config.agentExecutable ?? DEFAULT_EXECUTABLE_CHOICE
19415
19581
  } : null));
19416
19582
  return;
19417
19583
  }
@@ -19474,7 +19640,8 @@ function registerConfigRoutes(use) {
19474
19640
  networkPassword: finalPassword,
19475
19641
  terminalApp: parsed.terminalApp || void 0,
19476
19642
  editorApp: parsed.editorApp || void 0,
19477
- useBuiltInEditor: !!parsed.useBuiltInEditor
19643
+ useBuiltInEditor: !!parsed.useBuiltInEditor,
19644
+ agentExecutable: parseExecutableChoice(parsed.agentExecutable)
19478
19645
  });
19479
19646
  refreshDirs();
19480
19647
  if (currentConfig && resolve11(resolvedClaudeDir) !== resolve11(currentConfig.claudeDir)) {
@@ -19509,12 +19676,13 @@ var init_config2 = __esm({
19509
19676
  init_users();
19510
19677
  init_config();
19511
19678
  init_agent_descriptors();
19679
+ init_agentExecutable();
19512
19680
  init_sessionPersistence();
19513
19681
  }
19514
19682
  });
19515
19683
 
19516
19684
  // ../../server/routes/hello.ts
19517
- import { readFileSync } from "node:fs";
19685
+ import { readFileSync as readFileSync2 } from "node:fs";
19518
19686
  import { fileURLToPath as fileURLToPath2 } from "node:url";
19519
19687
  import { hostname } from "node:os";
19520
19688
  import { join as join18 } from "node:path";
@@ -19563,7 +19731,7 @@ var init_hello = __esm({
19563
19731
  join18(__dirname2, "../package.json")
19564
19732
  ]) {
19565
19733
  try {
19566
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
19734
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
19567
19735
  if (typeof pkg.version === "string") return pkg.version;
19568
19736
  } catch {
19569
19737
  }
@@ -19676,21 +19844,21 @@ function toPublic(device) {
19676
19844
  return rest;
19677
19845
  }
19678
19846
  function readJsonBody2(req) {
19679
- return new Promise((resolve21) => {
19847
+ return new Promise((resolve22) => {
19680
19848
  let raw = "";
19681
19849
  req.on("data", (chunk) => {
19682
19850
  raw += chunk.toString();
19683
19851
  });
19684
19852
  req.on("end", () => {
19685
- if (!raw.trim()) return resolve21({});
19853
+ if (!raw.trim()) return resolve22({});
19686
19854
  try {
19687
19855
  const parsed = JSON.parse(raw);
19688
- resolve21(parsed && typeof parsed === "object" ? parsed : null);
19856
+ resolve22(parsed && typeof parsed === "object" ? parsed : null);
19689
19857
  } catch {
19690
- resolve21(null);
19858
+ resolve22(null);
19691
19859
  }
19692
19860
  });
19693
- req.on("error", () => resolve21(null));
19861
+ req.on("error", () => resolve22(null));
19694
19862
  });
19695
19863
  }
19696
19864
  function handleList(res) {
@@ -20078,9 +20246,9 @@ function terminalCommand(terminal, dirPath) {
20078
20246
  return { cmd: terminal, args: ["--working-directory", dirPath] };
20079
20247
  }
20080
20248
  function whichEditor(name) {
20081
- return new Promise((resolve21) => {
20249
+ return new Promise((resolve22) => {
20082
20250
  const cmd = platform() === "win32" ? "where" : "which";
20083
- execFile(cmd, [name], (err) => resolve21(err ? null : name));
20251
+ execFile(cmd, [name], (err) => resolve22(err ? null : name));
20084
20252
  });
20085
20253
  }
20086
20254
  async function resolveEditor(configuredEditor) {
@@ -20094,10 +20262,10 @@ async function resolveEditor(configuredEditor) {
20094
20262
  return null;
20095
20263
  }
20096
20264
  function openWithEditor(editor, args) {
20097
- return new Promise((resolve21, reject) => {
20265
+ return new Promise((resolve22, reject) => {
20098
20266
  execFile(editor, args, (err) => {
20099
20267
  if (err) reject(err);
20100
- else resolve21();
20268
+ else resolve22();
20101
20269
  });
20102
20270
  });
20103
20271
  }
@@ -20110,14 +20278,14 @@ function editorOpenArgs(editor, filePath, line, column) {
20110
20278
  return [filePath];
20111
20279
  }
20112
20280
  function getGitHeadContent(filePath) {
20113
- return new Promise((resolve21, reject) => {
20281
+ return new Promise((resolve22, reject) => {
20114
20282
  execFile(
20115
20283
  "git",
20116
20284
  ["-C", dirname7(filePath), "show", `HEAD:./${basename7(filePath)}`],
20117
20285
  { maxBuffer: 10 * 1024 * 1024 },
20118
20286
  (err, stdout) => {
20119
20287
  if (err) reject(err);
20120
- else resolve21(stdout);
20288
+ else resolve22(stdout);
20121
20289
  }
20122
20290
  );
20123
20291
  });
@@ -20793,23 +20961,23 @@ function registerFileRoutes(use) {
20793
20961
  req.on("end", async () => {
20794
20962
  try {
20795
20963
  let spawnLines = function(args, cwd) {
20796
- return new Promise((resolve21) => {
20797
- const proc = spawn("git", args, { cwd });
20964
+ return new Promise((resolve22) => {
20965
+ const proc = spawn2("git", args, { cwd });
20798
20966
  let out = "";
20799
20967
  proc.stdout.on("data", (d) => out += d.toString());
20800
20968
  proc.on("close", (code) => {
20801
- if (code !== 0 || !out) return resolve21(0);
20802
- resolve21(out.split("\n").length);
20969
+ if (code !== 0 || !out) return resolve22(0);
20970
+ resolve22(out.split("\n").length);
20803
20971
  });
20804
- proc.on("error", () => resolve21(0));
20972
+ proc.on("error", () => resolve22(0));
20805
20973
  });
20806
20974
  }, spawnOutput = function(args, cwd) {
20807
- return new Promise((resolve21) => {
20808
- const proc = spawn("git", args, { cwd });
20975
+ return new Promise((resolve22) => {
20976
+ const proc = spawn2("git", args, { cwd });
20809
20977
  let out = "";
20810
20978
  proc.stdout.on("data", (d) => out += d.toString());
20811
- proc.on("close", () => resolve21(out.trim()));
20812
- proc.on("error", () => resolve21(""));
20979
+ proc.on("close", () => resolve22(out.trim()));
20980
+ proc.on("error", () => resolve22(""));
20813
20981
  });
20814
20982
  };
20815
20983
  const { files, dirs: dirs2 } = JSON.parse(body);
@@ -20833,18 +21001,18 @@ function registerFileRoutes(use) {
20833
21001
  cwd = cwd.substring(0, cwd.lastIndexOf("/")) || "/";
20834
21002
  }
20835
21003
  }
20836
- return new Promise((resolve21) => {
20837
- const proc = spawn("git", ["rev-parse", "--show-toplevel"], { cwd });
21004
+ return new Promise((resolve22) => {
21005
+ const proc = spawn2("git", ["rev-parse", "--show-toplevel"], { cwd });
20838
21006
  let out = "";
20839
21007
  proc.stdout.on("data", (d) => out += d.toString());
20840
21008
  proc.on("close", (code) => {
20841
21009
  const root = code === 0 ? out.trim() : null;
20842
21010
  gitRootCache.set(dir, root);
20843
- resolve21(root);
21011
+ resolve22(root);
20844
21012
  });
20845
21013
  proc.on("error", () => {
20846
21014
  gitRootCache.set(dir, null);
20847
- resolve21(null);
21015
+ resolve22(null);
20848
21016
  });
20849
21017
  });
20850
21018
  }
@@ -21079,11 +21247,11 @@ function parseGitStatus(output) {
21079
21247
  const branch = parseBranchHeader(header);
21080
21248
  const files = [];
21081
21249
  for (let index = 0; index < records.length; index += 1) {
21082
- const record2 = records[index];
21083
- if (!record2 || record2.length < 3) continue;
21084
- const indexStatus = record2[0];
21085
- const workTreeStatus = record2[1];
21086
- const path = record2.slice(3);
21250
+ const record4 = records[index];
21251
+ if (!record4 || record4.length < 3) continue;
21252
+ const indexStatus = record4[0];
21253
+ const workTreeStatus = record4[1];
21254
+ const path = record4.slice(3);
21087
21255
  const renamedOrCopied = /[RC]/.test(`${indexStatus}${workTreeStatus}`);
21088
21256
  const originalPath = renamedOrCopied ? records[index += 1] || void 0 : void 0;
21089
21257
  files.push({ path, originalPath, indexStatus, workTreeStatus });
@@ -21138,14 +21306,630 @@ var init_git_status = __esm({
21138
21306
  }
21139
21307
  });
21140
21308
 
21309
+ // ../../server/routes/github-actions.ts
21310
+ import { execFile as execFileCallback2 } from "node:child_process";
21311
+ import { promisify as promisify2 } from "node:util";
21312
+ function record2(value) {
21313
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
21314
+ }
21315
+ function stringValue(value, fallback = "") {
21316
+ return typeof value === "string" ? value : fallback;
21317
+ }
21318
+ function numberValue(value) {
21319
+ return typeof value === "number" && Number.isSafeInteger(value) ? value : null;
21320
+ }
21321
+ function nullableDate(value) {
21322
+ return typeof value === "string" && value ? value : null;
21323
+ }
21324
+ function workflowStatus(value) {
21325
+ return typeof value === "string" && RUN_STATUSES.has(value) ? value : "pending";
21326
+ }
21327
+ function workflowConclusion(value) {
21328
+ return typeof value === "string" && RUN_CONCLUSIONS.has(value) ? value : null;
21329
+ }
21330
+ function parseGitHubRemote(remoteUrl) {
21331
+ const trimmed = remoteUrl.trim();
21332
+ let host = "";
21333
+ let pathname = "";
21334
+ try {
21335
+ const parsed = new URL(trimmed);
21336
+ host = parsed.hostname;
21337
+ pathname = parsed.pathname;
21338
+ } catch {
21339
+ const scp = trimmed.match(/^(?:[^@\s]+@)?([^:/\s]+):(.+)$/);
21340
+ if (!scp) return null;
21341
+ host = scp[1];
21342
+ pathname = scp[2];
21343
+ }
21344
+ const parts = pathname.replace(/^\/+/, "").replace(/\.git$/, "").split("/");
21345
+ if (parts.length !== 2 || !GITHUB_HOST.test(host) || host.toLowerCase() !== "github.com" && !host.toLowerCase().startsWith("github.") || !GITHUB_NAME.test(parts[0]) || !GITHUB_NAME.test(parts[1])) {
21346
+ return null;
21347
+ }
21348
+ return { host: host.toLowerCase(), owner: parts[0], name: parts[1] };
21349
+ }
21350
+ function parseRun(value) {
21351
+ const source = record2(value);
21352
+ if (!source) return null;
21353
+ const id = numberValue(source.id);
21354
+ const url = stringValue(source.html_url);
21355
+ if (id === null || !url.startsWith("https://")) return null;
21356
+ const actor = record2(source.actor);
21357
+ return {
21358
+ id,
21359
+ name: stringValue(source.name, "Workflow"),
21360
+ displayTitle: stringValue(source.display_title, stringValue(source.name, "Workflow run")),
21361
+ status: workflowStatus(source.status),
21362
+ conclusion: workflowConclusion(source.conclusion),
21363
+ url,
21364
+ runNumber: numberValue(source.run_number) ?? 0,
21365
+ event: stringValue(source.event, "workflow"),
21366
+ branch: stringValue(source.head_branch),
21367
+ commitSha: stringValue(source.head_sha),
21368
+ createdAt: stringValue(source.created_at),
21369
+ updatedAt: stringValue(source.updated_at),
21370
+ actor: stringValue(actor?.login)
21371
+ };
21372
+ }
21373
+ function parseStep(value) {
21374
+ const source = record2(value);
21375
+ if (!source) return null;
21376
+ const number = numberValue(source.number);
21377
+ if (number === null) return null;
21378
+ return {
21379
+ number,
21380
+ name: stringValue(source.name, `Step ${number}`),
21381
+ status: workflowStatus(source.status),
21382
+ conclusion: workflowConclusion(source.conclusion),
21383
+ startedAt: nullableDate(source.started_at),
21384
+ completedAt: nullableDate(source.completed_at)
21385
+ };
21386
+ }
21387
+ function parseJob(value) {
21388
+ const source = record2(value);
21389
+ if (!source) return null;
21390
+ const id = numberValue(source.id);
21391
+ const url = stringValue(source.html_url);
21392
+ if (id === null || !url.startsWith("https://")) return null;
21393
+ return {
21394
+ id,
21395
+ name: stringValue(source.name, "Job"),
21396
+ status: workflowStatus(source.status),
21397
+ conclusion: workflowConclusion(source.conclusion),
21398
+ url,
21399
+ startedAt: nullableDate(source.started_at),
21400
+ completedAt: nullableDate(source.completed_at),
21401
+ steps: Array.isArray(source.steps) ? source.steps.map(parseStep).filter((step) => step !== null) : []
21402
+ };
21403
+ }
21404
+ function parseRunsResponse(value) {
21405
+ const source = record2(value);
21406
+ if (!source || !Array.isArray(source.workflow_runs)) {
21407
+ throw new GitHubActionsRouteError(502, "invalid_response", "GitHub returned an invalid workflow response");
21408
+ }
21409
+ return source.workflow_runs.map(parseRun).filter((run2) => run2 !== null);
21410
+ }
21411
+ function parseJobsResponse(value) {
21412
+ const source = record2(value);
21413
+ if (!source || !Array.isArray(source.jobs)) {
21414
+ throw new GitHubActionsRouteError(502, "invalid_response", "GitHub returned an invalid jobs response");
21415
+ }
21416
+ return source.jobs.map(parseJob).filter((job) => job !== null);
21417
+ }
21418
+ async function runGitHubApi(repository, endpoint) {
21419
+ try {
21420
+ const result = await execFile3("gh", [
21421
+ "api",
21422
+ endpoint,
21423
+ "--hostname",
21424
+ repository.host,
21425
+ "-H",
21426
+ "Accept: application/vnd.github+json"
21427
+ ], {
21428
+ encoding: "utf-8",
21429
+ env: { ...process.env, GH_PAGER: "cat", NO_COLOR: "1" },
21430
+ maxBuffer: 8 * 1024 * 1024,
21431
+ timeout: 2e4,
21432
+ windowsHide: true
21433
+ });
21434
+ return JSON.parse(result.stdout);
21435
+ } catch (error) {
21436
+ const failure = error;
21437
+ if (failure.code === "ENOENT") {
21438
+ throw new GitHubActionsRouteError(503, "gh_missing", "Install the GitHub CLI to view workflow runs");
21439
+ }
21440
+ const detail = `${failure.message ?? ""}
21441
+ ${failure.stderr ?? ""}`;
21442
+ if (/auth login|not logged|authentication|oauth token/i.test(detail)) {
21443
+ throw new GitHubActionsRouteError(503, "gh_auth_required", "Sign in with `gh auth login` to view workflow runs");
21444
+ }
21445
+ throw new GitHubActionsRouteError(502, "github_api_failed", "GitHub workflow data is unavailable");
21446
+ }
21447
+ }
21448
+ async function resolveRepository(cwd, dependencies) {
21449
+ const project = await dependencies.resolveProject(cwd);
21450
+ if (!project.ok) throw new GitHubActionsRouteError(project.status, "no_git_repository", project.error);
21451
+ if (!project.root) {
21452
+ throw new GitHubActionsRouteError(400, "no_git_repository", "This project is not a Git repository");
21453
+ }
21454
+ let remoteUrl = "";
21455
+ try {
21456
+ remoteUrl = (await dependencies.git(project.root, ["remote", "get-url", "origin"])).stdout;
21457
+ } catch {
21458
+ throw new GitHubActionsRouteError(400, "no_github_remote", "This repository has no origin remote");
21459
+ }
21460
+ const repository = parseGitHubRemote(remoteUrl);
21461
+ if (!repository) {
21462
+ throw new GitHubActionsRouteError(400, "no_github_remote", "The origin remote is not a supported GitHub repository");
21463
+ }
21464
+ const branchResult = await dependencies.git(project.root, ["branch", "--show-current"]);
21465
+ return {
21466
+ repository,
21467
+ branch: branchResult.stdout.trim() || null
21468
+ };
21469
+ }
21470
+ function repositoryName(repository) {
21471
+ return `${repository.owner}/${repository.name}`;
21472
+ }
21473
+ function repositoryUrl(repository) {
21474
+ return `https://${repository.host}/${repository.owner}/${repository.name}`;
21475
+ }
21476
+ function sendRouteError2(res, error) {
21477
+ if (error instanceof GitHubActionsRouteError) {
21478
+ sendJson(res, error.status, { error: error.message, code: error.code });
21479
+ return;
21480
+ }
21481
+ sendJson(res, 500, { error: "Unable to load GitHub Actions", code: "github_api_failed" });
21482
+ }
21483
+ function registerGitHubActionsRoutes(use, dependencies = defaultDependencies) {
21484
+ use("/api/github-actions", async (req, res, next) => {
21485
+ if (req.method !== "GET") return next();
21486
+ const url = new URL(req.url || "", "http://localhost");
21487
+ if (url.pathname !== "/" && url.pathname !== "") return next();
21488
+ const cwd = url.searchParams.get("cwd") ?? "";
21489
+ const requestedLimit = Number(url.searchParams.get("limit") ?? DEFAULT_RUNS);
21490
+ const limit = Number.isInteger(requestedLimit) ? Math.min(MAX_RUNS, Math.max(1, requestedLimit)) : DEFAULT_RUNS;
21491
+ try {
21492
+ const { repository, branch } = await resolveRepository(cwd, dependencies);
21493
+ const endpoint = `repos/${repository.owner}/${repository.name}/actions/runs?per_page=${limit}`;
21494
+ const runs = parseRunsResponse(await dependencies.githubApi(repository, endpoint));
21495
+ const response = {
21496
+ repository: repositoryName(repository),
21497
+ repositoryUrl: repositoryUrl(repository),
21498
+ branch,
21499
+ runs
21500
+ };
21501
+ sendJson(res, 200, response);
21502
+ } catch (error) {
21503
+ sendRouteError2(res, error);
21504
+ }
21505
+ });
21506
+ use("/api/github-actions/jobs", async (req, res, next) => {
21507
+ if (req.method !== "GET") return next();
21508
+ const url = new URL(req.url || "", "http://localhost");
21509
+ if (url.pathname !== "/" && url.pathname !== "") return next();
21510
+ const cwd = url.searchParams.get("cwd") ?? "";
21511
+ const runIdText = url.searchParams.get("runId") ?? "";
21512
+ if (!/^\d+$/.test(runIdText)) {
21513
+ return sendJson(res, 400, { error: "runId must be a positive integer", code: "github_api_failed" });
21514
+ }
21515
+ try {
21516
+ const { repository } = await resolveRepository(cwd, dependencies);
21517
+ const runId = Number(runIdText);
21518
+ const endpoint = `repos/${repository.owner}/${repository.name}/actions/runs/${runId}/jobs?filter=latest&per_page=100`;
21519
+ const jobs = parseJobsResponse(await dependencies.githubApi(repository, endpoint));
21520
+ const response = {
21521
+ repository: repositoryName(repository),
21522
+ runId,
21523
+ jobs
21524
+ };
21525
+ sendJson(res, 200, response);
21526
+ } catch (error) {
21527
+ sendRouteError2(res, error);
21528
+ }
21529
+ });
21530
+ }
21531
+ var execFile3, MAX_RUNS, DEFAULT_RUNS, GITHUB_NAME, GITHUB_HOST, RUN_STATUSES, RUN_CONCLUSIONS, GitHubActionsRouteError, defaultDependencies;
21532
+ var init_github_actions = __esm({
21533
+ "../../server/routes/github-actions.ts"() {
21534
+ init_http();
21535
+ init_gitProject();
21536
+ execFile3 = promisify2(execFileCallback2);
21537
+ MAX_RUNS = 30;
21538
+ DEFAULT_RUNS = 20;
21539
+ GITHUB_NAME = /^[A-Za-z0-9_.-]+$/;
21540
+ GITHUB_HOST = /^[A-Za-z0-9.-]+$/;
21541
+ RUN_STATUSES = /* @__PURE__ */ new Set([
21542
+ "completed",
21543
+ "in_progress",
21544
+ "pending",
21545
+ "queued",
21546
+ "requested",
21547
+ "waiting"
21548
+ ]);
21549
+ RUN_CONCLUSIONS = /* @__PURE__ */ new Set([
21550
+ "action_required",
21551
+ "cancelled",
21552
+ "failure",
21553
+ "neutral",
21554
+ "skipped",
21555
+ "stale",
21556
+ "startup_failure",
21557
+ "success",
21558
+ "timed_out"
21559
+ ]);
21560
+ GitHubActionsRouteError = class extends Error {
21561
+ constructor(status, code, message) {
21562
+ super(message);
21563
+ this.status = status;
21564
+ this.code = code;
21565
+ }
21566
+ };
21567
+ defaultDependencies = {
21568
+ resolveProject: resolveGitProject,
21569
+ git: runGit,
21570
+ githubApi: runGitHubApi
21571
+ };
21572
+ }
21573
+ });
21574
+
21575
+ // ../../server/routes/vercel-deployments.ts
21576
+ import { execFile as execFileCallback3 } from "node:child_process";
21577
+ import { readFile as readFile15, realpath as realpath8, stat as stat13 } from "node:fs/promises";
21578
+ import { isAbsolute as isAbsolute8, join as join20, resolve as resolve15 } from "node:path";
21579
+ import { promisify as promisify3 } from "node:util";
21580
+ function record3(value) {
21581
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
21582
+ }
21583
+ function stringValue2(value, fallback = "") {
21584
+ return typeof value === "string" ? value : fallback;
21585
+ }
21586
+ function nullableString(value) {
21587
+ return typeof value === "string" && value ? value : null;
21588
+ }
21589
+ function timestamp(value) {
21590
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
21591
+ }
21592
+ function firstString2(source, keys) {
21593
+ if (!source) return "";
21594
+ for (const key2 of keys) {
21595
+ const value = stringValue2(source[key2]);
21596
+ if (value) return value;
21597
+ }
21598
+ return "";
21599
+ }
21600
+ function deploymentState(value) {
21601
+ return typeof value === "string" && DEPLOYMENT_STATES.has(value) ? value : "QUEUED";
21602
+ }
21603
+ function httpsUrl(value, hostnameOnly = false) {
21604
+ const text = stringValue2(value);
21605
+ if (!text) return null;
21606
+ const candidate = hostnameOnly && !text.includes("://") ? `https://${text}` : text;
21607
+ try {
21608
+ const url = new URL(candidate);
21609
+ return url.protocol === "https:" ? url.toString().replace(/\/$/, "") : null;
21610
+ } catch {
21611
+ return null;
21612
+ }
21613
+ }
21614
+ function projectUrlFromInspector(value) {
21615
+ if (!value) return null;
21616
+ try {
21617
+ const url = new URL(value);
21618
+ const parts = url.pathname.split("/").filter(Boolean);
21619
+ if (parts.length < 3) return null;
21620
+ url.pathname = `/${parts.slice(0, -1).join("/")}`;
21621
+ url.search = "";
21622
+ url.hash = "";
21623
+ return url.toString().replace(/\/$/, "");
21624
+ } catch {
21625
+ return null;
21626
+ }
21627
+ }
21628
+ function parseDeployment(value) {
21629
+ const source = record3(value);
21630
+ if (!source) return null;
21631
+ const id = stringValue2(source.uid);
21632
+ const createdAt = timestamp(source.createdAt) ?? timestamp(source.created);
21633
+ if (!DEPLOYMENT_ID.test(id) || createdAt === null) return null;
21634
+ const meta = record3(source.meta);
21635
+ const creator = record3(source.creator);
21636
+ return {
21637
+ id,
21638
+ name: stringValue2(source.name, "Deployment"),
21639
+ url: httpsUrl(source.url, true),
21640
+ inspectorUrl: httpsUrl(source.inspectorUrl),
21641
+ state: deploymentState(source.readyState ?? source.state),
21642
+ target: nullableString(source.target),
21643
+ createdAt,
21644
+ buildingAt: timestamp(source.buildingAt),
21645
+ readyAt: timestamp(source.ready),
21646
+ branch: firstString2(meta, [
21647
+ "githubCommitRef",
21648
+ "gitlabCommitRef",
21649
+ "bitbucketCommitRef",
21650
+ "branchAlias"
21651
+ ]),
21652
+ commitSha: firstString2(meta, [
21653
+ "githubCommitSha",
21654
+ "gitlabCommitSha",
21655
+ "bitbucketCommitSha"
21656
+ ]),
21657
+ commitMessage: firstString2(meta, [
21658
+ "githubCommitMessage",
21659
+ "gitlabCommitMessage",
21660
+ "bitbucketCommitMessage"
21661
+ ]),
21662
+ creator: firstString2(creator, ["username", "githubLogin", "email"]),
21663
+ errorCode: nullableString(source.errorCode),
21664
+ errorMessage: nullableString(source.errorMessage)
21665
+ };
21666
+ }
21667
+ function parseDeploymentsResponse(value) {
21668
+ const source = record3(value);
21669
+ if (!source || !Array.isArray(source.deployments)) {
21670
+ throw new VercelDeploymentsRouteError(
21671
+ 502,
21672
+ "invalid_response",
21673
+ "Vercel returned an invalid deployments response"
21674
+ );
21675
+ }
21676
+ return source.deployments.map(parseDeployment).filter((deployment) => deployment !== null);
21677
+ }
21678
+ function parseBuildLog(value) {
21679
+ const source = record3(value);
21680
+ if (!source) return null;
21681
+ const createdAt = timestamp(source.created) ?? timestamp(source.date);
21682
+ const text = stringValue2(source.text);
21683
+ if (createdAt === null || !text) return null;
21684
+ return {
21685
+ id: stringValue2(source.id, `${createdAt}-${text}`),
21686
+ createdAt,
21687
+ type: stringValue2(source.type, "stdout"),
21688
+ text
21689
+ };
21690
+ }
21691
+ function parseBuildLogsResponse(value) {
21692
+ if (!Array.isArray(value)) {
21693
+ throw new VercelDeploymentsRouteError(
21694
+ 502,
21695
+ "invalid_response",
21696
+ "Vercel returned an invalid build log response"
21697
+ );
21698
+ }
21699
+ return value.map(parseBuildLog).filter((event) => event !== null).sort((left, right) => left.createdAt - right.createdAt);
21700
+ }
21701
+ function parseProjectFile(value, root) {
21702
+ const source = record3(value);
21703
+ const projectId = stringValue2(source?.projectId);
21704
+ const teamId = stringValue2(source?.orgId);
21705
+ const projectName = stringValue2(source?.projectName, "Vercel project");
21706
+ if (!VERCEL_ID.test(projectId) || !VERCEL_ID.test(teamId)) {
21707
+ throw new VercelDeploymentsRouteError(
21708
+ 400,
21709
+ "vercel_project_unlinked",
21710
+ "This project has an invalid .vercel/project.json link"
21711
+ );
21712
+ }
21713
+ return { root, projectId, projectName, teamId };
21714
+ }
21715
+ async function resolveLinkedVercelProject(cwd) {
21716
+ if (!isAbsolute8(cwd)) {
21717
+ throw new VercelDeploymentsRouteError(400, "vercel_project_unlinked", "cwd must be an absolute path");
21718
+ }
21719
+ let root;
21720
+ try {
21721
+ root = await realpath8(resolve15(cwd));
21722
+ if (!(await stat13(root)).isDirectory()) throw new Error("not a directory");
21723
+ } catch {
21724
+ throw new VercelDeploymentsRouteError(404, "vercel_project_unlinked", "Project directory not found");
21725
+ }
21726
+ const projectFile = join20(root, ".vercel", "project.json");
21727
+ try {
21728
+ const info = await stat13(projectFile);
21729
+ if (!info.isFile() || info.size > MAX_PROJECT_FILE_BYTES) throw new Error("invalid project file");
21730
+ return parseProjectFile(JSON.parse(await readFile15(projectFile, "utf8")), root);
21731
+ } catch (error) {
21732
+ if (error instanceof VercelDeploymentsRouteError) throw error;
21733
+ const detail = error;
21734
+ if (detail.code === "ENOENT") {
21735
+ throw new VercelDeploymentsRouteError(
21736
+ 400,
21737
+ "vercel_project_unlinked",
21738
+ "Link this project with `vercel link` before viewing deployments"
21739
+ );
21740
+ }
21741
+ throw new VercelDeploymentsRouteError(
21742
+ 400,
21743
+ "vercel_project_unlinked",
21744
+ "Unable to read this project's .vercel/project.json link"
21745
+ );
21746
+ }
21747
+ }
21748
+ async function executeVercel(cwd, args) {
21749
+ const cli = resolveAgentCommand("vercel", args);
21750
+ const result = await execFile4(cli.command, cli.args, {
21751
+ cwd,
21752
+ encoding: "utf-8",
21753
+ env: {
21754
+ ...process.env,
21755
+ NO_COLOR: "1",
21756
+ VERCEL_TELEMETRY_DISABLED: "1"
21757
+ },
21758
+ maxBuffer: 16 * 1024 * 1024,
21759
+ timeout: 3e4,
21760
+ windowsHide: true,
21761
+ ...cli.spawnOptions
21762
+ });
21763
+ return { stdout: result.stdout, stderr: result.stderr };
21764
+ }
21765
+ function parseCliVersion(output) {
21766
+ const match = output.match(/(?:^|\s)(\d+)\.(\d+)\.(\d+)(?:\s|$)/);
21767
+ return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : null;
21768
+ }
21769
+ function isVersionAtLeast(actual, minimum) {
21770
+ for (let index = 0; index < minimum.length; index += 1) {
21771
+ if (actual[index] > minimum[index]) return true;
21772
+ if (actual[index] < minimum[index]) return false;
21773
+ }
21774
+ return true;
21775
+ }
21776
+ function mapVercelFailure(error) {
21777
+ if (error instanceof VercelDeploymentsRouteError) return error;
21778
+ const failure = error;
21779
+ if (failure.code === "ENOENT") {
21780
+ return new VercelDeploymentsRouteError(503, "vercel_missing", "Install Vercel CLI to view deployments");
21781
+ }
21782
+ const detail = `${failure.message ?? ""}
21783
+ ${failure.stderr ?? ""}
21784
+ ${failure.stdout ?? ""}`;
21785
+ if (/not authenticated|not logged|log in|login|authentication|invalid token|unauthorized|401/i.test(detail)) {
21786
+ return new VercelDeploymentsRouteError(
21787
+ 503,
21788
+ "vercel_auth_required",
21789
+ "Sign in with `vercel login` to view deployments"
21790
+ );
21791
+ }
21792
+ if (/forbidden|access denied|not authorized|permission|403/i.test(detail)) {
21793
+ return new VercelDeploymentsRouteError(
21794
+ 403,
21795
+ "vercel_access_denied",
21796
+ "Your Vercel account cannot access this linked project"
21797
+ );
21798
+ }
21799
+ return new VercelDeploymentsRouteError(502, "vercel_api_failed", "Vercel deployment data is unavailable");
21800
+ }
21801
+ async function runVercelApi(project, endpoint, runCommand = executeVercel) {
21802
+ try {
21803
+ const versionResult = await runCommand(project.root, ["--version"]);
21804
+ const version = parseCliVersion(`${versionResult.stdout}
21805
+ ${versionResult.stderr}`);
21806
+ if (!version || !isVersionAtLeast(version, MINIMUM_API_CLI_VERSION)) {
21807
+ throw new VercelDeploymentsRouteError(
21808
+ 503,
21809
+ "vercel_cli_too_old",
21810
+ "Update Vercel CLI to version 50.5.1 or newer to view deployments safely"
21811
+ );
21812
+ }
21813
+ const result = await runCommand(project.root, [
21814
+ "api",
21815
+ endpoint,
21816
+ "--raw",
21817
+ "--cwd",
21818
+ project.root,
21819
+ "--non-interactive",
21820
+ "--no-color"
21821
+ ]);
21822
+ try {
21823
+ return JSON.parse(result.stdout);
21824
+ } catch {
21825
+ throw new VercelDeploymentsRouteError(
21826
+ 502,
21827
+ "invalid_response",
21828
+ "Vercel returned invalid JSON"
21829
+ );
21830
+ }
21831
+ } catch (error) {
21832
+ throw mapVercelFailure(error);
21833
+ }
21834
+ }
21835
+ function boundedLimit(value, fallback, maximum) {
21836
+ const requested = Number(value ?? fallback);
21837
+ return Number.isInteger(requested) ? Math.min(maximum, Math.max(1, requested)) : fallback;
21838
+ }
21839
+ function sendRouteError3(res, error) {
21840
+ const detail = mapVercelFailure(error);
21841
+ sendJson(res, detail.status, { error: detail.message, code: detail.code });
21842
+ }
21843
+ function registerVercelDeploymentRoutes(use, dependencies = defaultDependencies2) {
21844
+ use("/api/vercel-deployments", async (req, res, next) => {
21845
+ if (req.method !== "GET") return next();
21846
+ const url = new URL(req.url || "", "http://localhost");
21847
+ if (url.pathname !== "/" && url.pathname !== "") return next();
21848
+ const limit = boundedLimit(url.searchParams.get("limit"), DEFAULT_DEPLOYMENT_LIMIT, MAX_DEPLOYMENT_LIMIT);
21849
+ try {
21850
+ const project = await dependencies.resolveProject(url.searchParams.get("cwd") ?? "");
21851
+ const endpoint = `/v7/deployments?projectId=${encodeURIComponent(project.projectId)}&teamId=${encodeURIComponent(project.teamId)}&limit=${limit}`;
21852
+ const deployments = parseDeploymentsResponse(await dependencies.vercelApi(project, endpoint));
21853
+ const response = {
21854
+ projectId: project.projectId,
21855
+ projectName: project.projectName,
21856
+ teamId: project.teamId,
21857
+ projectUrl: projectUrlFromInspector(deployments[0]?.inspectorUrl ?? null),
21858
+ deployments
21859
+ };
21860
+ sendJson(res, 200, response);
21861
+ } catch (error) {
21862
+ sendRouteError3(res, error);
21863
+ }
21864
+ });
21865
+ use("/api/vercel-deployments/build-logs", async (req, res, next) => {
21866
+ if (req.method !== "GET") return next();
21867
+ const url = new URL(req.url || "", "http://localhost");
21868
+ if (url.pathname !== "/" && url.pathname !== "") return next();
21869
+ const deploymentId = url.searchParams.get("deploymentId") ?? "";
21870
+ if (!DEPLOYMENT_ID.test(deploymentId)) {
21871
+ return sendJson(res, 400, {
21872
+ error: "deploymentId must be a Vercel deployment ID",
21873
+ code: "vercel_api_failed"
21874
+ });
21875
+ }
21876
+ const limit = boundedLimit(url.searchParams.get("limit"), DEFAULT_LOG_LIMIT, MAX_LOG_LIMIT);
21877
+ try {
21878
+ const project = await dependencies.resolveProject(url.searchParams.get("cwd") ?? "");
21879
+ const endpoint = `/v3/deployments/${deploymentId}/events?teamId=${encodeURIComponent(project.teamId)}&direction=backward&limit=${limit}`;
21880
+ const events = parseBuildLogsResponse(await dependencies.vercelApi(project, endpoint));
21881
+ const response = { deploymentId, events };
21882
+ sendJson(res, 200, response);
21883
+ } catch (error) {
21884
+ sendRouteError3(res, error);
21885
+ }
21886
+ });
21887
+ }
21888
+ var execFile4, DEFAULT_DEPLOYMENT_LIMIT, MAX_DEPLOYMENT_LIMIT, DEFAULT_LOG_LIMIT, MAX_LOG_LIMIT, MAX_PROJECT_FILE_BYTES, MINIMUM_API_CLI_VERSION, VERCEL_ID, DEPLOYMENT_ID, DEPLOYMENT_STATES, VercelDeploymentsRouteError, defaultDependencies2;
21889
+ var init_vercel_deployments = __esm({
21890
+ "../../server/routes/vercel-deployments.ts"() {
21891
+ init_http();
21892
+ init_binaryResolver();
21893
+ execFile4 = promisify3(execFileCallback3);
21894
+ DEFAULT_DEPLOYMENT_LIMIT = 20;
21895
+ MAX_DEPLOYMENT_LIMIT = 30;
21896
+ DEFAULT_LOG_LIMIT = 200;
21897
+ MAX_LOG_LIMIT = 500;
21898
+ MAX_PROJECT_FILE_BYTES = 64 * 1024;
21899
+ MINIMUM_API_CLI_VERSION = [50, 5, 1];
21900
+ VERCEL_ID = /^[A-Za-z0-9_-]+$/;
21901
+ DEPLOYMENT_ID = /^dpl_[A-Za-z0-9]+$/;
21902
+ DEPLOYMENT_STATES = /* @__PURE__ */ new Set([
21903
+ "BLOCKED",
21904
+ "BUILDING",
21905
+ "CANCELED",
21906
+ "ERROR",
21907
+ "INITIALIZING",
21908
+ "QUEUED",
21909
+ "READY"
21910
+ ]);
21911
+ VercelDeploymentsRouteError = class extends Error {
21912
+ constructor(status, code, message) {
21913
+ super(message);
21914
+ this.status = status;
21915
+ this.code = code;
21916
+ }
21917
+ };
21918
+ defaultDependencies2 = {
21919
+ resolveProject: resolveLinkedVercelProject,
21920
+ vercelApi: runVercelApi
21921
+ };
21922
+ }
21923
+ });
21924
+
21141
21925
  // ../../server/lib/projectIcon.ts
21142
- import { realpath as realpath8, stat as stat13 } from "node:fs/promises";
21143
- import { basename as basename9, extname, join as join20, relative as relative8, sep as sep10 } from "node:path";
21926
+ import { realpath as realpath9, stat as stat14 } from "node:fs/promises";
21927
+ import { basename as basename9, extname, join as join21, relative as relative8, sep as sep10 } from "node:path";
21144
21928
  function namedIconCandidates(root) {
21145
21929
  const name = basename9(root);
21146
21930
  if (!name || name.startsWith(".")) return [];
21147
21931
  return ["public", "assets", "static", "."].flatMap(
21148
- (dir) => NAMED_ICON_EXTENSIONS.map((ext) => join20(dir, `${name}${ext}`))
21932
+ (dir) => NAMED_ICON_EXTENSIONS.map((ext) => join21(dir, `${name}${ext}`))
21149
21933
  );
21150
21934
  }
21151
21935
  function iconContentType(path) {
@@ -21158,7 +21942,7 @@ function isInside(root, candidate) {
21158
21942
  async function resolveProjectIcon(projectPath) {
21159
21943
  let root;
21160
21944
  try {
21161
- root = await realpath8(projectPath);
21945
+ root = await realpath9(projectPath);
21162
21946
  } catch {
21163
21947
  return null;
21164
21948
  }
@@ -21168,11 +21952,11 @@ async function resolveProjectIcon(projectPath) {
21168
21952
  ...PROJECT_ICON_CANDIDATES.slice(6)
21169
21953
  ];
21170
21954
  for (const candidate of candidates) {
21171
- const guess = join20(root, candidate);
21955
+ const guess = join21(root, candidate);
21172
21956
  try {
21173
- const resolved = await realpath8(guess);
21957
+ const resolved = await realpath9(guess);
21174
21958
  if (!isInside(root, resolved)) continue;
21175
- const info = await stat13(resolved);
21959
+ const info = await stat14(resolved);
21176
21960
  if (!info.isFile() || info.size === 0 || info.size > MAX_ICON_BYTES) continue;
21177
21961
  if (!iconContentType(resolved)) continue;
21178
21962
  return resolved;
@@ -21230,13 +22014,13 @@ var init_projectIcon = __esm({
21230
22014
 
21231
22015
  // ../../server/routes/project-icon.ts
21232
22016
  import { createReadStream } from "node:fs";
21233
- import { isAbsolute as isAbsolute8 } from "node:path";
22017
+ import { isAbsolute as isAbsolute9 } from "node:path";
21234
22018
  function registerProjectIconRoutes(use) {
21235
22019
  use("/api/project-icon", async (req, res, next) => {
21236
22020
  if (req.method !== "GET") return next();
21237
22021
  const url = new URL(req.url || "", "http://localhost");
21238
22022
  const cwd = url.searchParams.get("cwd") ?? "";
21239
- if (!isAbsolute8(cwd)) {
22023
+ if (!isAbsolute9(cwd)) {
21240
22024
  return sendJson(res, 400, { error: "cwd must be an absolute path" });
21241
22025
  }
21242
22026
  const icon = await resolveProjectIcon(cwd);
@@ -21321,14 +22105,14 @@ var init_local_file = __esm({
21321
22105
  });
21322
22106
 
21323
22107
  // ../../server/routes/mcp.ts
21324
- import { execFile as execFile3 } from "node:child_process";
21325
- import { isAbsolute as isAbsolute9, join as join21 } from "node:path";
21326
- import { readFile as readFile15 } from "node:fs/promises";
22108
+ import { execFile as execFile5 } from "node:child_process";
22109
+ import { isAbsolute as isAbsolute10, join as join22 } from "node:path";
22110
+ import { readFile as readFile16 } from "node:fs/promises";
21327
22111
  import { homedir as homedir7 } from "node:os";
21328
22112
  async function readMcpConfigs(cwd) {
21329
22113
  const configs = {};
21330
22114
  try {
21331
- const raw = await readFile15(join21(homedir7(), ".claude.json"), "utf-8");
22115
+ const raw = await readFile16(join22(homedir7(), ".claude.json"), "utf-8");
21332
22116
  const parsed = JSON.parse(raw);
21333
22117
  if (parsed.mcpServers && typeof parsed.mcpServers === "object") {
21334
22118
  Object.assign(configs, parsed.mcpServers);
@@ -21346,16 +22130,16 @@ async function readMcpConfigs(cwd) {
21346
22130
  } catch {
21347
22131
  }
21348
22132
  const otherSources = [
21349
- join21(homedir7(), ".claude", "settings.json"),
22133
+ join22(homedir7(), ".claude", "settings.json"),
21350
22134
  // global settings
21351
- join21(cwd, ".mcp.json"),
22135
+ join22(cwd, ".mcp.json"),
21352
22136
  // project
21353
- join21(cwd, ".claude", "settings.local.json")
22137
+ join22(cwd, ".claude", "settings.local.json")
21354
22138
  // project local
21355
22139
  ];
21356
22140
  for (const path of otherSources) {
21357
22141
  try {
21358
- const raw = await readFile15(path, "utf-8");
22142
+ const raw = await readFile16(path, "utf-8");
21359
22143
  const parsed = JSON.parse(raw);
21360
22144
  if (parsed.mcpServers && typeof parsed.mcpServers === "object") {
21361
22145
  Object.assign(configs, parsed.mcpServers);
@@ -21398,18 +22182,18 @@ async function getMcpServers(cwd) {
21398
22182
  return { servers: cached.servers, configs: cached.configs };
21399
22183
  }
21400
22184
  const configs = await readMcpConfigs(cwd);
21401
- return new Promise((resolve21) => {
22185
+ return new Promise((resolve22) => {
21402
22186
  const env = { ...process.env };
21403
22187
  delete env.CLAUDECODE;
21404
22188
  const cli = resolveAgentCommand("claude", ["mcp", "list"]);
21405
- execFile3(cli.command, cli.args, { cwd, env, timeout: 15e3, ...cli.spawnOptions }, (err, stdout) => {
22189
+ execFile5(cli.command, cli.args, { cwd, env, timeout: 15e3, ...cli.spawnOptions }, (err, stdout) => {
21406
22190
  if (err) {
21407
- resolve21({ servers: cached?.servers ?? [], configs });
22191
+ resolve22({ servers: cached?.servers ?? [], configs });
21408
22192
  return;
21409
22193
  }
21410
22194
  const servers = parseMcpListOutput(stdout);
21411
22195
  cache.set(cwd, { servers, configs, timestamp: Date.now() });
21412
- resolve21({ servers, configs });
22196
+ resolve22({ servers, configs });
21413
22197
  });
21414
22198
  });
21415
22199
  }
@@ -21419,7 +22203,7 @@ function registerMcpRoutes(use) {
21419
22203
  const url = new URL(req.url || "", `http://${req.headers.host}`);
21420
22204
  const cwd = url.searchParams.get("cwd");
21421
22205
  const refresh = url.searchParams.get("refresh") === "1";
21422
- if (!cwd || !isAbsolute9(cwd)) {
22206
+ if (!cwd || !isAbsolute10(cwd)) {
21423
22207
  return sendJson(res, 400, { error: "cwd must be an absolute path" });
21424
22208
  }
21425
22209
  if (refresh) clearMcpCache(cwd);
@@ -21531,7 +22315,7 @@ var init_diff_utils = __esm({
21531
22315
  function isObject9(value) {
21532
22316
  return typeof value === "object" && value !== null;
21533
22317
  }
21534
- function firstString2(...values) {
22318
+ function firstString3(...values) {
21535
22319
  return values.find((value) => typeof value === "string") ?? "";
21536
22320
  }
21537
22321
  function truncate(value, length = 140) {
@@ -21778,19 +22562,19 @@ function nativeWebPresentation(input) {
21778
22562
  if (type === "open_page" || type === "openPage") {
21779
22563
  return {
21780
22564
  label: "Open page",
21781
- summary: firstString2(action?.url, input.query),
22565
+ summary: firstString3(action?.url, input.query),
21782
22566
  styleName: "WebSearch"
21783
22567
  };
21784
22568
  }
21785
22569
  if (type === "find_in_page" || type === "findInPage") {
21786
22570
  return {
21787
22571
  label: "Find on page",
21788
- summary: [firstString2(action?.pattern), firstString2(action?.url)].filter(Boolean).join(" \xB7 "),
22572
+ summary: [firstString3(action?.pattern), firstString3(action?.url)].filter(Boolean).join(" \xB7 "),
21789
22573
  styleName: "WebSearch"
21790
22574
  };
21791
22575
  }
21792
22576
  const queries = Array.isArray(action?.queries) ? action.queries.filter((query5) => typeof query5 === "string") : [];
21793
- const query4 = firstString2(action?.query, input.query);
22577
+ const query4 = firstString3(action?.query, input.query);
21794
22578
  return {
21795
22579
  label: "Search web",
21796
22580
  summary: compactValues([query4, ...queries]),
@@ -21798,7 +22582,7 @@ function nativeWebPresentation(input) {
21798
22582
  };
21799
22583
  }
21800
22584
  function schemaFreeSummary(input) {
21801
- const gist = firstString2(...SCHEMA_FREE_GIST_KEYS.map((key2) => input[key2]));
22585
+ const gist = firstString3(...SCHEMA_FREE_GIST_KEYS.map((key2) => input[key2]));
21802
22586
  if (gist) return truncate(gist);
21803
22587
  for (const [key2, value] of Object.entries(input)) {
21804
22588
  if (!Array.isArray(value)) continue;
@@ -21808,11 +22592,11 @@ function schemaFreeSummary(input) {
21808
22592
  return "";
21809
22593
  }
21810
22594
  function workflowSummary(input) {
21811
- const description = firstString2(input.description);
22595
+ const description = firstString3(input.description);
21812
22596
  if (description) return truncate(description);
21813
- const script = firstString2(input.script);
22597
+ const script = firstString3(input.script);
21814
22598
  const metaName = script ? extractJsStringPropertyValues(script, "name")[0] ?? "" : "";
21815
- return metaName || firstString2(input.scriptPath);
22599
+ return metaName || firstString3(input.scriptPath);
21816
22600
  }
21817
22601
  function firstStringValue(input) {
21818
22602
  const keys = Object.keys(input);
@@ -21889,19 +22673,19 @@ function defaultToolSummary(tc) {
21889
22673
  case "ToolSearch":
21890
22674
  return String(input.query ?? "");
21891
22675
  case "SendMessage": {
21892
- const recipient = firstString2(input.to, input.recipient);
21893
- const gist = truncate(firstString2(input.summary, input.message, input.content));
22676
+ const recipient = firstString3(input.to, input.recipient);
22677
+ const gist = truncate(firstString3(input.summary, input.message, input.content));
21894
22678
  return [recipient, gist].filter(Boolean).join(" \xB7 ");
21895
22679
  }
21896
22680
  case "ListAgents":
21897
22681
  case "TaskList":
21898
22682
  return "";
21899
22683
  case "TaskCreate":
21900
- return truncate(firstString2(input.subject, input.description));
22684
+ return truncate(firstString3(input.subject, input.description));
21901
22685
  case "TaskUpdate": {
21902
22686
  const taskId = String(input.taskId ?? "");
21903
22687
  const blockers = Array.isArray(input.addBlockedBy) ? input.addBlockedBy.filter((id) => typeof id === "string") : [];
21904
- const change = firstString2(input.status) || (blockers.length > 0 ? `blocked by ${blockers.join(", ")}` : "");
22688
+ const change = firstString3(input.status) || (blockers.length > 0 ? `blocked by ${blockers.join(", ")}` : "");
21905
22689
  return change ? `${taskId} \u2192 ${change}` : taskId;
21906
22690
  }
21907
22691
  case "TaskOutput":
@@ -22201,8 +22985,8 @@ function copilotText(value) {
22201
22985
  if (!Array.isArray(value)) return "";
22202
22986
  return value.flatMap((part) => {
22203
22987
  if (typeof part === "string") return part ? [part] : [];
22204
- const record2 = asRecord5(part);
22205
- const text = str(record2.text) || str(record2.content);
22988
+ const record4 = asRecord5(part);
22989
+ const text = str(record4.text) || str(record4.content);
22206
22990
  return text ? [text] : [];
22207
22991
  }).join("\n");
22208
22992
  }
@@ -22534,7 +23318,7 @@ var init_summaryFolds = __esm({
22534
23318
  });
22535
23319
 
22536
23320
  // ../../server/lib/missionControlSummary.ts
22537
- import { open as open7, stat as stat14 } from "node:fs/promises";
23321
+ import { open as open7, stat as stat15 } from "node:fs/promises";
22538
23322
  function foldLine(acc, line) {
22539
23323
  const trimmed = line.trim();
22540
23324
  if (!trimmed) return;
@@ -22544,10 +23328,10 @@ function foldLine(acc, line) {
22544
23328
  } catch {
22545
23329
  return;
22546
23330
  }
22547
- const timestamp = str(entry.timestamp);
22548
- if (timestamp) {
22549
- acc.startedAt ??= timestamp;
22550
- acc.lastEventAt = timestamp;
23331
+ const timestamp2 = str(entry.timestamp);
23332
+ if (timestamp2) {
23333
+ acc.startedAt ??= timestamp2;
23334
+ acc.lastEventAt = timestamp2;
22551
23335
  }
22552
23336
  foldSummaryEntry(acc, entry);
22553
23337
  }
@@ -22609,7 +23393,7 @@ async function readSince(filePath, from, to) {
22609
23393
  async function summarizeSession(sessionId, filePath) {
22610
23394
  let size;
22611
23395
  try {
22612
- size = (await stat14(filePath)).size;
23396
+ size = (await stat15(filePath)).size;
22613
23397
  } catch {
22614
23398
  return null;
22615
23399
  }
@@ -22766,14 +23550,14 @@ var init_models = __esm({
22766
23550
  });
22767
23551
 
22768
23552
  // ../../server/lib/notificationHistory.ts
22769
- import { mkdir as mkdir5, readFile as readFile16 } from "node:fs/promises";
23553
+ import { mkdir as mkdir5, readFile as readFile17 } from "node:fs/promises";
22770
23554
  import { mkdirSync, writeFileSync } from "node:fs";
22771
23555
  import { homedir as homedir8 } from "node:os";
22772
- import { dirname as dirname9, join as join22 } from "node:path";
23556
+ import { dirname as dirname9, join as join23 } from "node:path";
22773
23557
  import { randomUUID as randomUUID4 } from "node:crypto";
22774
23558
  async function load() {
22775
23559
  if (entries) return entries;
22776
- loadPromise ??= readFile16(NOTIFICATION_HISTORY_FILE, "utf-8").then((raw) => {
23560
+ loadPromise ??= readFile17(NOTIFICATION_HISTORY_FILE, "utf-8").then((raw) => {
22777
23561
  const parsed = JSON.parse(raw);
22778
23562
  return Array.isArray(parsed) ? parsed.filter(isEntry) : [];
22779
23563
  }).catch(() => []).then((loaded2) => {
@@ -22857,7 +23641,7 @@ var NOTIFICATION_HISTORY_FILE, MAX_ENTRIES, PERSIST_DEBOUNCE_MS, entries, loadPr
22857
23641
  var init_notificationHistory = __esm({
22858
23642
  "../../server/lib/notificationHistory.ts"() {
22859
23643
  init_atomicJsonFile();
22860
- NOTIFICATION_HISTORY_FILE = join22(homedir8(), ".cogpit", "notifications.json");
23644
+ NOTIFICATION_HISTORY_FILE = join23(homedir8(), ".cogpit", "notifications.json");
22861
23645
  MAX_ENTRIES = 200;
22862
23646
  PERSIST_DEBOUNCE_MS = 500;
22863
23647
  entries = null;
@@ -22905,7 +23689,7 @@ var init_notifications = __esm({
22905
23689
  });
22906
23690
 
22907
23691
  // ../../server/lib/systemProcesses.ts
22908
- import { execFile as execFile4 } from "node:child_process";
23692
+ import { execFile as execFile6 } from "node:child_process";
22909
23693
  function parseEtimeSeconds(etime) {
22910
23694
  const match = /^(?:(\d+)-)?(?:(\d+):)?(\d+):(\d+)$/.exec(etime.trim());
22911
23695
  if (!match) return 0;
@@ -23026,12 +23810,12 @@ function classifyProcesses(rows, selfPid) {
23026
23810
  }).slice(0, MAX_LISTED_PROCESSES);
23027
23811
  }
23028
23812
  function listSystemProcesses() {
23029
- return new Promise((resolve21, reject) => {
23030
- execFile4(
23813
+ return new Promise((resolve22, reject) => {
23814
+ execFile6(
23031
23815
  "ps",
23032
23816
  ["-axo", "pid=,ppid=,pcpu=,rss=,etime=,args="],
23033
23817
  { maxBuffer: 8 * 1024 * 1024 },
23034
- (error, stdout) => error ? reject(error) : resolve21(stdout)
23818
+ (error, stdout) => error ? reject(error) : resolve22(stdout)
23035
23819
  );
23036
23820
  });
23037
23821
  }
@@ -23065,7 +23849,7 @@ var init_systemProcesses = __esm({
23065
23849
  });
23066
23850
 
23067
23851
  // ../../server/lib/desktopNotify.ts
23068
- import { execFile as execFile5 } from "node:child_process";
23852
+ import { execFile as execFile7 } from "node:child_process";
23069
23853
  function parentMessagePort() {
23070
23854
  const { parentPort } = process;
23071
23855
  return parentPort && typeof parentPort.postMessage === "function" ? parentPort : null;
@@ -23078,7 +23862,7 @@ function showNotification(title, body, nav, historyId) {
23078
23862
  return;
23079
23863
  }
23080
23864
  if (process.platform === "darwin") {
23081
- execFile5(
23865
+ execFile7(
23082
23866
  "osascript",
23083
23867
  ["-e", `display notification "${escapeAppleScript(body)}" with title "${escapeAppleScript(title)}"`],
23084
23868
  // This is the standalone server's only desktop channel, so a silent
@@ -23119,9 +23903,9 @@ var init_notifications2 = __esm({
23119
23903
  });
23120
23904
 
23121
23905
  // ../../server/lib/pushConfig.ts
23122
- import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
23906
+ import { readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
23123
23907
  import { homedir as homedir9 } from "node:os";
23124
- import { join as join23 } from "node:path";
23908
+ import { join as join24 } from "node:path";
23125
23909
  function warnOnce(message) {
23126
23910
  if (lastWarning === message) return;
23127
23911
  lastWarning = message;
@@ -23132,7 +23916,7 @@ function asString(value) {
23132
23916
  }
23133
23917
  function fileMtime(path) {
23134
23918
  try {
23135
- return statSync2(path).mtimeMs;
23919
+ return statSync3(path).mtimeMs;
23136
23920
  } catch {
23137
23921
  return null;
23138
23922
  }
@@ -23147,8 +23931,8 @@ function warnIfExposed(path, mode) {
23147
23931
  function readConfigFile(path) {
23148
23932
  let raw;
23149
23933
  try {
23150
- warnIfExposed(path, statSync2(path).mode);
23151
- raw = readFileSync2(path, "utf8");
23934
+ warnIfExposed(path, statSync3(path).mode);
23935
+ raw = readFileSync3(path, "utf8");
23152
23936
  } catch (err) {
23153
23937
  const code = err.code;
23154
23938
  if (code !== "ENOENT") warnOnce(`Could not read ${path}: ${code ?? String(err)}`);
@@ -23181,7 +23965,7 @@ function normalizeBaseUrl(value, label) {
23181
23965
  }
23182
23966
  return parsed.toString().replace(/\/+$/, "");
23183
23967
  }
23184
- function resolve15(path) {
23968
+ function resolve16(path) {
23185
23969
  const file = readConfigFile(path);
23186
23970
  const topic = asString(process.env.COGPIT_NTFY_TOPIC) ?? asString(file.topic);
23187
23971
  if (!topic) return null;
@@ -23209,14 +23993,14 @@ function getPushConfig(path = PUSH_CONFIG_FILE) {
23209
23993
  process.env.COGPIT_PUBLIC_URL
23210
23994
  ].join("\0");
23211
23995
  if (cache3?.key === key2) return cache3.config;
23212
- const config = resolve15(path);
23996
+ const config = resolve16(path);
23213
23997
  cache3 = { key: key2, config };
23214
23998
  return config;
23215
23999
  }
23216
24000
  var PUSH_CONFIG_FILE, DEFAULT_NTFY_URL, TOPIC_PATTERN, cache3, lastWarning;
23217
24001
  var init_pushConfig = __esm({
23218
24002
  "../../server/lib/pushConfig.ts"() {
23219
- PUSH_CONFIG_FILE = join23(homedir9(), ".cogpit", "push.json");
24003
+ PUSH_CONFIG_FILE = join24(homedir9(), ".cogpit", "push.json");
23220
24004
  DEFAULT_NTFY_URL = "https://ntfy.sh";
23221
24005
  TOPIC_PATTERN = /^[-_A-Za-z0-9]{1,64}$/;
23222
24006
  cache3 = null;
@@ -23831,22 +24615,22 @@ async function handleBackgroundTasks(req, res, next) {
23831
24615
  const portAlive = {};
23832
24616
  await Promise.all(
23833
24617
  allPorts.map(
23834
- (port) => new Promise((resolve21) => {
24618
+ (port) => new Promise((resolve22) => {
23835
24619
  const socket = createConnection({ port, host: "127.0.0.1" });
23836
24620
  socket.setTimeout(500);
23837
24621
  socket.on("connect", () => {
23838
24622
  portAlive[port] = true;
23839
24623
  socket.destroy();
23840
- resolve21();
24624
+ resolve22();
23841
24625
  });
23842
24626
  socket.on("timeout", () => {
23843
24627
  portAlive[port] = false;
23844
24628
  socket.destroy();
23845
- resolve21();
24629
+ resolve22();
23846
24630
  });
23847
24631
  socket.on("error", () => {
23848
24632
  portAlive[port] = false;
23849
- resolve21();
24633
+ resolve22();
23850
24634
  });
23851
24635
  })
23852
24636
  )
@@ -23950,14 +24734,14 @@ var init_backgroundAgents = __esm({
23950
24734
 
23951
24735
  // ../../server/routes/ports/listeningProcesses.ts
23952
24736
  function runCapture(command, args) {
23953
- return new Promise((resolve21, reject) => {
23954
- const child = spawn(command, args);
24737
+ return new Promise((resolve22, reject) => {
24738
+ const child = spawn2(command, args);
23955
24739
  let stdout = "";
23956
24740
  child.stdout?.on("data", (data) => {
23957
24741
  stdout += data.toString();
23958
24742
  });
23959
24743
  child.on("error", reject);
23960
- child.on("close", () => resolve21(stdout));
24744
+ child.on("close", () => resolve22(stdout));
23961
24745
  });
23962
24746
  }
23963
24747
  async function findListeningPids(port) {
@@ -23997,22 +24781,22 @@ function registerPortRoutes(use) {
23997
24781
  const results = {};
23998
24782
  await Promise.all(
23999
24783
  ports.map(
24000
- (port) => new Promise((resolve21) => {
24784
+ (port) => new Promise((resolve22) => {
24001
24785
  const socket = createConnection({ port, host: "127.0.0.1" });
24002
24786
  socket.setTimeout(500);
24003
24787
  socket.on("connect", () => {
24004
24788
  results[port] = true;
24005
24789
  socket.destroy();
24006
- resolve21();
24790
+ resolve22();
24007
24791
  });
24008
24792
  socket.on("timeout", () => {
24009
24793
  results[port] = false;
24010
24794
  socket.destroy();
24011
- resolve21();
24795
+ resolve22();
24012
24796
  });
24013
24797
  socket.on("error", () => {
24014
24798
  results[port] = false;
24015
- resolve21();
24799
+ resolve22();
24016
24800
  });
24017
24801
  })
24018
24802
  )
@@ -24082,8 +24866,8 @@ var init_ports2 = __esm({
24082
24866
 
24083
24867
  // ../../server/routes/project-file.ts
24084
24868
  import { randomUUID as randomUUID5 } from "node:crypto";
24085
- import { readFile as readFile17, realpath as realpath9, rename as rename3, stat as stat15, unlink as unlink6, writeFile as writeFile6 } from "node:fs/promises";
24086
- import { dirname as dirname10, isAbsolute as isAbsolute10, resolve as resolve16 } from "node:path";
24869
+ import { readFile as readFile18, realpath as realpath10, rename as rename3, stat as stat16, unlink as unlink6, writeFile as writeFile6 } from "node:fs/promises";
24870
+ import { dirname as dirname10, isAbsolute as isAbsolute11, resolve as resolve17 } from "node:path";
24087
24871
  function readBody(req) {
24088
24872
  return new Promise((resolveBody, reject) => {
24089
24873
  let body = "";
@@ -24101,26 +24885,26 @@ function readBody(req) {
24101
24885
  });
24102
24886
  }
24103
24887
  async function resolveProjectFile(cwd, filePath) {
24104
- if (!isAbsolute10(cwd)) throw new ProjectFileError(400, "cwd must be an absolute path");
24105
- if (!filePath || isAbsolute10(filePath) || filePath.includes("\0")) {
24888
+ if (!isAbsolute11(cwd)) throw new ProjectFileError(400, "cwd must be an absolute path");
24889
+ if (!filePath || isAbsolute11(filePath) || filePath.includes("\0")) {
24106
24890
  throw new ProjectFileError(400, "path must be a relative project file");
24107
24891
  }
24108
24892
  let root;
24109
24893
  try {
24110
- root = await realpath9(resolve16(cwd));
24894
+ root = await realpath10(resolve17(cwd));
24111
24895
  } catch {
24112
24896
  throw new ProjectFileError(404, "Project directory not found");
24113
24897
  }
24114
- const candidate = resolve16(root, filePath);
24898
+ const candidate = resolve17(root, filePath);
24115
24899
  if (!isWithinDir(root, candidate)) throw new ProjectFileError(403, "File is outside the project");
24116
24900
  let absolutePath;
24117
24901
  try {
24118
- absolutePath = await realpath9(candidate);
24902
+ absolutePath = await realpath10(candidate);
24119
24903
  } catch {
24120
24904
  throw new ProjectFileError(404, "File not found");
24121
24905
  }
24122
24906
  if (!isWithinDir(root, absolutePath)) throw new ProjectFileError(403, "File is outside the project");
24123
- const info = await stat15(absolutePath);
24907
+ const info = await stat16(absolutePath);
24124
24908
  if (!info.isFile()) throw new ProjectFileError(400, "Path must point to a file");
24125
24909
  if (info.size > MAX_FILE_BYTES) throw new ProjectFileError(413, "File is larger than 2 MB");
24126
24910
  return { absolutePath, info };
@@ -24140,14 +24924,14 @@ function decodeTextFile(buffer) {
24140
24924
  }
24141
24925
  }
24142
24926
  async function writeAtomically(absolutePath, content, mode, expectedMtimeMs) {
24143
- const latest = await stat15(absolutePath);
24927
+ const latest = await stat16(absolutePath);
24144
24928
  if (latest.mtimeMs !== expectedMtimeMs) {
24145
24929
  throw new ProjectFileError(409, "File changed on disk. Reload it before saving.");
24146
24930
  }
24147
- const temporaryPath = resolve16(dirname10(absolutePath), `.${randomUUID5()}.cogpit-save`);
24931
+ const temporaryPath = resolve17(dirname10(absolutePath), `.${randomUUID5()}.cogpit-save`);
24148
24932
  try {
24149
24933
  await writeFile6(temporaryPath, content, { encoding: "utf-8", mode });
24150
- const beforeRename = await stat15(absolutePath);
24934
+ const beforeRename = await stat16(absolutePath);
24151
24935
  if (beforeRename.mtimeMs !== expectedMtimeMs) {
24152
24936
  throw new ProjectFileError(409, "File changed on disk. Reload it before saving.");
24153
24937
  }
@@ -24164,7 +24948,7 @@ function registerProjectFileContentRoutes(use) {
24164
24948
  const filePath = url.searchParams.get("path") ?? "";
24165
24949
  try {
24166
24950
  const file = await resolveProjectFile(cwd, filePath);
24167
- const buffer = await readFile17(file.absolutePath);
24951
+ const buffer = await readFile18(file.absolutePath);
24168
24952
  return sendJson(res, 200, {
24169
24953
  content: decodeTextFile(buffer),
24170
24954
  mtimeMs: file.info.mtimeMs,
@@ -24188,7 +24972,7 @@ function registerProjectFileContentRoutes(use) {
24188
24972
  throw new ProjectFileError(409, "File changed on disk. Reload it before saving.");
24189
24973
  }
24190
24974
  await writeAtomically(file.absolutePath, body.content, file.info.mode, body.expectedMtimeMs);
24191
- const saved = await stat15(file.absolutePath);
24975
+ const saved = await stat16(file.absolutePath);
24192
24976
  return sendJson(res, 200, { ok: true, mtimeMs: saved.mtimeMs, size: saved.size });
24193
24977
  } catch (error) {
24194
24978
  return respondWithError(res, error);
@@ -24238,13 +25022,13 @@ var init_project_files_ranking = __esm({
24238
25022
  });
24239
25023
 
24240
25024
  // ../../server/routes/project-files.ts
24241
- import { execFile as execFileCallback2 } from "node:child_process";
24242
- import { readdir as readdir11, realpath as realpath10, stat as stat16 } from "node:fs/promises";
24243
- import { isAbsolute as isAbsolute11, relative as relative9, resolve as resolve17, sep as sep11 } from "node:path";
24244
- import { promisify as promisify2 } from "node:util";
25025
+ import { execFile as execFileCallback4 } from "node:child_process";
25026
+ import { readdir as readdir11, realpath as realpath11, stat as stat17 } from "node:fs/promises";
25027
+ import { isAbsolute as isAbsolute12, relative as relative9, resolve as resolve18, sep as sep11 } from "node:path";
25028
+ import { promisify as promisify4 } from "node:util";
24245
25029
  async function listGitProjectFiles(root) {
24246
25030
  try {
24247
- const result = await execFile6(
25031
+ const result = await execFile8(
24248
25032
  "git",
24249
25033
  ["ls-files", "--cached", "--others", "--exclude-standard", "-z", "--", "."],
24250
25034
  {
@@ -24280,7 +25064,7 @@ async function listProjectFiles(root, { skipCache = false } = {}) {
24280
25064
  }
24281
25065
  for (const entry of entries3) {
24282
25066
  if (entry.isSymbolicLink()) continue;
24283
- const absolutePath = resolve17(directory, entry.name);
25067
+ const absolutePath = resolve18(directory, entry.name);
24284
25068
  if (entry.isDirectory()) {
24285
25069
  if (!IGNORED_DIRECTORIES.has(entry.name)) pending.push(absolutePath);
24286
25070
  continue;
@@ -24302,12 +25086,12 @@ function registerProjectFileRoutes(use) {
24302
25086
  const query4 = url.searchParams.get("q") ?? "";
24303
25087
  const limit = Math.min(Math.max(Number(url.searchParams.get("limit")) || 30, 1), 100);
24304
25088
  const skipCache = url.searchParams.get("refresh") === "1";
24305
- if (!isAbsolute11(cwd)) return sendJson(res, 400, { error: "cwd must be an absolute path" });
24306
- let root = resolve17(cwd);
25089
+ if (!isAbsolute12(cwd)) return sendJson(res, 400, { error: "cwd must be an absolute path" });
25090
+ let root = resolve18(cwd);
24307
25091
  try {
24308
- const info = await stat16(root);
25092
+ const info = await stat17(root);
24309
25093
  if (!info.isDirectory()) return sendJson(res, 400, { error: "cwd must be a directory" });
24310
- root = await realpath10(root);
25094
+ root = await realpath11(root);
24311
25095
  const files = await listProjectFiles(root, { skipCache });
24312
25096
  const ranked = rankProjectFiles(files, query4, limit);
24313
25097
  return sendJson(res, 200, {
@@ -24320,7 +25104,7 @@ function registerProjectFileRoutes(use) {
24320
25104
  }
24321
25105
  });
24322
25106
  }
24323
- var MAX_FILES, CACHE_TTL_MS3, IGNORED_DIRECTORIES, fileCache, execFile6;
25107
+ var MAX_FILES, CACHE_TTL_MS3, IGNORED_DIRECTORIES, fileCache, execFile8;
24324
25108
  var init_project_files = __esm({
24325
25109
  "../../server/routes/project-files.ts"() {
24326
25110
  init_http();
@@ -24341,7 +25125,7 @@ var init_project_files = __esm({
24341
25125
  "target"
24342
25126
  ]);
24343
25127
  fileCache = /* @__PURE__ */ new Map();
24344
- execFile6 = promisify2(execFileCallback2);
25128
+ execFile8 = promisify4(execFileCallback4);
24345
25129
  }
24346
25130
  });
24347
25131
 
@@ -24555,7 +25339,7 @@ function createCollector() {
24555
25339
  return {
24556
25340
  pullRequests,
24557
25341
  add,
24558
- record(output, command, toolCallId, timestamp) {
25342
+ record(output, command, toolCallId, timestamp2) {
24559
25343
  const match = PR_URL.exec(output);
24560
25344
  if (!match) return;
24561
25345
  add({
@@ -24565,7 +25349,7 @@ function createCollector() {
24565
25349
  title: extractTitle(command),
24566
25350
  isDraft: /(?:^|\s)--draft(?:\s|$)/.test(command),
24567
25351
  toolCallId,
24568
- timestamp
25352
+ timestamp: timestamp2
24569
25353
  });
24570
25354
  }
24571
25355
  };
@@ -24594,22 +25378,22 @@ function createPullRequestScanner() {
24594
25378
  seenReferences.add(key2);
24595
25379
  references.push(reference);
24596
25380
  }
24597
- function recordToolCall(id, input, timestamp) {
25381
+ function recordToolCall(id, input, timestamp2) {
24598
25382
  const reference = findPullRequestReference(input);
24599
25383
  if (reference) recordReference(reference);
24600
- recordCreate(id, input, timestamp);
25384
+ recordCreate(id, input, timestamp2);
24601
25385
  }
24602
- function recordCreate(id, input, timestamp) {
25386
+ function recordCreate(id, input, timestamp2) {
24603
25387
  if (typeof id !== "string" || !id) return;
24604
25388
  const command = findCreateCommand(input);
24605
- if (command) openCreates.set(id, { command, timestamp });
25389
+ if (command) openCreates.set(id, { command, timestamp: timestamp2 });
24606
25390
  }
24607
- function recordPrLink(record2, timestamp) {
24608
- const url = record2.prUrl;
24609
- const number = record2.prNumber;
25391
+ function recordPrLink(record4, timestamp2) {
25392
+ const url = record4.prUrl;
25393
+ const number = record4.prNumber;
24610
25394
  if (typeof url !== "string" || !url) return;
24611
25395
  if (typeof number !== "number" || !Number.isInteger(number) || number <= 0) return;
24612
- const repo = typeof record2.prRepository === "string" ? record2.prRepository : "";
25396
+ const repo = typeof record4.prRepository === "string" ? record4.prRepository : "";
24613
25397
  collector.add({
24614
25398
  url,
24615
25399
  number,
@@ -24617,7 +25401,7 @@ function createPullRequestScanner() {
24617
25401
  title: null,
24618
25402
  isDraft: false,
24619
25403
  toolCallId: "",
24620
- timestamp
25404
+ timestamp: timestamp2
24621
25405
  });
24622
25406
  recordReference({ number, repo });
24623
25407
  }
@@ -24644,37 +25428,37 @@ function createPullRequestScanner() {
24644
25428
  if (!line.includes(GH_PR_HINT) && !line.includes(URL_HINT) && !line.includes(PR_LINK_HINT)) {
24645
25429
  return;
24646
25430
  }
24647
- let record2;
25431
+ let record4;
24648
25432
  try {
24649
- record2 = JSON.parse(line);
25433
+ record4 = JSON.parse(line);
24650
25434
  } catch {
24651
25435
  return;
24652
25436
  }
24653
- if (!isRecord5(record2)) return;
24654
- const timestamp = typeof record2.timestamp === "string" ? record2.timestamp : "";
24655
- if (record2.type === "pr-link") {
24656
- recordPrLink(record2, timestamp);
25437
+ if (!isRecord5(record4)) return;
25438
+ const timestamp2 = typeof record4.timestamp === "string" ? record4.timestamp : "";
25439
+ if (record4.type === "pr-link") {
25440
+ recordPrLink(record4, timestamp2);
24657
25441
  return;
24658
25442
  }
24659
- const payload = record2.payload;
25443
+ const payload = record4.payload;
24660
25444
  if (isRecord5(payload)) {
24661
25445
  const type = payload.type;
24662
25446
  if (type === "function_call" || type === "custom_tool_call") {
24663
- recordToolCall(payload.call_id, parseArgs2(payload.arguments ?? payload.input), timestamp);
25447
+ recordToolCall(payload.call_id, parseArgs2(payload.arguments ?? payload.input), timestamp2);
24664
25448
  } else if (type === "function_call_output" || type === "custom_tool_call_output") {
24665
25449
  recordResult(payload.call_id, payload.output, false);
24666
25450
  }
24667
25451
  return;
24668
25452
  }
24669
- const data = record2.data;
25453
+ const data = record4.data;
24670
25454
  if (isRecord5(data)) {
24671
- if (record2.type === "tool.execution_start") {
25455
+ if (record4.type === "tool.execution_start") {
24672
25456
  recordToolCall(
24673
25457
  data.toolCallId,
24674
25458
  parseArgs2(data.arguments ?? data.input),
24675
- timestamp
25459
+ timestamp2
24676
25460
  );
24677
- } else if (record2.type === "tool.execution_complete") {
25461
+ } else if (record4.type === "tool.execution_complete") {
24678
25462
  recordResult(
24679
25463
  data.toolCallId,
24680
25464
  data.result ?? data.output ?? data.error,
@@ -24683,12 +25467,12 @@ function createPullRequestScanner() {
24683
25467
  }
24684
25468
  return;
24685
25469
  }
24686
- const message = record2.message;
25470
+ const message = record4.message;
24687
25471
  if (!isRecord5(message) || !Array.isArray(message.content)) return;
24688
25472
  for (const block of message.content) {
24689
25473
  if (!isRecord5(block)) continue;
24690
25474
  if (block.type === "tool_use" && isRecord5(block.input)) {
24691
- recordToolCall(block.id, block.input, timestamp);
25475
+ recordToolCall(block.id, block.input, timestamp2);
24692
25476
  } else if (block.type === "tool_result") {
24693
25477
  recordResult(block.tool_use_id, block.content, block.is_error === true);
24694
25478
  }
@@ -24793,15 +25577,15 @@ var init_sessionPrIndex = __esm({
24793
25577
  });
24794
25578
 
24795
25579
  // ../../server/lib/sessionPrSearchIndex.ts
24796
- import { mkdir as mkdir6, readFile as readFile18 } from "node:fs/promises";
24797
- import { join as join24 } from "node:path";
25580
+ import { mkdir as mkdir6, readFile as readFile19 } from "node:fs/promises";
25581
+ import { join as join25 } from "node:path";
24798
25582
  function isIndexEntry(value) {
24799
25583
  if (typeof value !== "object" || value === null) return false;
24800
25584
  const entry = value;
24801
25585
  return typeof entry.size === "number" && typeof entry.mtimeMs === "number" && Array.isArray(entry.pullRequests) && Array.isArray(entry.references);
24802
25586
  }
24803
25587
  function currentIndexPath() {
24804
- return join24(dirs.SESSION_CONFIG_DIR, INDEX_FILE);
25588
+ return join25(dirs.SESSION_CONFIG_DIR, INDEX_FILE);
24805
25589
  }
24806
25590
  function resetForPath(indexPath) {
24807
25591
  activeIndexPath = indexPath;
@@ -24818,7 +25602,7 @@ async function loadIndex() {
24818
25602
  if (loaded) return;
24819
25603
  if (loading) return loading;
24820
25604
  const expectedGeneration = generation;
24821
- const pendingLoad = readFile18(indexPath, "utf-8").then((raw) => {
25605
+ const pendingLoad = readFile19(indexPath, "utf-8").then((raw) => {
24822
25606
  if (expectedGeneration !== generation) return;
24823
25607
  const parsed = JSON.parse(raw);
24824
25608
  if (typeof parsed !== "object" || parsed === null) return;
@@ -24862,7 +25646,7 @@ async function runQueue(expectedGeneration) {
24862
25646
  await persistIndex(expectedGeneration).catch(() => void 0);
24863
25647
  sincePersist = 0;
24864
25648
  }
24865
- await new Promise((resolve21) => setImmediate(resolve21));
25649
+ await new Promise((resolve22) => setImmediate(resolve22));
24866
25650
  }
24867
25651
  if (sincePersist > 0) await persistIndex(expectedGeneration).catch(() => void 0);
24868
25652
  } finally {
@@ -25547,6 +26331,19 @@ var init_projects2 = __esm({
25547
26331
  }
25548
26332
  });
25549
26333
 
26334
+ // ../../server/agents/executables.ts
26335
+ function activeExecutableFor(kind) {
26336
+ return kind === "claude" ? claudeCliPath() : void 0;
26337
+ }
26338
+ function describeExecutableFor(kind) {
26339
+ return kind === "claude" ? describeClaudeExecutable() : null;
26340
+ }
26341
+ var init_executables = __esm({
26342
+ "../../server/agents/executables.ts"() {
26343
+ init_claudeExecutable();
26344
+ }
26345
+ });
26346
+
25550
26347
  // ../../server/lib/providerUpdates.ts
25551
26348
  import { realpathSync } from "node:fs";
25552
26349
  function deriveStatus(current, latest) {
@@ -25649,8 +26446,8 @@ function buildUpdateCommand(provider, method) {
25649
26446
  function formatCommand(command) {
25650
26447
  return [command.executable, ...command.args].join(" ");
25651
26448
  }
25652
- function resolveBinaryPaths(binName) {
25653
- const onPath = findExecutableOnPath(binName);
26449
+ function resolveBinaryPaths(descriptor7) {
26450
+ const onPath = activeExecutableFor(descriptor7.kind) ?? findExecutableOnPath(descriptor7.binName);
25654
26451
  if (!onPath) return [];
25655
26452
  try {
25656
26453
  const real = realpathSync(onPath);
@@ -25699,7 +26496,7 @@ function fetchLatestVersion(packageName) {
25699
26496
  });
25700
26497
  }
25701
26498
  async function probeProvider(descriptor7) {
25702
- const paths = resolveBinaryPaths(descriptor7.binName);
26499
+ const paths = resolveBinaryPaths(descriptor7);
25703
26500
  const base = {
25704
26501
  provider: descriptor7.kind,
25705
26502
  displayName: descriptor7.displayName,
@@ -25808,6 +26605,7 @@ var init_providerUpdates = __esm({
25808
26605
  "../../server/lib/providerUpdates.ts"() {
25809
26606
  init_agent_descriptors();
25810
26607
  init_versions();
26608
+ init_executables();
25811
26609
  init_binaryResolver();
25812
26610
  init_cliProcess();
25813
26611
  REGISTRY_TIMEOUT_MS = 4e3;
@@ -25864,12 +26662,38 @@ var init_provider_updates = __esm({
25864
26662
  }
25865
26663
  });
25866
26664
 
26665
+ // ../../server/routes/agent-executable.ts
26666
+ function registerAgentExecutableRoutes(use) {
26667
+ use("/api/agent-executable", async (req, res, next) => {
26668
+ if (req.method !== "GET") return next();
26669
+ const kind = new URL(req.url || "/", "http://localhost").pathname.slice(1);
26670
+ if (!AGENT_KINDS.includes(kind)) return next();
26671
+ const report = describeExecutableFor(kind);
26672
+ if (!report) {
26673
+ sendJson(res, 404, { error: `${kind} has a single executable; nothing to choose` });
26674
+ return;
26675
+ }
26676
+ try {
26677
+ sendJson(res, 200, await report);
26678
+ } catch (err) {
26679
+ sendJson(res, 500, { error: String(err) });
26680
+ }
26681
+ });
26682
+ }
26683
+ var init_agent_executable = __esm({
26684
+ "../../server/routes/agent-executable.ts"() {
26685
+ init_agent_descriptors();
26686
+ init_executables();
26687
+ init_http();
26688
+ }
26689
+ });
26690
+
25867
26691
  // ../../server/routes/scripts/discovery.ts
25868
- import { readdir as readdir12, readFile as readFile19 } from "node:fs/promises";
25869
- import { join as join25, relative as relative10 } from "node:path";
26692
+ import { readdir as readdir12, readFile as readFile20 } from "node:fs/promises";
26693
+ import { join as join26, relative as relative10 } from "node:path";
25870
26694
  async function extractScripts(dir, dirLabel) {
25871
26695
  try {
25872
- const raw = await readFile19(join25(dir, "package.json"), "utf-8");
26696
+ const raw = await readFile20(join26(dir, "package.json"), "utf-8");
25873
26697
  const pkg = JSON.parse(raw);
25874
26698
  const scripts = pkg.scripts;
25875
26699
  if (!scripts || typeof scripts !== "object") return [];
@@ -25895,7 +26719,7 @@ async function discoverScripts(projectDir) {
25895
26719
  );
25896
26720
  const childResults = await Promise.all(
25897
26721
  childDirs.map(async (entry) => {
25898
- const childPath = join25(projectDir, entry.name);
26722
+ const childPath = join26(projectDir, entry.name);
25899
26723
  const label = relative10(projectDir, childPath) + "/";
25900
26724
  return extractScripts(childPath, label);
25901
26725
  })
@@ -25942,12 +26766,12 @@ var init_discovery = __esm({
25942
26766
  });
25943
26767
 
25944
26768
  // ../../server/routes/scripts/index.ts
25945
- import { stat as stat17 } from "node:fs/promises";
25946
- import { resolve as resolve18 } from "node:path";
26769
+ import { stat as stat18 } from "node:fs/promises";
26770
+ import { resolve as resolve19 } from "node:path";
25947
26771
  async function validateDir(dir) {
25948
26772
  try {
25949
- const resolved = resolve18(dir);
25950
- const info = await stat17(resolved);
26773
+ const resolved = resolve19(dir);
26774
+ const info = await stat18(resolved);
25951
26775
  return info.isDirectory() ? resolved : null;
25952
26776
  } catch {
25953
26777
  return null;
@@ -26012,7 +26836,7 @@ async function withTranscriptEffort(key2, stored) {
26012
26836
  }
26013
26837
  }
26014
26838
  function collectBody(req) {
26015
- return new Promise((resolve21, reject) => {
26839
+ return new Promise((resolve22, reject) => {
26016
26840
  let body = "";
26017
26841
  req.on("data", (chunk) => {
26018
26842
  body += chunk.toString();
@@ -26021,7 +26845,7 @@ function collectBody(req) {
26021
26845
  req.destroy();
26022
26846
  }
26023
26847
  });
26024
- req.on("end", () => resolve21(body));
26848
+ req.on("end", () => resolve22(body));
26025
26849
  req.on("error", reject);
26026
26850
  });
26027
26851
  }
@@ -26081,12 +26905,12 @@ var init_session_config = __esm({
26081
26905
 
26082
26906
  // ../../server/lib/agentTeamIdentity.ts
26083
26907
  import { open as open9, readdir as readdir13 } from "node:fs/promises";
26084
- import { join as join26 } from "node:path";
26908
+ import { join as join27 } from "node:path";
26085
26909
  async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
26086
26910
  const entries3 = await readdir13(dirs.PROJECTS_DIR, { withFileTypes: true });
26087
26911
  for (const entry of entries3) {
26088
26912
  if (!entry.isDirectory() || entry.name === "memory") continue;
26089
- const filePath = join26(
26913
+ const filePath = join27(
26090
26914
  dirs.PROJECTS_DIR,
26091
26915
  entry.name,
26092
26916
  leadSessionId,
@@ -26779,7 +27603,7 @@ function normalizeCopilotFileChangeEvents(jsonlContent) {
26779
27603
  }
26780
27604
  });
26781
27605
  }
26782
- return records.map((record2) => JSON.stringify(record2)).join("\n");
27606
+ return records.map((record4) => JSON.stringify(record4)).join("\n");
26783
27607
  }
26784
27608
  async function parseSessionFileChanges(jsonlContent, includeContent) {
26785
27609
  if (formatForText(jsonlContent).kind === "copilot") {
@@ -28199,8 +29023,8 @@ var init_paths = __esm({
28199
29023
  });
28200
29024
 
28201
29025
  // ../../server/routes/undo/fileOperations.ts
28202
- import { basename as basename12, dirname as dirname13, isAbsolute as isAbsolute12 } from "node:path";
28203
- import { lstat as lstat6, realpath as realpath11 } from "node:fs/promises";
29026
+ import { basename as basename12, dirname as dirname13, isAbsolute as isAbsolute13 } from "node:path";
29027
+ import { lstat as lstat6, realpath as realpath12 } from "node:fs/promises";
28204
29028
  function hasTraversalSegment(filePath) {
28205
29029
  return filePath.split(/[\\/]+/).includes("..");
28206
29030
  }
@@ -28211,7 +29035,7 @@ function isForbiddenPath(filePath) {
28211
29035
  return FORBIDDEN_PREFIXES.some((prefix) => isWithinDir(prefix, filePath));
28212
29036
  }
28213
29037
  async function resolveSafeOperationPath(filePath, home, canonicalHome) {
28214
- if (typeof filePath !== "string" || !isAbsolute12(filePath) || hasTraversalSegment(filePath)) {
29038
+ if (typeof filePath !== "string" || !isAbsolute13(filePath) || hasTraversalSegment(filePath)) {
28215
29039
  return null;
28216
29040
  }
28217
29041
  const resolved = resolve7(filePath);
@@ -28219,12 +29043,12 @@ async function resolveSafeOperationPath(filePath, home, canonicalHome) {
28219
29043
  try {
28220
29044
  const stats = await lstat6(resolved);
28221
29045
  if (stats.isSymbolicLink()) return null;
28222
- const canonicalTarget = await realpath11(resolved);
29046
+ const canonicalTarget = await realpath12(resolved);
28223
29047
  return isWithinDir(canonicalHome, canonicalTarget) && !isForbiddenPath(canonicalTarget) ? canonicalTarget : null;
28224
29048
  } catch (error) {
28225
29049
  if (!isMissingPathError(error)) return null;
28226
29050
  try {
28227
- const canonicalParent = await realpath11(dirname13(resolved));
29051
+ const canonicalParent = await realpath12(dirname13(resolved));
28228
29052
  const canonicalTarget = join11(canonicalParent, basename12(resolved));
28229
29053
  return isWithinDir(canonicalHome, canonicalTarget) && !isForbiddenPath(canonicalTarget) ? canonicalTarget : null;
28230
29054
  } catch {
@@ -28272,7 +29096,7 @@ async function prepareFileOperations(operationValues, options = {}) {
28272
29096
  const home = resolve7(homedir4());
28273
29097
  let canonicalHome;
28274
29098
  try {
28275
- canonicalHome = await realpath11(home);
29099
+ canonicalHome = await realpath12(home);
28276
29100
  } catch {
28277
29101
  throw new UndoOperationError(403, "File operations restricted to home directory");
28278
29102
  }
@@ -28476,7 +29300,7 @@ function applySessionMutation(content, mutation) {
28476
29300
  ` : "";
28477
29301
  }
28478
29302
  async function readBody2(req) {
28479
- return await new Promise((resolve21, reject) => {
29303
+ return await new Promise((resolve22, reject) => {
28480
29304
  let body = "";
28481
29305
  let bytes = 0;
28482
29306
  let settled = false;
@@ -28495,7 +29319,7 @@ async function readBody2(req) {
28495
29319
  req.on("end", () => {
28496
29320
  if (!settled) {
28497
29321
  settled = true;
28498
- resolve21(body);
29322
+ resolve22(body);
28499
29323
  }
28500
29324
  });
28501
29325
  req.on("error", (error) => {
@@ -28748,20 +29572,20 @@ var init_aggregate = __esm({
28748
29572
  this.#toDay = makeDayFormatter(options.timeZone);
28749
29573
  }
28750
29574
  /** Folds one record in; returns whether it actually contributed. */
28751
- add(record2) {
28752
- if (record2.dedupeKey !== null) {
28753
- if (this.#seen.has(record2.dedupeKey)) return false;
28754
- this.#seen.add(record2.dedupeKey);
29575
+ add(record4) {
29576
+ if (record4.dedupeKey !== null) {
29577
+ if (this.#seen.has(record4.dedupeKey)) return false;
29578
+ this.#seen.add(record4.dedupeKey);
28755
29579
  }
28756
- const day = this.#toDay(record2.timestampMs);
29580
+ const day = this.#toDay(record4.timestampMs);
28757
29581
  if (day < this.#options.sinceDay || day > this.#options.untilDay) return false;
28758
- const key2 = [day, record2.provider, record2.model].join(KEY_SEPARATOR);
29582
+ const key2 = [day, record4.provider, record4.model].join(KEY_SEPARATOR);
28759
29583
  let bucket = this.#buckets.get(key2);
28760
29584
  if (bucket === void 0) {
28761
29585
  bucket = {
28762
29586
  day,
28763
- provider: record2.provider,
28764
- model: record2.model,
29587
+ provider: record4.provider,
29588
+ model: record4.model,
28765
29589
  totals: emptyUsageCostTotals(),
28766
29590
  costUsd: 0,
28767
29591
  cacheSavingsUsd: 0,
@@ -28774,19 +29598,19 @@ var init_aggregate = __esm({
28774
29598
  }
28775
29599
  const priced = priceUsage(
28776
29600
  this.#options.rates,
28777
- record2.model,
28778
- record2.totals,
28779
- record2.reportedCostUsd
29601
+ record4.model,
29602
+ record4.totals,
29603
+ record4.reportedCostUsd
28780
29604
  );
28781
- bucket.totals = addUsageCostTotals(bucket.totals, record2.totals);
29605
+ bucket.totals = addUsageCostTotals(bucket.totals, record4.totals);
28782
29606
  bucket.costUsd += priced.costUsd;
28783
- bucket.cacheSavingsUsd += cacheSavingsUsd(this.#options.rates, record2.model, record2.totals);
29607
+ bucket.cacheSavingsUsd += cacheSavingsUsd(this.#options.rates, record4.model, record4.totals);
28784
29608
  bucket.records += 1;
28785
29609
  if (priced.costSource === "unpriced") bucket.unpricedRecords += 1;
28786
29610
  if (priced.costSource === "providerReported") bucket.providerReportedRecords += 1;
28787
- if (record2.sessionId.length > 0) {
28788
- bucket.sessions.add(record2.sessionId);
28789
- this.#sessions.add(record2.sessionId);
29611
+ if (record4.sessionId.length > 0) {
29612
+ bucket.sessions.add(record4.sessionId);
29613
+ this.#sessions.add(record4.sessionId);
28790
29614
  }
28791
29615
  return true;
28792
29616
  }
@@ -28816,8 +29640,8 @@ var init_aggregate = __esm({
28816
29640
 
28817
29641
  // ../../server/lib/usageCost/reader.ts
28818
29642
  import { createReadStream as createReadStream3 } from "node:fs";
28819
- import { readdir as readdir14, stat as stat18 } from "node:fs/promises";
28820
- import { join as join27 } from "node:path";
29643
+ import { readdir as readdir14, stat as stat19 } from "node:fs/promises";
29644
+ import { join as join28 } from "node:path";
28821
29645
  import { createInterface as createInterface3 } from "node:readline";
28822
29646
  async function listTranscriptFiles(root, sinceMs) {
28823
29647
  const found = [];
@@ -28829,14 +29653,14 @@ async function listTranscriptFiles(root, sinceMs) {
28829
29653
  return;
28830
29654
  }
28831
29655
  for (const entry of entries3) {
28832
- const child = join27(dir, entry.name);
29656
+ const child = join28(dir, entry.name);
28833
29657
  if (entry.isDirectory()) {
28834
29658
  await walk2(child);
28835
29659
  continue;
28836
29660
  }
28837
29661
  if (!entry.name.endsWith(".jsonl")) continue;
28838
29662
  try {
28839
- const stats = await stat18(child);
29663
+ const stats = await stat19(child);
28840
29664
  if (stats.mtimeMs >= sinceMs) {
28841
29665
  found.push({ path: child, size: stats.size, mtimeMs: stats.mtimeMs });
28842
29666
  }
@@ -28867,17 +29691,17 @@ async function readTranscriptRecords(filePath, provider) {
28867
29691
  function dedupeWithinFile(records) {
28868
29692
  const slotByKey = /* @__PURE__ */ new Map();
28869
29693
  const kept = [];
28870
- for (const record2 of records) {
28871
- if (record2.dedupeKey === null) {
28872
- kept.push(record2);
29694
+ for (const record4 of records) {
29695
+ if (record4.dedupeKey === null) {
29696
+ kept.push(record4);
28873
29697
  continue;
28874
29698
  }
28875
- const slot = slotByKey.get(record2.dedupeKey);
29699
+ const slot = slotByKey.get(record4.dedupeKey);
28876
29700
  if (slot === void 0) {
28877
- slotByKey.set(record2.dedupeKey, kept.push(record2) - 1);
29701
+ slotByKey.set(record4.dedupeKey, kept.push(record4) - 1);
28878
29702
  continue;
28879
29703
  }
28880
- if (record2.totals.outputTokens > kept[slot].totals.outputTokens) kept[slot] = record2;
29704
+ if (record4.totals.outputTokens > kept[slot].totals.outputTokens) kept[slot] = record4;
28881
29705
  }
28882
29706
  return kept;
28883
29707
  }
@@ -28888,10 +29712,10 @@ var init_reader = __esm({
28888
29712
  });
28889
29713
 
28890
29714
  // ../../server/lib/usageCost/service.ts
28891
- import { readFile as readFile20, writeFile as writeFile7 } from "node:fs/promises";
28892
- import { join as join28 } from "node:path";
29715
+ import { readFile as readFile21, writeFile as writeFile7 } from "node:fs/promises";
29716
+ import { join as join29 } from "node:path";
28893
29717
  function ratesCachePath() {
28894
- return join28(getDataRoot(), "usage-model-rates.json");
29718
+ return join29(getDataRoot(), "usage-model-rates.json");
28895
29719
  }
28896
29720
  function ratesFetchedAt() {
28897
29721
  return ratesFetchedAtMs === null ? null : new Date(ratesFetchedAtMs).toISOString();
@@ -28901,7 +29725,7 @@ async function ensureRatesInner() {
28901
29725
  if (ratesFetchedAtMs !== null && now - ratesFetchedAtMs < RATES_TTL_MS) return;
28902
29726
  if (ratesFetchedAtMs === null) {
28903
29727
  try {
28904
- const raw = JSON.parse(await readFile20(ratesCachePath(), "utf8"));
29728
+ const raw = JSON.parse(await readFile21(ratesCachePath(), "utf8"));
28905
29729
  if (typeof raw.fetchedAtMs === "number") {
28906
29730
  const parsed2 = parseRateTable(raw.document);
28907
29731
  if (parsed2.size > 0) {
@@ -28986,23 +29810,23 @@ async function readUsageCostSummary(input) {
28986
29810
  for (const file of files) {
28987
29811
  const records = await readFileRecords(file, provider);
28988
29812
  scannedFiles += 1;
28989
- for (const record2 of records) {
28990
- aggregator.add(record2);
28991
- if (!liveSessionIds.has(record2.sessionId)) continue;
28992
- const byModel = durableTotals.get(record2.sessionId) ?? /* @__PURE__ */ new Map();
29813
+ for (const record4 of records) {
29814
+ aggregator.add(record4);
29815
+ if (!liveSessionIds.has(record4.sessionId)) continue;
29816
+ const byModel = durableTotals.get(record4.sessionId) ?? /* @__PURE__ */ new Map();
28993
29817
  byModel.set(
28994
- record2.model,
29818
+ record4.model,
28995
29819
  addUsageCostTotals(
28996
- byModel.get(record2.model) ?? emptyUsageCostTotals(),
28997
- record2.totals
29820
+ byModel.get(record4.model) ?? emptyUsageCostTotals(),
29821
+ record4.totals
28998
29822
  )
28999
29823
  );
29000
- durableTotals.set(record2.sessionId, byModel);
29824
+ durableTotals.set(record4.sessionId, byModel);
29001
29825
  }
29002
29826
  }
29003
29827
  }
29004
29828
  for (const runtime of runtimes2) {
29005
- for (const record2 of await runtime.liveUsageRecords(durableTotals)) aggregator.add(record2);
29829
+ for (const record4 of await runtime.liveUsageRecords(durableTotals)) aggregator.add(record4);
29006
29830
  }
29007
29831
  const retentionCutoffMs = startedAtMs - 90 * 24 * 60 * 60 * 1e3;
29008
29832
  for (const [path, entry] of fileCache2) {
@@ -29088,12 +29912,12 @@ async function readKeychainCredentials() {
29088
29912
  if (process.platform !== "darwin") {
29089
29913
  return null;
29090
29914
  }
29091
- return new Promise((resolve21) => {
29915
+ return new Promise((resolve22) => {
29092
29916
  let resolved = false;
29093
29917
  const done = (value) => {
29094
29918
  if (resolved) return;
29095
29919
  resolved = true;
29096
- resolve21(value);
29920
+ resolve22(value);
29097
29921
  };
29098
29922
  const child = spawn3("/usr/bin/security", [
29099
29923
  "find-generic-password",
@@ -29729,8 +30553,8 @@ var init_workflows2 = __esm({
29729
30553
  });
29730
30554
 
29731
30555
  // ../../server/routes/worktrees/worktreeIo.ts
29732
- import { execFile as execFile7 } from "node:child_process";
29733
- import { promisify as promisify3 } from "node:util";
30556
+ import { execFile as execFile9 } from "node:child_process";
30557
+ import { promisify as promisify5 } from "node:util";
29734
30558
  async function runWorktreeCommand(file, args, { cwd, timeoutMs = WORKTREE_COMMAND_TIMEOUT_MS }) {
29735
30559
  const result = await execFileAsync(file, [...args], {
29736
30560
  cwd,
@@ -29769,7 +30593,7 @@ var init_worktreeIo = __esm({
29769
30593
  WORKTREE_COMMAND_MAX_BUFFER = 4 * 1024 * 1024;
29770
30594
  WORKTREE_SCAN_CONCURRENCY = 4;
29771
30595
  SESSION_HEADER_CONCURRENCY = 8;
29772
- execFileAsync = promisify3(execFile7);
30596
+ execFileAsync = promisify5(execFile9);
29773
30597
  NONINTERACTIVE_ENV = {
29774
30598
  ...process.env,
29775
30599
  GCM_INTERACTIVE: "Never",
@@ -29782,7 +30606,7 @@ var init_worktreeIo = __esm({
29782
30606
  });
29783
30607
 
29784
30608
  // ../../server/routes/worktrees/worktreeUtils.ts
29785
- import { resolve as resolve19, dirname as dirname14 } from "node:path";
30609
+ import { resolve as resolve20, dirname as dirname14 } from "node:path";
29786
30610
  function isValidWorktreeName(name) {
29787
30611
  return /^[a-zA-Z0-9._-]+$/.test(name) && name.length <= 40;
29788
30612
  }
@@ -29845,7 +30669,7 @@ async function getMainWorktreeRoot(projectPath) {
29845
30669
  const commonDir = (await runWorktreeCommand("git", ["rev-parse", "--git-common-dir"], {
29846
30670
  cwd: projectPath
29847
30671
  })).trim();
29848
- return dirname14(resolve19(projectPath, commonDir));
30672
+ return dirname14(resolve20(projectPath, commonDir));
29849
30673
  } catch {
29850
30674
  return null;
29851
30675
  }
@@ -29870,7 +30694,7 @@ var init_worktreeUtils = __esm({
29870
30694
  });
29871
30695
 
29872
30696
  // ../../server/routes/worktrees/worktreeListRoute.ts
29873
- import { stat as stat19 } from "node:fs/promises";
30697
+ import { stat as stat20 } from "node:fs/promises";
29874
30698
  async function loadSessionBranches(projectDir) {
29875
30699
  const sessionBranches = /* @__PURE__ */ new Map();
29876
30700
  try {
@@ -29985,7 +30809,7 @@ async function buildWorktreeInfo(worktree, defaultBranch, sessionBranches) {
29985
30809
  }
29986
30810
  let createdAt = "";
29987
30811
  try {
29988
- createdAt = (await stat19(worktree.path)).birthtime.toISOString();
30812
+ createdAt = (await stat20(worktree.path)).birthtime.toISOString();
29989
30813
  } catch {
29990
30814
  }
29991
30815
  return {
@@ -30046,9 +30870,9 @@ var init_worktreeListRoute = __esm({
30046
30870
  });
30047
30871
 
30048
30872
  // ../../server/routes/worktrees/index.ts
30049
- import { stat as stat20 } from "node:fs/promises";
30873
+ import { stat as stat21 } from "node:fs/promises";
30050
30874
  async function readJsonRequestBody(req) {
30051
- const body = await new Promise((resolve21, reject) => {
30875
+ const body = await new Promise((resolve22, reject) => {
30052
30876
  let data = "";
30053
30877
  let bytesRead = 0;
30054
30878
  let settled = false;
@@ -30065,7 +30889,7 @@ async function readJsonRequestBody(req) {
30065
30889
  req.on("end", () => {
30066
30890
  if (!settled) {
30067
30891
  settled = true;
30068
- resolve21(data);
30892
+ resolve22(data);
30069
30893
  }
30070
30894
  });
30071
30895
  req.on("error", () => {
@@ -30116,7 +30940,7 @@ async function findStaleWorktrees(worktrees, cutoff) {
30116
30940
  cwd: worktree.path
30117
30941
  });
30118
30942
  if (status.trim()) return null;
30119
- const worktreeStat = await stat20(worktree.path);
30943
+ const worktreeStat = await stat21(worktree.path);
30120
30944
  return worktreeStat.birthtime.getTime() < cutoff ? worktree : null;
30121
30945
  } catch {
30122
30946
  return null;
@@ -30357,6 +31181,8 @@ var init_api_routes = __esm({
30357
31181
  init_files();
30358
31182
  init_git_diff();
30359
31183
  init_git_status();
31184
+ init_github_actions();
31185
+ init_vercel_deployments();
30360
31186
  init_project_icon();
30361
31187
  init_hello();
30362
31188
  init_local_file();
@@ -30371,6 +31197,7 @@ var init_api_routes = __esm({
30371
31197
  init_project_files();
30372
31198
  init_projects2();
30373
31199
  init_provider_updates();
31200
+ init_agent_executable();
30374
31201
  init_scripts();
30375
31202
  init_session_config();
30376
31203
  init_session_context();
@@ -30425,6 +31252,8 @@ var init_api_routes = __esm({
30425
31252
  apiRoute("project-files", registerProjectFileRoutes),
30426
31253
  apiRoute("project-file", registerProjectFileContentRoutes),
30427
31254
  apiRoute("git-status", registerGitStatusRoutes),
31255
+ apiRoute("github-actions", registerGitHubActionsRoutes),
31256
+ apiRoute("vercel-deployments", registerVercelDeploymentRoutes),
30428
31257
  apiRoute("project-icon", registerProjectIconRoutes),
30429
31258
  apiRoute("git-diff", registerGitDiffRoutes),
30430
31259
  apiRoute("mcp", registerMcpRoutes),
@@ -30438,7 +31267,8 @@ var init_api_routes = __esm({
30438
31267
  apiRoute("models", registerModelRoutes),
30439
31268
  apiRoute("codex-threads", registerCodexThreadRoutes),
30440
31269
  apiRoute("agent-runtime", registerAgentRuntimeRoutes),
30441
- apiRoute("provider-updates", registerProviderUpdateRoutes)
31270
+ apiRoute("provider-updates", registerProviderUpdateRoutes),
31271
+ apiRoute("agent-executable", registerAgentExecutableRoutes)
30442
31272
  ];
30443
31273
  }
30444
31274
  });
@@ -30854,18 +31684,18 @@ var init_pty_authorization = __esm({
30854
31684
  // ../../server/app-server.ts
30855
31685
  import express from "express";
30856
31686
  import { createServer, request as httpRequest2 } from "node:http";
30857
- import { join as join29 } from "node:path";
31687
+ import { join as join30 } from "node:path";
30858
31688
  import { WebSocketServer as WebSocketServer2 } from "ws";
30859
31689
  async function createServerComposition(staticDir, userDataDir, environment) {
30860
31690
  setDataRoot(userDataDir);
30861
- setConfigPath(join29(userDataDir, "config.local.json"));
31691
+ setConfigPath(join30(userDataDir, "config.local.json"));
30862
31692
  await loadConfig();
30863
31693
  const configEdition = getConfiguredEditionValue();
30864
31694
  initEdition({ shell: environment.mode, configEdition });
30865
31695
  const suppression = describeEditionSuppression(process.env, configEdition, environment.mode);
30866
31696
  if (suppression) console.warn(suppression);
30867
31697
  if (isTeamEdition()) {
30868
- const teamDir = join29(getDataRoot(), "team");
31698
+ const teamDir = join30(getDataRoot(), "team");
30869
31699
  await initUsersStore(teamDir);
30870
31700
  await initSessionPersistence(teamDir);
30871
31701
  initializeBootstrapToken(userCount());
@@ -30976,7 +31806,7 @@ async function createServerComposition(staticDir, userDataDir, environment) {
30976
31806
  for (const socket of upgradedSockets) socket.destroy();
30977
31807
  upgradedSockets.clear();
30978
31808
  await Promise.all([
30979
- new Promise((resolve21) => wss.close(() => resolve21())),
31809
+ new Promise((resolve22) => wss.close(() => resolve22())),
30980
31810
  cleanupProcesses(),
30981
31811
  ...allRuntimes().map((runtime) => runtime.shutdown()),
30982
31812
  flushSessionPersistence()
@@ -30988,8 +31818,8 @@ async function createServerComposition(staticDir, userDataDir, environment) {
30988
31818
  void cleanupRuntime();
30989
31819
  });
30990
31820
  const dispose = async () => {
30991
- const serverClosed = httpServer.listening ? new Promise((resolve21, reject) => {
30992
- httpServer.close((error) => error ? reject(error) : resolve21());
31821
+ const serverClosed = httpServer.listening ? new Promise((resolve22, reject) => {
31822
+ httpServer.close((error) => error ? reject(error) : resolve22());
30993
31823
  }) : Promise.resolve();
30994
31824
  await cleanupRuntime();
30995
31825
  await serverClosed;
@@ -31036,7 +31866,7 @@ var init_standalone_app_server = __esm({
31036
31866
  // ../../server/lib/portFile.ts
31037
31867
  import { mkdirSync as mkdirSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
31038
31868
  import { homedir as homedir12 } from "node:os";
31039
- import { dirname as dirname15, join as join30 } from "node:path";
31869
+ import { dirname as dirname15, join as join31 } from "node:path";
31040
31870
  function writePortFile(port) {
31041
31871
  try {
31042
31872
  mkdirSync2(dirname15(PORT_FILE), { recursive: true });
@@ -31056,7 +31886,7 @@ function removePortFile() {
31056
31886
  var PORT_FILE;
31057
31887
  var init_portFile = __esm({
31058
31888
  "../../server/lib/portFile.ts"() {
31059
- PORT_FILE = join30(homedir12(), ".cogpit", "port");
31889
+ PORT_FILE = join31(homedir12(), ".cogpit", "port");
31060
31890
  }
31061
31891
  });
31062
31892
 
@@ -31266,8 +32096,8 @@ var init_sessionActivityMonitor = __esm({
31266
32096
  });
31267
32097
 
31268
32098
  // ../../server/lib/standalone-bootstrap.ts
31269
- import { readFileSync as readFileSync3 } from "node:fs";
31270
- function resolveEnvPassword(env = process.env, readFileFn = (p) => readFileSync3(p, "utf-8")) {
32099
+ import { readFileSync as readFileSync4 } from "node:fs";
32100
+ function resolveEnvPassword(env = process.env, readFileFn = (p) => readFileSync4(p, "utf-8")) {
31271
32101
  const file = env.COGPIT_NETWORK_PASSWORD_FILE;
31272
32102
  if (file && file.length > 0) {
31273
32103
  const trimmed = readFileFn(file).replace(/\r?\n$/, "");
@@ -31305,9 +32135,9 @@ __export(standalone_runtime_exports, {
31305
32135
  });
31306
32136
  import { existsSync, mkdirSync as mkdirSync3 } from "node:fs";
31307
32137
  import { homedir as homedir13 } from "node:os";
31308
- import { join as join31 } from "node:path";
32138
+ import { join as join32 } from "node:path";
31309
32139
  function listen(server, port, host) {
31310
- return new Promise((resolve21, reject) => {
32140
+ return new Promise((resolve22, reject) => {
31311
32141
  const onError = (error) => reject(error);
31312
32142
  server.once("error", onError);
31313
32143
  server.listen(port, host, () => {
@@ -31317,27 +32147,27 @@ function listen(server, port, host) {
31317
32147
  reject(new Error("Cogpit started without a listening address."));
31318
32148
  return;
31319
32149
  }
31320
- resolve21(address.port);
32150
+ resolve22(address.port);
31321
32151
  });
31322
32152
  });
31323
32153
  }
31324
32154
  async function startStandaloneServer({
31325
32155
  staticDir,
31326
- dataDir = join31(homedir13(), ".config", "cogpit"),
32156
+ dataDir = join32(homedir13(), ".config", "cogpit"),
31327
32157
  host = "127.0.0.1",
31328
32158
  port = 19384,
31329
32159
  env = process.env,
31330
32160
  publishPort = false
31331
32161
  }) {
31332
32162
  mkdirSync3(dataDir, { recursive: true });
31333
- const configPath = join31(dataDir, "config.local.json");
32163
+ const configPath = join32(dataDir, "config.local.json");
31334
32164
  setConfigPath(configPath);
31335
32165
  const configExisted = existsSync(configPath);
31336
32166
  await loadConfig();
31337
32167
  let createdConfig;
31338
32168
  if (!configExisted) {
31339
- const claudeDir = join31(homedir13(), ".claude");
31340
- if (existsSync(join31(claudeDir, "projects"))) {
32169
+ const claudeDir = join32(homedir13(), ".claude");
32170
+ if (existsSync(join32(claudeDir, "projects"))) {
31341
32171
  await saveConfig({ claudeDir });
31342
32172
  createdConfig = `${configPath} for ${claudeDir}`;
31343
32173
  }
@@ -31410,7 +32240,7 @@ var init_standalone_runtime = __esm({
31410
32240
  // src/index.ts
31411
32241
  import { spawn as spawn4 } from "node:child_process";
31412
32242
  import { homedir as homedir14 } from "node:os";
31413
- import { join as join32, resolve as resolve20 } from "node:path";
32243
+ import { join as join33, resolve as resolve21 } from "node:path";
31414
32244
  var SESSION_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/;
31415
32245
  var USAGE = `Cogpit
31416
32246
 
@@ -31477,7 +32307,7 @@ function parseArgs(argv) {
31477
32307
  if (value === "--data-dir") {
31478
32308
  const path = argv[index + 1];
31479
32309
  if (!path) throw new Error("--data-dir requires a directory.");
31480
- dataDir = resolve20(path);
32310
+ dataDir = resolve21(path);
31481
32311
  index += 1;
31482
32312
  continue;
31483
32313
  }
@@ -31519,8 +32349,8 @@ async function openExternalUrl(url) {
31519
32349
  async function startPackagedServer(options) {
31520
32350
  const { startStandaloneServer: startStandaloneServer2 } = await Promise.resolve().then(() => (init_standalone_runtime(), standalone_runtime_exports));
31521
32351
  return startStandaloneServer2({
31522
- staticDir: join32(import.meta.dirname, "web"),
31523
- dataDir: options.dataDir ?? join32(homedir14(), ".config", "cogpit"),
32352
+ staticDir: join33(import.meta.dirname, "web"),
32353
+ dataDir: options.dataDir ?? join33(homedir14(), ".config", "cogpit"),
31524
32354
  host: "127.0.0.1",
31525
32355
  port: options.port,
31526
32356
  publishPort: false
@@ -31536,7 +32366,7 @@ async function waitForShutdownSignal() {
31536
32366
  for (const signal of signals) process.once(signal, done);
31537
32367
  });
31538
32368
  }
31539
- var defaultDependencies = {
32369
+ var defaultDependencies3 = {
31540
32370
  fetch,
31541
32371
  openUrl: openExternalUrl,
31542
32372
  startServer: startPackagedServer,
@@ -31563,7 +32393,7 @@ async function verifyServer(server, command, deps) {
31563
32393
  }
31564
32394
  }
31565
32395
  async function run(argv, overrides = {}) {
31566
- const deps = { ...defaultDependencies, ...overrides };
32396
+ const deps = { ...defaultDependencies3, ...overrides };
31567
32397
  let command;
31568
32398
  try {
31569
32399
  command = parseArgs(argv);