cogpit 2.1.3 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/cli.js +902 -425
  2. package/dist/web/assets/CommandPaletteHost--_g3tlgk.js +1 -0
  3. package/dist/web/assets/ConfigBrowser-DrAZQBx8.js +1 -0
  4. package/dist/web/assets/{HighlightedEditor-qhEWgnBF.js → HighlightedEditor-Byq8pOUC.js} +1 -1
  5. package/dist/web/assets/{KeyboardShortcutsDialog-B9nMtf5U.js → KeyboardShortcutsDialog-CFhdeGBw.js} +1 -1
  6. package/dist/web/assets/{MobileFileChanges-j9DCxvz6.js → MobileFileChanges-uxpxh1W6.js} +1 -1
  7. package/dist/web/assets/{PreviewPanel-DZSVN3mt.js → PreviewPanel-DC6OTZfZ.js} +1 -1
  8. package/dist/web/assets/ProjectFilesPanel-ByyaiSGy.js +4 -0
  9. package/dist/web/assets/{ProjectSwitcherModal-o8NhzySH.js → ProjectSwitcherModal-BRbFj3Dd.js} +1 -1
  10. package/dist/web/assets/{TerminalOutput-CcWkSv29.js → TerminalOutput-Aavw8QCx.js} +1 -1
  11. package/dist/web/assets/{ThemeSelectorModal-CnbSCgJj.js → ThemeSelectorModal-CxGMhlkF.js} +1 -1
  12. package/dist/web/assets/WorkflowsPanel-Beg1AAtq.js +1 -0
  13. package/dist/web/assets/{WorktreePanel-DahbK2L0.js → WorktreePanel-B17_SlFC.js} +1 -1
  14. package/dist/web/assets/{index-_0HhakEy.js → index-C-5Kgwol.js} +4 -4
  15. package/dist/web/assets/{index-DXTQExVH.js → index-CJcccHRp.js} +1 -1
  16. package/dist/web/assets/index-CTpAqQye.js +1 -0
  17. package/dist/web/assets/index-DB1wEO_I.js +148 -0
  18. package/dist/web/assets/index-DU9XxwBy.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-CyII6N5s.js} +152 -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/ProjectFilesPanel-DSvO4CrB.js +0 -4
  26. package/dist/web/assets/WorkflowsPanel-CvBweQMf.js +0 -1
  27. package/dist/web/assets/index-7UiltNKa.js +0 -1
  28. package/dist/web/assets/index-BESnPMZk.js +0 -144
  29. package/dist/web/assets/index-Bif4Kdtn.css +0 -1
package/dist/cli.js CHANGED
@@ -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 record3 = { at: Date.now(), generation: generation2 };
490
+ lastAttempt.set(id, record3);
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
+ record3.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
+ record3.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
+ record3.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
+ record3.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",
@@ -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 record3 = {
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(record3.sessionId, record3);
4012
+ return { changed: true, value: toPublicShare(record3) };
3973
4013
  });
3974
4014
  return { share, passphrase };
3975
4015
  }
@@ -4819,6 +4859,7 @@ 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"),
4822
4863
  "project-icon": admin("/api/project-icon"),
4823
4864
  "git-diff": admin("/api/git-diff"),
4824
4865
  mcp: admin("/api/mcp-servers"),
@@ -4847,6 +4888,10 @@ var init_policy = __esm({
4847
4888
  "provider-updates": [
4848
4889
  { prefix: "/api/provider-updates", methods: ["GET"], requires: "authed" },
4849
4890
  { prefix: "/api/provider-updates/run", requires: "admin" }
4891
+ ],
4892
+ // Reports which binary the server spawns; the choice itself is saved through /api/config.
4893
+ "agent-executable": [
4894
+ { prefix: "/api/agent-executable", methods: ["GET"], requires: "authed" }
4850
4895
  ]
4851
4896
  };
4852
4897
  ALL_RULES = Object.values(ROUTE_POLICIES).flat();
@@ -5619,6 +5664,274 @@ var init_subagentWatcher = __esm({
5619
5664
  }
5620
5665
  });
5621
5666
 
5667
+ // ../../shared/versions.ts
5668
+ function parseVersion(raw) {
5669
+ const match = raw.trim().replace(/^v/i, "").match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/);
5670
+ if (!match) return null;
5671
+ return {
5672
+ parts: [Number(match[1]), Number(match[2]), Number(match[3])],
5673
+ prerelease: match[4] ? match[4].split(".") : []
5674
+ };
5675
+ }
5676
+ function extractVersion(output) {
5677
+ const match = output.match(/\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/);
5678
+ return match ? match[0] : null;
5679
+ }
5680
+ function comparePrerelease(a, b) {
5681
+ if (a.length === 0 && b.length === 0) return 0;
5682
+ if (a.length === 0) return 1;
5683
+ if (b.length === 0) return -1;
5684
+ for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
5685
+ const left = a[i];
5686
+ const right = b[i];
5687
+ if (left === void 0) return -1;
5688
+ if (right === void 0) return 1;
5689
+ const leftNumeric = /^\d+$/.test(left);
5690
+ const rightNumeric = /^\d+$/.test(right);
5691
+ if (leftNumeric && rightNumeric) {
5692
+ if (Number(left) !== Number(right)) return Number(left) < Number(right) ? -1 : 1;
5693
+ continue;
5694
+ }
5695
+ if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1;
5696
+ if (left !== right) return left < right ? -1 : 1;
5697
+ }
5698
+ return 0;
5699
+ }
5700
+ function compareVersions(a, b) {
5701
+ const left = parseVersion(a);
5702
+ const right = parseVersion(b);
5703
+ if (!left || !right) return null;
5704
+ for (let i = 0; i < 3; i += 1) {
5705
+ if (left.parts[i] !== right.parts[i]) return left.parts[i] < right.parts[i] ? -1 : 1;
5706
+ }
5707
+ return comparePrerelease(left.prerelease, right.prerelease);
5708
+ }
5709
+ var init_versions = __esm({
5710
+ "../../shared/versions.ts"() {
5711
+ }
5712
+ });
5713
+
5714
+ // ../../server/lib/cliProcess.ts
5715
+ import { spawn } from "node:child_process";
5716
+ function runCli(executable, args, timeoutMs) {
5717
+ return new Promise((resolve21) => {
5718
+ const resolved = resolveAgentCommand(executable, [...args]);
5719
+ const child = spawn(resolved.command, resolved.args, {
5720
+ stdio: ["ignore", "pipe", "pipe"],
5721
+ ...resolved.spawnOptions
5722
+ });
5723
+ let stdout = "";
5724
+ let stderr = "";
5725
+ let timedOut = false;
5726
+ const timer = setTimeout(() => {
5727
+ timedOut = true;
5728
+ child.kill("SIGKILL");
5729
+ }, timeoutMs);
5730
+ const append = (buffer, chunk) => buffer.length >= CLI_OUTPUT_MAX_CHARS ? buffer : buffer + chunk.toString();
5731
+ child.stdout?.on("data", (chunk) => {
5732
+ stdout = append(stdout, chunk);
5733
+ });
5734
+ child.stderr?.on("data", (chunk) => {
5735
+ stderr = append(stderr, chunk);
5736
+ });
5737
+ child.on("error", () => {
5738
+ clearTimeout(timer);
5739
+ resolve21({ code: null, stdout, stderr, timedOut });
5740
+ });
5741
+ child.on("close", (code) => {
5742
+ clearTimeout(timer);
5743
+ resolve21({ code, stdout, stderr, timedOut });
5744
+ });
5745
+ });
5746
+ }
5747
+ async function probeCliVersion(command, versionArgs, timeoutMs = DEFAULT_PROBE_TIMEOUT_MS) {
5748
+ const probe = await runCli(command, versionArgs, timeoutMs);
5749
+ return extractVersion(`${probe.stdout}
5750
+ ${probe.stderr}`);
5751
+ }
5752
+ var DEFAULT_PROBE_TIMEOUT_MS, CLI_OUTPUT_MAX_CHARS;
5753
+ var init_cliProcess = __esm({
5754
+ "../../server/lib/cliProcess.ts"() {
5755
+ init_versions();
5756
+ init_binaryResolver();
5757
+ DEFAULT_PROBE_TIMEOUT_MS = 5e3;
5758
+ CLI_OUTPUT_MAX_CHARS = 1e4;
5759
+ }
5760
+ });
5761
+
5762
+ // ../../server/agents/claudeExecutable.ts
5763
+ import { execFileSync } from "node:child_process";
5764
+ import { readFileSync, statSync as statSync2 } from "node:fs";
5765
+ import { createRequire } from "node:module";
5766
+ import { posix as posix2, win32 as win322 } from "node:path";
5767
+ function realIsFile(path) {
5768
+ try {
5769
+ return statSync2(path).isFile();
5770
+ } catch {
5771
+ return false;
5772
+ }
5773
+ }
5774
+ function realReadFile(path) {
5775
+ try {
5776
+ return readFileSync(path, "utf-8");
5777
+ } catch {
5778
+ return void 0;
5779
+ }
5780
+ }
5781
+ function binField(manifest) {
5782
+ let bin;
5783
+ try {
5784
+ bin = JSON.parse(manifest).bin;
5785
+ } catch {
5786
+ return void 0;
5787
+ }
5788
+ if (typeof bin === "string") return bin;
5789
+ if (!bin || typeof bin !== "object") return void 0;
5790
+ const entry = bin[BIN_NAME];
5791
+ return typeof entry === "string" ? entry : void 0;
5792
+ }
5793
+ function findNpmClaude(options = {}) {
5794
+ const platform2 = options.platform ?? process.platform;
5795
+ const windows = platform2 === "win32";
5796
+ const path = windows ? win322 : posix2;
5797
+ const isFile = options.isFile ?? realIsFile;
5798
+ const readFile21 = options.readFile ?? realReadFile;
5799
+ const shim = findExecutableOnPath(BIN_NAME, { platform: platform2, env: options.env, isExecutable: isFile });
5800
+ if (!shim) return void 0;
5801
+ const shimDir = path.dirname(shim);
5802
+ const packageDirs = [
5803
+ path.join(shimDir, "node_modules", NPM_PACKAGE),
5804
+ path.join(shimDir, "..", "lib", "node_modules", NPM_PACKAGE)
5805
+ ];
5806
+ for (const packageDir of packageDirs) {
5807
+ const manifest = readFile21(path.join(packageDir, "package.json"));
5808
+ if (!manifest) continue;
5809
+ const relative11 = binField(manifest);
5810
+ if (!relative11) continue;
5811
+ const target = path.normalize(path.join(packageDir, relative11));
5812
+ if (windows && !isDirectlyLaunchable(target)) continue;
5813
+ if (isFile(target)) return target;
5814
+ }
5815
+ return void 0;
5816
+ }
5817
+ function findInstalledClaude() {
5818
+ return findExecutableOnPath(BIN_NAME, { directOnly: true });
5819
+ }
5820
+ function findBundledClaude(resolveModule2) {
5821
+ try {
5822
+ const platformPkg = `@anthropic-ai/claude-agent-sdk-${process.platform}-${process.arch}`;
5823
+ return resolveModule2(`${platformPkg}/package.json`).replace(/package\.json$/, CLI_BIN_NAME).replace(ASAR_SEGMENT, "$1app.asar.unpacked$2");
5824
+ } catch {
5825
+ return void 0;
5826
+ }
5827
+ }
5828
+ function discoverClaudeExecutables(resolveModule2, probes = {}) {
5829
+ return {
5830
+ installed: (probes.findOnPath ?? findInstalledClaude)(),
5831
+ npm: (probes.findNpm ?? findNpmClaude)(),
5832
+ bundled: findBundledClaude(resolveModule2)
5833
+ };
5834
+ }
5835
+ function readCliVersionSync(binPath) {
5836
+ try {
5837
+ const output = execFileSync(binPath, ["--version"], {
5838
+ encoding: "utf-8",
5839
+ timeout: 5e3,
5840
+ stdio: ["ignore", "pipe", "ignore"]
5841
+ });
5842
+ const match = output.match(/(\d+)\.(\d+)\.(\d+)/);
5843
+ return match ? [Number(match[1]), Number(match[2]), Number(match[3])] : void 0;
5844
+ } catch {
5845
+ return void 0;
5846
+ }
5847
+ }
5848
+ function isAtLeast(version, floor) {
5849
+ for (let i = 0; i < 3; i += 1) {
5850
+ if (version[i] !== floor[i]) return version[i] > floor[i];
5851
+ }
5852
+ return true;
5853
+ }
5854
+ function chooseAutomatically(found, readVersion) {
5855
+ const bundled = found.bundled ? { source: "bundled", path: found.bundled } : void 0;
5856
+ if (!found.installed) return bundled;
5857
+ const installed = { source: "path", path: found.installed };
5858
+ const installedVersion = readVersion(found.installed);
5859
+ if (!installedVersion) return bundled ?? installed;
5860
+ const bundledVersion = bundled ? readVersion(bundled.path) : void 0;
5861
+ if (bundledVersion && !isAtLeast(installedVersion, bundledVersion)) return bundled;
5862
+ return installed;
5863
+ }
5864
+ function chooseClaudeExecutable(choice, found, readVersion) {
5865
+ switch (choice.source) {
5866
+ case "auto":
5867
+ return chooseAutomatically(found, readVersion);
5868
+ case "custom":
5869
+ return choice.path ? { source: "custom", path: choice.path } : void 0;
5870
+ case "path":
5871
+ return found.installed ? { source: "path", path: found.installed } : void 0;
5872
+ case "npm":
5873
+ return found.npm ? { source: "npm", path: found.npm } : void 0;
5874
+ case "bundled":
5875
+ return found.bundled ? { source: "bundled", path: found.bundled } : void 0;
5876
+ }
5877
+ }
5878
+ function configuredChoice() {
5879
+ return getConfig()?.agentExecutable ?? DEFAULT_EXECUTABLE_CHOICE;
5880
+ }
5881
+ function resolveClaudeExecutable() {
5882
+ const choice = configuredChoice();
5883
+ const key2 = JSON.stringify(choice);
5884
+ if (memo?.key !== key2) {
5885
+ memo = {
5886
+ key: key2,
5887
+ resolved: chooseClaudeExecutable(choice, discoverClaudeExecutables(resolveModule), readCliVersionSync)
5888
+ };
5889
+ }
5890
+ return memo.resolved;
5891
+ }
5892
+ function claudeCliPath() {
5893
+ return resolveClaudeExecutable()?.path;
5894
+ }
5895
+ async function describeClaudeExecutable() {
5896
+ const choice = configuredChoice();
5897
+ const found = discoverClaudeExecutables(resolveModule);
5898
+ const active = resolveClaudeExecutable();
5899
+ const pathBySource = {
5900
+ path: found.installed,
5901
+ npm: found.npm,
5902
+ bundled: found.bundled
5903
+ };
5904
+ const detected = DETECTED_EXECUTABLE_SOURCES.filter((source) => pathBySource[source] !== void 0).map((source) => ({ source, path: pathBySource[source] }));
5905
+ const paths = /* @__PURE__ */ new Set([...detected.map(({ path }) => path), ...active ? [active.path] : []]);
5906
+ const versions = new Map(
5907
+ await Promise.all(
5908
+ [...paths].map(async (path) => [path, await probeCliVersion(path, ["--version"])])
5909
+ )
5910
+ );
5911
+ return {
5912
+ choice,
5913
+ candidates: detected.map((candidate) => ({
5914
+ ...candidate,
5915
+ version: versions.get(candidate.path) ?? null
5916
+ })),
5917
+ active: active ? { ...active, version: versions.get(active.path) ?? null } : null
5918
+ };
5919
+ }
5920
+ var BIN_NAME, NPM_PACKAGE, CLI_BIN_NAME, ASAR_SEGMENT, resolveModule, memo;
5921
+ var init_claudeExecutable = __esm({
5922
+ "../../server/agents/claudeExecutable.ts"() {
5923
+ init_agentExecutable();
5924
+ init_config();
5925
+ init_binaryResolver();
5926
+ init_cliProcess();
5927
+ BIN_NAME = "claude";
5928
+ NPM_PACKAGE = "@anthropic-ai/claude-code";
5929
+ CLI_BIN_NAME = nativeBinaryName(BIN_NAME);
5930
+ ASAR_SEGMENT = /([\\/])app\.asar([\\/])/;
5931
+ resolveModule = (id) => createRequire(import.meta.url).resolve(id);
5932
+ }
5933
+ });
5934
+
5622
5935
  // ../../server/lib/streamBus.ts
5623
5936
  function getOrCreate(sessionId) {
5624
5937
  let state = sessions2.get(sessionId);
@@ -5887,58 +6200,6 @@ var init_streamBus = __esm({
5887
6200
 
5888
6201
  // ../../server/sdk-session.ts
5889
6202
  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
6203
  function streamingEnabled() {
5943
6204
  const raw = process.env.COGPIT_STREAM_PARTIAL;
5944
6205
  if (raw === void 0) return true;
@@ -6824,15 +7085,12 @@ function cleanupAllSDKSessions() {
6824
7085
  sdkSessions.clear();
6825
7086
  return killed;
6826
7087
  }
6827
- var CLI_BIN_NAME, ASAR_SEGMENT, cliPathProbed, cliPath, sdkSessions, REFUSAL_FALLBACK_DIALOG, DIALOG_CHOICES, SUPPORTED_DIALOG_KINDS, SDKMessageStream, EDIT_TOOL_NAMES;
7088
+ var sdkSessions, REFUSAL_FALLBACK_DIALOG, DIALOG_CHOICES, SUPPORTED_DIALOG_KINDS, SDKMessageStream, EDIT_TOOL_NAMES;
6828
7089
  var init_sdk_session = __esm({
6829
7090
  "../../server/sdk-session.ts"() {
6830
7091
  init_subagentWatcher();
6831
- init_binaryResolver();
7092
+ init_claudeExecutable();
6832
7093
  init_streamBus();
6833
- CLI_BIN_NAME = nativeBinaryName("claude");
6834
- ASAR_SEGMENT = /([\\/])app\.asar([\\/])/;
6835
- cliPathProbed = false;
6836
7094
  sdkSessions = /* @__PURE__ */ new Map();
6837
7095
  REFUSAL_FALLBACK_DIALOG = "refusal_fallback_prompt";
6838
7096
  DIALOG_CHOICES = {
@@ -8320,9 +8578,9 @@ function safeParseLine(line) {
8320
8578
  function isObject2(value) {
8321
8579
  return typeof value === "object" && value !== null;
8322
8580
  }
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";
8581
+ function isCodexRecord(record3) {
8582
+ if (!record3 || typeof record3.type !== "string") return false;
8583
+ return record3.type === "session_meta" || record3.type === "turn_context" || record3.type === "event_msg" || record3.type === "response_item" || record3.type === "inter_agent_communication_metadata" || record3.type === "compacted" || record3.type === "world_state";
8326
8584
  }
8327
8585
  function extractMessageText(payload, blockType) {
8328
8586
  const content = payload?.content;
@@ -8523,22 +8781,22 @@ function createTurn(turnId, timestamp, model) {
8523
8781
  model
8524
8782
  };
8525
8783
  }
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);
8784
+ function extractPromptFromRecord(record3) {
8785
+ if (record3.type === "event_msg" && isObject2(record3.payload) && record3.payload.type === "user_message" && typeof record3.payload.message === "string") {
8786
+ return normalizePromptText(record3.payload.message);
8529
8787
  }
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"));
8788
+ if (record3.type === "response_item" && isObject2(record3.payload) && record3.payload.type === "message" && record3.payload.role === "user") {
8789
+ return normalizePromptText(extractMessageText(record3.payload, "input_text"));
8532
8790
  }
8533
8791
  return "";
8534
8792
  }
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") {
8793
+ function recordOpensTurn(record3, payload) {
8794
+ if (record3.type === "session_meta") return false;
8795
+ if (record3.type === "event_msg" && payload?.type === "task_started") return false;
8796
+ if (record3.type === "response_item" && payload?.type === "message") {
8539
8797
  if (payload.role === "developer" || payload.role === "system") return false;
8540
8798
  if (payload.role === "user") {
8541
- return extractPromptFromRecord(record2) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
8799
+ return extractPromptFromRecord(record3) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
8542
8800
  }
8543
8801
  }
8544
8802
  return true;
@@ -8559,22 +8817,22 @@ function extractMetadataFromRecords(records) {
8559
8817
  let parentSessionId = null;
8560
8818
  let agentPath = "/root";
8561
8819
  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 : "";
8820
+ for (const record3 of records) {
8821
+ if (!isObject2(record3.payload)) continue;
8822
+ if (record3.type === "session_meta") {
8823
+ sessionId ||= typeof record3.payload.id === "string" ? record3.payload.id : "";
8824
+ version ||= typeof record3.payload.cli_version === "string" ? record3.payload.cli_version : "";
8825
+ cwd ||= typeof record3.payload.cwd === "string" ? record3.payload.cwd : "";
8826
+ if (!branchedFrom && isObject2(record3.payload.branchedFrom)) {
8827
+ const sourceId = typeof record3.payload.branchedFrom.sessionId === "string" ? record3.payload.branchedFrom.sessionId : "";
8570
8828
  if (sourceId) {
8571
8829
  branchedFrom = {
8572
8830
  sessionId: sourceId,
8573
- turnIndex: typeof record2.payload.branchedFrom.turnIndex === "number" ? record2.payload.branchedFrom.turnIndex : null
8831
+ turnIndex: typeof record3.payload.branchedFrom.turnIndex === "number" ? record3.payload.branchedFrom.turnIndex : null
8574
8832
  };
8575
8833
  }
8576
8834
  }
8577
- const source = isObject2(record2.payload.source) ? record2.payload.source : null;
8835
+ const source = isObject2(record3.payload.source) ? record3.payload.source : null;
8578
8836
  if (source && isObject2(source.subagent)) {
8579
8837
  isSubagent = true;
8580
8838
  const threadSpawn = isObject2(source.subagent.thread_spawn) ? source.subagent.thread_spawn : null;
@@ -8582,25 +8840,25 @@ function extractMetadataFromRecords(records) {
8582
8840
  agentPath = threadSpawn.agent_path;
8583
8841
  }
8584
8842
  }
8585
- if (typeof record2.payload.forked_from_id === "string" && record2.payload.forked_from_id) {
8586
- parentSessionId = record2.payload.forked_from_id;
8843
+ if (typeof record3.payload.forked_from_id === "string" && record3.payload.forked_from_id) {
8844
+ parentSessionId = record3.payload.forked_from_id;
8587
8845
  }
8588
- const git = isObject2(record2.payload.git) ? record2.payload.git : null;
8846
+ const git = isObject2(record3.payload.git) ? record3.payload.git : null;
8589
8847
  gitBranch ||= git && typeof git.branch === "string" ? git.branch : "";
8590
8848
  }
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 : "";
8849
+ if (record3.type === "turn_context") {
8850
+ model ||= typeof record3.payload.model === "string" ? record3.payload.model : "";
8851
+ cwd ||= typeof record3.payload.cwd === "string" ? record3.payload.cwd : "";
8594
8852
  }
8595
- const prompt = extractPromptFromRecord(record2);
8853
+ const prompt = extractPromptFromRecord(record3);
8596
8854
  if (!prompt) continue;
8597
8855
  if (prompt === previousPrompt) continue;
8598
8856
  if (!firstUserMessage) firstUserMessage = prompt;
8599
8857
  lastUserMessage = prompt;
8600
8858
  previousPrompt = prompt;
8601
8859
  turnCount++;
8602
- if (!timestamp) timestamp = record2.timestamp ?? "";
8603
- lastTimestamp = record2.timestamp ?? lastTimestamp;
8860
+ if (!timestamp) timestamp = record3.timestamp ?? "";
8861
+ lastTimestamp = record3.timestamp ?? lastTimestamp;
8604
8862
  }
8605
8863
  if (lastTimestamp === "") lastTimestamp = timestamp;
8606
8864
  return {
@@ -8758,19 +9016,19 @@ function walkCodexRecords(records, options) {
8758
9016
  appendToolCall(targetTurn, toolCall, timestamp);
8759
9017
  }
8760
9018
  for (let index = 0; index < records.length; index++) {
8761
- const record2 = records[index];
8762
- if (!isCodexRecord(record2)) continue;
9019
+ const record3 = records[index];
9020
+ if (!isCodexRecord(record3)) continue;
8763
9021
  recordIndex = index;
8764
- const payload = isObject2(record2.payload) ? record2.payload : void 0;
8765
- const timestamp = record2.timestamp ?? "";
8766
- if (record2.type === "compacted") {
9022
+ const payload = isObject2(record3.payload) ? record3.payload : void 0;
9023
+ const timestamp = record3.timestamp ?? "";
9024
+ if (record3.type === "compacted") {
8767
9025
  current = commitTurn(current);
8768
9026
  pendingCompaction = "Conversation compacted";
8769
9027
  lastTurnTimestamp = timestamp;
8770
9028
  continue;
8771
9029
  }
8772
- if (record2.type === "world_state") continue;
8773
- if (record2.type === "turn_context") {
9030
+ if (record3.type === "world_state") continue;
9031
+ if (record3.type === "turn_context") {
8774
9032
  current = commitTurn(current);
8775
9033
  pendingContextIndex = index;
8776
9034
  currentTurnId = typeof payload?.turn_id === "string" ? payload.turn_id : null;
@@ -8779,7 +9037,7 @@ function walkCodexRecords(records, options) {
8779
9037
  sawTurnStart = true;
8780
9038
  continue;
8781
9039
  }
8782
- if (record2.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
9040
+ if (record3.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
8783
9041
  if (current && (current.assistantText.length > 0 || current.toolCalls.length > 0 || current.thinking.length > 0)) {
8784
9042
  current = commitTurn(current);
8785
9043
  }
@@ -8803,12 +9061,12 @@ function walkCodexRecords(records, options) {
8803
9061
  lastTurnTimestamp = timestamp;
8804
9062
  continue;
8805
9063
  }
8806
- if (!current && !recordOpensTurn(record2, payload)) continue;
9064
+ if (!current && !recordOpensTurn(record3, payload)) continue;
8807
9065
  current ??= createActiveTurn(currentTurnId, timestamp, currentModel);
8808
9066
  if (!current.model && currentModel) current.model = currentModel;
8809
9067
  if (!current.timestamp) current.timestamp = timestamp;
8810
9068
  if (timestamp) lastTurnTimestamp = timestamp;
8811
- if (record2.type === "event_msg" && payload?.type === "token_count") {
9069
+ if (record3.type === "event_msg" && payload?.type === "token_count") {
8812
9070
  const info = isObject2(payload.info) ? payload.info : null;
8813
9071
  const lastUsage = info ? parseTokenUsage(info.last_token_usage) : null;
8814
9072
  if (lastUsage) {
@@ -8816,14 +9074,14 @@ function walkCodexRecords(records, options) {
8816
9074
  }
8817
9075
  continue;
8818
9076
  }
8819
- if (record2.type === "event_msg" && payload?.type === "web_search_end" && typeof payload.call_id === "string") {
9077
+ if (record3.type === "event_msg" && payload?.type === "web_search_end" && typeof payload.call_id === "string") {
8820
9078
  const input = {};
8821
9079
  if (typeof payload.query === "string" && payload.query) input.query = payload.query;
8822
9080
  if (isObject2(payload.action)) input.action = payload.action;
8823
9081
  upsertWebSearchCall(current, payload.call_id, input, "completed", timestamp);
8824
9082
  continue;
8825
9083
  }
8826
- if (record2.type === "event_msg" && payload?.type === "mcp_tool_call_end" && typeof payload.call_id === "string" && isObject2(payload.invocation)) {
9084
+ if (record3.type === "event_msg" && payload?.type === "mcp_tool_call_end" && typeof payload.call_id === "string" && isObject2(payload.invocation)) {
8827
9085
  const invocation = payload.invocation;
8828
9086
  const server = typeof invocation.server === "string" ? invocation.server : "mcp";
8829
9087
  const tool = typeof invocation.tool === "string" ? invocation.tool : "tool";
@@ -8846,7 +9104,7 @@ function walkCodexRecords(records, options) {
8846
9104
  }
8847
9105
  continue;
8848
9106
  }
8849
- if (record2.type === "event_msg" && payload?.type === "sub_agent_activity" && typeof payload.agent_thread_id === "string" && typeof payload.agent_path === "string") {
9107
+ if (record3.type === "event_msg" && payload?.type === "sub_agent_activity" && typeof payload.agent_thread_id === "string" && typeof payload.agent_path === "string") {
8850
9108
  const agentId = payload.agent_thread_id;
8851
9109
  const eventId2 = typeof payload.event_id === "string" ? payload.event_id : "";
8852
9110
  const kind = typeof payload.kind === "string" ? payload.kind : "started";
@@ -8880,7 +9138,7 @@ function walkCodexRecords(records, options) {
8880
9138
  upsertAgentMessage(agentId, current, timestamp, { status });
8881
9139
  continue;
8882
9140
  }
8883
- if (record2.type !== "response_item" || !payload) continue;
9141
+ if (record3.type !== "response_item" || !payload) continue;
8884
9142
  if (payload.type === "reasoning") {
8885
9143
  const summary = Array.isArray(payload.summary) ? payload.summary.filter((item) => typeof item === "string").join("\n") : "";
8886
9144
  appendThinking(current, summary.trim(), timestamp);
@@ -9150,7 +9408,7 @@ function parseCodexSession(jsonlText, options) {
9150
9408
  return session;
9151
9409
  }
9152
9410
  function appendCodexSession(existing, newJsonlText) {
9153
- const prefix = existing.rawMessages.map((record2) => JSON.stringify(record2)).join("\n");
9411
+ const prefix = existing.rawMessages.map((record3) => JSON.stringify(record3)).join("\n");
9154
9412
  return parseCodexSession(prefix ? `${prefix}
9155
9413
  ${newJsonlText}` : newJsonlText);
9156
9414
  }
@@ -9345,16 +9603,16 @@ async function readCodexSessionIdentity(filePath) {
9345
9603
  let parentSessionId = null;
9346
9604
  let sawSessionMeta = false;
9347
9605
  for (const line of await readHeadLines(filePath, HEAD_BYTES)) {
9348
- let record2;
9606
+ let record3;
9349
9607
  try {
9350
- record2 = JSON.parse(line);
9608
+ record3 = JSON.parse(line);
9351
9609
  } catch {
9352
9610
  continue;
9353
9611
  }
9354
- if (!isRecord2(record2) || !isRecord2(record2.payload)) continue;
9355
- if (record2.type === "session_meta") {
9612
+ if (!isRecord2(record3) || !isRecord2(record3.payload)) continue;
9613
+ if (record3.type === "session_meta") {
9356
9614
  sawSessionMeta = true;
9357
- const payload = record2.payload;
9615
+ const payload = record3.payload;
9358
9616
  if (!sessionId && typeof payload.id === "string") sessionId = payload.id;
9359
9617
  if (!cwd && typeof payload.cwd === "string") cwd = payload.cwd;
9360
9618
  if (!parentSessionId && typeof payload.forked_from_id === "string") {
@@ -9364,8 +9622,8 @@ async function readCodexSessionIdentity(filePath) {
9364
9622
  if (source && isRecord2(source.subagent)) isSubagent = true;
9365
9623
  const git = isRecord2(payload.git) ? payload.git : null;
9366
9624
  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;
9625
+ } else if (record3.type === "turn_context") {
9626
+ if (!cwd && typeof record3.payload.cwd === "string") cwd = record3.payload.cwd;
9369
9627
  }
9370
9628
  }
9371
9629
  if (!sawSessionMeta || !cwd) return null;
@@ -10387,7 +10645,7 @@ function parseCopilotSession(jsonlText, options) {
10387
10645
  };
10388
10646
  }
10389
10647
  function appendCopilotSession(existing, newJsonlText) {
10390
- const prefix = existing.rawMessages.map((record2) => JSON.stringify(record2)).join("\n");
10648
+ const prefix = existing.rawMessages.map((record3) => JSON.stringify(record3)).join("\n");
10391
10649
  return parseCopilotSession(prefix ? `${prefix}
10392
10650
  ${newJsonlText}` : newJsonlText);
10393
10651
  }
@@ -10495,11 +10753,11 @@ function brandCopilotBranch() {
10495
10753
  function copilotTurnBoundaries(records) {
10496
10754
  const boundaries = [];
10497
10755
  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;
10756
+ const record3 = records[index];
10757
+ if (record3.type !== "user.message" || typeof record3.agentId === "string") continue;
10758
+ const data = record3.data;
10501
10759
  if (!data || typeof data !== "object" || Array.isArray(data)) continue;
10502
- if (typeof record2.id !== "string" || !record2.id) continue;
10760
+ if (typeof record3.id !== "string" || !record3.id) continue;
10503
10761
  boundaries.push(index);
10504
10762
  }
10505
10763
  return boundaries;
@@ -10556,14 +10814,14 @@ async function readCopilotSessionIdentity(filePath) {
10556
10814
  let cwd = "";
10557
10815
  let gitBranch = "";
10558
10816
  for (const line of await readHeadLines(filePath, HEAD_BYTES)) {
10559
- let record2;
10817
+ let record3;
10560
10818
  try {
10561
- record2 = JSON.parse(line);
10819
+ record3 = JSON.parse(line);
10562
10820
  } catch {
10563
10821
  continue;
10564
10822
  }
10565
- if (!isRecord3(record2) || record2.type !== "session.start" && record2.type !== "session.resume") continue;
10566
- const data = isRecord3(record2.data) ? record2.data : null;
10823
+ if (!isRecord3(record3) || record3.type !== "session.start" && record3.type !== "session.resume") continue;
10824
+ const data = isRecord3(record3.data) ? record3.data : null;
10567
10825
  if (!data) continue;
10568
10826
  if (typeof data.sessionId === "string" && data.sessionId) sessionId = data.sessionId;
10569
10827
  const context = isRecord3(data.context) ? data.context : null;
@@ -11926,9 +12184,9 @@ function nonEmpty(value) {
11926
12184
  function stripTaggedBlocks(text) {
11927
12185
  return text.replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g, "").trim();
11928
12186
  }
11929
- function effortFromRecord(record2) {
12187
+ function effortFromRecord(record3) {
11930
12188
  for (const kind of AGENT_KINDS) {
11931
- const effort = READERS[kind].effort(record2);
12189
+ const effort = READERS[kind].effort(record3);
11932
12190
  if (effort) return effort;
11933
12191
  }
11934
12192
  return null;
@@ -11938,15 +12196,15 @@ function userMessageTextFromLine(line) {
11938
12196
  (kind) => READERS[kind].userMessageMarkers.some((marker) => line.includes(marker))
11939
12197
  );
11940
12198
  if (candidates.length === 0) return null;
11941
- let record2;
12199
+ let record3;
11942
12200
  try {
11943
- record2 = JSON.parse(line);
12201
+ record3 = JSON.parse(line);
11944
12202
  } catch {
11945
12203
  return null;
11946
12204
  }
11947
- if (!isRecord4(record2)) return null;
12205
+ if (!isRecord4(record3)) return null;
11948
12206
  for (const kind of candidates) {
11949
- const text = READERS[kind].userMessageText(record2);
12207
+ const text = READERS[kind].userMessageText(record3);
11950
12208
  if (text !== null) return text;
11951
12209
  }
11952
12210
  return null;
@@ -11958,11 +12216,11 @@ var init_recordReaders = __esm({
11958
12216
  claudeReader = {
11959
12217
  kind: "claude",
11960
12218
  // Every assistant record is tagged with the effort that turn ran at.
11961
- effort: (record2) => record2.type === "assistant" ? nonEmpty(record2.effort) : null,
12219
+ effort: (record3) => record3.type === "assistant" ? nonEmpty(record3.effort) : null,
11962
12220
  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;
12221
+ userMessageText(record3) {
12222
+ if (record3.type !== "user" || record3.isMeta) return null;
12223
+ const content = isRecord4(record3.message) ? record3.message.content : void 0;
11966
12224
  if (typeof content === "string") return stripTaggedBlocks(content);
11967
12225
  if (!Array.isArray(content)) return "";
11968
12226
  let text = "";
@@ -11977,32 +12235,32 @@ var init_recordReaders = __esm({
11977
12235
  codexReader = {
11978
12236
  kind: "codex",
11979
12237
  // 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;
12238
+ effort(record3) {
12239
+ if (record3.type !== "turn_context" || !isRecord4(record3.payload)) return null;
12240
+ const { payload } = record3;
11983
12241
  const direct = nonEmpty(payload.effort);
11984
12242
  if (direct) return direct;
11985
12243
  const settings = isRecord4(payload.thread_settings) ? payload.thread_settings : null;
11986
12244
  return nonEmpty(settings?.reasoning_effort);
11987
12245
  },
11988
12246
  userMessageMarkers: ['"event_msg"'],
11989
- userMessageText(record2) {
11990
- if (record2.type !== "event_msg" || !isRecord4(record2.payload)) return null;
11991
- const { payload } = record2;
12247
+ userMessageText(record3) {
12248
+ if (record3.type !== "event_msg" || !isRecord4(record3.payload)) return null;
12249
+ const { payload } = record3;
11992
12250
  return payload.type === "user_message" && typeof payload.message === "string" ? payload.message.trim() : null;
11993
12251
  }
11994
12252
  };
11995
12253
  copilotReader = {
11996
12254
  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);
12255
+ effort(record3) {
12256
+ if (record3.type !== "session.start" && record3.type !== "session.resume" && record3.type !== "session.model_change" || !isRecord4(record3.data)) return null;
12257
+ return nonEmpty(record3.data.reasoningEffort ?? record3.data.effort);
12000
12258
  },
12001
12259
  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;
12260
+ userMessageText(record3) {
12261
+ if (record3.type !== "user.message") return null;
12262
+ if (typeof record3.agentId === "string" && record3.agentId) return null;
12263
+ const data = isRecord4(record3.data) ? record3.data : null;
12006
12264
  return typeof data?.content === "string" ? data.content.trim() : "";
12007
12265
  }
12008
12266
  };
@@ -12015,16 +12273,16 @@ var init_recordReaders = __esm({
12015
12273
  });
12016
12274
 
12017
12275
  // ../../server/agents/tailRecords.ts
12018
- function isSubagentLifecycle(record2) {
12019
- return record2.type.startsWith("subagent.") && typeof record2.agentId === "string" && record2.agentId.length > 0;
12276
+ function isSubagentLifecycle(record3) {
12277
+ return record3.type.startsWith("subagent.") && typeof record3.agentId === "string" && record3.agentId.length > 0;
12020
12278
  }
12021
- function isSubagentNoise(record2) {
12022
- return typeof record2.agentId === "string" && record2.agentId.length > 0;
12279
+ function isSubagentNoise(record3) {
12280
+ return typeof record3.agentId === "string" && record3.agentId.length > 0;
12023
12281
  }
12024
- function classifyTailRecord(record2) {
12282
+ function classifyTailRecord(record3) {
12025
12283
  for (const kind of AGENT_KINDS) {
12026
12284
  const format = TAIL_FORMATS[kind];
12027
- const verdict = format.classify(record2);
12285
+ const verdict = format.classify(record3);
12028
12286
  if (verdict.kind !== "ignore") return { format, verdict };
12029
12287
  }
12030
12288
  return null;
@@ -12041,31 +12299,31 @@ var init_tailRecords = __esm({
12041
12299
  // Background agent/workflow launches, task notifications and TaskStop calls
12042
12300
  // can all still change a verdict that a turn-ending line looked to settle.
12043
12301
  markers: ["async_launched", "task-notification", '"TaskStop"'],
12044
- classify(record2) {
12045
- if (record2.type === "system" && record2.subtype === "terminal_reason") {
12046
- const reason = record2.reason;
12302
+ classify(record3) {
12303
+ if (record3.type === "system" && record3.subtype === "terminal_reason") {
12304
+ const reason = record3.reason;
12047
12305
  return reason ? { kind: "final", status: { status: "completed", terminalReason: reason } } : IGNORE;
12048
12306
  }
12049
- if (record2.type === "progress") {
12050
- const data = record2.data;
12307
+ if (record3.type === "progress") {
12308
+ const data = record3.data;
12051
12309
  if (data?.type !== "hook_progress") return IGNORE;
12052
12310
  const decision = data.decision ?? data.hookSpecificOutput?.permissionDecision;
12053
12311
  return decision === "defer" ? ANSWER : IGNORE;
12054
12312
  }
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") {
12313
+ if (record3.type === "attachment") return KEEP;
12314
+ if (record3.type === "assistant" || record3.type === "user" || record3.type === "queue-operation") {
12315
+ const stopReason = record3.message?.stop_reason;
12316
+ if (record3.type === "assistant" && stopReason === "end_turn") {
12059
12317
  return { kind: "turn-end", awaitUserActivity: true };
12060
12318
  }
12061
- const canDerive = record2.type === "assistant" || record2.type === "user" && !record2.isMeta;
12319
+ const canDerive = record3.type === "assistant" || record3.type === "user" && !record3.isMeta;
12062
12320
  return canDerive ? ANSWER : KEEP;
12063
12321
  }
12064
12322
  return IGNORE;
12065
12323
  },
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;
12324
+ classifyAfterTurnEnd(record3) {
12325
+ if (record3.type !== "user" && record3.type !== "assistant" && record3.type !== "queue-operation" && record3.type !== "attachment") return IGNORE;
12326
+ const isRealUserTurn = record3.type === "user" && !record3.isMeta;
12069
12327
  return { kind: "keep", sawUserActivity: isRealUserTurn };
12070
12328
  }
12071
12329
  };
@@ -12084,9 +12342,9 @@ var init_tailRecords = __esm({
12084
12342
  "agent_message",
12085
12343
  "function_call_output"
12086
12344
  ],
12087
- classify(record2) {
12088
- if (record2.type === "event_msg") {
12089
- const payload = record2.payload;
12345
+ classify(record3) {
12346
+ if (record3.type === "event_msg") {
12347
+ const payload = record3.payload;
12090
12348
  switch (payload?.type) {
12091
12349
  case "task_complete":
12092
12350
  return { kind: "turn-end" };
@@ -12098,32 +12356,32 @@ var init_tailRecords = __esm({
12098
12356
  return IGNORE;
12099
12357
  }
12100
12358
  }
12101
- if (record2.type === "response_item") {
12102
- const payload = record2.payload;
12359
+ if (record3.type === "response_item") {
12360
+ const payload = record3.payload;
12103
12361
  const decides = payload?.type === "function_call" || payload?.type === "message" && (payload.role === "assistant" || payload.role === "user");
12104
12362
  return decides ? ANSWER : IGNORE;
12105
12363
  }
12106
12364
  return IGNORE;
12107
12365
  },
12108
- classifyAfterTurnEnd(record2) {
12109
- return record2.type === "event_msg" || record2.type === "response_item" ? KEEP : IGNORE;
12366
+ classifyAfterTurnEnd(record3) {
12367
+ return record3.type === "event_msg" || record3.type === "response_item" ? KEEP : IGNORE;
12110
12368
  }
12111
12369
  };
12112
12370
  copilotTail = {
12113
12371
  kind: "copilot",
12114
12372
  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;
12373
+ classify(record3) {
12374
+ if (isSubagentLifecycle(record3)) return KEEP;
12375
+ const decidable = record3.type === "abort" || record3.type === "user.message" || record3.type.startsWith("assistant.") || record3.type.startsWith("permission.") || record3.type.startsWith("session.") || record3.type.startsWith("tool.") || record3.type.startsWith("user_input.");
12376
+ if (!decidable || isSubagentNoise(record3)) return IGNORE;
12377
+ if (record3.type === "assistant.turn_end") return { kind: "turn-end" };
12378
+ if (record3.type === "session.start" || record3.type === "session.resume") return ANSWER;
12121
12379
  return { kind: "answer-if-active" };
12122
12380
  },
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";
12381
+ classifyAfterTurnEnd(record3) {
12382
+ if (isSubagentLifecycle(record3)) return KEEP;
12383
+ if (isSubagentNoise(record3)) return IGNORE;
12384
+ const decides = record3.type === "abort" || record3.type === "assistant.message" || record3.type === "user.message";
12127
12385
  return decides ? ANSWER : IGNORE;
12128
12386
  }
12129
12387
  };
@@ -12178,14 +12436,14 @@ async function readTranscriptEffort(filePath) {
12178
12436
  for (let i = lines.length - 1; i >= 0; i--) {
12179
12437
  const line = lines[i];
12180
12438
  if (!line || !line.includes("effort") && !line.includes("Effort")) continue;
12181
- let record2;
12439
+ let record3;
12182
12440
  try {
12183
- record2 = JSON.parse(line);
12441
+ record3 = JSON.parse(line);
12184
12442
  } catch {
12185
12443
  continue;
12186
12444
  }
12187
- if (typeof record2 !== "object" || record2 === null) continue;
12188
- const effort = effortFromRecord(record2);
12445
+ if (typeof record3 !== "object" || record3 === null) continue;
12446
+ const effort = effortFromRecord(record3);
12189
12447
  if (effort) return effort;
12190
12448
  }
12191
12449
  }
@@ -12221,14 +12479,14 @@ async function getSessionStatus(filePath) {
12221
12479
  const line = lines[i];
12222
12480
  if (!line) continue;
12223
12481
  if (turnEnded && !isTailCandidate(line, turnEnded)) continue;
12224
- let record2;
12482
+ let record3;
12225
12483
  try {
12226
- record2 = JSON.parse(line);
12484
+ record3 = JSON.parse(line);
12227
12485
  } catch {
12228
12486
  continue;
12229
12487
  }
12230
- if (typeof record2?.type !== "string") continue;
12231
- const match = turnEnded ? { format: turnEnded, verdict: turnEnded.classifyAfterTurnEnd(record2) } : classifyTailRecord(record2);
12488
+ if (typeof record3?.type !== "string") continue;
12489
+ const match = turnEnded ? { format: turnEnded, verdict: turnEnded.classifyAfterTurnEnd(record3) } : classifyTailRecord(record3);
12232
12490
  if (!match) continue;
12233
12491
  const { verdict } = match;
12234
12492
  switch (verdict.kind) {
@@ -12237,20 +12495,20 @@ async function getSessionStatus(filePath) {
12237
12495
  case "final":
12238
12496
  return verdict.status;
12239
12497
  case "keep":
12240
- meaningful.unshift(record2);
12498
+ meaningful.unshift(record3);
12241
12499
  if (verdict.sawUserActivity) needUserActivity = false;
12242
12500
  continue;
12243
12501
  case "answer":
12244
- meaningful.unshift(record2);
12502
+ meaningful.unshift(record3);
12245
12503
  return deriveSessionStatus(meaningful);
12246
12504
  case "answer-if-active": {
12247
- meaningful.unshift(record2);
12505
+ meaningful.unshift(record3);
12248
12506
  const status = deriveSessionStatus(meaningful);
12249
12507
  if (status.status !== "idle") return status;
12250
12508
  continue;
12251
12509
  }
12252
12510
  case "turn-end":
12253
- meaningful.unshift(record2);
12511
+ meaningful.unshift(record3);
12254
12512
  turnEnded = match.format;
12255
12513
  needUserActivity = verdict.awaitUserActivity === true;
12256
12514
  continue;
@@ -12352,7 +12610,7 @@ var init_sessionPaths = __esm({
12352
12610
  });
12353
12611
 
12354
12612
  // ../../server/helpers.ts
12355
- import { spawn } from "node:child_process";
12613
+ import { spawn as spawn2 } from "node:child_process";
12356
12614
  import { homedir as homedir4 } from "node:os";
12357
12615
  import { randomUUID as randomUUID2 } from "node:crypto";
12358
12616
  import { createInterface } from "node:readline";
@@ -12525,7 +12783,7 @@ async function fetchClaudeModels() {
12525
12783
  }
12526
12784
  var init_claudeModels = __esm({
12527
12785
  "../../server/agents/claudeModels.ts"() {
12528
- init_sdk_session();
12786
+ init_claudeExecutable();
12529
12787
  init_modelCatalog();
12530
12788
  init_timeout();
12531
12789
  init_model_names();
@@ -12634,7 +12892,7 @@ function startOneShot(req) {
12634
12892
  ]);
12635
12893
  const cleanEnv = { ...process.env };
12636
12894
  delete cleanEnv.CLAUDECODE;
12637
- const child = spawn(cli.command, cli.args, {
12895
+ const child = spawn2(cli.command, cli.args, {
12638
12896
  cwd: req.cwd,
12639
12897
  env: cleanEnv,
12640
12898
  stdio: ["ignore", "pipe", "pipe"],
@@ -12795,6 +13053,7 @@ var init_claudeRuntime = __esm({
12795
13053
  "../../server/agents/claudeRuntime.ts"() {
12796
13054
  init_agent_descriptors();
12797
13055
  init_helpers();
13056
+ init_claudeExecutable();
12798
13057
  init_claudeModels();
12799
13058
  init_spawnError();
12800
13059
  init_binaryResolver();
@@ -12941,7 +13200,7 @@ var init_package = __esm({
12941
13200
  package_default = {
12942
13201
  name: "cogpit",
12943
13202
  private: true,
12944
- version: "2.1.3",
13203
+ version: "2.2.1",
12945
13204
  description: "Control center for Claude Code, OpenAI Codex, and GitHub Copilot CLI sessions",
12946
13205
  license: "MIT",
12947
13206
  author: {
@@ -13051,11 +13310,11 @@ var init_package = __esm({
13051
13310
  overrides: {
13052
13311
  "@babel/core": "7.29.7",
13053
13312
  "@hono/node-server": "1.19.15",
13054
- "@xmldom/xmldom": "0.8.13",
13313
+ "@xmldom/xmldom": "0.8.15",
13055
13314
  "app-builder-lib": "26.15.3",
13056
13315
  "body-parser": "2.3.0",
13057
13316
  "builder-util-runtime": "9.7.0",
13058
- "fast-uri": "3.1.5",
13317
+ "fast-uri": "4.1.4",
13059
13318
  flatted: "3.4.2",
13060
13319
  "form-data": "4.0.6",
13061
13320
  hono: "4.13.1",
@@ -13064,7 +13323,7 @@ var init_package = __esm({
13064
13323
  lodash: "4.18.1",
13065
13324
  nanoid: "3.3.18",
13066
13325
  postcss: "8.5.26",
13067
- qs: "6.15.3",
13326
+ qs: "6.16.0",
13068
13327
  tar: "7.5.21",
13069
13328
  tmp: "0.2.7",
13070
13329
  undici: "7.29.0"
@@ -13180,101 +13439,6 @@ var init_codexStreamAdapter = __esm({
13180
13439
  }
13181
13440
  });
13182
13441
 
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;
13275
- }
13276
- });
13277
-
13278
13442
  // ../../server/lib/codexVersion.ts
13279
13443
  function parseUserAgentVersion(userAgent) {
13280
13444
  if (typeof userAgent !== "string") return null;
@@ -14505,7 +14669,7 @@ async function startLegacy(req, knownPaths) {
14505
14669
  ...args.turnArgs,
14506
14670
  ...args.promptArgs
14507
14671
  ]);
14508
- const child = spawn(cli.command, cli.args, {
14672
+ const child = spawn2(cli.command, cli.args, {
14509
14673
  cwd: req.cwd,
14510
14674
  env: process.env,
14511
14675
  stdio: ["ignore", "pipe", "pipe"],
@@ -14597,7 +14761,7 @@ async function sendLegacy(sessionId, req) {
14597
14761
  sessionId,
14598
14762
  ...args.promptArgs
14599
14763
  ]);
14600
- const child = spawn(cli.command, cli.args, {
14764
+ const child = spawn2(cli.command, cli.args, {
14601
14765
  cwd: req.cwd,
14602
14766
  env: process.env,
14603
14767
  stdio: ["ignore", "pipe", "pipe"],
@@ -16040,17 +16204,17 @@ function parseJsonRecord(line) {
16040
16204
  }
16041
16205
  }
16042
16206
  function parseClaudeUsageLine(line) {
16043
- const record2 = parseJsonRecord(line);
16044
- if (!record2 || record2.type !== "assistant") return null;
16045
- const message = asRecord3(record2.message);
16207
+ const record3 = parseJsonRecord(line);
16208
+ if (!record3 || record3.type !== "assistant") return null;
16209
+ const message = asRecord3(record3.message);
16046
16210
  const usage = message ? asRecord3(message.usage) : null;
16047
16211
  if (!message || !usage) return null;
16048
- const timestampMs = parseTimestampMs(record2.timestamp);
16212
+ const timestampMs = parseTimestampMs(record3.timestamp);
16049
16213
  if (timestampMs === null) return null;
16050
16214
  const model = typeof message.model === "string" ? message.model : "";
16051
16215
  if (model.length === 0) return null;
16052
16216
  const messageId = typeof message.id === "string" ? message.id : null;
16053
- const requestId = typeof record2.requestId === "string" ? record2.requestId : null;
16217
+ const requestId = typeof record3.requestId === "string" ? record3.requestId : null;
16054
16218
  const dedupeKey = messageId === null && requestId === null ? null : `${messageId ?? ""}:${requestId ?? ""}`;
16055
16219
  const cacheCreationTokens = int(usage.cache_creation_input_tokens);
16056
16220
  const byTtl = asRecord3(usage.cache_creation);
@@ -16069,12 +16233,12 @@ function parseClaudeUsageLine(line) {
16069
16233
  reasoningTokens: 0
16070
16234
  };
16071
16235
  if (totalUsageCostTokens(totals) === 0) return null;
16072
- const cost = record2.costUSD;
16236
+ const cost = record3.costUSD;
16073
16237
  return {
16074
16238
  provider: "claude",
16075
16239
  timestampMs,
16076
16240
  model,
16077
- sessionId: typeof record2.sessionId === "string" ? record2.sessionId : "",
16241
+ sessionId: typeof record3.sessionId === "string" ? record3.sessionId : "",
16078
16242
  totals,
16079
16243
  reportedCostUsd: typeof cost === "number" && Number.isFinite(cost) ? cost : null,
16080
16244
  dedupeKey
@@ -16096,30 +16260,30 @@ function isForkedSessionMeta(payload) {
16096
16260
  return typeof spawn5?.parent_thread_id === "string";
16097
16261
  }
16098
16262
  function parseCodexUsageLine(line, state) {
16099
- const record2 = parseJsonRecord(line);
16100
- if (!record2) return null;
16101
- const payload = asRecord3(record2.payload);
16263
+ const record3 = parseJsonRecord(line);
16264
+ if (!record3) return null;
16265
+ const payload = asRecord3(record3.payload);
16102
16266
  if (!payload) return null;
16103
- if (record2.type === "session_meta") {
16267
+ if (record3.type === "session_meta") {
16104
16268
  if (state.sawSessionMeta) return null;
16105
16269
  state.sawSessionMeta = true;
16106
16270
  const id = payload.id ?? payload.session_id;
16107
16271
  if (typeof id === "string") state.sessionId = id;
16108
- const metaTimestampMs = parseTimestampMs(record2.timestamp);
16272
+ const metaTimestampMs = parseTimestampMs(record3.timestamp);
16109
16273
  if (metaTimestampMs !== null && isForkedSessionMeta(payload)) {
16110
16274
  state.suppressingForkCopies = true;
16111
16275
  state.forkCopyAnchorMs = metaTimestampMs;
16112
16276
  }
16113
16277
  return null;
16114
16278
  }
16115
- if (record2.type === "turn_context") {
16279
+ if (record3.type === "turn_context") {
16116
16280
  if (typeof payload.model === "string") state.model = payload.model;
16117
16281
  return null;
16118
16282
  }
16119
16283
  if (payload.type !== "token_count") return null;
16120
16284
  const last = asRecord3(asRecord3(payload.info)?.last_token_usage);
16121
16285
  if (!last) return null;
16122
- const timestampMs = parseTimestampMs(record2.timestamp);
16286
+ const timestampMs = parseTimestampMs(record3.timestamp);
16123
16287
  if (timestampMs === null) return null;
16124
16288
  if (state.model.length === 0) return null;
16125
16289
  const signature = JSON.stringify(last);
@@ -16218,17 +16382,17 @@ function parseCopilotUsageMetrics(value, state, timestampMs) {
16218
16382
  return records;
16219
16383
  }
16220
16384
  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);
16385
+ const record3 = parseJsonRecord(line);
16386
+ if (!record3 || typeof record3.agentId === "string" && record3.agentId.length > 0) return [];
16387
+ const data = asRecord3(record3.data);
16224
16388
  if (!data) return [];
16225
- if (record2.type === "session.start") {
16389
+ if (record3.type === "session.start") {
16226
16390
  const sessionId = data.sessionId;
16227
16391
  if (typeof sessionId === "string" && sessionId.length > 0) state.sessionId = sessionId;
16228
16392
  return [];
16229
16393
  }
16230
- if (record2.type !== "session.shutdown") return [];
16231
- const timestampMs = parseTimestampMs(record2.timestamp);
16394
+ if (record3.type !== "session.shutdown") return [];
16395
+ const timestampMs = parseTimestampMs(record3.timestamp);
16232
16396
  return timestampMs === null ? [] : parseCopilotUsageMetrics(data, state, timestampMs);
16233
16397
  }
16234
16398
  function createUsageScanner(provider, filePath) {
@@ -16245,8 +16409,8 @@ var init_usageScanners = __esm({
16245
16409
  // object, so a line is either self-contained or of no interest.
16246
16410
  wantsLine: (line) => line.includes('"usage"'),
16247
16411
  accept: (line) => {
16248
- const record2 = parseClaudeUsageLine(line);
16249
- return record2 === null ? [] : [record2];
16412
+ const record3 = parseClaudeUsageLine(line);
16413
+ return record3 === null ? [] : [record3];
16250
16414
  }
16251
16415
  }),
16252
16416
  codex: () => {
@@ -16257,8 +16421,8 @@ var init_usageScanners = __esm({
16257
16421
  // at all but still have to reach the reducer.
16258
16422
  wantsLine: (line) => line.includes('"token_count"') || line.includes('"turn_context"') || line.includes('"session_meta"'),
16259
16423
  accept: (line) => {
16260
- const record2 = parseCodexUsageLine(line, state);
16261
- return record2 === null ? [] : [record2];
16424
+ const record3 = parseCodexUsageLine(line, state);
16425
+ return record3 === null ? [] : [record3];
16262
16426
  }
16263
16427
  };
16264
16428
  },
@@ -17140,11 +17304,11 @@ function registerRunningProcessesRoute(use) {
17140
17304
  if (url.pathname.split("/").filter(Boolean).length > 0) return next();
17141
17305
  const isWindows2 = process.platform === "win32";
17142
17306
  const nameFilter = allDescriptors().map(windowsProcessNameFilter).join(" or ");
17143
- const child = isWindows2 ? spawn("powershell", [
17307
+ const child = isWindows2 ? spawn2("powershell", [
17144
17308
  "-NoProfile",
17145
17309
  "-Command",
17146
17310
  `Get-CimInstance Win32_Process -Filter "${nameFilter}" | Select-Object ProcessId, WorkingSetSize, CommandLine | ConvertTo-Json -Compress`
17147
- ]) : spawn("ps", ["aux"]);
17311
+ ]) : spawn2("ps", ["aux"]);
17148
17312
  let stdout = "";
17149
17313
  let responded = false;
17150
17314
  child.stdout?.on("data", (data) => {
@@ -17507,12 +17671,12 @@ function registerBranchSessionRoute(use) {
17507
17671
  }
17508
17672
  }
17509
17673
  const newSessionId = randomUUID2();
17510
- const { record: record2, originalId } = format.brandBranch(
17674
+ const { record: record3, originalId } = format.brandBranch(
17511
17675
  JSON.parse(lines[0]),
17512
17676
  newSessionId,
17513
17677
  turnIndex ?? null
17514
17678
  );
17515
- lines[0] = JSON.stringify(record2);
17679
+ lines[0] = JSON.stringify(record3);
17516
17680
  const target = storeForDirName(dirName).transcriptPath(dirName, newSessionId);
17517
17681
  if (!target) {
17518
17682
  res.statusCode = 500;
@@ -18055,11 +18219,11 @@ import {
18055
18219
  dirname as dirname5,
18056
18220
  isAbsolute as isAbsolute3,
18057
18221
  join as join13,
18058
- posix as posix2,
18222
+ posix as posix3,
18059
18223
  relative as relative4,
18060
18224
  resolve as resolve9,
18061
18225
  sep as sep5,
18062
- win32 as win322
18226
+ win32 as win323
18063
18227
  } from "node:path";
18064
18228
  function configuredAgentHomes() {
18065
18229
  return new Set(AGENT_KINDS.map((kind) => agentHomeDir(kind)));
@@ -18168,7 +18332,7 @@ async function resolveConfigBrowserPath(filePath, options = {}) {
18168
18332
  function isSafeConfigName(name) {
18169
18333
  if (!name || name === "." || name === ".." || name.includes("\0")) return false;
18170
18334
  if (name.includes("/") || name.includes("\\")) return false;
18171
- if (isAbsolute3(name) || posix2.parse(name).root || win322.parse(name).root) return false;
18335
+ if (isAbsolute3(name) || posix3.parse(name).root || win323.parse(name).root) return false;
18172
18336
  return true;
18173
18337
  }
18174
18338
  function isUnderDir(parentDir, dirName) {
@@ -19411,7 +19575,8 @@ function registerConfigRoutes(use) {
19411
19575
  networkPassword: config.networkPassword ? "set" : null,
19412
19576
  terminalApp: config.terminalApp || null,
19413
19577
  editorApp: config.editorApp || null,
19414
- useBuiltInEditor: config.useBuiltInEditor || false
19578
+ useBuiltInEditor: config.useBuiltInEditor || false,
19579
+ agentExecutable: config.agentExecutable ?? DEFAULT_EXECUTABLE_CHOICE
19415
19580
  } : null));
19416
19581
  return;
19417
19582
  }
@@ -19474,7 +19639,8 @@ function registerConfigRoutes(use) {
19474
19639
  networkPassword: finalPassword,
19475
19640
  terminalApp: parsed.terminalApp || void 0,
19476
19641
  editorApp: parsed.editorApp || void 0,
19477
- useBuiltInEditor: !!parsed.useBuiltInEditor
19642
+ useBuiltInEditor: !!parsed.useBuiltInEditor,
19643
+ agentExecutable: parseExecutableChoice(parsed.agentExecutable)
19478
19644
  });
19479
19645
  refreshDirs();
19480
19646
  if (currentConfig && resolve11(resolvedClaudeDir) !== resolve11(currentConfig.claudeDir)) {
@@ -19509,12 +19675,13 @@ var init_config2 = __esm({
19509
19675
  init_users();
19510
19676
  init_config();
19511
19677
  init_agent_descriptors();
19678
+ init_agentExecutable();
19512
19679
  init_sessionPersistence();
19513
19680
  }
19514
19681
  });
19515
19682
 
19516
19683
  // ../../server/routes/hello.ts
19517
- import { readFileSync } from "node:fs";
19684
+ import { readFileSync as readFileSync2 } from "node:fs";
19518
19685
  import { fileURLToPath as fileURLToPath2 } from "node:url";
19519
19686
  import { hostname } from "node:os";
19520
19687
  import { join as join18 } from "node:path";
@@ -19563,7 +19730,7 @@ var init_hello = __esm({
19563
19730
  join18(__dirname2, "../package.json")
19564
19731
  ]) {
19565
19732
  try {
19566
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
19733
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
19567
19734
  if (typeof pkg.version === "string") return pkg.version;
19568
19735
  } catch {
19569
19736
  }
@@ -20794,7 +20961,7 @@ function registerFileRoutes(use) {
20794
20961
  try {
20795
20962
  let spawnLines = function(args, cwd) {
20796
20963
  return new Promise((resolve21) => {
20797
- const proc = spawn("git", args, { cwd });
20964
+ const proc = spawn2("git", args, { cwd });
20798
20965
  let out = "";
20799
20966
  proc.stdout.on("data", (d) => out += d.toString());
20800
20967
  proc.on("close", (code) => {
@@ -20805,7 +20972,7 @@ function registerFileRoutes(use) {
20805
20972
  });
20806
20973
  }, spawnOutput = function(args, cwd) {
20807
20974
  return new Promise((resolve21) => {
20808
- const proc = spawn("git", args, { cwd });
20975
+ const proc = spawn2("git", args, { cwd });
20809
20976
  let out = "";
20810
20977
  proc.stdout.on("data", (d) => out += d.toString());
20811
20978
  proc.on("close", () => resolve21(out.trim()));
@@ -20834,7 +21001,7 @@ function registerFileRoutes(use) {
20834
21001
  }
20835
21002
  }
20836
21003
  return new Promise((resolve21) => {
20837
- const proc = spawn("git", ["rev-parse", "--show-toplevel"], { cwd });
21004
+ const proc = spawn2("git", ["rev-parse", "--show-toplevel"], { cwd });
20838
21005
  let out = "";
20839
21006
  proc.stdout.on("data", (d) => out += d.toString());
20840
21007
  proc.on("close", (code) => {
@@ -21079,11 +21246,11 @@ function parseGitStatus(output) {
21079
21246
  const branch = parseBranchHeader(header);
21080
21247
  const files = [];
21081
21248
  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);
21249
+ const record3 = records[index];
21250
+ if (!record3 || record3.length < 3) continue;
21251
+ const indexStatus = record3[0];
21252
+ const workTreeStatus = record3[1];
21253
+ const path = record3.slice(3);
21087
21254
  const renamedOrCopied = /[RC]/.test(`${indexStatus}${workTreeStatus}`);
21088
21255
  const originalPath = renamedOrCopied ? records[index += 1] || void 0 : void 0;
21089
21256
  files.push({ path, originalPath, indexStatus, workTreeStatus });
@@ -21138,6 +21305,272 @@ var init_git_status = __esm({
21138
21305
  }
21139
21306
  });
21140
21307
 
21308
+ // ../../server/routes/github-actions.ts
21309
+ import { execFile as execFileCallback2 } from "node:child_process";
21310
+ import { promisify as promisify2 } from "node:util";
21311
+ function record2(value) {
21312
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
21313
+ }
21314
+ function stringValue(value, fallback = "") {
21315
+ return typeof value === "string" ? value : fallback;
21316
+ }
21317
+ function numberValue(value) {
21318
+ return typeof value === "number" && Number.isSafeInteger(value) ? value : null;
21319
+ }
21320
+ function nullableDate(value) {
21321
+ return typeof value === "string" && value ? value : null;
21322
+ }
21323
+ function workflowStatus(value) {
21324
+ return typeof value === "string" && RUN_STATUSES.has(value) ? value : "pending";
21325
+ }
21326
+ function workflowConclusion(value) {
21327
+ return typeof value === "string" && RUN_CONCLUSIONS.has(value) ? value : null;
21328
+ }
21329
+ function parseGitHubRemote(remoteUrl) {
21330
+ const trimmed = remoteUrl.trim();
21331
+ let host = "";
21332
+ let pathname = "";
21333
+ try {
21334
+ const parsed = new URL(trimmed);
21335
+ host = parsed.hostname;
21336
+ pathname = parsed.pathname;
21337
+ } catch {
21338
+ const scp = trimmed.match(/^(?:[^@\s]+@)?([^:/\s]+):(.+)$/);
21339
+ if (!scp) return null;
21340
+ host = scp[1];
21341
+ pathname = scp[2];
21342
+ }
21343
+ const parts = pathname.replace(/^\/+/, "").replace(/\.git$/, "").split("/");
21344
+ 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])) {
21345
+ return null;
21346
+ }
21347
+ return { host: host.toLowerCase(), owner: parts[0], name: parts[1] };
21348
+ }
21349
+ function parseRun(value) {
21350
+ const source = record2(value);
21351
+ if (!source) return null;
21352
+ const id = numberValue(source.id);
21353
+ const url = stringValue(source.html_url);
21354
+ if (id === null || !url.startsWith("https://")) return null;
21355
+ const actor = record2(source.actor);
21356
+ return {
21357
+ id,
21358
+ name: stringValue(source.name, "Workflow"),
21359
+ displayTitle: stringValue(source.display_title, stringValue(source.name, "Workflow run")),
21360
+ status: workflowStatus(source.status),
21361
+ conclusion: workflowConclusion(source.conclusion),
21362
+ url,
21363
+ runNumber: numberValue(source.run_number) ?? 0,
21364
+ event: stringValue(source.event, "workflow"),
21365
+ branch: stringValue(source.head_branch),
21366
+ commitSha: stringValue(source.head_sha),
21367
+ createdAt: stringValue(source.created_at),
21368
+ updatedAt: stringValue(source.updated_at),
21369
+ actor: stringValue(actor?.login)
21370
+ };
21371
+ }
21372
+ function parseStep(value) {
21373
+ const source = record2(value);
21374
+ if (!source) return null;
21375
+ const number = numberValue(source.number);
21376
+ if (number === null) return null;
21377
+ return {
21378
+ number,
21379
+ name: stringValue(source.name, `Step ${number}`),
21380
+ status: workflowStatus(source.status),
21381
+ conclusion: workflowConclusion(source.conclusion),
21382
+ startedAt: nullableDate(source.started_at),
21383
+ completedAt: nullableDate(source.completed_at)
21384
+ };
21385
+ }
21386
+ function parseJob(value) {
21387
+ const source = record2(value);
21388
+ if (!source) return null;
21389
+ const id = numberValue(source.id);
21390
+ const url = stringValue(source.html_url);
21391
+ if (id === null || !url.startsWith("https://")) return null;
21392
+ return {
21393
+ id,
21394
+ name: stringValue(source.name, "Job"),
21395
+ status: workflowStatus(source.status),
21396
+ conclusion: workflowConclusion(source.conclusion),
21397
+ url,
21398
+ startedAt: nullableDate(source.started_at),
21399
+ completedAt: nullableDate(source.completed_at),
21400
+ steps: Array.isArray(source.steps) ? source.steps.map(parseStep).filter((step) => step !== null) : []
21401
+ };
21402
+ }
21403
+ function parseRunsResponse(value) {
21404
+ const source = record2(value);
21405
+ if (!source || !Array.isArray(source.workflow_runs)) {
21406
+ throw new GitHubActionsRouteError(502, "invalid_response", "GitHub returned an invalid workflow response");
21407
+ }
21408
+ return source.workflow_runs.map(parseRun).filter((run2) => run2 !== null);
21409
+ }
21410
+ function parseJobsResponse(value) {
21411
+ const source = record2(value);
21412
+ if (!source || !Array.isArray(source.jobs)) {
21413
+ throw new GitHubActionsRouteError(502, "invalid_response", "GitHub returned an invalid jobs response");
21414
+ }
21415
+ return source.jobs.map(parseJob).filter((job) => job !== null);
21416
+ }
21417
+ async function runGitHubApi(repository, endpoint) {
21418
+ try {
21419
+ const result = await execFile3("gh", [
21420
+ "api",
21421
+ endpoint,
21422
+ "--hostname",
21423
+ repository.host,
21424
+ "-H",
21425
+ "Accept: application/vnd.github+json"
21426
+ ], {
21427
+ encoding: "utf-8",
21428
+ env: { ...process.env, GH_PAGER: "cat", NO_COLOR: "1" },
21429
+ maxBuffer: 8 * 1024 * 1024,
21430
+ timeout: 2e4,
21431
+ windowsHide: true
21432
+ });
21433
+ return JSON.parse(result.stdout);
21434
+ } catch (error) {
21435
+ const failure = error;
21436
+ if (failure.code === "ENOENT") {
21437
+ throw new GitHubActionsRouteError(503, "gh_missing", "Install the GitHub CLI to view workflow runs");
21438
+ }
21439
+ const detail = `${failure.message ?? ""}
21440
+ ${failure.stderr ?? ""}`;
21441
+ if (/auth login|not logged|authentication|oauth token/i.test(detail)) {
21442
+ throw new GitHubActionsRouteError(503, "gh_auth_required", "Sign in with `gh auth login` to view workflow runs");
21443
+ }
21444
+ throw new GitHubActionsRouteError(502, "github_api_failed", "GitHub workflow data is unavailable");
21445
+ }
21446
+ }
21447
+ async function resolveRepository(cwd, dependencies) {
21448
+ const project = await dependencies.resolveProject(cwd);
21449
+ if (!project.ok) throw new GitHubActionsRouteError(project.status, "no_git_repository", project.error);
21450
+ if (!project.root) {
21451
+ throw new GitHubActionsRouteError(400, "no_git_repository", "This project is not a Git repository");
21452
+ }
21453
+ let remoteUrl = "";
21454
+ try {
21455
+ remoteUrl = (await dependencies.git(project.root, ["remote", "get-url", "origin"])).stdout;
21456
+ } catch {
21457
+ throw new GitHubActionsRouteError(400, "no_github_remote", "This repository has no origin remote");
21458
+ }
21459
+ const repository = parseGitHubRemote(remoteUrl);
21460
+ if (!repository) {
21461
+ throw new GitHubActionsRouteError(400, "no_github_remote", "The origin remote is not a supported GitHub repository");
21462
+ }
21463
+ const branchResult = await dependencies.git(project.root, ["branch", "--show-current"]);
21464
+ return {
21465
+ repository,
21466
+ branch: branchResult.stdout.trim() || null
21467
+ };
21468
+ }
21469
+ function repositoryName(repository) {
21470
+ return `${repository.owner}/${repository.name}`;
21471
+ }
21472
+ function repositoryUrl(repository) {
21473
+ return `https://${repository.host}/${repository.owner}/${repository.name}`;
21474
+ }
21475
+ function sendRouteError2(res, error) {
21476
+ if (error instanceof GitHubActionsRouteError) {
21477
+ sendJson(res, error.status, { error: error.message, code: error.code });
21478
+ return;
21479
+ }
21480
+ sendJson(res, 500, { error: "Unable to load GitHub Actions", code: "github_api_failed" });
21481
+ }
21482
+ function registerGitHubActionsRoutes(use, dependencies = defaultDependencies) {
21483
+ use("/api/github-actions", async (req, res, next) => {
21484
+ if (req.method !== "GET") return next();
21485
+ const url = new URL(req.url || "", "http://localhost");
21486
+ if (url.pathname !== "/" && url.pathname !== "") return next();
21487
+ const cwd = url.searchParams.get("cwd") ?? "";
21488
+ const requestedLimit = Number(url.searchParams.get("limit") ?? DEFAULT_RUNS);
21489
+ const limit = Number.isInteger(requestedLimit) ? Math.min(MAX_RUNS, Math.max(1, requestedLimit)) : DEFAULT_RUNS;
21490
+ try {
21491
+ const { repository, branch } = await resolveRepository(cwd, dependencies);
21492
+ const endpoint = `repos/${repository.owner}/${repository.name}/actions/runs?per_page=${limit}`;
21493
+ const runs = parseRunsResponse(await dependencies.githubApi(repository, endpoint));
21494
+ const response = {
21495
+ repository: repositoryName(repository),
21496
+ repositoryUrl: repositoryUrl(repository),
21497
+ branch,
21498
+ runs
21499
+ };
21500
+ sendJson(res, 200, response);
21501
+ } catch (error) {
21502
+ sendRouteError2(res, error);
21503
+ }
21504
+ });
21505
+ use("/api/github-actions/jobs", async (req, res, next) => {
21506
+ if (req.method !== "GET") return next();
21507
+ const url = new URL(req.url || "", "http://localhost");
21508
+ if (url.pathname !== "/" && url.pathname !== "") return next();
21509
+ const cwd = url.searchParams.get("cwd") ?? "";
21510
+ const runIdText = url.searchParams.get("runId") ?? "";
21511
+ if (!/^\d+$/.test(runIdText)) {
21512
+ return sendJson(res, 400, { error: "runId must be a positive integer", code: "github_api_failed" });
21513
+ }
21514
+ try {
21515
+ const { repository } = await resolveRepository(cwd, dependencies);
21516
+ const runId = Number(runIdText);
21517
+ const endpoint = `repos/${repository.owner}/${repository.name}/actions/runs/${runId}/jobs?filter=latest&per_page=100`;
21518
+ const jobs = parseJobsResponse(await dependencies.githubApi(repository, endpoint));
21519
+ const response = {
21520
+ repository: repositoryName(repository),
21521
+ runId,
21522
+ jobs
21523
+ };
21524
+ sendJson(res, 200, response);
21525
+ } catch (error) {
21526
+ sendRouteError2(res, error);
21527
+ }
21528
+ });
21529
+ }
21530
+ var execFile3, MAX_RUNS, DEFAULT_RUNS, GITHUB_NAME, GITHUB_HOST, RUN_STATUSES, RUN_CONCLUSIONS, GitHubActionsRouteError, defaultDependencies;
21531
+ var init_github_actions = __esm({
21532
+ "../../server/routes/github-actions.ts"() {
21533
+ init_http();
21534
+ init_gitProject();
21535
+ execFile3 = promisify2(execFileCallback2);
21536
+ MAX_RUNS = 30;
21537
+ DEFAULT_RUNS = 20;
21538
+ GITHUB_NAME = /^[A-Za-z0-9_.-]+$/;
21539
+ GITHUB_HOST = /^[A-Za-z0-9.-]+$/;
21540
+ RUN_STATUSES = /* @__PURE__ */ new Set([
21541
+ "completed",
21542
+ "in_progress",
21543
+ "pending",
21544
+ "queued",
21545
+ "requested",
21546
+ "waiting"
21547
+ ]);
21548
+ RUN_CONCLUSIONS = /* @__PURE__ */ new Set([
21549
+ "action_required",
21550
+ "cancelled",
21551
+ "failure",
21552
+ "neutral",
21553
+ "skipped",
21554
+ "stale",
21555
+ "startup_failure",
21556
+ "success",
21557
+ "timed_out"
21558
+ ]);
21559
+ GitHubActionsRouteError = class extends Error {
21560
+ constructor(status, code, message) {
21561
+ super(message);
21562
+ this.status = status;
21563
+ this.code = code;
21564
+ }
21565
+ };
21566
+ defaultDependencies = {
21567
+ resolveProject: resolveGitProject,
21568
+ git: runGit,
21569
+ githubApi: runGitHubApi
21570
+ };
21571
+ }
21572
+ });
21573
+
21141
21574
  // ../../server/lib/projectIcon.ts
21142
21575
  import { realpath as realpath8, stat as stat13 } from "node:fs/promises";
21143
21576
  import { basename as basename9, extname, join as join20, relative as relative8, sep as sep10 } from "node:path";
@@ -21321,7 +21754,7 @@ var init_local_file = __esm({
21321
21754
  });
21322
21755
 
21323
21756
  // ../../server/routes/mcp.ts
21324
- import { execFile as execFile3 } from "node:child_process";
21757
+ import { execFile as execFile4 } from "node:child_process";
21325
21758
  import { isAbsolute as isAbsolute9, join as join21 } from "node:path";
21326
21759
  import { readFile as readFile15 } from "node:fs/promises";
21327
21760
  import { homedir as homedir7 } from "node:os";
@@ -21402,7 +21835,7 @@ async function getMcpServers(cwd) {
21402
21835
  const env = { ...process.env };
21403
21836
  delete env.CLAUDECODE;
21404
21837
  const cli = resolveAgentCommand("claude", ["mcp", "list"]);
21405
- execFile3(cli.command, cli.args, { cwd, env, timeout: 15e3, ...cli.spawnOptions }, (err, stdout) => {
21838
+ execFile4(cli.command, cli.args, { cwd, env, timeout: 15e3, ...cli.spawnOptions }, (err, stdout) => {
21406
21839
  if (err) {
21407
21840
  resolve21({ servers: cached?.servers ?? [], configs });
21408
21841
  return;
@@ -22201,8 +22634,8 @@ function copilotText(value) {
22201
22634
  if (!Array.isArray(value)) return "";
22202
22635
  return value.flatMap((part) => {
22203
22636
  if (typeof part === "string") return part ? [part] : [];
22204
- const record2 = asRecord5(part);
22205
- const text = str(record2.text) || str(record2.content);
22637
+ const record3 = asRecord5(part);
22638
+ const text = str(record3.text) || str(record3.content);
22206
22639
  return text ? [text] : [];
22207
22640
  }).join("\n");
22208
22641
  }
@@ -22905,7 +23338,7 @@ var init_notifications = __esm({
22905
23338
  });
22906
23339
 
22907
23340
  // ../../server/lib/systemProcesses.ts
22908
- import { execFile as execFile4 } from "node:child_process";
23341
+ import { execFile as execFile5 } from "node:child_process";
22909
23342
  function parseEtimeSeconds(etime) {
22910
23343
  const match = /^(?:(\d+)-)?(?:(\d+):)?(\d+):(\d+)$/.exec(etime.trim());
22911
23344
  if (!match) return 0;
@@ -23027,7 +23460,7 @@ function classifyProcesses(rows, selfPid) {
23027
23460
  }
23028
23461
  function listSystemProcesses() {
23029
23462
  return new Promise((resolve21, reject) => {
23030
- execFile4(
23463
+ execFile5(
23031
23464
  "ps",
23032
23465
  ["-axo", "pid=,ppid=,pcpu=,rss=,etime=,args="],
23033
23466
  { maxBuffer: 8 * 1024 * 1024 },
@@ -23065,7 +23498,7 @@ var init_systemProcesses = __esm({
23065
23498
  });
23066
23499
 
23067
23500
  // ../../server/lib/desktopNotify.ts
23068
- import { execFile as execFile5 } from "node:child_process";
23501
+ import { execFile as execFile6 } from "node:child_process";
23069
23502
  function parentMessagePort() {
23070
23503
  const { parentPort } = process;
23071
23504
  return parentPort && typeof parentPort.postMessage === "function" ? parentPort : null;
@@ -23078,7 +23511,7 @@ function showNotification(title, body, nav, historyId) {
23078
23511
  return;
23079
23512
  }
23080
23513
  if (process.platform === "darwin") {
23081
- execFile5(
23514
+ execFile6(
23082
23515
  "osascript",
23083
23516
  ["-e", `display notification "${escapeAppleScript(body)}" with title "${escapeAppleScript(title)}"`],
23084
23517
  // This is the standalone server's only desktop channel, so a silent
@@ -23119,7 +23552,7 @@ var init_notifications2 = __esm({
23119
23552
  });
23120
23553
 
23121
23554
  // ../../server/lib/pushConfig.ts
23122
- import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
23555
+ import { readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
23123
23556
  import { homedir as homedir9 } from "node:os";
23124
23557
  import { join as join23 } from "node:path";
23125
23558
  function warnOnce(message) {
@@ -23132,7 +23565,7 @@ function asString(value) {
23132
23565
  }
23133
23566
  function fileMtime(path) {
23134
23567
  try {
23135
- return statSync2(path).mtimeMs;
23568
+ return statSync3(path).mtimeMs;
23136
23569
  } catch {
23137
23570
  return null;
23138
23571
  }
@@ -23147,8 +23580,8 @@ function warnIfExposed(path, mode) {
23147
23580
  function readConfigFile(path) {
23148
23581
  let raw;
23149
23582
  try {
23150
- warnIfExposed(path, statSync2(path).mode);
23151
- raw = readFileSync2(path, "utf8");
23583
+ warnIfExposed(path, statSync3(path).mode);
23584
+ raw = readFileSync3(path, "utf8");
23152
23585
  } catch (err) {
23153
23586
  const code = err.code;
23154
23587
  if (code !== "ENOENT") warnOnce(`Could not read ${path}: ${code ?? String(err)}`);
@@ -23951,7 +24384,7 @@ var init_backgroundAgents = __esm({
23951
24384
  // ../../server/routes/ports/listeningProcesses.ts
23952
24385
  function runCapture(command, args) {
23953
24386
  return new Promise((resolve21, reject) => {
23954
- const child = spawn(command, args);
24387
+ const child = spawn2(command, args);
23955
24388
  let stdout = "";
23956
24389
  child.stdout?.on("data", (data) => {
23957
24390
  stdout += data.toString();
@@ -24238,13 +24671,13 @@ var init_project_files_ranking = __esm({
24238
24671
  });
24239
24672
 
24240
24673
  // ../../server/routes/project-files.ts
24241
- import { execFile as execFileCallback2 } from "node:child_process";
24674
+ import { execFile as execFileCallback3 } from "node:child_process";
24242
24675
  import { readdir as readdir11, realpath as realpath10, stat as stat16 } from "node:fs/promises";
24243
24676
  import { isAbsolute as isAbsolute11, relative as relative9, resolve as resolve17, sep as sep11 } from "node:path";
24244
- import { promisify as promisify2 } from "node:util";
24677
+ import { promisify as promisify3 } from "node:util";
24245
24678
  async function listGitProjectFiles(root) {
24246
24679
  try {
24247
- const result = await execFile6(
24680
+ const result = await execFile7(
24248
24681
  "git",
24249
24682
  ["ls-files", "--cached", "--others", "--exclude-standard", "-z", "--", "."],
24250
24683
  {
@@ -24320,7 +24753,7 @@ function registerProjectFileRoutes(use) {
24320
24753
  }
24321
24754
  });
24322
24755
  }
24323
- var MAX_FILES, CACHE_TTL_MS3, IGNORED_DIRECTORIES, fileCache, execFile6;
24756
+ var MAX_FILES, CACHE_TTL_MS3, IGNORED_DIRECTORIES, fileCache, execFile7;
24324
24757
  var init_project_files = __esm({
24325
24758
  "../../server/routes/project-files.ts"() {
24326
24759
  init_http();
@@ -24341,7 +24774,7 @@ var init_project_files = __esm({
24341
24774
  "target"
24342
24775
  ]);
24343
24776
  fileCache = /* @__PURE__ */ new Map();
24344
- execFile6 = promisify2(execFileCallback2);
24777
+ execFile7 = promisify3(execFileCallback3);
24345
24778
  }
24346
24779
  });
24347
24780
 
@@ -24604,12 +25037,12 @@ function createPullRequestScanner() {
24604
25037
  const command = findCreateCommand(input);
24605
25038
  if (command) openCreates.set(id, { command, timestamp });
24606
25039
  }
24607
- function recordPrLink(record2, timestamp) {
24608
- const url = record2.prUrl;
24609
- const number = record2.prNumber;
25040
+ function recordPrLink(record3, timestamp) {
25041
+ const url = record3.prUrl;
25042
+ const number = record3.prNumber;
24610
25043
  if (typeof url !== "string" || !url) return;
24611
25044
  if (typeof number !== "number" || !Number.isInteger(number) || number <= 0) return;
24612
- const repo = typeof record2.prRepository === "string" ? record2.prRepository : "";
25045
+ const repo = typeof record3.prRepository === "string" ? record3.prRepository : "";
24613
25046
  collector.add({
24614
25047
  url,
24615
25048
  number,
@@ -24644,19 +25077,19 @@ function createPullRequestScanner() {
24644
25077
  if (!line.includes(GH_PR_HINT) && !line.includes(URL_HINT) && !line.includes(PR_LINK_HINT)) {
24645
25078
  return;
24646
25079
  }
24647
- let record2;
25080
+ let record3;
24648
25081
  try {
24649
- record2 = JSON.parse(line);
25082
+ record3 = JSON.parse(line);
24650
25083
  } catch {
24651
25084
  return;
24652
25085
  }
24653
- if (!isRecord5(record2)) return;
24654
- const timestamp = typeof record2.timestamp === "string" ? record2.timestamp : "";
24655
- if (record2.type === "pr-link") {
24656
- recordPrLink(record2, timestamp);
25086
+ if (!isRecord5(record3)) return;
25087
+ const timestamp = typeof record3.timestamp === "string" ? record3.timestamp : "";
25088
+ if (record3.type === "pr-link") {
25089
+ recordPrLink(record3, timestamp);
24657
25090
  return;
24658
25091
  }
24659
- const payload = record2.payload;
25092
+ const payload = record3.payload;
24660
25093
  if (isRecord5(payload)) {
24661
25094
  const type = payload.type;
24662
25095
  if (type === "function_call" || type === "custom_tool_call") {
@@ -24666,15 +25099,15 @@ function createPullRequestScanner() {
24666
25099
  }
24667
25100
  return;
24668
25101
  }
24669
- const data = record2.data;
25102
+ const data = record3.data;
24670
25103
  if (isRecord5(data)) {
24671
- if (record2.type === "tool.execution_start") {
25104
+ if (record3.type === "tool.execution_start") {
24672
25105
  recordToolCall(
24673
25106
  data.toolCallId,
24674
25107
  parseArgs2(data.arguments ?? data.input),
24675
25108
  timestamp
24676
25109
  );
24677
- } else if (record2.type === "tool.execution_complete") {
25110
+ } else if (record3.type === "tool.execution_complete") {
24678
25111
  recordResult(
24679
25112
  data.toolCallId,
24680
25113
  data.result ?? data.output ?? data.error,
@@ -24683,7 +25116,7 @@ function createPullRequestScanner() {
24683
25116
  }
24684
25117
  return;
24685
25118
  }
24686
- const message = record2.message;
25119
+ const message = record3.message;
24687
25120
  if (!isRecord5(message) || !Array.isArray(message.content)) return;
24688
25121
  for (const block of message.content) {
24689
25122
  if (!isRecord5(block)) continue;
@@ -25547,6 +25980,19 @@ var init_projects2 = __esm({
25547
25980
  }
25548
25981
  });
25549
25982
 
25983
+ // ../../server/agents/executables.ts
25984
+ function activeExecutableFor(kind) {
25985
+ return kind === "claude" ? claudeCliPath() : void 0;
25986
+ }
25987
+ function describeExecutableFor(kind) {
25988
+ return kind === "claude" ? describeClaudeExecutable() : null;
25989
+ }
25990
+ var init_executables = __esm({
25991
+ "../../server/agents/executables.ts"() {
25992
+ init_claudeExecutable();
25993
+ }
25994
+ });
25995
+
25550
25996
  // ../../server/lib/providerUpdates.ts
25551
25997
  import { realpathSync } from "node:fs";
25552
25998
  function deriveStatus(current, latest) {
@@ -25649,8 +26095,8 @@ function buildUpdateCommand(provider, method) {
25649
26095
  function formatCommand(command) {
25650
26096
  return [command.executable, ...command.args].join(" ");
25651
26097
  }
25652
- function resolveBinaryPaths(binName) {
25653
- const onPath = findExecutableOnPath(binName);
26098
+ function resolveBinaryPaths(descriptor7) {
26099
+ const onPath = activeExecutableFor(descriptor7.kind) ?? findExecutableOnPath(descriptor7.binName);
25654
26100
  if (!onPath) return [];
25655
26101
  try {
25656
26102
  const real = realpathSync(onPath);
@@ -25699,7 +26145,7 @@ function fetchLatestVersion(packageName) {
25699
26145
  });
25700
26146
  }
25701
26147
  async function probeProvider(descriptor7) {
25702
- const paths = resolveBinaryPaths(descriptor7.binName);
26148
+ const paths = resolveBinaryPaths(descriptor7);
25703
26149
  const base = {
25704
26150
  provider: descriptor7.kind,
25705
26151
  displayName: descriptor7.displayName,
@@ -25808,6 +26254,7 @@ var init_providerUpdates = __esm({
25808
26254
  "../../server/lib/providerUpdates.ts"() {
25809
26255
  init_agent_descriptors();
25810
26256
  init_versions();
26257
+ init_executables();
25811
26258
  init_binaryResolver();
25812
26259
  init_cliProcess();
25813
26260
  REGISTRY_TIMEOUT_MS = 4e3;
@@ -25864,6 +26311,32 @@ var init_provider_updates = __esm({
25864
26311
  }
25865
26312
  });
25866
26313
 
26314
+ // ../../server/routes/agent-executable.ts
26315
+ function registerAgentExecutableRoutes(use) {
26316
+ use("/api/agent-executable", async (req, res, next) => {
26317
+ if (req.method !== "GET") return next();
26318
+ const kind = new URL(req.url || "/", "http://localhost").pathname.slice(1);
26319
+ if (!AGENT_KINDS.includes(kind)) return next();
26320
+ const report = describeExecutableFor(kind);
26321
+ if (!report) {
26322
+ sendJson(res, 404, { error: `${kind} has a single executable; nothing to choose` });
26323
+ return;
26324
+ }
26325
+ try {
26326
+ sendJson(res, 200, await report);
26327
+ } catch (err) {
26328
+ sendJson(res, 500, { error: String(err) });
26329
+ }
26330
+ });
26331
+ }
26332
+ var init_agent_executable = __esm({
26333
+ "../../server/routes/agent-executable.ts"() {
26334
+ init_agent_descriptors();
26335
+ init_executables();
26336
+ init_http();
26337
+ }
26338
+ });
26339
+
25867
26340
  // ../../server/routes/scripts/discovery.ts
25868
26341
  import { readdir as readdir12, readFile as readFile19 } from "node:fs/promises";
25869
26342
  import { join as join25, relative as relative10 } from "node:path";
@@ -26779,7 +27252,7 @@ function normalizeCopilotFileChangeEvents(jsonlContent) {
26779
27252
  }
26780
27253
  });
26781
27254
  }
26782
- return records.map((record2) => JSON.stringify(record2)).join("\n");
27255
+ return records.map((record3) => JSON.stringify(record3)).join("\n");
26783
27256
  }
26784
27257
  async function parseSessionFileChanges(jsonlContent, includeContent) {
26785
27258
  if (formatForText(jsonlContent).kind === "copilot") {
@@ -28748,20 +29221,20 @@ var init_aggregate = __esm({
28748
29221
  this.#toDay = makeDayFormatter(options.timeZone);
28749
29222
  }
28750
29223
  /** 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);
29224
+ add(record3) {
29225
+ if (record3.dedupeKey !== null) {
29226
+ if (this.#seen.has(record3.dedupeKey)) return false;
29227
+ this.#seen.add(record3.dedupeKey);
28755
29228
  }
28756
- const day = this.#toDay(record2.timestampMs);
29229
+ const day = this.#toDay(record3.timestampMs);
28757
29230
  if (day < this.#options.sinceDay || day > this.#options.untilDay) return false;
28758
- const key2 = [day, record2.provider, record2.model].join(KEY_SEPARATOR);
29231
+ const key2 = [day, record3.provider, record3.model].join(KEY_SEPARATOR);
28759
29232
  let bucket = this.#buckets.get(key2);
28760
29233
  if (bucket === void 0) {
28761
29234
  bucket = {
28762
29235
  day,
28763
- provider: record2.provider,
28764
- model: record2.model,
29236
+ provider: record3.provider,
29237
+ model: record3.model,
28765
29238
  totals: emptyUsageCostTotals(),
28766
29239
  costUsd: 0,
28767
29240
  cacheSavingsUsd: 0,
@@ -28774,19 +29247,19 @@ var init_aggregate = __esm({
28774
29247
  }
28775
29248
  const priced = priceUsage(
28776
29249
  this.#options.rates,
28777
- record2.model,
28778
- record2.totals,
28779
- record2.reportedCostUsd
29250
+ record3.model,
29251
+ record3.totals,
29252
+ record3.reportedCostUsd
28780
29253
  );
28781
- bucket.totals = addUsageCostTotals(bucket.totals, record2.totals);
29254
+ bucket.totals = addUsageCostTotals(bucket.totals, record3.totals);
28782
29255
  bucket.costUsd += priced.costUsd;
28783
- bucket.cacheSavingsUsd += cacheSavingsUsd(this.#options.rates, record2.model, record2.totals);
29256
+ bucket.cacheSavingsUsd += cacheSavingsUsd(this.#options.rates, record3.model, record3.totals);
28784
29257
  bucket.records += 1;
28785
29258
  if (priced.costSource === "unpriced") bucket.unpricedRecords += 1;
28786
29259
  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);
29260
+ if (record3.sessionId.length > 0) {
29261
+ bucket.sessions.add(record3.sessionId);
29262
+ this.#sessions.add(record3.sessionId);
28790
29263
  }
28791
29264
  return true;
28792
29265
  }
@@ -28867,17 +29340,17 @@ async function readTranscriptRecords(filePath, provider) {
28867
29340
  function dedupeWithinFile(records) {
28868
29341
  const slotByKey = /* @__PURE__ */ new Map();
28869
29342
  const kept = [];
28870
- for (const record2 of records) {
28871
- if (record2.dedupeKey === null) {
28872
- kept.push(record2);
29343
+ for (const record3 of records) {
29344
+ if (record3.dedupeKey === null) {
29345
+ kept.push(record3);
28873
29346
  continue;
28874
29347
  }
28875
- const slot = slotByKey.get(record2.dedupeKey);
29348
+ const slot = slotByKey.get(record3.dedupeKey);
28876
29349
  if (slot === void 0) {
28877
- slotByKey.set(record2.dedupeKey, kept.push(record2) - 1);
29350
+ slotByKey.set(record3.dedupeKey, kept.push(record3) - 1);
28878
29351
  continue;
28879
29352
  }
28880
- if (record2.totals.outputTokens > kept[slot].totals.outputTokens) kept[slot] = record2;
29353
+ if (record3.totals.outputTokens > kept[slot].totals.outputTokens) kept[slot] = record3;
28881
29354
  }
28882
29355
  return kept;
28883
29356
  }
@@ -28986,23 +29459,23 @@ async function readUsageCostSummary(input) {
28986
29459
  for (const file of files) {
28987
29460
  const records = await readFileRecords(file, provider);
28988
29461
  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();
29462
+ for (const record3 of records) {
29463
+ aggregator.add(record3);
29464
+ if (!liveSessionIds.has(record3.sessionId)) continue;
29465
+ const byModel = durableTotals.get(record3.sessionId) ?? /* @__PURE__ */ new Map();
28993
29466
  byModel.set(
28994
- record2.model,
29467
+ record3.model,
28995
29468
  addUsageCostTotals(
28996
- byModel.get(record2.model) ?? emptyUsageCostTotals(),
28997
- record2.totals
29469
+ byModel.get(record3.model) ?? emptyUsageCostTotals(),
29470
+ record3.totals
28998
29471
  )
28999
29472
  );
29000
- durableTotals.set(record2.sessionId, byModel);
29473
+ durableTotals.set(record3.sessionId, byModel);
29001
29474
  }
29002
29475
  }
29003
29476
  }
29004
29477
  for (const runtime of runtimes2) {
29005
- for (const record2 of await runtime.liveUsageRecords(durableTotals)) aggregator.add(record2);
29478
+ for (const record3 of await runtime.liveUsageRecords(durableTotals)) aggregator.add(record3);
29006
29479
  }
29007
29480
  const retentionCutoffMs = startedAtMs - 90 * 24 * 60 * 60 * 1e3;
29008
29481
  for (const [path, entry] of fileCache2) {
@@ -29729,8 +30202,8 @@ var init_workflows2 = __esm({
29729
30202
  });
29730
30203
 
29731
30204
  // ../../server/routes/worktrees/worktreeIo.ts
29732
- import { execFile as execFile7 } from "node:child_process";
29733
- import { promisify as promisify3 } from "node:util";
30205
+ import { execFile as execFile8 } from "node:child_process";
30206
+ import { promisify as promisify4 } from "node:util";
29734
30207
  async function runWorktreeCommand(file, args, { cwd, timeoutMs = WORKTREE_COMMAND_TIMEOUT_MS }) {
29735
30208
  const result = await execFileAsync(file, [...args], {
29736
30209
  cwd,
@@ -29769,7 +30242,7 @@ var init_worktreeIo = __esm({
29769
30242
  WORKTREE_COMMAND_MAX_BUFFER = 4 * 1024 * 1024;
29770
30243
  WORKTREE_SCAN_CONCURRENCY = 4;
29771
30244
  SESSION_HEADER_CONCURRENCY = 8;
29772
- execFileAsync = promisify3(execFile7);
30245
+ execFileAsync = promisify4(execFile8);
29773
30246
  NONINTERACTIVE_ENV = {
29774
30247
  ...process.env,
29775
30248
  GCM_INTERACTIVE: "Never",
@@ -30357,6 +30830,7 @@ var init_api_routes = __esm({
30357
30830
  init_files();
30358
30831
  init_git_diff();
30359
30832
  init_git_status();
30833
+ init_github_actions();
30360
30834
  init_project_icon();
30361
30835
  init_hello();
30362
30836
  init_local_file();
@@ -30371,6 +30845,7 @@ var init_api_routes = __esm({
30371
30845
  init_project_files();
30372
30846
  init_projects2();
30373
30847
  init_provider_updates();
30848
+ init_agent_executable();
30374
30849
  init_scripts();
30375
30850
  init_session_config();
30376
30851
  init_session_context();
@@ -30425,6 +30900,7 @@ var init_api_routes = __esm({
30425
30900
  apiRoute("project-files", registerProjectFileRoutes),
30426
30901
  apiRoute("project-file", registerProjectFileContentRoutes),
30427
30902
  apiRoute("git-status", registerGitStatusRoutes),
30903
+ apiRoute("github-actions", registerGitHubActionsRoutes),
30428
30904
  apiRoute("project-icon", registerProjectIconRoutes),
30429
30905
  apiRoute("git-diff", registerGitDiffRoutes),
30430
30906
  apiRoute("mcp", registerMcpRoutes),
@@ -30438,7 +30914,8 @@ var init_api_routes = __esm({
30438
30914
  apiRoute("models", registerModelRoutes),
30439
30915
  apiRoute("codex-threads", registerCodexThreadRoutes),
30440
30916
  apiRoute("agent-runtime", registerAgentRuntimeRoutes),
30441
- apiRoute("provider-updates", registerProviderUpdateRoutes)
30917
+ apiRoute("provider-updates", registerProviderUpdateRoutes),
30918
+ apiRoute("agent-executable", registerAgentExecutableRoutes)
30442
30919
  ];
30443
30920
  }
30444
30921
  });
@@ -31266,8 +31743,8 @@ var init_sessionActivityMonitor = __esm({
31266
31743
  });
31267
31744
 
31268
31745
  // ../../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")) {
31746
+ import { readFileSync as readFileSync4 } from "node:fs";
31747
+ function resolveEnvPassword(env = process.env, readFileFn = (p) => readFileSync4(p, "utf-8")) {
31271
31748
  const file = env.COGPIT_NETWORK_PASSWORD_FILE;
31272
31749
  if (file && file.length > 0) {
31273
31750
  const trimmed = readFileFn(file).replace(/\r?\n$/, "");
@@ -31536,7 +32013,7 @@ async function waitForShutdownSignal() {
31536
32013
  for (const signal of signals) process.once(signal, done);
31537
32014
  });
31538
32015
  }
31539
- var defaultDependencies = {
32016
+ var defaultDependencies2 = {
31540
32017
  fetch,
31541
32018
  openUrl: openExternalUrl,
31542
32019
  startServer: startPackagedServer,
@@ -31563,7 +32040,7 @@ async function verifyServer(server, command, deps) {
31563
32040
  }
31564
32041
  }
31565
32042
  async function run(argv, overrides = {}) {
31566
- const deps = { ...defaultDependencies, ...overrides };
32043
+ const deps = { ...defaultDependencies2, ...overrides };
31567
32044
  let command;
31568
32045
  try {
31569
32046
  command = parseArgs(argv);