cogpit 2.4.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/cli.js +1374 -556
  2. package/dist/web/assets/{CommandPaletteHost-DU1jhhYG.js → CommandPaletteHost-D43icOGh.js} +1 -1
  3. package/dist/web/assets/{ConfigBrowser-CTZR8nw6.js → ConfigBrowser-BailHbYr.js} +1 -1
  4. package/dist/web/assets/{HighlightedEditor-CNTtimUO.js → HighlightedEditor-Kf1cQYyg.js} +1 -1
  5. package/dist/web/assets/{KeyboardShortcutsDialog-DtTE4xjZ.js → KeyboardShortcutsDialog-CHb_hQuK.js} +1 -1
  6. package/dist/web/assets/{MobileFileChanges-DaJh6sQ7.js → MobileFileChanges-C9Xk9gfg.js} +1 -1
  7. package/dist/web/assets/{PreviewPanel-BOL9gNaQ.js → PreviewPanel-Djv1bZZJ.js} +1 -1
  8. package/dist/web/assets/ProjectFilesPanel-DuBqjGFA.js +4 -0
  9. package/dist/web/assets/{ProjectSwitcherModal-UUQMoktd.js → ProjectSwitcherModal-CxQ6p2B4.js} +1 -1
  10. package/dist/web/assets/{TerminalOutput-T82q4Tf9.js → TerminalOutput-Cm-dLkUR.js} +1 -1
  11. package/dist/web/assets/ThemeSelectorModal-CTuOdp5Q.js +1 -0
  12. package/dist/web/assets/WorkflowsPanel-P7HtcaDf.js +1 -0
  13. package/dist/web/assets/{WorktreePanel-DvZNvNhH.js → WorktreePanel-DcjYVMuA.js} +1 -1
  14. package/dist/web/assets/index-CEBq1nya.js +1 -0
  15. package/dist/web/assets/{index-BhjwMUil.js → index-CVfvPIib.js} +4 -4
  16. package/dist/web/assets/index-CWj7TiFf.css +1 -0
  17. package/dist/web/assets/{index-CpHg1sRc.js → index-D2LNKOXE.js} +1 -1
  18. package/dist/web/assets/index-DFiPbdIb.js +153 -0
  19. package/dist/web/assets/session-parser.worker-SrNyVFwl.js +29 -0
  20. package/dist/web/assets/{vendor-ui-B9m2oOMV.js → vendor-ui-DUTyrBOX.js} +175 -160
  21. package/dist/web/index.html +3 -3
  22. package/package.json +1 -1
  23. package/dist/web/assets/ProjectFilesPanel-CBFFT9qJ.js +0 -4
  24. package/dist/web/assets/ThemeSelectorModal-rFVnzZuC.js +0 -1
  25. package/dist/web/assets/WorkflowsPanel-COZwo8h-.js +0 -1
  26. package/dist/web/assets/index-CghBqEmp.js +0 -153
  27. package/dist/web/assets/index-XlQRZ_Un.js +0 -1
  28. package/dist/web/assets/index-f2DFkgKZ.css +0 -1
  29. package/dist/web/assets/session-parser.worker-QY58jiXs.js +0 -29
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 record4 = { at: Date.now(), generation: generation2 };
490
- lastAttempt.set(id, record4);
489
+ const record5 = { at: Date.now(), generation: generation2 };
490
+ lastAttempt.set(id, record5);
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
- record4.error = error;
506
+ record5.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
- record4.error = error;
514
+ record5.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
- record4.error = error;
525
+ record5.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
- record4.error = error;
539
+ record5.error = error;
540
540
  if (generationIsCurrent(id, generation2)) {
541
541
  setDeviceRuntime(id, { authState: "bad-password", lastProbe: Date.now() });
542
542
  }
@@ -845,6 +845,7 @@ var init_agent_descriptors = __esm({
845
845
  ultracode: true,
846
846
  contextWindow: true,
847
847
  externalProcesses: false,
848
+ accountSwitching: true,
848
849
  modelFallbackNotices: true,
849
850
  autoPermissionMode: "per-model",
850
851
  settingsApply: "live",
@@ -972,6 +973,7 @@ var init_agent_descriptors = __esm({
972
973
  ultracode: false,
973
974
  contextWindow: false,
974
975
  externalProcesses: false,
976
+ accountSwitching: false,
975
977
  modelFallbackNotices: false,
976
978
  autoPermissionMode: "never",
977
979
  settingsApply: "next-turn",
@@ -1088,6 +1090,7 @@ var init_agent_descriptors = __esm({
1088
1090
  ultracode: false,
1089
1091
  contextWindow: false,
1090
1092
  externalProcesses: true,
1093
+ accountSwitching: false,
1091
1094
  modelFallbackNotices: false,
1092
1095
  autoPermissionMode: "always",
1093
1096
  settingsApply: "next-turn",
@@ -1271,8 +1274,8 @@ function quoteArgument(arg) {
1271
1274
  const escaped = arg.replace(/(\\*)"/g, '$1$1\\"').replace(/(\\*)$/, "$1$1");
1272
1275
  return `"${escaped}"`;
1273
1276
  }
1274
- function escapeForCmd(text) {
1275
- return text.replace(CMD_META_CHARS, "^$1");
1277
+ function escapeForCmd(text2) {
1278
+ return text2.replace(CMD_META_CHARS, "^$1");
1276
1279
  }
1277
1280
  function throughCmdExe(executable, args, options) {
1278
1281
  const line = [
@@ -1980,17 +1983,17 @@ function shareRequestAllowed(method, rawUrl, share) {
1980
1983
  const path = parseRequestPath(rawUrl);
1981
1984
  if (path === null) return false;
1982
1985
  const verb = method.toUpperCase();
1983
- const route = path.raw[1];
1986
+ const route2 = path.raw[1];
1984
1987
  const identity = path.decoded.slice(2);
1985
1988
  const routePath = `/${path.raw.join("/")}`;
1986
1989
  if (SHARE_NAMESPACE.some(([allowedVerb, allowedPath]) => allowedVerb === verb && allowedPath === routePath)) return true;
1987
- if (verb === "GET" && (route === "sessions" || route === "watch")) {
1990
+ if (verb === "GET" && (route2 === "sessions" || route2 === "watch")) {
1988
1991
  return identity.length === 2 && identity[0] === share.dirName && identity[1] === share.fileName;
1989
1992
  }
1990
- if (verb === "GET" && (route === "session-status" || route === "session-file-changes")) {
1993
+ if (verb === "GET" && (route2 === "session-status" || route2 === "session-file-changes")) {
1991
1994
  return identity.length === 1 && identity[0] === share.sessionId;
1992
1995
  }
1993
- if (verb === "GET" && route === "session-config") {
1996
+ if (verb === "GET" && route2 === "session-config") {
1994
1997
  return identity.length === 1 && identity[0] === share.fileName;
1995
1998
  }
1996
1999
  return false;
@@ -4002,7 +4005,7 @@ async function createShare(input) {
4002
4005
  const passwordHash = hashPassword(passphrase);
4003
4006
  const share = await commitShareMutation((draft) => {
4004
4007
  const existing = draft.get(input.sessionId);
4005
- const record4 = {
4008
+ const record5 = {
4006
4009
  sessionId: input.sessionId,
4007
4010
  dirName: input.dirName,
4008
4011
  fileName: input.fileName,
@@ -4011,8 +4014,8 @@ async function createShare(input) {
4011
4014
  // No guest has ever used this passphrase; the UI renders 0 as "never".
4012
4015
  lastAccessAt: 0
4013
4016
  };
4014
- draft.set(record4.sessionId, record4);
4015
- return { changed: true, value: toPublicShare(record4) };
4017
+ draft.set(record5.sessionId, record5);
4018
+ return { changed: true, value: toPublicShare(record5) };
4016
4019
  });
4017
4020
  return { share, passphrase };
4018
4021
  }
@@ -4865,6 +4868,7 @@ var init_policy = __esm({
4865
4868
  "git-status": admin("/api/git-status"),
4866
4869
  github: admin("/api/github"),
4867
4870
  "vercel-deployments": admin("/api/vercel-deployments"),
4871
+ clickup: admin("/api/clickup"),
4868
4872
  "project-icon": admin("/api/project-icon"),
4869
4873
  "git-diff": admin("/api/git-diff"),
4870
4874
  mcp: admin("/api/mcp-servers"),
@@ -4897,6 +4901,10 @@ var init_policy = __esm({
4897
4901
  // Reports which binary the server spawns; the choice itself is saved through /api/config.
4898
4902
  "agent-executable": [
4899
4903
  { prefix: "/api/agent-executable", methods: ["GET"], requires: "authed" }
4904
+ ],
4905
+ "agent-accounts": [
4906
+ { prefix: "/api/agent-accounts", methods: ["GET"], requires: "authed" },
4907
+ { prefix: "/api/agent-accounts", requires: "admin" }
4900
4908
  ]
4901
4909
  };
4902
4910
  ALL_RULES = Object.values(ROUTE_POLICIES).flat();
@@ -5800,7 +5808,7 @@ function findNpmClaude(options = {}) {
5800
5808
  const windows = platform2 === "win32";
5801
5809
  const path = windows ? win322 : posix2;
5802
5810
  const isFile = options.isFile ?? realIsFile;
5803
- const readFile22 = options.readFile ?? realReadFile;
5811
+ const readFile23 = options.readFile ?? realReadFile;
5804
5812
  const shim = findExecutableOnPath(BIN_NAME, { platform: platform2, env: options.env, isExecutable: isFile });
5805
5813
  if (!shim) return void 0;
5806
5814
  const shimDir = path.dirname(shim);
@@ -5809,7 +5817,7 @@ function findNpmClaude(options = {}) {
5809
5817
  path.join(shimDir, "..", "lib", "node_modules", NPM_PACKAGE)
5810
5818
  ];
5811
5819
  for (const packageDir of packageDirs) {
5812
- const manifest = readFile22(path.join(packageDir, "package.json"));
5820
+ const manifest = readFile23(path.join(packageDir, "package.json"));
5813
5821
  if (!manifest) continue;
5814
5822
  const relative11 = binField(manifest);
5815
5823
  if (!relative11) continue;
@@ -6039,8 +6047,8 @@ function publish(sessionId, ev, parentToolUseId) {
6039
6047
  const msg = messageId ? state.messages.get(messageId) : void 0;
6040
6048
  if (!messageId || !msg || ev.index === void 0) return;
6041
6049
  const d = ev.delta;
6042
- const text = d?.type === "text_delta" ? d.text : d?.type === "thinking_delta" ? d.thinking : d?.type === "input_json_delta" ? d.partial_json : void 0;
6043
- if (!text) return;
6050
+ const text2 = d?.type === "text_delta" ? d.text : d?.type === "thinking_delta" ? d.thinking : d?.type === "input_json_delta" ? d.partial_json : void 0;
6051
+ if (!text2) return;
6044
6052
  let block = msg.blocks.find((b) => b.index === ev.index);
6045
6053
  if (!block) {
6046
6054
  const inferred = d?.type === "thinking_delta" ? "thinking" : d?.type === "input_json_delta" ? "tool_use" : "text";
@@ -6048,7 +6056,7 @@ function publish(sessionId, ev, parentToolUseId) {
6048
6056
  msg.blocks.push(block);
6049
6057
  }
6050
6058
  if (block.text.length < MAX_BLOCK_TEXT) {
6051
- block.text += text;
6059
+ block.text += text2;
6052
6060
  }
6053
6061
  queueDelta(state, {
6054
6062
  messageId,
@@ -6056,7 +6064,7 @@ function publish(sessionId, ev, parentToolUseId) {
6056
6064
  blockIndex: ev.index,
6057
6065
  blockType: block.blockType,
6058
6066
  ...block.toolName ? { toolName: block.toolName } : {},
6059
- delta: text
6067
+ delta: text2
6060
6068
  });
6061
6069
  return;
6062
6070
  }
@@ -6080,8 +6088,8 @@ function publish(sessionId, ev, parentToolUseId) {
6080
6088
  return;
6081
6089
  }
6082
6090
  }
6083
- function publishTextDelta(sessionId, messageId, text, parentToolUseId = null) {
6084
- if (!sessionId || !messageId || !text) return;
6091
+ function publishTextDelta(sessionId, messageId, text2, parentToolUseId = null) {
6092
+ if (!sessionId || !messageId || !text2) return;
6085
6093
  const state = getOrCreate(sessionId);
6086
6094
  let msg = state.messages.get(messageId);
6087
6095
  if (!msg) {
@@ -6094,13 +6102,13 @@ function publishTextDelta(sessionId, messageId, text, parentToolUseId = null) {
6094
6102
  block = { index: 0, blockType: "text", text: "" };
6095
6103
  msg.blocks.push(block);
6096
6104
  }
6097
- if (block.text.length < MAX_BLOCK_TEXT) block.text += text;
6105
+ if (block.text.length < MAX_BLOCK_TEXT) block.text += text2;
6098
6106
  queueDelta(state, {
6099
6107
  messageId,
6100
6108
  parentToolUseId,
6101
6109
  blockIndex: 0,
6102
6110
  blockType: "text",
6103
- delta: text
6111
+ delta: text2
6104
6112
  });
6105
6113
  }
6106
6114
  function publishCompleteMessage(sessionId, msg) {
@@ -7486,12 +7494,12 @@ async function readHeadLines(filePath, byteLimit) {
7486
7494
  try {
7487
7495
  const buf = Buffer.allocUnsafe(byteLimit);
7488
7496
  const { bytesRead } = await fh.read(buf, 0, byteLimit, 0);
7489
- let text = buf.subarray(0, bytesRead).toString("utf-8");
7497
+ let text2 = buf.subarray(0, bytesRead).toString("utf-8");
7490
7498
  if (bytesRead === byteLimit) {
7491
- const lastNewline = text.lastIndexOf("\n");
7492
- if (lastNewline >= 0) text = text.slice(0, lastNewline);
7499
+ const lastNewline = text2.lastIndexOf("\n");
7500
+ if (lastNewline >= 0) text2 = text2.slice(0, lastNewline);
7493
7501
  }
7494
- return text.split("\n").filter(Boolean);
7502
+ return text2.split("\n").filter(Boolean);
7495
7503
  } finally {
7496
7504
  await fh.close();
7497
7505
  }
@@ -7529,9 +7537,9 @@ var init_transcriptHead = __esm({
7529
7537
 
7530
7538
  // ../../server/agents/claudeMetadata.ts
7531
7539
  import { open as open3 } from "node:fs/promises";
7532
- function lastRealModel(text) {
7540
+ function lastRealModel(text2) {
7533
7541
  let found = null;
7534
- for (const match of text.matchAll(MODEL_RE)) {
7542
+ for (const match of text2.matchAll(MODEL_RE)) {
7535
7543
  if (!match[1].startsWith("<")) found = match[1];
7536
7544
  }
7537
7545
  return found;
@@ -7650,15 +7658,15 @@ async function readClaudeSessionMeta(filePath, head) {
7650
7658
  cursor -= readSize;
7651
7659
  const buf = Buffer.alloc(readSize);
7652
7660
  const { bytesRead } = await fh.read(buf, 0, readSize, cursor);
7653
- const text = buf.subarray(0, bytesRead).toString("utf-8") + leftover;
7661
+ const text2 = buf.subarray(0, bytesRead).toString("utf-8") + leftover;
7654
7662
  if (!foundModel) {
7655
- const found = lastRealModel(text);
7663
+ const found = lastRealModel(text2);
7656
7664
  if (found) {
7657
7665
  model = found;
7658
7666
  foundModel = true;
7659
7667
  }
7660
7668
  }
7661
- const splitLines = text.split("\n");
7669
+ const splitLines = text2.split("\n");
7662
7670
  leftover = cursor > 0 ? splitLines[0] : "";
7663
7671
  const startIdx = cursor > 0 ? 1 : 0;
7664
7672
  for (let j = splitLines.length - 1; j >= startIdx; j--) {
@@ -8003,15 +8011,15 @@ var init_sessionStats = __esm({
8003
8011
  });
8004
8012
 
8005
8013
  // ../../shared/session/turnContent.ts
8006
- function appendAssistantText(turn, text, timestamp2) {
8007
- if (!text) return;
8008
- turn.assistantText.push(text);
8014
+ function appendAssistantText(turn, text2, timestamp2) {
8015
+ if (!text2) return;
8016
+ turn.assistantText.push(text2);
8009
8017
  const last = turn.contentBlocks[turn.contentBlocks.length - 1];
8010
8018
  if (last?.kind === "text") {
8011
- last.text.push(text);
8019
+ last.text.push(text2);
8012
8020
  return;
8013
8021
  }
8014
- turn.contentBlocks.push({ kind: "text", text: [text], timestamp: timestamp2 });
8022
+ turn.contentBlocks.push({ kind: "text", text: [text2], timestamp: timestamp2 });
8015
8023
  }
8016
8024
  var init_turnContent = __esm({
8017
8025
  "../../shared/session/turnContent.ts"() {
@@ -8143,8 +8151,21 @@ function resolveAssignedArgument(source, invocationStart, argumentSource) {
8143
8151
  const identifier = argumentSource.trim().match(/^([A-Za-z_$][\w$]*)$/)?.[1];
8144
8152
  if (!identifier) return argumentSource;
8145
8153
  const prefix = source.slice(0, invocationStart);
8146
- const assignment = new RegExp(`\\b(?:const|let|var)\\s+${identifier.replace(/[$]/g, "\\$")}\\s*=`, "g");
8147
- const lastMatch = [...prefix.matchAll(assignment)].at(-1);
8154
+ const assignment = new RegExp(`\\b(?:const|let|var)\\s+${identifier.replace(/[$]/g, "\\$")}\\s*=`, "y");
8155
+ let lastMatch = null;
8156
+ for (let index = 0; index < prefix.length; index++) {
8157
+ const skipped = skipStringOrComment(prefix, index);
8158
+ if (skipped) {
8159
+ index = skipped.endIndex - 1;
8160
+ continue;
8161
+ }
8162
+ assignment.lastIndex = index;
8163
+ const match = assignment.exec(prefix);
8164
+ if (match) {
8165
+ lastMatch = match;
8166
+ index += match[0].length - 1;
8167
+ }
8168
+ }
8148
8169
  if (!lastMatch || lastMatch.index === void 0) return argumentSource;
8149
8170
  const valueStart = skipTrivia(prefix, lastMatch.index + lastMatch[0].length);
8150
8171
  const opening = prefix[valueStart];
@@ -8158,13 +8179,17 @@ function resolveAssignedArgument(source, invocationStart, argumentSource) {
8158
8179
  }
8159
8180
  function extractCodexExecInvocations(source) {
8160
8181
  const calls = [];
8182
+ let previousSignificant = "";
8161
8183
  for (let index = 0; index < source.length; index++) {
8162
8184
  const skipped = skipStringOrComment(source, index);
8163
8185
  if (skipped) {
8186
+ if (skipped.isString) previousSignificant = "literal";
8164
8187
  index = skipped.endIndex - 1;
8165
8188
  continue;
8166
8189
  }
8167
- if (!source.startsWith("tools", index) || isIdentifierPart(source[index - 1]) || isIdentifierPart(source[index + 5])) {
8190
+ const isPropertyAccess = previousSignificant === ".";
8191
+ if (!/\s/.test(source[index])) previousSignificant = source[index];
8192
+ if (isPropertyAccess || !source.startsWith("tools", index) || isIdentifierPart(source[index - 1]) || isIdentifierPart(source[index + 5])) {
8168
8193
  continue;
8169
8194
  }
8170
8195
  let cursor = skipTrivia(source, index + 5);
@@ -8512,8 +8537,9 @@ function isObject(value) {
8512
8537
  return typeof value === "object" && value !== null;
8513
8538
  }
8514
8539
  function normalizeFunctionName(rawName) {
8540
+ if (rawName.startsWith("mcp__")) return rawName;
8515
8541
  const leaf = rawName.split(/(?:__|[.:/])+/).filter(Boolean).at(-1) ?? rawName;
8516
- return COLLABORATION_TOOL_NAMES.get(leaf) ?? rawName;
8542
+ return COLLABORATION_TOOL_NAMES.get(leaf) ?? (NATIVE_TOOL_NAMES.has(leaf) ? leaf : rawName);
8517
8543
  }
8518
8544
  function inferToolError(output) {
8519
8545
  if (!output) return false;
@@ -8531,25 +8557,53 @@ function normalizePlanToTodos(input) {
8531
8557
  }));
8532
8558
  return { todos };
8533
8559
  }
8534
- function extractCustomToolOutputText(output) {
8535
- if (typeof output === "string") return output;
8536
- if (!Array.isArray(output)) return "";
8537
- return output.filter((block) => isObject(block) && typeof block.text === "string").map((block) => block.text).join("");
8560
+ function outputImage(block) {
8561
+ if (block.type !== "image" && block.type !== "input_image" && block.type !== "image_url") return null;
8562
+ const source = isObject(block.source) ? block.source : block;
8563
+ const mediaType = source.media_type ?? source.mimeType;
8564
+ if (typeof mediaType === "string" && mediaType.startsWith("image/") && typeof source.data === "string" && source.data) {
8565
+ return { type: "image", source: { type: "base64", media_type: mediaType, data: source.data } };
8566
+ }
8567
+ const url = isObject(block.image_url) ? block.image_url.url : block.image_url;
8568
+ const match = typeof url === "string" ? /^data:(image\/[^;,]+);base64,(.+)$/is.exec(url) : null;
8569
+ return match ? { type: "image", source: { type: "base64", media_type: match[1].toLowerCase(), data: match[2] } } : null;
8570
+ }
8571
+ function outputContent(output) {
8572
+ if (typeof output === "string") return { text: output, images: [] };
8573
+ if (!Array.isArray(output)) {
8574
+ return { text: output == null ? "" : JSON.stringify(output), images: [] };
8575
+ }
8576
+ const text2 = [];
8577
+ const images = [];
8578
+ for (const block of output) {
8579
+ if (!isObject(block)) continue;
8580
+ if (typeof block.text === "string") text2.push(block.text);
8581
+ const image = outputImage(block);
8582
+ if (image) images.push(image);
8583
+ }
8584
+ return { text: text2.join(""), images };
8538
8585
  }
8539
8586
  function parseCustomToolOutput(output) {
8540
- const rawOutput = extractCustomToolOutputText(output);
8541
- if (!rawOutput) return { text: "", isError: false };
8587
+ const original = outputContent(output);
8588
+ let envelope = isObject(output) && !Array.isArray(output) ? output : null;
8542
8589
  try {
8543
- const parsed = JSON.parse(rawOutput);
8544
- const text = typeof parsed.output === "string" ? parsed.output : rawOutput;
8545
- const meta = isObject(parsed.metadata) ? parsed.metadata : null;
8546
- const isError = meta ? meta.exit_code !== 0 && meta.exit_code !== void 0 : inferToolError(text);
8547
- return { text, isError };
8590
+ const parsed = envelope ?? JSON.parse(original.text);
8591
+ if (isObject(parsed) && !Array.isArray(parsed)) envelope = parsed;
8548
8592
  } catch {
8549
- return { text: rawOutput, isError: inferToolError(rawOutput) };
8550
8593
  }
8594
+ const content = envelope && ("output" in envelope || "content" in envelope) ? outputContent(envelope.output ?? envelope.content) : original;
8595
+ const images = content === original ? original.images : [...original.images, ...content.images];
8596
+ const metadata = isObject(envelope?.metadata) ? envelope.metadata : null;
8597
+ const exitCode = metadata?.exit_code ?? envelope?.exit_code;
8598
+ const explicitError = typeof envelope?.isError === "boolean" ? envelope.isError : typeof envelope?.is_error === "boolean" ? envelope.is_error : void 0;
8599
+ const isError = explicitError === true || (typeof exitCode === "number" ? exitCode !== 0 : explicitError ?? inferToolError(content.text));
8600
+ return {
8601
+ text: content.text,
8602
+ isError,
8603
+ ...images.length > 0 ? { images } : {}
8604
+ };
8551
8605
  }
8552
- var COLLABORATION_TOOL_NAMES;
8606
+ var COLLABORATION_TOOL_NAMES, NATIVE_TOOL_NAMES;
8553
8607
  var init_codex_tool_normalization = __esm({
8554
8608
  "../../shared/session/codex-tool-normalization.ts"() {
8555
8609
  COLLABORATION_TOOL_NAMES = /* @__PURE__ */ new Map([
@@ -8566,6 +8620,25 @@ var init_codex_tool_normalization = __esm({
8566
8620
  ["interrupt_agent", "interrupt_agent"],
8567
8621
  ["interruptAgent", "interrupt_agent"]
8568
8622
  ]);
8623
+ NATIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
8624
+ "exec",
8625
+ "exec_command",
8626
+ "write_stdin",
8627
+ "apply_patch",
8628
+ "update_plan",
8629
+ "view_image",
8630
+ "request_user_input",
8631
+ "request_user_input_async",
8632
+ "tool_search",
8633
+ "list_mcp_resources",
8634
+ "list_mcp_resource_templates",
8635
+ "read_mcp_resource",
8636
+ "request_plugin_install",
8637
+ "create_goal",
8638
+ "get_goal",
8639
+ "update_goal",
8640
+ "wait"
8641
+ ]);
8569
8642
  }
8570
8643
  });
8571
8644
 
@@ -8583,9 +8656,9 @@ function safeParseLine(line) {
8583
8656
  function isObject2(value) {
8584
8657
  return typeof value === "object" && value !== null;
8585
8658
  }
8586
- function isCodexRecord(record4) {
8587
- if (!record4 || typeof record4.type !== "string") return false;
8588
- return record4.type === "session_meta" || record4.type === "turn_context" || record4.type === "event_msg" || record4.type === "response_item" || record4.type === "inter_agent_communication_metadata" || record4.type === "compacted" || record4.type === "world_state";
8659
+ function isCodexRecord(record5) {
8660
+ if (!record5 || typeof record5.type !== "string") return false;
8661
+ return record5.type === "session_meta" || record5.type === "turn_context" || record5.type === "event_msg" || record5.type === "response_item" || record5.type === "inter_agent_communication_metadata" || record5.type === "compacted" || record5.type === "world_state";
8589
8662
  }
8590
8663
  function extractMessageText(payload, blockType) {
8591
8664
  const content = payload?.content;
@@ -8641,12 +8714,12 @@ function buildCodexUserContent(message, images, audio = [], localImages = [], lo
8641
8714
  ...localAudio.map((path) => `
8642
8715
  [audio attachment](<${path}>)`)
8643
8716
  ].join("");
8644
- const text = message + attachmentSuffix;
8645
- if (images.length === 0 && audio.length === 0) return text;
8717
+ const text2 = message + attachmentSuffix;
8718
+ if (images.length === 0 && audio.length === 0) return text2;
8646
8719
  return [
8647
8720
  ...images,
8648
8721
  ...audio,
8649
- ...text ? [{ type: "text", text }] : []
8722
+ ...text2 ? [{ type: "text", text: text2 }] : []
8650
8723
  ];
8651
8724
  }
8652
8725
  function extractInterAgentMessage(payload) {
@@ -8658,8 +8731,8 @@ function extractInterAgentMessage(payload) {
8658
8731
  }
8659
8732
  const header = rawText.slice(0, headerEnd.index);
8660
8733
  const messageType = header.match(/^Message Type:\s*([^\r\n]+)/)?.[1]?.trim().toUpperCase() ?? null;
8661
- const text = rawText.slice(headerEnd.index + headerEnd[0].length).trim();
8662
- return { messageType, text };
8734
+ const text2 = rawText.slice(headerEnd.index + headerEnd[0].length).trim();
8735
+ return { messageType, text: text2 };
8663
8736
  }
8664
8737
  function agentNameFromPath(agentPath) {
8665
8738
  const segments2 = agentPath.split(/[\\/]/).filter(Boolean);
@@ -8671,8 +8744,8 @@ function readableAgentPrompt(value) {
8671
8744
  if (/^gAAAAA[A-Za-z0-9_-]+$/.test(prompt)) return "";
8672
8745
  return prompt;
8673
8746
  }
8674
- function normalizePromptText(text) {
8675
- const trimmed = text.trim();
8747
+ function normalizePromptText(text2) {
8748
+ const trimmed = text2.trim();
8676
8749
  if (!trimmed) return "";
8677
8750
  if (SKIP_PROMPT_PREFIXES.some((prefix) => trimmed.startsWith(prefix))) return "";
8678
8751
  return trimmed;
@@ -8702,9 +8775,9 @@ function parseTokenUsage(value) {
8702
8775
  cache_read_input_tokens: cacheRead
8703
8776
  };
8704
8777
  }
8705
- function appendThinking(turn, text, timestamp2) {
8706
- if (!text) return;
8707
- const block = { type: "thinking", thinking: text, signature: "" };
8778
+ function appendThinking(turn, text2, timestamp2) {
8779
+ if (!text2) return;
8780
+ const block = { type: "thinking", thinking: text2, signature: "" };
8708
8781
  turn.thinking.push(block);
8709
8782
  const last = turn.contentBlocks[turn.contentBlocks.length - 1];
8710
8783
  if (last && last.kind === "thinking") {
@@ -8764,11 +8837,12 @@ function parseMcpEventResult(value) {
8764
8837
  if ("Err" in value) return { text: safeStringify(value.Err), isError: true };
8765
8838
  const ok = isObject2(value.Ok) ? value.Ok : null;
8766
8839
  if (!ok) return { text: safeStringify(value), isError: false };
8767
- const parsedContent = parseCustomToolOutput(ok.content);
8768
- const text = parsedContent.text || (ok.structuredContent !== void 0 ? safeStringify(ok.structuredContent) : safeStringify(ok));
8840
+ const parsedContent = parseCustomToolOutput({ ...ok, content: ok.content });
8841
+ const text2 = parsedContent.text || (parsedContent.images?.length ? "" : ok.structuredContent !== void 0 ? safeStringify(ok.structuredContent) : safeStringify(ok));
8769
8842
  return {
8770
- text,
8771
- isError: ok.isError === true || parsedContent.isError
8843
+ ...parsedContent,
8844
+ text: text2,
8845
+ isError: parsedContent.isError
8772
8846
  };
8773
8847
  }
8774
8848
  function createTurn(turnId, timestamp2, model) {
@@ -8786,22 +8860,22 @@ function createTurn(turnId, timestamp2, model) {
8786
8860
  model
8787
8861
  };
8788
8862
  }
8789
- function extractPromptFromRecord(record4) {
8790
- if (record4.type === "event_msg" && isObject2(record4.payload) && record4.payload.type === "user_message" && typeof record4.payload.message === "string") {
8791
- return normalizePromptText(record4.payload.message);
8863
+ function extractPromptFromRecord(record5) {
8864
+ if (record5.type === "event_msg" && isObject2(record5.payload) && record5.payload.type === "user_message" && typeof record5.payload.message === "string") {
8865
+ return normalizePromptText(record5.payload.message);
8792
8866
  }
8793
- if (record4.type === "response_item" && isObject2(record4.payload) && record4.payload.type === "message" && record4.payload.role === "user") {
8794
- return normalizePromptText(extractMessageText(record4.payload, "input_text"));
8867
+ if (record5.type === "response_item" && isObject2(record5.payload) && record5.payload.type === "message" && record5.payload.role === "user") {
8868
+ return normalizePromptText(extractMessageText(record5.payload, "input_text"));
8795
8869
  }
8796
8870
  return "";
8797
8871
  }
8798
- function recordOpensTurn(record4, payload) {
8799
- if (record4.type === "session_meta") return false;
8800
- if (record4.type === "event_msg" && payload?.type === "task_started") return false;
8801
- if (record4.type === "response_item" && payload?.type === "message") {
8872
+ function recordOpensTurn(record5, payload) {
8873
+ if (record5.type === "session_meta") return false;
8874
+ if (record5.type === "event_msg" && payload?.type === "task_started") return false;
8875
+ if (record5.type === "response_item" && payload?.type === "message") {
8802
8876
  if (payload.role === "developer" || payload.role === "system") return false;
8803
8877
  if (payload.role === "user") {
8804
- return extractPromptFromRecord(record4) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
8878
+ return extractPromptFromRecord(record5) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
8805
8879
  }
8806
8880
  }
8807
8881
  return true;
@@ -8822,22 +8896,22 @@ function extractMetadataFromRecords(records) {
8822
8896
  let parentSessionId = null;
8823
8897
  let agentPath = "/root";
8824
8898
  let previousPrompt = "";
8825
- for (const record4 of records) {
8826
- if (!isObject2(record4.payload)) continue;
8827
- if (record4.type === "session_meta") {
8828
- sessionId ||= typeof record4.payload.id === "string" ? record4.payload.id : "";
8829
- version ||= typeof record4.payload.cli_version === "string" ? record4.payload.cli_version : "";
8830
- cwd ||= typeof record4.payload.cwd === "string" ? record4.payload.cwd : "";
8831
- if (!branchedFrom && isObject2(record4.payload.branchedFrom)) {
8832
- const sourceId = typeof record4.payload.branchedFrom.sessionId === "string" ? record4.payload.branchedFrom.sessionId : "";
8899
+ for (const record5 of records) {
8900
+ if (!isObject2(record5.payload)) continue;
8901
+ if (record5.type === "session_meta") {
8902
+ sessionId ||= typeof record5.payload.id === "string" ? record5.payload.id : "";
8903
+ version ||= typeof record5.payload.cli_version === "string" ? record5.payload.cli_version : "";
8904
+ cwd ||= typeof record5.payload.cwd === "string" ? record5.payload.cwd : "";
8905
+ if (!branchedFrom && isObject2(record5.payload.branchedFrom)) {
8906
+ const sourceId = typeof record5.payload.branchedFrom.sessionId === "string" ? record5.payload.branchedFrom.sessionId : "";
8833
8907
  if (sourceId) {
8834
8908
  branchedFrom = {
8835
8909
  sessionId: sourceId,
8836
- turnIndex: typeof record4.payload.branchedFrom.turnIndex === "number" ? record4.payload.branchedFrom.turnIndex : null
8910
+ turnIndex: typeof record5.payload.branchedFrom.turnIndex === "number" ? record5.payload.branchedFrom.turnIndex : null
8837
8911
  };
8838
8912
  }
8839
8913
  }
8840
- const source = isObject2(record4.payload.source) ? record4.payload.source : null;
8914
+ const source = isObject2(record5.payload.source) ? record5.payload.source : null;
8841
8915
  if (source && isObject2(source.subagent)) {
8842
8916
  isSubagent = true;
8843
8917
  const threadSpawn = isObject2(source.subagent.thread_spawn) ? source.subagent.thread_spawn : null;
@@ -8845,25 +8919,25 @@ function extractMetadataFromRecords(records) {
8845
8919
  agentPath = threadSpawn.agent_path;
8846
8920
  }
8847
8921
  }
8848
- if (typeof record4.payload.forked_from_id === "string" && record4.payload.forked_from_id) {
8849
- parentSessionId = record4.payload.forked_from_id;
8922
+ if (typeof record5.payload.forked_from_id === "string" && record5.payload.forked_from_id) {
8923
+ parentSessionId = record5.payload.forked_from_id;
8850
8924
  }
8851
- const git = isObject2(record4.payload.git) ? record4.payload.git : null;
8925
+ const git = isObject2(record5.payload.git) ? record5.payload.git : null;
8852
8926
  gitBranch ||= git && typeof git.branch === "string" ? git.branch : "";
8853
8927
  }
8854
- if (record4.type === "turn_context") {
8855
- model ||= typeof record4.payload.model === "string" ? record4.payload.model : "";
8856
- cwd ||= typeof record4.payload.cwd === "string" ? record4.payload.cwd : "";
8928
+ if (record5.type === "turn_context") {
8929
+ model ||= typeof record5.payload.model === "string" ? record5.payload.model : "";
8930
+ cwd ||= typeof record5.payload.cwd === "string" ? record5.payload.cwd : "";
8857
8931
  }
8858
- const prompt = extractPromptFromRecord(record4);
8932
+ const prompt = extractPromptFromRecord(record5);
8859
8933
  if (!prompt) continue;
8860
8934
  if (prompt === previousPrompt) continue;
8861
8935
  if (!firstUserMessage) firstUserMessage = prompt;
8862
8936
  lastUserMessage = prompt;
8863
8937
  previousPrompt = prompt;
8864
8938
  turnCount++;
8865
- if (!timestamp2) timestamp2 = record4.timestamp ?? "";
8866
- lastTimestamp = record4.timestamp ?? lastTimestamp;
8939
+ if (!timestamp2) timestamp2 = record5.timestamp ?? "";
8940
+ lastTimestamp = record5.timestamp ?? lastTimestamp;
8867
8941
  }
8868
8942
  if (lastTimestamp === "") lastTimestamp = timestamp2;
8869
8943
  return {
@@ -9021,19 +9095,19 @@ function walkCodexRecords(records, options) {
9021
9095
  appendToolCall(targetTurn, toolCall, timestamp2);
9022
9096
  }
9023
9097
  for (let index = 0; index < records.length; index++) {
9024
- const record4 = records[index];
9025
- if (!isCodexRecord(record4)) continue;
9098
+ const record5 = records[index];
9099
+ if (!isCodexRecord(record5)) continue;
9026
9100
  recordIndex = index;
9027
- const payload = isObject2(record4.payload) ? record4.payload : void 0;
9028
- const timestamp2 = record4.timestamp ?? "";
9029
- if (record4.type === "compacted") {
9101
+ const payload = isObject2(record5.payload) ? record5.payload : void 0;
9102
+ const timestamp2 = record5.timestamp ?? "";
9103
+ if (record5.type === "compacted") {
9030
9104
  current = commitTurn(current);
9031
9105
  pendingCompaction = "Conversation compacted";
9032
9106
  lastTurnTimestamp = timestamp2;
9033
9107
  continue;
9034
9108
  }
9035
- if (record4.type === "world_state") continue;
9036
- if (record4.type === "turn_context") {
9109
+ if (record5.type === "world_state") continue;
9110
+ if (record5.type === "turn_context") {
9037
9111
  current = commitTurn(current);
9038
9112
  pendingContextIndex = index;
9039
9113
  currentTurnId = typeof payload?.turn_id === "string" ? payload.turn_id : null;
@@ -9042,7 +9116,7 @@ function walkCodexRecords(records, options) {
9042
9116
  sawTurnStart = true;
9043
9117
  continue;
9044
9118
  }
9045
- if (record4.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
9119
+ if (record5.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
9046
9120
  if (current && (current.assistantText.length > 0 || current.toolCalls.length > 0 || current.thinking.length > 0)) {
9047
9121
  current = commitTurn(current);
9048
9122
  }
@@ -9066,12 +9140,12 @@ function walkCodexRecords(records, options) {
9066
9140
  lastTurnTimestamp = timestamp2;
9067
9141
  continue;
9068
9142
  }
9069
- if (!current && !recordOpensTurn(record4, payload)) continue;
9143
+ if (!current && !recordOpensTurn(record5, payload)) continue;
9070
9144
  current ??= createActiveTurn(currentTurnId, timestamp2, currentModel);
9071
9145
  if (!current.model && currentModel) current.model = currentModel;
9072
9146
  if (!current.timestamp) current.timestamp = timestamp2;
9073
9147
  if (timestamp2) lastTurnTimestamp = timestamp2;
9074
- if (record4.type === "event_msg" && payload?.type === "token_count") {
9148
+ if (record5.type === "event_msg" && payload?.type === "token_count") {
9075
9149
  const info = isObject2(payload.info) ? payload.info : null;
9076
9150
  const lastUsage = info ? parseTokenUsage(info.last_token_usage) : null;
9077
9151
  if (lastUsage) {
@@ -9079,14 +9153,14 @@ function walkCodexRecords(records, options) {
9079
9153
  }
9080
9154
  continue;
9081
9155
  }
9082
- if (record4.type === "event_msg" && payload?.type === "web_search_end" && typeof payload.call_id === "string") {
9156
+ if (record5.type === "event_msg" && payload?.type === "web_search_end" && typeof payload.call_id === "string") {
9083
9157
  const input = {};
9084
9158
  if (typeof payload.query === "string" && payload.query) input.query = payload.query;
9085
9159
  if (isObject2(payload.action)) input.action = payload.action;
9086
9160
  upsertWebSearchCall(current, payload.call_id, input, "completed", timestamp2);
9087
9161
  continue;
9088
9162
  }
9089
- if (record4.type === "event_msg" && payload?.type === "mcp_tool_call_end" && typeof payload.call_id === "string" && isObject2(payload.invocation)) {
9163
+ if (record5.type === "event_msg" && payload?.type === "mcp_tool_call_end" && typeof payload.call_id === "string" && isObject2(payload.invocation)) {
9090
9164
  const invocation = payload.invocation;
9091
9165
  const server = typeof invocation.server === "string" ? invocation.server : "mcp";
9092
9166
  const tool = typeof invocation.tool === "string" ? invocation.tool : "tool";
@@ -9096,6 +9170,7 @@ function walkCodexRecords(records, options) {
9096
9170
  if (existing) {
9097
9171
  existing.result = result.text;
9098
9172
  existing.isError = result.isError;
9173
+ if (result.images) existing.resultImages = result.images;
9099
9174
  pendingToolCalls.delete(payload.call_id);
9100
9175
  } else if (!isCodeModeChild(payload.call_id)) {
9101
9176
  appendToolCall(current, {
@@ -9104,12 +9179,13 @@ function walkCodexRecords(records, options) {
9104
9179
  input,
9105
9180
  result: result.text,
9106
9181
  isError: result.isError,
9182
+ ...result.images ? { resultImages: result.images } : {},
9107
9183
  timestamp: timestamp2
9108
9184
  }, timestamp2);
9109
9185
  }
9110
9186
  continue;
9111
9187
  }
9112
- if (record4.type === "event_msg" && payload?.type === "sub_agent_activity" && typeof payload.agent_thread_id === "string" && typeof payload.agent_path === "string") {
9188
+ if (record5.type === "event_msg" && payload?.type === "sub_agent_activity" && typeof payload.agent_thread_id === "string" && typeof payload.agent_path === "string") {
9113
9189
  const agentId = payload.agent_thread_id;
9114
9190
  const eventId2 = typeof payload.event_id === "string" ? payload.event_id : "";
9115
9191
  const kind = typeof payload.kind === "string" ? payload.kind : "started";
@@ -9143,7 +9219,7 @@ function walkCodexRecords(records, options) {
9143
9219
  upsertAgentMessage(agentId, current, timestamp2, { status });
9144
9220
  continue;
9145
9221
  }
9146
- if (record4.type !== "response_item" || !payload) continue;
9222
+ if (record5.type !== "response_item" || !payload) continue;
9147
9223
  if (payload.type === "reasoning") {
9148
9224
  const summary = Array.isArray(payload.summary) ? payload.summary.filter((item) => typeof item === "string").join("\n") : "";
9149
9225
  appendThinking(current, summary.trim(), timestamp2);
@@ -9154,11 +9230,11 @@ function walkCodexRecords(records, options) {
9154
9230
  continue;
9155
9231
  }
9156
9232
  if (payload.type === "message" && payload.role === "user" && current.userMessage === null) {
9157
- const text = normalizePromptText(extractMessageText(payload, "input_text"));
9233
+ const text2 = normalizePromptText(extractMessageText(payload, "input_text"));
9158
9234
  const images = extractResponseMessageImages(payload);
9159
9235
  const audio = extractResponseMessageAudio(payload);
9160
- if (text || images.length > 0 || audio.length > 0) {
9161
- current.userMessage = buildCodexUserContent(text, images, audio);
9236
+ if (text2 || images.length > 0 || audio.length > 0) {
9237
+ current.userMessage = buildCodexUserContent(text2, images, audio);
9162
9238
  current.isFragment = false;
9163
9239
  sawTurnStart = true;
9164
9240
  }
@@ -9270,9 +9346,11 @@ function walkCodexRecords(records, options) {
9270
9346
  if (payload.type === "function_call_output" && typeof payload.call_id === "string") {
9271
9347
  const toolCall = pendingToolCalls.get(payload.call_id);
9272
9348
  if (!toolCall) continue;
9273
- const output = typeof payload.output === "string" ? payload.output : null;
9349
+ const parsedOutput = parseCustomToolOutput(payload.output);
9350
+ const output = parsedOutput.text;
9274
9351
  toolCall.result = output;
9275
- toolCall.isError = inferToolError(output);
9352
+ toolCall.isError = parsedOutput.isError;
9353
+ if (parsedOutput.images) toolCall.resultImages = parsedOutput.images;
9276
9354
  pendingToolCalls.delete(payload.call_id);
9277
9355
  if (toolCall.name === "spawn_agent" && output) {
9278
9356
  try {
@@ -9334,7 +9412,7 @@ function walkCodexRecords(records, options) {
9334
9412
  continue;
9335
9413
  }
9336
9414
  if (payload.type === "custom_tool_call" && typeof payload.call_id === "string") {
9337
- const name = typeof payload.name === "string" ? payload.name : "tool";
9415
+ const name = normalizeFunctionName(typeof payload.name === "string" ? payload.name : "tool");
9338
9416
  const rawInput = typeof payload.input === "string" ? payload.input : "";
9339
9417
  const callId = payload.call_id;
9340
9418
  const perFileCalls = rawInput ? parseCodexToolPatches(name, rawInput, callId, timestamp2, metadata.cwd) : [];
@@ -9364,14 +9442,14 @@ function walkCodexRecords(records, options) {
9364
9442
  }
9365
9443
  if (payload.type === "custom_tool_call_output" && typeof payload.call_id === "string") {
9366
9444
  const callId = payload.call_id;
9367
- const { text, isError } = parseCustomToolOutput(payload.output);
9445
+ const { text: text2, isError, images } = parseCustomToolOutput(payload.output);
9368
9446
  const patchCalls = patchCallIds.get(callId);
9369
9447
  if (patchCalls) {
9370
- const failedIds = patchCalls.direct && isError ? new Set(patchCalls.calls.map((call) => call.id)) : findFailedNestedPatchCallIds(text, isError, patchCalls.calls);
9448
+ const failedIds = patchCalls.direct && isError ? new Set(patchCalls.calls.map((call) => call.id)) : findFailedNestedPatchCallIds(text2, isError, patchCalls.calls);
9371
9449
  for (const patchCall of patchCalls.calls) {
9372
9450
  const tc = pendingToolCalls.get(patchCall.id);
9373
9451
  if (tc) {
9374
- tc.result = text;
9452
+ tc.result = text2;
9375
9453
  tc.isError = failedIds.has(tc.id);
9376
9454
  pendingToolCalls.delete(tc.id);
9377
9455
  }
@@ -9380,8 +9458,9 @@ function walkCodexRecords(records, options) {
9380
9458
  }
9381
9459
  const toolCall = pendingToolCalls.get(callId);
9382
9460
  if (toolCall) {
9383
- toolCall.result = text;
9461
+ toolCall.result = text2;
9384
9462
  toolCall.isError = isError;
9463
+ if (images) toolCall.resultImages = images;
9385
9464
  pendingToolCalls.delete(callId);
9386
9465
  }
9387
9466
  continue;
@@ -9413,7 +9492,7 @@ function parseCodexSession(jsonlText, options) {
9413
9492
  return session;
9414
9493
  }
9415
9494
  function appendCodexSession(existing, newJsonlText) {
9416
- const prefix = existing.rawMessages.map((record4) => JSON.stringify(record4)).join("\n");
9495
+ const prefix = existing.rawMessages.map((record5) => JSON.stringify(record5)).join("\n");
9417
9496
  return parseCodexSession(prefix ? `${prefix}
9418
9497
  ${newJsonlText}` : newJsonlText);
9419
9498
  }
@@ -9513,8 +9592,8 @@ function collectCodexPendingAgents(rawMessages) {
9513
9592
  continue;
9514
9593
  }
9515
9594
  if (payload.type === "agent_message" && typeof payload.author === "string") {
9516
- const text = codexPayloadText(payload);
9517
- const messageType = text.match(/^Message Type:\s*([^\r\n]+)/)?.[1]?.trim().toUpperCase() ?? "";
9595
+ const text2 = codexPayloadText(payload);
9596
+ const messageType = text2.match(/^Message Type:\s*([^\r\n]+)/)?.[1]?.trim().toUpperCase() ?? "";
9518
9597
  if (!TERMINAL_INTER_AGENT_TYPES.has(messageType)) continue;
9519
9598
  const agentId = agentIdByPath.get(payload.author) ?? payload.author;
9520
9599
  done.add(agentId);
@@ -9608,16 +9687,16 @@ async function readCodexSessionIdentity(filePath) {
9608
9687
  let parentSessionId = null;
9609
9688
  let sawSessionMeta = false;
9610
9689
  for (const line of await readHeadLines(filePath, HEAD_BYTES)) {
9611
- let record4;
9690
+ let record5;
9612
9691
  try {
9613
- record4 = JSON.parse(line);
9692
+ record5 = JSON.parse(line);
9614
9693
  } catch {
9615
9694
  continue;
9616
9695
  }
9617
- if (!isRecord2(record4) || !isRecord2(record4.payload)) continue;
9618
- if (record4.type === "session_meta") {
9696
+ if (!isRecord2(record5) || !isRecord2(record5.payload)) continue;
9697
+ if (record5.type === "session_meta") {
9619
9698
  sawSessionMeta = true;
9620
- const payload = record4.payload;
9699
+ const payload = record5.payload;
9621
9700
  if (!sessionId && typeof payload.id === "string") sessionId = payload.id;
9622
9701
  if (!cwd && typeof payload.cwd === "string") cwd = payload.cwd;
9623
9702
  if (!parentSessionId && typeof payload.forked_from_id === "string") {
@@ -9627,8 +9706,8 @@ async function readCodexSessionIdentity(filePath) {
9627
9706
  if (source && isRecord2(source.subagent)) isSubagent = true;
9628
9707
  const git = isRecord2(payload.git) ? payload.git : null;
9629
9708
  if (!gitBranch && git && typeof git.branch === "string") gitBranch = git.branch;
9630
- } else if (record4.type === "turn_context") {
9631
- if (!cwd && typeof record4.payload.cwd === "string") cwd = record4.payload.cwd;
9709
+ } else if (record5.type === "turn_context") {
9710
+ if (!cwd && typeof record5.payload.cwd === "string") cwd = record5.payload.cwd;
9632
9711
  }
9633
9712
  }
9634
9713
  if (!sawSessionMeta || !cwd) return null;
@@ -10028,8 +10107,8 @@ function textFromValue(value) {
10028
10107
  if (typeof value === "string") return value;
10029
10108
  if (!Array.isArray(value)) return "";
10030
10109
  return value.flatMap((part) => {
10031
- const text = typeof part === "string" ? part : isObject3(part) ? readString(part.text, part.content) : "";
10032
- return text ? [text] : [];
10110
+ const text2 = typeof part === "string" ? part : isObject3(part) ? readString(part.text, part.content) : "";
10111
+ return text2 ? [text2] : [];
10033
10112
  }).join("\n");
10034
10113
  }
10035
10114
  function collectBinaryAssets(events) {
@@ -10069,10 +10148,10 @@ function extractImages(values, assets) {
10069
10148
  return images;
10070
10149
  }
10071
10150
  function buildUserContent(data, assets) {
10072
- const text = readString(data.content);
10151
+ const text2 = readString(data.content);
10073
10152
  const images = extractImages(data.attachments, assets);
10074
- if (images.length === 0) return text;
10075
- return [...images, ...text ? [{ type: "text", text }] : []];
10153
+ if (images.length === 0) return text2;
10154
+ return [...images, ...text2 ? [{ type: "text", text: text2 }] : []];
10076
10155
  }
10077
10156
  function extractToolResultImages(data, assets) {
10078
10157
  if (!isObject3(data.result)) return [];
@@ -10201,17 +10280,17 @@ function extractToolResult(data) {
10201
10280
  if (typeof result.content === "string") return result.content;
10202
10281
  if (Array.isArray(result.contents)) {
10203
10282
  const content = result.contents.flatMap((part) => {
10204
- const text = typeof part === "string" ? part : isObject3(part) ? readString(part.text, part.content, part.output) : "";
10205
- return text ? [text] : [];
10283
+ const text2 = typeof part === "string" ? part : isObject3(part) ? readString(part.text, part.content, part.output) : "";
10284
+ return text2 ? [text2] : [];
10206
10285
  }).join("\n");
10207
10286
  if (content) return content;
10208
10287
  }
10209
10288
  if (result.structuredContent !== void 0) return safeStringify2(result.structuredContent);
10210
10289
  return safeStringify2(result);
10211
10290
  }
10212
- function appendThinking2(turn, text, timestamp2, signature) {
10213
- if (!text || turn.thinking.some((block2) => block2.thinking === text)) return;
10214
- const block = { type: "thinking", thinking: text, signature };
10291
+ function appendThinking2(turn, text2, timestamp2, signature) {
10292
+ if (!text2 || turn.thinking.some((block2) => block2.thinking === text2)) return;
10293
+ const block = { type: "thinking", thinking: text2, signature };
10215
10294
  turn.thinking.push(block);
10216
10295
  const last = turn.contentBlocks[turn.contentBlocks.length - 1];
10217
10296
  if (last?.kind === "thinking") {
@@ -10389,8 +10468,8 @@ function parseCopilotSession(jsonlText, options) {
10389
10468
  message.model = readString(data.model) || message.model;
10390
10469
  const reasoning = readString(data.reasoningText);
10391
10470
  if (reasoning && !message.thinking.includes(reasoning)) message.thinking.push(reasoning);
10392
- const text = textFromValue(data.content);
10393
- if (text && !message.text.includes(text)) message.text.push(text);
10471
+ const text2 = textFromValue(data.content);
10472
+ if (text2 && !message.text.includes(text2)) message.text.push(text2);
10394
10473
  for (const call of toolCallsFromRequests(
10395
10474
  data.toolRequests,
10396
10475
  timestamp2,
@@ -10645,7 +10724,7 @@ function parseCopilotSession(jsonlText, options) {
10645
10724
  };
10646
10725
  }
10647
10726
  function appendCopilotSession(existing, newJsonlText) {
10648
- const prefix = existing.rawMessages.map((record4) => JSON.stringify(record4)).join("\n");
10727
+ const prefix = existing.rawMessages.map((record5) => JSON.stringify(record5)).join("\n");
10649
10728
  return parseCopilotSession(prefix ? `${prefix}
10650
10729
  ${newJsonlText}` : newJsonlText);
10651
10730
  }
@@ -10753,11 +10832,11 @@ function brandCopilotBranch() {
10753
10832
  function copilotTurnBoundaries(records) {
10754
10833
  const boundaries = [];
10755
10834
  for (let index = 0; index < records.length; index++) {
10756
- const record4 = records[index];
10757
- if (record4.type !== "user.message" || typeof record4.agentId === "string") continue;
10758
- const data = record4.data;
10835
+ const record5 = records[index];
10836
+ if (record5.type !== "user.message" || typeof record5.agentId === "string") continue;
10837
+ const data = record5.data;
10759
10838
  if (!data || typeof data !== "object" || Array.isArray(data)) continue;
10760
- if (typeof record4.id !== "string" || !record4.id) continue;
10839
+ if (typeof record5.id !== "string" || !record5.id) continue;
10761
10840
  boundaries.push(index);
10762
10841
  }
10763
10842
  return boundaries;
@@ -10814,14 +10893,14 @@ async function readCopilotSessionIdentity(filePath) {
10814
10893
  let cwd = "";
10815
10894
  let gitBranch = "";
10816
10895
  for (const line of await readHeadLines(filePath, HEAD_BYTES)) {
10817
- let record4;
10896
+ let record5;
10818
10897
  try {
10819
- record4 = JSON.parse(line);
10898
+ record5 = JSON.parse(line);
10820
10899
  } catch {
10821
10900
  continue;
10822
10901
  }
10823
- if (!isRecord3(record4) || record4.type !== "session.start" && record4.type !== "session.resume") continue;
10824
- const data = isRecord3(record4.data) ? record4.data : null;
10902
+ if (!isRecord3(record5) || record5.type !== "session.start" && record5.type !== "session.resume") continue;
10903
+ const data = isRecord3(record5.data) ? record5.data : null;
10825
10904
  if (!data) continue;
10826
10905
  if (typeof data.sessionId === "string" && data.sessionId) sessionId = data.sessionId;
10827
10906
  const context = isRecord3(data.context) ? data.context : null;
@@ -11013,15 +11092,15 @@ function readSender(attrs) {
11013
11092
  }
11014
11093
  return null;
11015
11094
  }
11016
- function parseAgentEnvelope(text) {
11095
+ function parseAgentEnvelope(text2) {
11017
11096
  let sender = null;
11018
11097
  let matched = false;
11019
- const unwrapped = text.replace(ENVELOPE_RE, (_full, _tag, attrs, inner) => {
11098
+ const unwrapped = text2.replace(ENVELOPE_RE, (_full, _tag, attrs, inner) => {
11020
11099
  matched = true;
11021
11100
  if (sender === null) sender = readSender(attrs);
11022
11101
  return inner.trim();
11023
11102
  });
11024
- return { sender, matched, body: matched ? unwrapped.trim() : text };
11103
+ return { sender, matched, body: matched ? unwrapped.trim() : text2 };
11025
11104
  }
11026
11105
  var ENVELOPE_RE, SENDER_PATTERNS;
11027
11106
  var init_agentEnvelope = __esm({
@@ -11055,9 +11134,9 @@ function isVisibleQueuedPrompt(content) {
11055
11134
  }
11056
11135
  function isTaskNotificationRecord(msg) {
11057
11136
  if (msg.origin?.kind === "task-notification") return true;
11058
- const text = extractTextFromContent(msg.message.content);
11059
- if (!text.includes("<task-notification>")) return false;
11060
- return text.replace(TASK_NOTIFICATION_BLOCK_RE, "").replace(ANY_TAG_RE, "").trim() === "";
11137
+ const text2 = extractTextFromContent(msg.message.content);
11138
+ if (!text2.includes("<task-notification>")) return false;
11139
+ return text2.replace(TASK_NOTIFICATION_BLOCK_RE, "").replace(ANY_TAG_RE, "").trim() === "";
11061
11140
  }
11062
11141
  function queuedCommandPrompt(msg) {
11063
11142
  if (!isAttachmentMessage(msg)) return null;
@@ -11109,8 +11188,8 @@ function mergeTokenUsage3(existing, incoming) {
11109
11188
  };
11110
11189
  }
11111
11190
  function extractCompactionSummary(content) {
11112
- const text = extractTextFromContent(content).trim();
11113
- return text.replace(RESUME_PREAMBLE_RE, "").replace(RESUME_INSTRUCTIONS_RE, "").trim();
11191
+ const text2 = extractTextFromContent(content).trim();
11192
+ return text2.replace(RESUME_PREAMBLE_RE, "").replace(RESUME_INSTRUCTIONS_RE, "").trim();
11114
11193
  }
11115
11194
  function normalizeCompactionMeta(meta) {
11116
11195
  if (!meta) return void 0;
@@ -11891,13 +11970,13 @@ function collectClaudeBackgroundWork(rawMessages) {
11891
11970
  const resolved = /* @__PURE__ */ new Set();
11892
11971
  const queuedIds = /* @__PURE__ */ new Set();
11893
11972
  const deliveredIds = /* @__PURE__ */ new Set();
11894
- function noteNotifications(text, sink) {
11895
- if (!text.includes(TASK_NOTIFICATION_MARKER)) return;
11896
- for (const match of text.matchAll(TASK_ID_RE)) {
11973
+ function noteNotifications(text2, sink) {
11974
+ if (!text2.includes(TASK_NOTIFICATION_MARKER)) return;
11975
+ for (const match of text2.matchAll(TASK_ID_RE)) {
11897
11976
  resolved.add(match[1]);
11898
11977
  sink?.add(match[1]);
11899
11978
  }
11900
- for (const match of text.matchAll(TOOL_USE_ID_RE)) {
11979
+ for (const match of text2.matchAll(TOOL_USE_ID_RE)) {
11901
11980
  resolved.add(match[1]);
11902
11981
  sink?.add(match[1]);
11903
11982
  }
@@ -11913,7 +11992,7 @@ function collectClaudeBackgroundWork(rawMessages) {
11913
11992
  const description = [toolUseResult.description, toolUseResult.workflowName, toolUseResult.summary].find((value) => typeof value === "string" && value.length > 0) ?? "";
11914
11993
  if (ids.length > 0) launches.push({ ids, description });
11915
11994
  }
11916
- for (const text of userMessageTexts(msg)) noteNotifications(text, deliveredIds);
11995
+ for (const text2 of userMessageTexts(msg)) noteNotifications(text2, deliveredIds);
11917
11996
  continue;
11918
11997
  }
11919
11998
  if (msg.type === "assistant") {
@@ -12181,12 +12260,12 @@ function isRecord4(value) {
12181
12260
  function nonEmpty(value) {
12182
12261
  return typeof value === "string" && value ? value : null;
12183
12262
  }
12184
- function stripTaggedBlocks(text) {
12185
- return text.replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g, "").trim();
12263
+ function stripTaggedBlocks(text2) {
12264
+ return text2.replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g, "").trim();
12186
12265
  }
12187
- function effortFromRecord(record4) {
12266
+ function effortFromRecord(record5) {
12188
12267
  for (const kind of AGENT_KINDS) {
12189
- const effort = READERS[kind].effort(record4);
12268
+ const effort = READERS[kind].effort(record5);
12190
12269
  if (effort) return effort;
12191
12270
  }
12192
12271
  return null;
@@ -12196,16 +12275,16 @@ function userMessageTextFromLine(line) {
12196
12275
  (kind) => READERS[kind].userMessageMarkers.some((marker) => line.includes(marker))
12197
12276
  );
12198
12277
  if (candidates.length === 0) return null;
12199
- let record4;
12278
+ let record5;
12200
12279
  try {
12201
- record4 = JSON.parse(line);
12280
+ record5 = JSON.parse(line);
12202
12281
  } catch {
12203
12282
  return null;
12204
12283
  }
12205
- if (!isRecord4(record4)) return null;
12284
+ if (!isRecord4(record5)) return null;
12206
12285
  for (const kind of candidates) {
12207
- const text = READERS[kind].userMessageText(record4);
12208
- if (text !== null) return text;
12286
+ const text2 = READERS[kind].userMessageText(record5);
12287
+ if (text2 !== null) return text2;
12209
12288
  }
12210
12289
  return null;
12211
12290
  }
@@ -12216,51 +12295,51 @@ var init_recordReaders = __esm({
12216
12295
  claudeReader = {
12217
12296
  kind: "claude",
12218
12297
  // Every assistant record is tagged with the effort that turn ran at.
12219
- effort: (record4) => record4.type === "assistant" ? nonEmpty(record4.effort) : null,
12298
+ effort: (record5) => record5.type === "assistant" ? nonEmpty(record5.effort) : null,
12220
12299
  userMessageMarkers: ['"user"'],
12221
- userMessageText(record4) {
12222
- if (record4.type !== "user" || record4.isMeta) return null;
12223
- const content = isRecord4(record4.message) ? record4.message.content : void 0;
12300
+ userMessageText(record5) {
12301
+ if (record5.type !== "user" || record5.isMeta) return null;
12302
+ const content = isRecord4(record5.message) ? record5.message.content : void 0;
12224
12303
  if (typeof content === "string") return stripTaggedBlocks(content);
12225
12304
  if (!Array.isArray(content)) return "";
12226
- let text = "";
12305
+ let text2 = "";
12227
12306
  for (const block of content) {
12228
12307
  if (isRecord4(block) && block.type === "text" && typeof block.text === "string") {
12229
- text += stripTaggedBlocks(block.text) + " ";
12308
+ text2 += stripTaggedBlocks(block.text) + " ";
12230
12309
  }
12231
12310
  }
12232
- return text.trim();
12311
+ return text2.trim();
12233
12312
  }
12234
12313
  };
12235
12314
  codexReader = {
12236
12315
  kind: "codex",
12237
12316
  // Effort is recorded per turn; newer CLI versions moved it under `thread_settings`.
12238
- effort(record4) {
12239
- if (record4.type !== "turn_context" || !isRecord4(record4.payload)) return null;
12240
- const { payload } = record4;
12317
+ effort(record5) {
12318
+ if (record5.type !== "turn_context" || !isRecord4(record5.payload)) return null;
12319
+ const { payload } = record5;
12241
12320
  const direct = nonEmpty(payload.effort);
12242
12321
  if (direct) return direct;
12243
12322
  const settings = isRecord4(payload.thread_settings) ? payload.thread_settings : null;
12244
12323
  return nonEmpty(settings?.reasoning_effort);
12245
12324
  },
12246
12325
  userMessageMarkers: ['"event_msg"'],
12247
- userMessageText(record4) {
12248
- if (record4.type !== "event_msg" || !isRecord4(record4.payload)) return null;
12249
- const { payload } = record4;
12326
+ userMessageText(record5) {
12327
+ if (record5.type !== "event_msg" || !isRecord4(record5.payload)) return null;
12328
+ const { payload } = record5;
12250
12329
  return payload.type === "user_message" && typeof payload.message === "string" ? payload.message.trim() : null;
12251
12330
  }
12252
12331
  };
12253
12332
  copilotReader = {
12254
12333
  kind: "copilot",
12255
- effort(record4) {
12256
- if (record4.type !== "session.start" && record4.type !== "session.resume" && record4.type !== "session.model_change" || !isRecord4(record4.data)) return null;
12257
- return nonEmpty(record4.data.reasoningEffort ?? record4.data.effort);
12334
+ effort(record5) {
12335
+ if (record5.type !== "session.start" && record5.type !== "session.resume" && record5.type !== "session.model_change" || !isRecord4(record5.data)) return null;
12336
+ return nonEmpty(record5.data.reasoningEffort ?? record5.data.effort);
12258
12337
  },
12259
12338
  userMessageMarkers: ['"user.message"'],
12260
- userMessageText(record4) {
12261
- if (record4.type !== "user.message") return null;
12262
- if (typeof record4.agentId === "string" && record4.agentId) return null;
12263
- const data = isRecord4(record4.data) ? record4.data : null;
12339
+ userMessageText(record5) {
12340
+ if (record5.type !== "user.message") return null;
12341
+ if (typeof record5.agentId === "string" && record5.agentId) return null;
12342
+ const data = isRecord4(record5.data) ? record5.data : null;
12264
12343
  return typeof data?.content === "string" ? data.content.trim() : "";
12265
12344
  }
12266
12345
  };
@@ -12273,16 +12352,16 @@ var init_recordReaders = __esm({
12273
12352
  });
12274
12353
 
12275
12354
  // ../../server/agents/tailRecords.ts
12276
- function isSubagentLifecycle(record4) {
12277
- return record4.type.startsWith("subagent.") && typeof record4.agentId === "string" && record4.agentId.length > 0;
12355
+ function isSubagentLifecycle(record5) {
12356
+ return record5.type.startsWith("subagent.") && typeof record5.agentId === "string" && record5.agentId.length > 0;
12278
12357
  }
12279
- function isSubagentNoise(record4) {
12280
- return typeof record4.agentId === "string" && record4.agentId.length > 0;
12358
+ function isSubagentNoise(record5) {
12359
+ return typeof record5.agentId === "string" && record5.agentId.length > 0;
12281
12360
  }
12282
- function classifyTailRecord(record4) {
12361
+ function classifyTailRecord(record5) {
12283
12362
  for (const kind of AGENT_KINDS) {
12284
12363
  const format = TAIL_FORMATS[kind];
12285
- const verdict = format.classify(record4);
12364
+ const verdict = format.classify(record5);
12286
12365
  if (verdict.kind !== "ignore") return { format, verdict };
12287
12366
  }
12288
12367
  return null;
@@ -12299,31 +12378,31 @@ var init_tailRecords = __esm({
12299
12378
  // Background agent/workflow launches, task notifications and TaskStop calls
12300
12379
  // can all still change a verdict that a turn-ending line looked to settle.
12301
12380
  markers: ["async_launched", "task-notification", '"TaskStop"'],
12302
- classify(record4) {
12303
- if (record4.type === "system" && record4.subtype === "terminal_reason") {
12304
- const reason = record4.reason;
12381
+ classify(record5) {
12382
+ if (record5.type === "system" && record5.subtype === "terminal_reason") {
12383
+ const reason = record5.reason;
12305
12384
  return reason ? { kind: "final", status: { status: "completed", terminalReason: reason } } : IGNORE;
12306
12385
  }
12307
- if (record4.type === "progress") {
12308
- const data = record4.data;
12386
+ if (record5.type === "progress") {
12387
+ const data = record5.data;
12309
12388
  if (data?.type !== "hook_progress") return IGNORE;
12310
12389
  const decision = data.decision ?? data.hookSpecificOutput?.permissionDecision;
12311
12390
  return decision === "defer" ? ANSWER : IGNORE;
12312
12391
  }
12313
- if (record4.type === "attachment") return KEEP;
12314
- if (record4.type === "assistant" || record4.type === "user" || record4.type === "queue-operation") {
12315
- const stopReason = record4.message?.stop_reason;
12316
- if (record4.type === "assistant" && stopReason === "end_turn") {
12392
+ if (record5.type === "attachment") return KEEP;
12393
+ if (record5.type === "assistant" || record5.type === "user" || record5.type === "queue-operation") {
12394
+ const stopReason = record5.message?.stop_reason;
12395
+ if (record5.type === "assistant" && stopReason === "end_turn") {
12317
12396
  return { kind: "turn-end", awaitUserActivity: true };
12318
12397
  }
12319
- const canDerive = record4.type === "assistant" || record4.type === "user" && !record4.isMeta;
12398
+ const canDerive = record5.type === "assistant" || record5.type === "user" && !record5.isMeta;
12320
12399
  return canDerive ? ANSWER : KEEP;
12321
12400
  }
12322
12401
  return IGNORE;
12323
12402
  },
12324
- classifyAfterTurnEnd(record4) {
12325
- if (record4.type !== "user" && record4.type !== "assistant" && record4.type !== "queue-operation" && record4.type !== "attachment") return IGNORE;
12326
- const isRealUserTurn = record4.type === "user" && !record4.isMeta;
12403
+ classifyAfterTurnEnd(record5) {
12404
+ if (record5.type !== "user" && record5.type !== "assistant" && record5.type !== "queue-operation" && record5.type !== "attachment") return IGNORE;
12405
+ const isRealUserTurn = record5.type === "user" && !record5.isMeta;
12327
12406
  return { kind: "keep", sawUserActivity: isRealUserTurn };
12328
12407
  }
12329
12408
  };
@@ -12342,9 +12421,9 @@ var init_tailRecords = __esm({
12342
12421
  "agent_message",
12343
12422
  "function_call_output"
12344
12423
  ],
12345
- classify(record4) {
12346
- if (record4.type === "event_msg") {
12347
- const payload = record4.payload;
12424
+ classify(record5) {
12425
+ if (record5.type === "event_msg") {
12426
+ const payload = record5.payload;
12348
12427
  switch (payload?.type) {
12349
12428
  case "task_complete":
12350
12429
  return { kind: "turn-end" };
@@ -12356,32 +12435,32 @@ var init_tailRecords = __esm({
12356
12435
  return IGNORE;
12357
12436
  }
12358
12437
  }
12359
- if (record4.type === "response_item") {
12360
- const payload = record4.payload;
12438
+ if (record5.type === "response_item") {
12439
+ const payload = record5.payload;
12361
12440
  const decides = payload?.type === "function_call" || payload?.type === "message" && (payload.role === "assistant" || payload.role === "user");
12362
12441
  return decides ? ANSWER : IGNORE;
12363
12442
  }
12364
12443
  return IGNORE;
12365
12444
  },
12366
- classifyAfterTurnEnd(record4) {
12367
- return record4.type === "event_msg" || record4.type === "response_item" ? KEEP : IGNORE;
12445
+ classifyAfterTurnEnd(record5) {
12446
+ return record5.type === "event_msg" || record5.type === "response_item" ? KEEP : IGNORE;
12368
12447
  }
12369
12448
  };
12370
12449
  copilotTail = {
12371
12450
  kind: "copilot",
12372
12451
  markers: ['"abort"', '"assistant.message"', '"user.message"', '"subagent.'],
12373
- classify(record4) {
12374
- if (isSubagentLifecycle(record4)) return KEEP;
12375
- const decidable = record4.type === "abort" || record4.type === "user.message" || record4.type.startsWith("assistant.") || record4.type.startsWith("permission.") || record4.type.startsWith("session.") || record4.type.startsWith("tool.") || record4.type.startsWith("user_input.");
12376
- if (!decidable || isSubagentNoise(record4)) return IGNORE;
12377
- if (record4.type === "assistant.turn_end") return { kind: "turn-end" };
12378
- if (record4.type === "session.start" || record4.type === "session.resume") return ANSWER;
12452
+ classify(record5) {
12453
+ if (isSubagentLifecycle(record5)) return KEEP;
12454
+ const decidable = record5.type === "abort" || record5.type === "user.message" || record5.type.startsWith("assistant.") || record5.type.startsWith("permission.") || record5.type.startsWith("session.") || record5.type.startsWith("tool.") || record5.type.startsWith("user_input.");
12455
+ if (!decidable || isSubagentNoise(record5)) return IGNORE;
12456
+ if (record5.type === "assistant.turn_end") return { kind: "turn-end" };
12457
+ if (record5.type === "session.start" || record5.type === "session.resume") return ANSWER;
12379
12458
  return { kind: "answer-if-active" };
12380
12459
  },
12381
- classifyAfterTurnEnd(record4) {
12382
- if (isSubagentLifecycle(record4)) return KEEP;
12383
- if (isSubagentNoise(record4)) return IGNORE;
12384
- const decides = record4.type === "abort" || record4.type === "assistant.message" || record4.type === "user.message";
12460
+ classifyAfterTurnEnd(record5) {
12461
+ if (isSubagentLifecycle(record5)) return KEEP;
12462
+ if (isSubagentNoise(record5)) return IGNORE;
12463
+ const decides = record5.type === "abort" || record5.type === "assistant.message" || record5.type === "user.message";
12385
12464
  return decides ? ANSWER : IGNORE;
12386
12465
  }
12387
12466
  };
@@ -12436,14 +12515,14 @@ async function readTranscriptEffort(filePath) {
12436
12515
  for (let i = lines.length - 1; i >= 0; i--) {
12437
12516
  const line = lines[i];
12438
12517
  if (!line || !line.includes("effort") && !line.includes("Effort")) continue;
12439
- let record4;
12518
+ let record5;
12440
12519
  try {
12441
- record4 = JSON.parse(line);
12520
+ record5 = JSON.parse(line);
12442
12521
  } catch {
12443
12522
  continue;
12444
12523
  }
12445
- if (typeof record4 !== "object" || record4 === null) continue;
12446
- const effort = effortFromRecord(record4);
12524
+ if (typeof record5 !== "object" || record5 === null) continue;
12525
+ const effort = effortFromRecord(record5);
12447
12526
  if (effort) return effort;
12448
12527
  }
12449
12528
  }
@@ -12471,22 +12550,22 @@ async function getSessionStatus(filePath) {
12471
12550
  cursor -= readSize;
12472
12551
  const buf = Buffer.alloc(readSize);
12473
12552
  const { bytesRead } = await fh.read(buf, 0, readSize, cursor);
12474
- const text = buf.subarray(0, bytesRead).toString("utf-8") + leftover;
12475
- const lines = text.split("\n");
12553
+ const text2 = buf.subarray(0, bytesRead).toString("utf-8") + leftover;
12554
+ const lines = text2.split("\n");
12476
12555
  leftover = cursor > 0 ? lines[0] : "";
12477
12556
  const startIdx = cursor > 0 ? 1 : 0;
12478
12557
  for (let i = lines.length - 1; i >= startIdx; i--) {
12479
12558
  const line = lines[i];
12480
12559
  if (!line) continue;
12481
12560
  if (turnEnded && !isTailCandidate(line, turnEnded)) continue;
12482
- let record4;
12561
+ let record5;
12483
12562
  try {
12484
- record4 = JSON.parse(line);
12563
+ record5 = JSON.parse(line);
12485
12564
  } catch {
12486
12565
  continue;
12487
12566
  }
12488
- if (typeof record4?.type !== "string") continue;
12489
- const match = turnEnded ? { format: turnEnded, verdict: turnEnded.classifyAfterTurnEnd(record4) } : classifyTailRecord(record4);
12567
+ if (typeof record5?.type !== "string") continue;
12568
+ const match = turnEnded ? { format: turnEnded, verdict: turnEnded.classifyAfterTurnEnd(record5) } : classifyTailRecord(record5);
12490
12569
  if (!match) continue;
12491
12570
  const { verdict } = match;
12492
12571
  switch (verdict.kind) {
@@ -12495,20 +12574,20 @@ async function getSessionStatus(filePath) {
12495
12574
  case "final":
12496
12575
  return verdict.status;
12497
12576
  case "keep":
12498
- meaningful.unshift(record4);
12577
+ meaningful.unshift(record5);
12499
12578
  if (verdict.sawUserActivity) needUserActivity = false;
12500
12579
  continue;
12501
12580
  case "answer":
12502
- meaningful.unshift(record4);
12581
+ meaningful.unshift(record5);
12503
12582
  return deriveSessionStatus(meaningful);
12504
12583
  case "answer-if-active": {
12505
- meaningful.unshift(record4);
12584
+ meaningful.unshift(record5);
12506
12585
  const status = deriveSessionStatus(meaningful);
12507
12586
  if (status.status !== "idle") return status;
12508
12587
  continue;
12509
12588
  }
12510
12589
  case "turn-end":
12511
- meaningful.unshift(record4);
12590
+ meaningful.unshift(record5);
12512
12591
  turnEnded = match.format;
12513
12592
  needUserActivity = verdict.awaitUserActivity === true;
12514
12593
  continue;
@@ -12523,12 +12602,12 @@ async function getSessionStatus(filePath) {
12523
12602
  return { status: "idle" };
12524
12603
  }
12525
12604
  }
12526
- function snippetAround(text, query4) {
12527
- const lower = text.toLowerCase();
12605
+ function snippetAround(text2, query4) {
12606
+ const lower = text2.toLowerCase();
12528
12607
  const idx = lower.indexOf(query4.toLowerCase());
12529
12608
  const start = Math.max(0, idx - 30);
12530
- const end = Math.min(text.length, idx + query4.length + 70);
12531
- const snippet = (start > 0 ? "..." : "") + text.slice(start, end).trim() + (end < text.length ? "..." : "");
12609
+ const end = Math.min(text2.length, idx + query4.length + 70);
12610
+ const snippet = (start > 0 ? "..." : "") + text2.slice(start, end).trim() + (end < text2.length ? "..." : "");
12532
12611
  return snippet.slice(0, 150);
12533
12612
  }
12534
12613
  async function searchSessionMessages(filePath, query4) {
@@ -12540,8 +12619,8 @@ async function searchSessionMessages(filePath, query4) {
12540
12619
  return null;
12541
12620
  }
12542
12621
  for (const line of content.split("\n")) {
12543
- const text = userMessageTextFromLine(line);
12544
- if (text !== null && text.toLowerCase().includes(q)) return snippetAround(text, query4);
12622
+ const text2 = userMessageTextFromLine(line);
12623
+ if (text2 !== null && text2.toLowerCase().includes(q)) return snippetAround(text2, query4);
12545
12624
  }
12546
12625
  return null;
12547
12626
  }
@@ -12847,10 +12926,10 @@ function transcriptPath2(dirName, sessionId) {
12847
12926
  }
12848
12927
  function turnResultFrom(result) {
12849
12928
  if (!result.is_error) return { isError: false };
12850
- const { result: text, subtype } = result;
12929
+ const { result: text2, subtype } = result;
12851
12930
  return {
12852
12931
  isError: true,
12853
- message: text != null ? String(text) : `Claude returned an error${subtype ? ` (${subtype})` : ""}`
12932
+ message: text2 != null ? String(text2) : `Claude returned an error${subtype ? ` (${subtype})` : ""}`
12854
12933
  };
12855
12934
  }
12856
12935
  async function awaitTranscript(filePath, isSettled) {
@@ -13200,7 +13279,7 @@ var init_package = __esm({
13200
13279
  package_default = {
13201
13280
  name: "cogpit",
13202
13281
  private: true,
13203
- version: "2.4.0",
13282
+ version: "2.5.0",
13204
13283
  description: "Control center for Claude Code, OpenAI Codex, and GitHub Copilot CLI sessions",
13205
13284
  license: "MIT",
13206
13285
  author: {
@@ -16209,17 +16288,17 @@ function parseJsonRecord(line) {
16209
16288
  }
16210
16289
  }
16211
16290
  function parseClaudeUsageLine(line) {
16212
- const record4 = parseJsonRecord(line);
16213
- if (!record4 || record4.type !== "assistant") return null;
16214
- const message = asRecord3(record4.message);
16291
+ const record5 = parseJsonRecord(line);
16292
+ if (!record5 || record5.type !== "assistant") return null;
16293
+ const message = asRecord3(record5.message);
16215
16294
  const usage = message ? asRecord3(message.usage) : null;
16216
16295
  if (!message || !usage) return null;
16217
- const timestampMs = parseTimestampMs(record4.timestamp);
16296
+ const timestampMs = parseTimestampMs(record5.timestamp);
16218
16297
  if (timestampMs === null) return null;
16219
16298
  const model = typeof message.model === "string" ? message.model : "";
16220
16299
  if (model.length === 0) return null;
16221
16300
  const messageId = typeof message.id === "string" ? message.id : null;
16222
- const requestId = typeof record4.requestId === "string" ? record4.requestId : null;
16301
+ const requestId = typeof record5.requestId === "string" ? record5.requestId : null;
16223
16302
  const dedupeKey = messageId === null && requestId === null ? null : `${messageId ?? ""}:${requestId ?? ""}`;
16224
16303
  const cacheCreationTokens = int(usage.cache_creation_input_tokens);
16225
16304
  const byTtl = asRecord3(usage.cache_creation);
@@ -16238,12 +16317,12 @@ function parseClaudeUsageLine(line) {
16238
16317
  reasoningTokens: 0
16239
16318
  };
16240
16319
  if (totalUsageCostTokens(totals) === 0) return null;
16241
- const cost = record4.costUSD;
16320
+ const cost = record5.costUSD;
16242
16321
  return {
16243
16322
  provider: "claude",
16244
16323
  timestampMs,
16245
16324
  model,
16246
- sessionId: typeof record4.sessionId === "string" ? record4.sessionId : "",
16325
+ sessionId: typeof record5.sessionId === "string" ? record5.sessionId : "",
16247
16326
  totals,
16248
16327
  reportedCostUsd: typeof cost === "number" && Number.isFinite(cost) ? cost : null,
16249
16328
  speed: requestSpeed(usage.speed ?? usage.service_tier),
@@ -16267,23 +16346,23 @@ function isForkedSessionMeta(payload) {
16267
16346
  return typeof spawn5?.parent_thread_id === "string";
16268
16347
  }
16269
16348
  function parseCodexUsageLine(line, state) {
16270
- const record4 = parseJsonRecord(line);
16271
- if (!record4) return null;
16272
- const payload = asRecord3(record4.payload);
16349
+ const record5 = parseJsonRecord(line);
16350
+ if (!record5) return null;
16351
+ const payload = asRecord3(record5.payload);
16273
16352
  if (!payload) return null;
16274
- if (record4.type === "session_meta") {
16353
+ if (record5.type === "session_meta") {
16275
16354
  if (state.sawSessionMeta) return null;
16276
16355
  state.sawSessionMeta = true;
16277
16356
  const id = payload.id ?? payload.session_id;
16278
16357
  if (typeof id === "string") state.sessionId = id;
16279
- const metaTimestampMs = parseTimestampMs(record4.timestamp);
16358
+ const metaTimestampMs = parseTimestampMs(record5.timestamp);
16280
16359
  if (metaTimestampMs !== null && isForkedSessionMeta(payload)) {
16281
16360
  state.suppressingForkCopies = true;
16282
16361
  state.forkCopyAnchorMs = metaTimestampMs;
16283
16362
  }
16284
16363
  return null;
16285
16364
  }
16286
- if (record4.type === "turn_context") {
16365
+ if (record5.type === "turn_context") {
16287
16366
  if (typeof payload.model === "string") state.model = payload.model;
16288
16367
  return null;
16289
16368
  }
@@ -16297,7 +16376,7 @@ function parseCodexUsageLine(line, state) {
16297
16376
  if (payload.type !== "token_count") return null;
16298
16377
  const last = asRecord3(asRecord3(payload.info)?.last_token_usage);
16299
16378
  if (!last) return null;
16300
- const timestampMs = parseTimestampMs(record4.timestamp);
16379
+ const timestampMs = parseTimestampMs(record5.timestamp);
16301
16380
  if (timestampMs === null) return null;
16302
16381
  if (state.model.length === 0) return null;
16303
16382
  const signature = JSON.stringify(last);
@@ -16398,17 +16477,17 @@ function parseCopilotUsageMetrics(value, state, timestampMs) {
16398
16477
  return records;
16399
16478
  }
16400
16479
  function parseCopilotUsageLine(line, state) {
16401
- const record4 = parseJsonRecord(line);
16402
- if (!record4 || typeof record4.agentId === "string" && record4.agentId.length > 0) return [];
16403
- const data = asRecord3(record4.data);
16480
+ const record5 = parseJsonRecord(line);
16481
+ if (!record5 || typeof record5.agentId === "string" && record5.agentId.length > 0) return [];
16482
+ const data = asRecord3(record5.data);
16404
16483
  if (!data) return [];
16405
- if (record4.type === "session.start") {
16484
+ if (record5.type === "session.start") {
16406
16485
  const sessionId = data.sessionId;
16407
16486
  if (typeof sessionId === "string" && sessionId.length > 0) state.sessionId = sessionId;
16408
16487
  return [];
16409
16488
  }
16410
- if (record4.type !== "session.shutdown") return [];
16411
- const timestampMs = parseTimestampMs(record4.timestamp);
16489
+ if (record5.type !== "session.shutdown") return [];
16490
+ const timestampMs = parseTimestampMs(record5.timestamp);
16412
16491
  return timestampMs === null ? [] : parseCopilotUsageMetrics(data, state, timestampMs);
16413
16492
  }
16414
16493
  function createUsageScanner(provider, filePath) {
@@ -16425,8 +16504,8 @@ var init_usageScanners = __esm({
16425
16504
  // object, so a line is either self-contained or of no interest.
16426
16505
  wantsLine: (line) => line.includes('"usage"'),
16427
16506
  accept: (line) => {
16428
- const record4 = parseClaudeUsageLine(line);
16429
- return record4 === null ? [] : [record4];
16507
+ const record5 = parseClaudeUsageLine(line);
16508
+ return record5 === null ? [] : [record5];
16430
16509
  }
16431
16510
  }),
16432
16511
  codex: () => {
@@ -16437,8 +16516,8 @@ var init_usageScanners = __esm({
16437
16516
  // at all but still have to reach the reducer.
16438
16517
  wantsLine: (line) => line.includes('"token_count"') || line.includes('"turn_context"') || line.includes('"session_meta"') || line.includes('"thread_settings_applied"'),
16439
16518
  accept: (line) => {
16440
- const record4 = parseCodexUsageLine(line, state);
16441
- return record4 === null ? [] : [record4];
16519
+ const record5 = parseCodexUsageLine(line, state);
16520
+ return record5 === null ? [] : [record5];
16442
16521
  }
16443
16522
  };
16444
16523
  },
@@ -17161,7 +17240,7 @@ async function releaseInspectedSession(sessionId, state, runtime) {
17161
17240
  });
17162
17241
  }
17163
17242
  }
17164
- async function respondFromInspectedSession(res, sessionId, runtime, failureMessage, operation) {
17243
+ async function respondFromInspectedSession(res, sessionId, runtime, failureMessage2, operation) {
17165
17244
  let state = null;
17166
17245
  try {
17167
17246
  state = await ensureCopilotSession(sessionId, runtime);
@@ -17172,7 +17251,7 @@ async function respondFromInspectedSession(res, sessionId, runtime, failureMessa
17172
17251
  sendJson(res, 200, await operation());
17173
17252
  } catch (error) {
17174
17253
  sendJson(res, 502, {
17175
- error: error instanceof Error ? error.message : failureMessage
17254
+ error: error instanceof Error ? error.message : failureMessage2
17176
17255
  });
17177
17256
  } finally {
17178
17257
  await releaseInspectedSession(sessionId, state, runtime);
@@ -17687,12 +17766,12 @@ function registerBranchSessionRoute(use) {
17687
17766
  }
17688
17767
  }
17689
17768
  const newSessionId = randomUUID2();
17690
- const { record: record4, originalId } = format.brandBranch(
17769
+ const { record: record5, originalId } = format.brandBranch(
17691
17770
  JSON.parse(lines[0]),
17692
17771
  newSessionId,
17693
17772
  turnIndex ?? null
17694
17773
  );
17695
- lines[0] = JSON.stringify(record4);
17774
+ lines[0] = JSON.stringify(record5);
17696
17775
  const target = storeForDirName(dirName).transcriptPath(dirName, newSessionId);
17697
17776
  if (!target) {
17698
17777
  res.statusCode = 500;
@@ -20656,9 +20735,9 @@ function registerFileWatchRoutes(use) {
20656
20735
  if (bytesRead <= 0) return;
20657
20736
  offset += bytesRead;
20658
20737
  recordActivity("Task output reads", { bytes: bytesRead });
20659
- const text = decoder.write(buf.subarray(0, bytesRead));
20660
- if (text) {
20661
- res.write(`data: ${JSON.stringify({ type: "output", text })}
20738
+ const text2 = decoder.write(buf.subarray(0, bytesRead));
20739
+ if (text2) {
20740
+ res.write(`data: ${JSON.stringify({ type: "output", text: text2 })}
20662
20741
 
20663
20742
  `);
20664
20743
  }
@@ -21262,11 +21341,11 @@ function parseGitStatus(output) {
21262
21341
  const branch = parseBranchHeader(header);
21263
21342
  const files = [];
21264
21343
  for (let index = 0; index < records.length; index += 1) {
21265
- const record4 = records[index];
21266
- if (!record4 || record4.length < 3) continue;
21267
- const indexStatus = record4[0];
21268
- const workTreeStatus = record4[1];
21269
- const path = record4.slice(3);
21344
+ const record5 = records[index];
21345
+ if (!record5 || record5.length < 3) continue;
21346
+ const indexStatus = record5[0];
21347
+ const workTreeStatus = record5[1];
21348
+ const path = record5.slice(3);
21270
21349
  const renamedOrCopied = /[RC]/.test(`${indexStatus}${workTreeStatus}`);
21271
21350
  const originalPath = renamedOrCopied ? records[index += 1] || void 0 : void 0;
21272
21351
  files.push({ path, originalPath, indexStatus, workTreeStatus });
@@ -21482,12 +21561,12 @@ function createPullRequestScanner() {
21482
21561
  const command = findCreateCommand(input);
21483
21562
  if (command) openCreates.set(id, { command, timestamp: timestamp2 });
21484
21563
  }
21485
- function recordPrLink(record4, timestamp2) {
21486
- const url = record4.prUrl;
21487
- const number = record4.prNumber;
21564
+ function recordPrLink(record5, timestamp2) {
21565
+ const url = record5.prUrl;
21566
+ const number = record5.prNumber;
21488
21567
  if (typeof url !== "string" || !url) return;
21489
21568
  if (typeof number !== "number" || !Number.isInteger(number) || number <= 0) return;
21490
- const repo = typeof record4.prRepository === "string" ? record4.prRepository : "";
21569
+ const repo = typeof record5.prRepository === "string" ? record5.prRepository : "";
21491
21570
  collector.add({
21492
21571
  url,
21493
21572
  number,
@@ -21503,9 +21582,9 @@ function createPullRequestScanner() {
21503
21582
  if (typeof id !== "string") return;
21504
21583
  const create = openCreates.get(id);
21505
21584
  if (!create || isError) return;
21506
- const text = resultText(output);
21507
- collector.record(text, create.command, id, create.timestamp);
21508
- const match = PR_URL.exec(text);
21585
+ const text2 = resultText(output);
21586
+ collector.record(text2, create.command, id, create.timestamp);
21587
+ const match = PR_URL.exec(text2);
21509
21588
  if (match) recordReference({ number: Number(match[3]), repo: `${match[1]}/${match[2]}` });
21510
21589
  }
21511
21590
  function parseArgs2(raw) {
@@ -21522,19 +21601,19 @@ function createPullRequestScanner() {
21522
21601
  if (!line.includes(GH_PR_HINT) && !line.includes(URL_HINT) && !line.includes(PR_LINK_HINT)) {
21523
21602
  return;
21524
21603
  }
21525
- let record4;
21604
+ let record5;
21526
21605
  try {
21527
- record4 = JSON.parse(line);
21606
+ record5 = JSON.parse(line);
21528
21607
  } catch {
21529
21608
  return;
21530
21609
  }
21531
- if (!isRecord5(record4)) return;
21532
- const timestamp2 = typeof record4.timestamp === "string" ? record4.timestamp : "";
21533
- if (record4.type === "pr-link") {
21534
- recordPrLink(record4, timestamp2);
21610
+ if (!isRecord5(record5)) return;
21611
+ const timestamp2 = typeof record5.timestamp === "string" ? record5.timestamp : "";
21612
+ if (record5.type === "pr-link") {
21613
+ recordPrLink(record5, timestamp2);
21535
21614
  return;
21536
21615
  }
21537
- const payload = record4.payload;
21616
+ const payload = record5.payload;
21538
21617
  if (isRecord5(payload)) {
21539
21618
  const type = payload.type;
21540
21619
  if (type === "function_call" || type === "custom_tool_call") {
@@ -21544,15 +21623,15 @@ function createPullRequestScanner() {
21544
21623
  }
21545
21624
  return;
21546
21625
  }
21547
- const data = record4.data;
21626
+ const data = record5.data;
21548
21627
  if (isRecord5(data)) {
21549
- if (record4.type === "tool.execution_start") {
21628
+ if (record5.type === "tool.execution_start") {
21550
21629
  recordToolCall(
21551
21630
  data.toolCallId,
21552
21631
  parseArgs2(data.arguments ?? data.input),
21553
21632
  timestamp2
21554
21633
  );
21555
- } else if (record4.type === "tool.execution_complete") {
21634
+ } else if (record5.type === "tool.execution_complete") {
21556
21635
  recordResult(
21557
21636
  data.toolCallId,
21558
21637
  data.result ?? data.output ?? data.error,
@@ -21561,7 +21640,7 @@ function createPullRequestScanner() {
21561
21640
  }
21562
21641
  return;
21563
21642
  }
21564
- const message = record4.message;
21643
+ const message = record5.message;
21565
21644
  if (!isRecord5(message) || !Array.isArray(message.content)) return;
21566
21645
  for (const block of message.content) {
21567
21646
  if (!isRecord5(block)) continue;
@@ -22438,9 +22517,9 @@ function deploymentState(value) {
22438
22517
  return typeof value === "string" && DEPLOYMENT_STATES.has(value) ? value : "QUEUED";
22439
22518
  }
22440
22519
  function httpsUrl(value, hostnameOnly = false) {
22441
- const text = stringValue2(value);
22442
- if (!text) return null;
22443
- const candidate = hostnameOnly && !text.includes("://") ? `https://${text}` : text;
22520
+ const text2 = stringValue2(value);
22521
+ if (!text2) return null;
22522
+ const candidate = hostnameOnly && !text2.includes("://") ? `https://${text2}` : text2;
22444
22523
  try {
22445
22524
  const url = new URL(candidate);
22446
22525
  return url.protocol === "https:" ? url.toString().replace(/\/$/, "") : null;
@@ -22516,13 +22595,13 @@ function parseBuildLog(value) {
22516
22595
  const source = record3(value);
22517
22596
  if (!source) return null;
22518
22597
  const createdAt = timestamp(source.created) ?? timestamp(source.date);
22519
- const text = stringValue2(source.text);
22520
- if (createdAt === null || !text) return null;
22598
+ const text2 = stringValue2(source.text);
22599
+ if (createdAt === null || !text2) return null;
22521
22600
  return {
22522
- id: stringValue2(source.id, `${createdAt}-${text}`),
22601
+ id: stringValue2(source.id, `${createdAt}-${text2}`),
22523
22602
  createdAt,
22524
22603
  type: stringValue2(source.type, "stdout"),
22525
- text
22604
+ text: text2
22526
22605
  };
22527
22606
  }
22528
22607
  function parseBuildLogsResponse(value) {
@@ -22759,14 +22838,440 @@ var init_vercel_deployments = __esm({
22759
22838
  }
22760
22839
  });
22761
22840
 
22841
+ // ../../server/lib/clickupConfig.ts
22842
+ import { mkdir as mkdir6, readFile as readFile17 } from "node:fs/promises";
22843
+ import { homedir as homedir7 } from "node:os";
22844
+ import { dirname as dirname9, join as join22 } from "node:path";
22845
+ function isClickUpToken(value) {
22846
+ return typeof value === "string" && TOKEN_PATTERN.test(value);
22847
+ }
22848
+ async function readStored() {
22849
+ let raw;
22850
+ try {
22851
+ raw = await readFile17(configPath, "utf8");
22852
+ } catch {
22853
+ return {};
22854
+ }
22855
+ try {
22856
+ const parsed = JSON.parse(raw);
22857
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
22858
+ const source = parsed;
22859
+ const projects = {};
22860
+ const storedProjects = source.projects;
22861
+ if (typeof storedProjects === "object" && storedProjects !== null) {
22862
+ for (const [path, listId] of Object.entries(storedProjects)) {
22863
+ if (typeof listId === "string" && /^\d+$/.test(listId)) projects[path] = listId;
22864
+ }
22865
+ }
22866
+ return { token: isClickUpToken(source.token) ? source.token : void 0, projects };
22867
+ } catch {
22868
+ return {};
22869
+ }
22870
+ }
22871
+ async function loadClickUpConfig() {
22872
+ const stored = await readStored();
22873
+ const envToken = TOKEN_ENV_VARS.map((name) => process.env[name]?.trim()).find(isClickUpToken);
22874
+ if (envToken) {
22875
+ return { token: envToken, tokenFromEnv: true, projects: stored.projects ?? {} };
22876
+ }
22877
+ return { token: stored.token ?? null, tokenFromEnv: false, projects: stored.projects ?? {} };
22878
+ }
22879
+ async function writeStored(next) {
22880
+ await mkdir6(dirname9(configPath), { recursive: true });
22881
+ const file = { projects: next.projects ?? {} };
22882
+ if (next.token) file.token = next.token;
22883
+ await writeOwnerOnlyJson(configPath, file);
22884
+ }
22885
+ async function saveClickUpToken(token) {
22886
+ const stored = await readStored();
22887
+ await writeStored({ ...stored, token: token ?? void 0 });
22888
+ }
22889
+ async function saveClickUpProjectLink(projectPath, listId) {
22890
+ const stored = await readStored();
22891
+ const projects = { ...stored.projects };
22892
+ if (listId === null) delete projects[projectPath];
22893
+ else projects[projectPath] = listId;
22894
+ await writeStored({ ...stored, projects });
22895
+ }
22896
+ var CLICKUP_CONFIG_FILE, TOKEN_PATTERN, configPath, TOKEN_ENV_VARS;
22897
+ var init_clickupConfig = __esm({
22898
+ "../../server/lib/clickupConfig.ts"() {
22899
+ init_atomicJsonFile();
22900
+ CLICKUP_CONFIG_FILE = join22(homedir7(), ".cogpit", "clickup.json");
22901
+ TOKEN_PATTERN = /^pk_[A-Za-z0-9_]{8,}$/;
22902
+ configPath = CLICKUP_CONFIG_FILE;
22903
+ TOKEN_ENV_VARS = ["COGPIT_CLICKUP_TOKEN", "CLICKUP_API_TOKEN"];
22904
+ }
22905
+ });
22906
+
22907
+ // ../../server/routes/clickup.ts
22908
+ function record4(value) {
22909
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
22910
+ }
22911
+ function text(value, fallback = "") {
22912
+ return typeof value === "string" ? value : fallback;
22913
+ }
22914
+ function idText(value) {
22915
+ if (typeof value === "number") return String(value);
22916
+ return text(value);
22917
+ }
22918
+ function epoch(value) {
22919
+ const parsed = typeof value === "string" ? Number(value) : value;
22920
+ return typeof parsed === "number" && Number.isFinite(parsed) && parsed > 0 ? parsed : null;
22921
+ }
22922
+ function folderNameOf(value) {
22923
+ const folder = record4(value);
22924
+ return folder && folder.hidden !== true ? text(folder.name) || null : null;
22925
+ }
22926
+ function invalid(what) {
22927
+ return new ClickUpRouteError(502, "invalid_response", `ClickUp returned an invalid ${what} response`);
22928
+ }
22929
+ function parseUser(value) {
22930
+ const source = record4(value);
22931
+ if (!source || typeof source.id !== "number") return null;
22932
+ const username = text(source.username) || text(source.email);
22933
+ return {
22934
+ id: source.id,
22935
+ username,
22936
+ initials: text(source.initials) || username.slice(0, 2).toUpperCase(),
22937
+ color: text(source.color) || null
22938
+ };
22939
+ }
22940
+ function parseViewerResponse(value) {
22941
+ const viewer = parseUser(record4(value)?.user);
22942
+ if (!viewer) throw invalid("user");
22943
+ return viewer;
22944
+ }
22945
+ function parseNamedEntities(entries3, fallbackName) {
22946
+ return entries3.flatMap((entry) => {
22947
+ const source = record4(entry);
22948
+ const id = idText(source?.id);
22949
+ return source && NUMERIC_ID.test(id) ? [{ id, name: text(source.name, fallbackName) }] : [];
22950
+ });
22951
+ }
22952
+ function parseWorkspacesResponse(value) {
22953
+ const teams = record4(value)?.teams;
22954
+ if (!Array.isArray(teams)) throw invalid("workspace");
22955
+ return parseNamedEntities(teams, "Workspace");
22956
+ }
22957
+ function parseStatus(value) {
22958
+ const source = record4(value);
22959
+ if (!source) return null;
22960
+ const name = text(source.status);
22961
+ if (!name) return null;
22962
+ const type = text(source.type);
22963
+ return {
22964
+ name,
22965
+ type: STATUS_TYPES.has(type) ? type : "custom",
22966
+ color: text(source.color, "#d3d3d3"),
22967
+ order: typeof source.orderindex === "number" ? source.orderindex : 0
22968
+ };
22969
+ }
22970
+ function parseTag(value) {
22971
+ const source = record4(value);
22972
+ const name = text(source?.name);
22973
+ return name ? { name, background: text(source?.tag_bg) || null } : null;
22974
+ }
22975
+ function parsePriority(value) {
22976
+ const name = text(record4(value)?.priority);
22977
+ return PRIORITIES.has(name) ? name : null;
22978
+ }
22979
+ function parseTask(value) {
22980
+ const source = record4(value);
22981
+ if (!source) return null;
22982
+ const id = text(source.id);
22983
+ const status = parseStatus(source.status);
22984
+ const list = record4(source.list);
22985
+ if (!id || !status || !list) return null;
22986
+ const customId = text(source.custom_id);
22987
+ return {
22988
+ id,
22989
+ customId: customId || null,
22990
+ name: text(source.name, "Untitled task"),
22991
+ description: text(source.markdown_description) || text(source.description),
22992
+ status,
22993
+ priority: parsePriority(source.priority),
22994
+ url: text(source.url) || `https://app.clickup.com/t/${id}`,
22995
+ assignees: Array.isArray(source.assignees) ? source.assignees.map(parseUser).filter((user) => user !== null) : [],
22996
+ tags: Array.isArray(source.tags) ? source.tags.map(parseTag).filter((tag) => tag !== null) : [],
22997
+ parentId: text(source.parent) || null,
22998
+ listId: idText(list.id),
22999
+ listName: text(list.name, "List"),
23000
+ folderName: folderNameOf(source.folder),
23001
+ spaceId: idText(record4(source.space)?.id),
23002
+ createdAt: epoch(source.date_created) ?? 0,
23003
+ updatedAt: epoch(source.date_updated) ?? epoch(source.date_created) ?? 0,
23004
+ dueAt: epoch(source.due_date),
23005
+ startAt: epoch(source.start_date),
23006
+ closedAt: epoch(source.date_closed) ?? epoch(source.date_done)
23007
+ };
23008
+ }
23009
+ function parseTasksPage(value) {
23010
+ const source = record4(value);
23011
+ if (!source || !Array.isArray(source.tasks)) throw invalid("task list");
23012
+ return {
23013
+ tasks: source.tasks.map(parseTask).filter((task) => task !== null),
23014
+ lastPage: source.last_page !== false
23015
+ };
23016
+ }
23017
+ function parseListResponse(value) {
23018
+ const source = record4(value);
23019
+ const id = idText(source?.id);
23020
+ if (!source || !NUMERIC_ID.test(id)) throw invalid("list");
23021
+ const statuses = Array.isArray(source.statuses) ? source.statuses.map(parseStatus).filter((status) => status !== null) : [];
23022
+ return {
23023
+ id,
23024
+ name: text(source.name, "List"),
23025
+ folderName: folderNameOf(source.folder),
23026
+ spaceId: idText(record4(source.space)?.id),
23027
+ statuses: statuses.sort((left, right) => left.order - right.order),
23028
+ url: `https://app.clickup.com/v/li/${id}`
23029
+ };
23030
+ }
23031
+ function parseSpacesResponse(value) {
23032
+ const spaces = record4(value)?.spaces;
23033
+ if (!Array.isArray(spaces)) throw invalid("space");
23034
+ return parseNamedEntities(spaces, "Space");
23035
+ }
23036
+ function parseListOptions(value, folderName) {
23037
+ if (!Array.isArray(value)) return [];
23038
+ return parseNamedEntities(value, "List").map((list) => ({ ...list, folderName }));
23039
+ }
23040
+ function parseFoldersResponse(value) {
23041
+ const folders = record4(value)?.folders;
23042
+ if (!Array.isArray(folders)) throw invalid("folder");
23043
+ return folders.flatMap((folder) => {
23044
+ const source = record4(folder);
23045
+ return source ? parseListOptions(source.lists, text(source.name) || null) : [];
23046
+ });
23047
+ }
23048
+ function parseFolderlessListsResponse(value) {
23049
+ const source = record4(value);
23050
+ if (!source || !Array.isArray(source.lists)) throw invalid("list");
23051
+ return parseListOptions(source.lists, null);
23052
+ }
23053
+ async function runClickUpApi(token, path) {
23054
+ let response;
23055
+ try {
23056
+ response = await fetch(`${API_BASE}${path}`, {
23057
+ headers: { Authorization: token, Accept: "application/json" },
23058
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
23059
+ });
23060
+ } catch {
23061
+ throw new ClickUpRouteError(502, "clickup_api_failed", "ClickUp is unreachable");
23062
+ }
23063
+ if (response.status === 401) {
23064
+ throw new ClickUpRouteError(401, "clickup_auth_failed", "ClickUp rejected the API token");
23065
+ }
23066
+ if (response.status === 429) {
23067
+ throw new ClickUpRouteError(429, "clickup_rate_limited", "ClickUp rate limit reached; try again in a minute");
23068
+ }
23069
+ if (!response.ok) {
23070
+ throw new ClickUpRouteError(502, "clickup_api_failed", `ClickUp request failed (${response.status})`);
23071
+ }
23072
+ try {
23073
+ return await response.json();
23074
+ } catch {
23075
+ throw invalid("JSON");
23076
+ }
23077
+ }
23078
+ function identityFor(token, deps) {
23079
+ let cached = identityCache.get(token);
23080
+ if (!cached) {
23081
+ cached = (async () => {
23082
+ const [viewer, workspaces] = await Promise.all([
23083
+ deps.api(token, "/user").then(parseViewerResponse),
23084
+ deps.api(token, "/team").then(parseWorkspacesResponse)
23085
+ ]);
23086
+ const workspace = workspaces[0];
23087
+ if (!workspace) throw new ClickUpRouteError(502, "clickup_api_failed", "The token belongs to no ClickUp workspace");
23088
+ return { token, viewer, workspace };
23089
+ })();
23090
+ identityCache.set(token, cached);
23091
+ cached.catch(() => identityCache.delete(token));
23092
+ }
23093
+ return cached;
23094
+ }
23095
+ async function requireIdentity(deps) {
23096
+ const config = await deps.loadConfig();
23097
+ if (!config.token) {
23098
+ throw new ClickUpRouteError(503, "clickup_not_configured", "Add a ClickUp API token to view your tasks");
23099
+ }
23100
+ return { ...await identityFor(config.token, deps), config };
23101
+ }
23102
+ async function statusFor(config, deps) {
23103
+ if (!config.token) return { configured: false, tokenFromEnv: false, viewer: null, workspace: null };
23104
+ const identity = await identityFor(config.token, deps);
23105
+ return { configured: true, tokenFromEnv: config.tokenFromEnv, viewer: identity.viewer, workspace: identity.workspace };
23106
+ }
23107
+ async function fetchTaskPages(token, path, deps, maxPages = MAX_TASK_PAGES) {
23108
+ const tasks = [];
23109
+ for (let page = 0; page < maxPages; page += 1) {
23110
+ const result = parseTasksPage(await deps.api(token, `${path}&page=${page}`));
23111
+ tasks.push(...result.tasks);
23112
+ if (result.lastPage) return { tasks, truncated: false };
23113
+ }
23114
+ return { tasks, truncated: true };
23115
+ }
23116
+ async function resolveProjectPath2(cwd, deps) {
23117
+ const project = await deps.resolveProject(cwd);
23118
+ if (!project.ok) throw new ClickUpRouteError(project.status, "clickup_api_failed", project.error);
23119
+ return project.projectPath;
23120
+ }
23121
+ function sendRouteError4(res, error) {
23122
+ if (error instanceof ClickUpRouteError) {
23123
+ sendJson(res, error.status, { error: error.message, code: error.code });
23124
+ return;
23125
+ }
23126
+ sendJson(res, 500, { error: "Unable to load ClickUp data", code: "clickup_api_failed" });
23127
+ }
23128
+ function route(use, path, methods, handler) {
23129
+ use(path, async (req, res, next) => {
23130
+ if (!methods.includes(req.method ?? "")) return next();
23131
+ const url = new URL(req.url || "", "http://localhost");
23132
+ if (url.pathname !== "/" && url.pathname !== "") return next();
23133
+ try {
23134
+ const result = await handler(req, url);
23135
+ sendJson(res, result.status, result.body);
23136
+ } catch (error) {
23137
+ sendRouteError4(res, error);
23138
+ }
23139
+ });
23140
+ }
23141
+ function registerClickUpRoutes(use, deps = defaultDependencies3) {
23142
+ route(use, "/api/clickup/status", ["GET"], async () => ({
23143
+ status: 200,
23144
+ body: await statusFor(await deps.loadConfig(), deps)
23145
+ }));
23146
+ route(use, "/api/clickup/token", ["POST", "DELETE"], async (req) => {
23147
+ const current = await deps.loadConfig();
23148
+ if (current.tokenFromEnv) {
23149
+ throw new ClickUpRouteError(409, "clickup_api_failed", "The ClickUp token comes from the server environment; change it there");
23150
+ }
23151
+ if (current.token) identityCache.delete(current.token);
23152
+ if (req.method === "DELETE") {
23153
+ await deps.saveToken(null);
23154
+ return { status: 200, body: await statusFor({ ...current, token: null }, deps) };
23155
+ }
23156
+ const { token } = await readJsonBody(req);
23157
+ const candidate = typeof token === "string" ? token.trim() : "";
23158
+ if (!isClickUpToken(candidate)) {
23159
+ throw new ClickUpRouteError(400, "clickup_auth_failed", "That does not look like a ClickUp personal API token (pk_\u2026)");
23160
+ }
23161
+ await identityFor(candidate, deps);
23162
+ await deps.saveToken(candidate);
23163
+ return { status: 200, body: await statusFor({ ...current, token: candidate }, deps) };
23164
+ });
23165
+ route(use, "/api/clickup/tasks/mine", ["GET"], async () => {
23166
+ const { token, viewer, workspace } = await requireIdentity(deps);
23167
+ const path = `/team/${workspace.id}/task?assignees[]=${viewer.id}&include_closed=false&subtasks=true&order_by=due_date&reverse=true`;
23168
+ const { tasks, truncated } = await fetchTaskPages(token, path, deps);
23169
+ const body = { workspace, viewer, tasks, truncated };
23170
+ return { status: 200, body };
23171
+ });
23172
+ route(use, "/api/clickup/tasks/list", ["GET"], async (_req, url) => {
23173
+ const projectPath = await resolveProjectPath2(url.searchParams.get("cwd") ?? "", deps);
23174
+ const { token, viewer, workspace, config } = await requireIdentity(deps);
23175
+ const listId = config.projects[projectPath];
23176
+ if (!listId) throw new ClickUpRouteError(404, "project_unlinked", "This project is not linked to a ClickUp list");
23177
+ const since = deps.now() - CLOSED_WINDOW_MS;
23178
+ const [list, open10, closed] = await Promise.all([
23179
+ deps.api(token, `/list/${listId}`).then(parseListResponse),
23180
+ fetchTaskPages(token, `/list/${listId}/task?include_closed=false&subtasks=true&order_by=updated`, deps),
23181
+ fetchTaskPages(token, `/list/${listId}/task?include_closed=true&subtasks=true&order_by=updated&date_updated_gt=${since}`, deps, 1)
23182
+ ]);
23183
+ const seen = new Set(open10.tasks.map((task) => task.id));
23184
+ const recentlyClosed = closed.tasks.filter((task) => !seen.has(task.id) && task.status.type === "closed");
23185
+ const body = {
23186
+ workspace,
23187
+ viewer,
23188
+ list,
23189
+ tasks: [...open10.tasks, ...recentlyClosed],
23190
+ truncated: open10.truncated
23191
+ };
23192
+ return { status: 200, body };
23193
+ });
23194
+ route(use, "/api/clickup/spaces", ["GET"], async () => {
23195
+ const { token, workspace } = await requireIdentity(deps);
23196
+ const spaces = parseSpacesResponse(await deps.api(token, `/team/${workspace.id}/space?archived=false`));
23197
+ const body = { workspace, spaces };
23198
+ return { status: 200, body };
23199
+ });
23200
+ route(use, "/api/clickup/lists", ["GET"], async (_req, url) => {
23201
+ const spaceId = url.searchParams.get("spaceId") ?? "";
23202
+ if (!NUMERIC_ID.test(spaceId)) {
23203
+ throw new ClickUpRouteError(400, "clickup_api_failed", "spaceId must be a ClickUp space id");
23204
+ }
23205
+ const { token } = await requireIdentity(deps);
23206
+ const [inFolders, folderless] = await Promise.all([
23207
+ deps.api(token, `/space/${spaceId}/folder?archived=false`).then(parseFoldersResponse),
23208
+ deps.api(token, `/space/${spaceId}/list?archived=false`).then(parseFolderlessListsResponse)
23209
+ ]);
23210
+ const body = { spaceId, lists: [...folderless, ...inFolders] };
23211
+ return { status: 200, body };
23212
+ });
23213
+ route(use, "/api/clickup/project-list", ["GET", "PUT"], async (req, url) => {
23214
+ if (req.method === "GET") {
23215
+ const projectPath2 = await resolveProjectPath2(url.searchParams.get("cwd") ?? "", deps);
23216
+ const config = await deps.loadConfig();
23217
+ const body2 = { cwd: projectPath2, listId: config.projects[projectPath2] ?? null };
23218
+ return { status: 200, body: body2 };
23219
+ }
23220
+ const request = await readJsonBody(req);
23221
+ const projectPath = await resolveProjectPath2(typeof request.cwd === "string" ? request.cwd : "", deps);
23222
+ const listId = request.listId === null || request.listId === void 0 ? null : String(request.listId);
23223
+ if (listId !== null && !NUMERIC_ID.test(listId)) {
23224
+ throw new ClickUpRouteError(400, "clickup_api_failed", "listId must be a ClickUp list id");
23225
+ }
23226
+ if (listId !== null) {
23227
+ const { token } = await requireIdentity(deps);
23228
+ parseListResponse(await deps.api(token, `/list/${listId}`));
23229
+ }
23230
+ await deps.saveProjectLink(projectPath, listId);
23231
+ const body = { cwd: projectPath, listId };
23232
+ return { status: 200, body };
23233
+ });
23234
+ }
23235
+ var API_BASE, REQUEST_TIMEOUT_MS, MAX_TASK_PAGES, CLOSED_WINDOW_MS, NUMERIC_ID, STATUS_TYPES, PRIORITIES, ClickUpRouteError, defaultDependencies3, identityCache;
23236
+ var init_clickup = __esm({
23237
+ "../../server/routes/clickup.ts"() {
23238
+ init_http();
23239
+ init_clickupConfig();
23240
+ init_gitProject();
23241
+ API_BASE = "https://api.clickup.com/api/v2";
23242
+ REQUEST_TIMEOUT_MS = 2e4;
23243
+ MAX_TASK_PAGES = 3;
23244
+ CLOSED_WINDOW_MS = 14 * 24 * 60 * 60 * 1e3;
23245
+ NUMERIC_ID = /^\d+$/;
23246
+ STATUS_TYPES = /* @__PURE__ */ new Set(["open", "custom", "closed", "done"]);
23247
+ PRIORITIES = /* @__PURE__ */ new Set(["urgent", "high", "normal", "low"]);
23248
+ ClickUpRouteError = class extends Error {
23249
+ constructor(status, code, message) {
23250
+ super(message);
23251
+ this.status = status;
23252
+ this.code = code;
23253
+ }
23254
+ };
23255
+ defaultDependencies3 = {
23256
+ api: runClickUpApi,
23257
+ loadConfig: loadClickUpConfig,
23258
+ saveToken: saveClickUpToken,
23259
+ saveProjectLink: saveClickUpProjectLink,
23260
+ resolveProject: resolveGitProject,
23261
+ now: () => Date.now()
23262
+ };
23263
+ identityCache = /* @__PURE__ */ new Map();
23264
+ }
23265
+ });
23266
+
22762
23267
  // ../../server/lib/projectIcon.ts
22763
23268
  import { realpath as realpath10, stat as stat14 } from "node:fs/promises";
22764
- import { basename as basename9, extname, join as join22, relative as relative8, sep as sep10 } from "node:path";
23269
+ import { basename as basename9, extname, join as join23, relative as relative8, sep as sep10 } from "node:path";
22765
23270
  function namedIconCandidates(root) {
22766
23271
  const name = basename9(root);
22767
23272
  if (!name || name.startsWith(".")) return [];
22768
23273
  return ["public", "assets", "static", "."].flatMap(
22769
- (dir) => NAMED_ICON_EXTENSIONS.map((ext) => join22(dir, `${name}${ext}`))
23274
+ (dir) => NAMED_ICON_EXTENSIONS.map((ext) => join23(dir, `${name}${ext}`))
22770
23275
  );
22771
23276
  }
22772
23277
  function iconContentType(path) {
@@ -22789,7 +23294,7 @@ async function resolveProjectIcon(projectPath) {
22789
23294
  ...PROJECT_ICON_CANDIDATES.slice(6)
22790
23295
  ];
22791
23296
  for (const candidate of candidates) {
22792
- const guess = join22(root, candidate);
23297
+ const guess = join23(root, candidate);
22793
23298
  try {
22794
23299
  const resolved = await realpath10(guess);
22795
23300
  if (!isInside(root, resolved)) continue;
@@ -22943,13 +23448,13 @@ var init_local_file = __esm({
22943
23448
 
22944
23449
  // ../../server/routes/mcp.ts
22945
23450
  import { execFile as execFile5 } from "node:child_process";
22946
- import { isAbsolute as isAbsolute10, join as join23 } from "node:path";
22947
- import { readFile as readFile17 } from "node:fs/promises";
22948
- import { homedir as homedir7 } from "node:os";
23451
+ import { isAbsolute as isAbsolute10, join as join24 } from "node:path";
23452
+ import { readFile as readFile18 } from "node:fs/promises";
23453
+ import { homedir as homedir8 } from "node:os";
22949
23454
  async function readMcpConfigs(cwd) {
22950
23455
  const configs = {};
22951
23456
  try {
22952
- const raw = await readFile17(join23(homedir7(), ".claude.json"), "utf-8");
23457
+ const raw = await readFile18(join24(homedir8(), ".claude.json"), "utf-8");
22953
23458
  const parsed = JSON.parse(raw);
22954
23459
  if (parsed.mcpServers && typeof parsed.mcpServers === "object") {
22955
23460
  Object.assign(configs, parsed.mcpServers);
@@ -22967,16 +23472,16 @@ async function readMcpConfigs(cwd) {
22967
23472
  } catch {
22968
23473
  }
22969
23474
  const otherSources = [
22970
- join23(homedir7(), ".claude", "settings.json"),
23475
+ join24(homedir8(), ".claude", "settings.json"),
22971
23476
  // global settings
22972
- join23(cwd, ".mcp.json"),
23477
+ join24(cwd, ".mcp.json"),
22973
23478
  // project
22974
- join23(cwd, ".claude", "settings.local.json")
23479
+ join24(cwd, ".claude", "settings.local.json")
22975
23480
  // project local
22976
23481
  ];
22977
23482
  for (const path of otherSources) {
22978
23483
  try {
22979
- const raw = await readFile17(path, "utf-8");
23484
+ const raw = await readFile18(path, "utf-8");
22980
23485
  const parsed = JSON.parse(raw);
22981
23486
  if (parsed.mcpServers && typeof parsed.mcpServers === "object") {
22982
23487
  Object.assign(configs, parsed.mcpServers);
@@ -23155,6 +23660,16 @@ function isObject9(value) {
23155
23660
  function firstString3(...values) {
23156
23661
  return values.find((value) => typeof value === "string") ?? "";
23157
23662
  }
23663
+ function readableToolText(value) {
23664
+ if (typeof value !== "string") return "";
23665
+ return /^gAAAAA[A-Za-z0-9_-]+={0,2}$/.test(value.trim()) ? "Encrypted message" : value;
23666
+ }
23667
+ function getCommandText(input) {
23668
+ const command = input.command ?? input.cmd;
23669
+ if (typeof command === "string") return command;
23670
+ if (!Array.isArray(command) || !command.every((value) => typeof value === "string")) return "";
23671
+ return command.map((value) => /^[A-Za-z0-9_./:@%+=,-]+$/.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`).join(" ");
23672
+ }
23158
23673
  function truncate(value, length = 140) {
23159
23674
  const singleLine = value.replace(/\s+/g, " ").trim();
23160
23675
  return singleLine.length > length ? `${singleLine.slice(0, length - 1)}\u2026` : singleLine;
@@ -23187,8 +23702,8 @@ function humanizeIdentifier(value, titleCase = false) {
23187
23702
  return titleCase ? lower[0].toUpperCase() + lower.slice(1) : lower;
23188
23703
  });
23189
23704
  if (words.length === 0) return "Tool";
23190
- const text = words.join(" ");
23191
- return text[0].toUpperCase() + text.slice(1);
23705
+ const text2 = words.join(" ");
23706
+ return text2[0].toUpperCase() + text2.slice(1);
23192
23707
  }
23193
23708
  function stringExpression(source) {
23194
23709
  if (!source) return null;
@@ -23309,7 +23824,7 @@ function patchSummary(args) {
23309
23824
  }
23310
23825
  function presentExecInvocation(invocation) {
23311
23826
  const args = invocation.argumentSource;
23312
- switch (invocation.name) {
23827
+ switch (normalizeFunctionName(invocation.name)) {
23313
23828
  case "exec_command":
23314
23829
  return { label: "Run command", summary: argumentString(args, "cmd", "command"), styleName: "Bash" };
23315
23830
  case "write_stdin": {
@@ -23340,7 +23855,7 @@ function presentExecInvocation(invocation) {
23340
23855
  case "create_goal":
23341
23856
  return { label: "Create goal", summary: argumentString(args, "objective"), styleName: "TodoWrite" };
23342
23857
  case "get_goal":
23343
- return { label: "Check goal", summary: "", styleName: "TodoWrite" };
23858
+ return { label: "Check goal", summary: "", styleName: "TaskList" };
23344
23859
  case "update_goal":
23345
23860
  return { label: "Update goal", summary: argumentString(args, "status"), styleName: "TodoWrite" };
23346
23861
  case "list_mcp_resources":
@@ -23359,12 +23874,23 @@ function presentExecInvocation(invocation) {
23359
23874
  return { label: "Find tools", summary: argumentString(args, "query"), styleName: "ToolSearch" };
23360
23875
  case "image_gen__imagegen":
23361
23876
  return { label: "Generate image", summary: argumentString(args, "prompt"), styleName: "Image" };
23362
- default:
23363
- return invocation.name.startsWith("mcp__") ? presentMcpInvocation(invocation.name, args) : {
23364
- label: humanizeIdentifier(invocation.name),
23365
- summary: invocationDetail(args),
23366
- styleName: invocation.name
23877
+ case "spawn_agent":
23878
+ return { label: "Spawn agent", summary: readableToolText(argumentString(args, "task_name", "message")), styleName: "Task" };
23879
+ case "send_message":
23880
+ case "followup_task":
23881
+ return {
23882
+ ...TOOL_LABELS[normalizeFunctionName(invocation.name)],
23883
+ summary: [argumentString(args, "target"), readableToolText(argumentString(args, "message"))].filter(Boolean).join(" \xB7 ")
23884
+ };
23885
+ default: {
23886
+ const name = normalizeFunctionName(invocation.name);
23887
+ const definition = TOOL_LABELS[name];
23888
+ return name.startsWith("mcp__") ? presentMcpInvocation(name, args) : {
23889
+ label: definition?.label ?? humanizeIdentifier(name),
23890
+ summary: readableToolText(invocationDetail(args)),
23891
+ styleName: definition?.styleName ?? name
23367
23892
  };
23893
+ }
23368
23894
  }
23369
23895
  }
23370
23896
  function isCodexExecCall(tc) {
@@ -23436,11 +23962,27 @@ function workflowSummary(input) {
23436
23962
  return metaName || firstString3(input.scriptPath);
23437
23963
  }
23438
23964
  function firstStringValue(input) {
23439
- const keys = Object.keys(input);
23440
- if (keys.length === 0) return "";
23441
- const first = input[keys[0]];
23442
- if (typeof first !== "string") return "";
23443
- return first.length > 80 ? first.slice(0, 80) + "..." : first;
23965
+ const detail = firstString3(...[
23966
+ "description",
23967
+ "summary",
23968
+ "query",
23969
+ "q",
23970
+ "command",
23971
+ "cmd",
23972
+ "file_path",
23973
+ "path",
23974
+ "url",
23975
+ "uri",
23976
+ "pattern",
23977
+ "prompt",
23978
+ "objective",
23979
+ "message",
23980
+ "title",
23981
+ "name"
23982
+ ].map((key2) => input[key2]));
23983
+ if (detail) return truncate(detail);
23984
+ const entry = Object.entries(input).find(([key2, value]) => key2 !== "raw" && key2 !== "script" && typeof value === "string");
23985
+ return entry ? truncate(entry[1]) : "";
23444
23986
  }
23445
23987
  function defaultToolSummary(tc) {
23446
23988
  const input = tc.input;
@@ -23450,13 +23992,23 @@ function defaultToolSummary(tc) {
23450
23992
  case "Edit":
23451
23993
  return String(input.file_path ?? input.path ?? "");
23452
23994
  case "Bash":
23453
- return String(input.command ?? input.cmd ?? "");
23995
+ case "exec_command":
23996
+ return getCommandText(input);
23997
+ case "write_stdin":
23998
+ return [input.session_id !== void 0 ? `session ${input.session_id}` : "", firstString3(input.chars)].filter(Boolean).join(" \xB7 ");
23999
+ case "apply_patch":
24000
+ return patchSummary(firstString3(input.patch, input.raw, input.input));
24001
+ case "TodoWrite":
24002
+ case "update_plan": {
24003
+ const steps = Array.isArray(input.todos) ? input.todos : Array.isArray(input.plan) ? input.plan : [];
24004
+ return steps.length > 0 ? plural(steps.length, "step") : firstString3(input.explanation);
24005
+ }
23454
24006
  case "Grep":
23455
24007
  case "Glob":
23456
24008
  return String(input.pattern ?? "");
23457
24009
  case "Task":
23458
24010
  case "Agent":
23459
- return String(input.description ?? input.prompt ?? "");
24011
+ return readableToolText(input.description ?? input.prompt);
23460
24012
  case "WebFetch":
23461
24013
  return String(input.url ?? "");
23462
24014
  case "NotebookEdit":
@@ -23465,9 +24017,11 @@ function defaultToolSummary(tc) {
23465
24017
  return "Entered plan mode";
23466
24018
  case "ExitPlanMode":
23467
24019
  return "Waiting for plan approval";
23468
- case "AskUserQuestion": {
23469
- const questions = input.questions;
23470
- return questions?.[0]?.question ?? "";
24020
+ case "AskUserQuestion":
24021
+ case "request_user_input":
24022
+ case "request_user_input_async": {
24023
+ const question = Array.isArray(input.questions) ? input.questions.find(isObject9) : null;
24024
+ return firstString3(question?.question, question?.title);
23471
24025
  }
23472
24026
  case "Monitor": {
23473
24027
  const bashId = String(input.bash_id ?? "");
@@ -23511,7 +24065,7 @@ function defaultToolSummary(tc) {
23511
24065
  return String(input.query ?? "");
23512
24066
  case "SendMessage": {
23513
24067
  const recipient = firstString3(input.to, input.recipient);
23514
- const gist = truncate(firstString3(input.summary, input.message, input.content));
24068
+ const gist = truncate(readableToolText(firstString3(input.summary, input.message, input.content)));
23515
24069
  return [recipient, gist].filter(Boolean).join(" \xB7 ");
23516
24070
  }
23517
24071
  case "ListAgents":
@@ -23537,14 +24091,14 @@ function defaultToolSummary(tc) {
23537
24091
  case "LSP":
23538
24092
  return schemaFreeSummary(input) || firstStringValue(input);
23539
24093
  case "spawn_agent":
23540
- return String(input.task_name ?? input.message ?? "");
24094
+ return readableToolText(input.task_name ?? input.message);
23541
24095
  case "wait_agent": {
23542
24096
  const targets = Array.isArray(input.ids) ? input.ids.filter((id) => typeof id === "string") : [];
23543
24097
  return compactValues(targets);
23544
24098
  }
23545
24099
  case "send_message":
23546
24100
  case "followup_task":
23547
- return [input.target, input.message].filter((value) => typeof value === "string").join(" \xB7 ");
24101
+ return [input.target, readableToolText(input.message)].filter((value) => typeof value === "string" && value.length > 0).join(" \xB7 ");
23548
24102
  case "list_agents":
23549
24103
  return String(input.path_prefix ?? "");
23550
24104
  case "interrupt_agent":
@@ -23568,7 +24122,9 @@ function defaultToolSummary(tc) {
23568
24122
  }
23569
24123
  function getToolPresentation(tc) {
23570
24124
  if (isCodexExecCall(tc)) return presentExecScript(tc.input.raw);
23571
- if (tc.name === "WebSearch") return nativeWebPresentation(tc.input);
24125
+ const name = normalizeFunctionName(tc.name);
24126
+ if (name === "WebSearch" || name === "web_search") return nativeWebPresentation(tc.input);
24127
+ if (name === "web__run" || name === "web.run") return presentWebInvocation(JSON.stringify(tc.input));
23572
24128
  const mcp = mcpParts(tc.name);
23573
24129
  if (mcp) {
23574
24130
  return {
@@ -23577,26 +24133,60 @@ function getToolPresentation(tc) {
23577
24133
  styleName: "Mcp"
23578
24134
  };
23579
24135
  }
23580
- const codex2 = CODEX_TOOL_LABELS[tc.name];
24136
+ const definition = TOOL_LABELS[name];
23581
24137
  return {
23582
- label: codex2?.label ?? tc.name,
23583
- summary: defaultToolSummary(tc),
23584
- styleName: codex2?.styleName ?? tc.name
24138
+ label: definition?.label ?? humanizeIdentifier(name),
24139
+ summary: truncate(defaultToolSummary({ name, input: tc.input })),
24140
+ styleName: definition?.styleName ?? name
23585
24141
  };
23586
24142
  }
23587
24143
  function getToolSummary(tc) {
23588
24144
  return getToolPresentation(tc).summary;
23589
24145
  }
23590
- var CODEX_TOOL_LABELS, WORD_SPELLINGS, WEB_OPERATIONS, SCHEMA_FREE_GIST_KEYS;
24146
+ var TOOL_LABELS, WORD_SPELLINGS, WEB_OPERATIONS, SCHEMA_FREE_GIST_KEYS;
23591
24147
  var init_toolSummary = __esm({
23592
24148
  "../../shared/session/toolSummary.ts"() {
23593
24149
  init_codex_exec();
23594
- CODEX_TOOL_LABELS = {
24150
+ init_codex_tool_normalization();
24151
+ TOOL_LABELS = {
24152
+ Read: { label: "Read file", styleName: "Read" },
24153
+ Write: { label: "Write file", styleName: "Write" },
24154
+ Edit: { label: "Edit file", styleName: "Edit" },
24155
+ Bash: { label: "Run command", styleName: "Bash" },
24156
+ Grep: { label: "Search files", styleName: "Grep" },
24157
+ Glob: { label: "Find files", styleName: "Glob" },
24158
+ Task: { label: "Spawn agent", styleName: "Task" },
24159
+ Agent: { label: "Spawn agent", styleName: "Task" },
24160
+ WebFetch: { label: "Open page", styleName: "WebFetch" },
24161
+ TodoWrite: { label: "Update plan", styleName: "TodoWrite" },
24162
+ AskUserQuestion: { label: "Ask question", styleName: "AskUserQuestion" },
24163
+ Skill: { label: "Use skill", styleName: "Skill" },
24164
+ ToolSearch: { label: "Find tools", styleName: "ToolSearch" },
24165
+ SendMessage: { label: "Message agent", styleName: "SendMessage" },
24166
+ ListAgents: { label: "List agents", styleName: "ListAgents" },
24167
+ TaskCreate: { label: "Create task", styleName: "TaskCreate" },
24168
+ TaskUpdate: { label: "Update task", styleName: "TaskUpdate" },
24169
+ TaskList: { label: "List tasks", styleName: "TaskList" },
24170
+ TaskOutput: { label: "Read task output", styleName: "TaskOutput" },
24171
+ TaskStop: { label: "Stop task", styleName: "TaskStop" },
24172
+ NotebookEdit: { label: "Edit notebook", styleName: "Edit" },
24173
+ EnterPlanMode: { label: "Enter plan mode", styleName: "EnterPlanMode" },
24174
+ ExitPlanMode: { label: "Exit plan mode", styleName: "ExitPlanMode" },
24175
+ EnterWorktree: { label: "Enter worktree", styleName: "EnterWorktree" },
24176
+ ExitWorktree: { label: "Exit worktree", styleName: "ExitWorktree" },
24177
+ Workflow: { label: "Run workflow", styleName: "Workflow" },
24178
+ exec_command: { label: "Run command", styleName: "Bash" },
24179
+ write_stdin: { label: "Continue command", styleName: "Bash" },
24180
+ apply_patch: { label: "Apply patch", styleName: "Edit" },
24181
+ update_plan: { label: "Update plan", styleName: "TodoWrite" },
24182
+ request_user_input: { label: "Ask question", styleName: "AskUserQuestion" },
24183
+ request_user_input_async: { label: "Ask question", styleName: "AskUserQuestion" },
24184
+ wait: { label: "Wait for tools", styleName: "Mcp" },
23595
24185
  spawn_agent: { label: "Spawn agent", styleName: "Task" },
23596
- wait_agent: { label: "Wait for agents", styleName: "Task" },
23597
- send_message: { label: "Message agent", styleName: "Task" },
24186
+ wait_agent: { label: "Wait for agents", styleName: "TaskOutput" },
24187
+ send_message: { label: "Message agent", styleName: "SendMessage" },
23598
24188
  followup_task: { label: "Follow up", styleName: "Task" },
23599
- list_agents: { label: "List agents", styleName: "Task" },
24189
+ list_agents: { label: "List agents", styleName: "ListAgents" },
23600
24190
  interrupt_agent: { label: "Interrupt agent", styleName: "Task" },
23601
24191
  tool_search: { label: "Find tools", styleName: "ToolSearch" },
23602
24192
  list_mcp_resources: { label: "List MCP resources", styleName: "Mcp" },
@@ -23604,7 +24194,7 @@ var init_toolSummary = __esm({
23604
24194
  read_mcp_resource: { label: "Read MCP resource", styleName: "Mcp" },
23605
24195
  request_plugin_install: { label: "Install plugin", styleName: "Mcp" },
23606
24196
  create_goal: { label: "Create goal", styleName: "TodoWrite" },
23607
- get_goal: { label: "Check goal", styleName: "TodoWrite" },
24197
+ get_goal: { label: "Check goal", styleName: "TaskList" },
23608
24198
  update_goal: { label: "Update goal", styleName: "TodoWrite" },
23609
24199
  view_image: { label: "View image", styleName: "Read" }
23610
24200
  };
@@ -23718,8 +24308,8 @@ function foldFileEdit(acc, name, input) {
23718
24308
  }
23719
24309
  return true;
23720
24310
  }
23721
- function notePreview(acc, text) {
23722
- const trimmed = text.trim();
24311
+ function notePreview(acc, text2) {
24312
+ const trimmed = text2.trim();
23723
24313
  if (trimmed) acc.lastAssistantText = trimmed.slice(0, PREVIEW_LIMIT);
23724
24314
  }
23725
24315
  var TRAIL_LENGTH, PREVIEW_LIMIT;
@@ -23822,9 +24412,9 @@ function copilotText(value) {
23822
24412
  if (!Array.isArray(value)) return "";
23823
24413
  return value.flatMap((part) => {
23824
24414
  if (typeof part === "string") return part ? [part] : [];
23825
- const record4 = asRecord5(part);
23826
- const text = str(record4.text) || str(record4.content);
23827
- return text ? [text] : [];
24415
+ const record5 = asRecord5(part);
24416
+ const text2 = str(record5.text) || str(record5.content);
24417
+ return text2 ? [text2] : [];
23828
24418
  }).join("\n");
23829
24419
  }
23830
24420
  function normalizeCopilotToolName(name) {
@@ -24387,14 +24977,14 @@ var init_models = __esm({
24387
24977
  });
24388
24978
 
24389
24979
  // ../../server/lib/notificationHistory.ts
24390
- import { mkdir as mkdir6, readFile as readFile18 } from "node:fs/promises";
24980
+ import { mkdir as mkdir7, readFile as readFile19 } from "node:fs/promises";
24391
24981
  import { mkdirSync, writeFileSync } from "node:fs";
24392
- import { homedir as homedir8 } from "node:os";
24393
- import { dirname as dirname9, join as join24 } from "node:path";
24982
+ import { homedir as homedir9 } from "node:os";
24983
+ import { dirname as dirname10, join as join25 } from "node:path";
24394
24984
  import { randomUUID as randomUUID4 } from "node:crypto";
24395
24985
  async function load() {
24396
24986
  if (entries2) return entries2;
24397
- loadPromise ??= readFile18(NOTIFICATION_HISTORY_FILE, "utf-8").then((raw) => {
24987
+ loadPromise ??= readFile19(NOTIFICATION_HISTORY_FILE, "utf-8").then((raw) => {
24398
24988
  const parsed = JSON.parse(raw);
24399
24989
  return Array.isArray(parsed) ? parsed.filter(isEntry) : [];
24400
24990
  }).catch(() => []).then((loaded2) => {
@@ -24420,7 +25010,7 @@ function schedulePersist2() {
24420
25010
  const snapshot = entries2;
24421
25011
  if (!snapshot) return;
24422
25012
  dirty = false;
24423
- void mkdir6(dirname9(NOTIFICATION_HISTORY_FILE), { recursive: true }).then(() => writeOwnerOnlyJson(NOTIFICATION_HISTORY_FILE, snapshot)).catch((err) => console.error("[notify] Failed to persist history:", err));
25013
+ void mkdir7(dirname10(NOTIFICATION_HISTORY_FILE), { recursive: true }).then(() => writeOwnerOnlyJson(NOTIFICATION_HISTORY_FILE, snapshot)).catch((err) => console.error("[notify] Failed to persist history:", err));
24424
25014
  }, PERSIST_DEBOUNCE_MS);
24425
25015
  persistTimer.unref?.();
24426
25016
  }
@@ -24428,7 +25018,7 @@ function flushSync() {
24428
25018
  if (!dirty || !entries2) return;
24429
25019
  dirty = false;
24430
25020
  try {
24431
- mkdirSync(dirname9(NOTIFICATION_HISTORY_FILE), { recursive: true });
25021
+ mkdirSync(dirname10(NOTIFICATION_HISTORY_FILE), { recursive: true });
24432
25022
  writeFileSync(NOTIFICATION_HISTORY_FILE, JSON.stringify(entries2, null, 2), { mode: 384 });
24433
25023
  } catch {
24434
25024
  }
@@ -24478,7 +25068,7 @@ var NOTIFICATION_HISTORY_FILE, MAX_ENTRIES3, PERSIST_DEBOUNCE_MS, entries2, load
24478
25068
  var init_notificationHistory = __esm({
24479
25069
  "../../server/lib/notificationHistory.ts"() {
24480
25070
  init_atomicJsonFile();
24481
- NOTIFICATION_HISTORY_FILE = join24(homedir8(), ".cogpit", "notifications.json");
25071
+ NOTIFICATION_HISTORY_FILE = join25(homedir9(), ".cogpit", "notifications.json");
24482
25072
  MAX_ENTRIES3 = 200;
24483
25073
  PERSIST_DEBOUNCE_MS = 500;
24484
25074
  entries2 = null;
@@ -24533,9 +25123,9 @@ function parseEtimeSeconds(etime) {
24533
25123
  const [, days, hours, minutes, seconds] = match;
24534
25124
  return Number(days ?? 0) * 86400 + Number(hours ?? 0) * 3600 + Number(minutes) * 60 + Number(seconds);
24535
25125
  }
24536
- function parsePsOutput(text) {
25126
+ function parsePsOutput(text2) {
24537
25127
  const rows = [];
24538
- for (const line of text.split("\n")) {
25128
+ for (const line of text2.split("\n")) {
24539
25129
  const match = /^\s*(\d+)\s+(\d+)\s+([\d.]+)\s+(\d+)\s+(\S+)\s+(.*\S)/.exec(line);
24540
25130
  if (!match) continue;
24541
25131
  rows.push({
@@ -24741,8 +25331,8 @@ var init_notifications2 = __esm({
24741
25331
 
24742
25332
  // ../../server/lib/pushConfig.ts
24743
25333
  import { readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
24744
- import { homedir as homedir9 } from "node:os";
24745
- import { join as join25 } from "node:path";
25334
+ import { homedir as homedir10 } from "node:os";
25335
+ import { join as join26 } from "node:path";
24746
25336
  function warnOnce(message) {
24747
25337
  if (lastWarning === message) return;
24748
25338
  lastWarning = message;
@@ -24837,7 +25427,7 @@ function getPushConfig(path = PUSH_CONFIG_FILE) {
24837
25427
  var PUSH_CONFIG_FILE, DEFAULT_NTFY_URL, TOPIC_PATTERN, cache5, lastWarning;
24838
25428
  var init_pushConfig = __esm({
24839
25429
  "../../server/lib/pushConfig.ts"() {
24840
- PUSH_CONFIG_FILE = join25(homedir9(), ".cogpit", "push.json");
25430
+ PUSH_CONFIG_FILE = join26(homedir10(), ".cogpit", "push.json");
24841
25431
  DEFAULT_NTFY_URL = "https://ntfy.sh";
24842
25432
  TOPIC_PATTERN = /^[-_A-Za-z0-9]{1,64}$/;
24843
25433
  cache5 = null;
@@ -24846,12 +25436,12 @@ var init_pushConfig = __esm({
24846
25436
  });
24847
25437
 
24848
25438
  // ../../server/lib/pushNotify.ts
24849
- function truncateBytes(text, maxBytes) {
24850
- if (encoder.encode(text).length <= maxBytes) return text;
25439
+ function truncateBytes(text2, maxBytes) {
25440
+ if (encoder.encode(text2).length <= maxBytes) return text2;
24851
25441
  const budget = maxBytes - 3;
24852
25442
  let out = "";
24853
25443
  let used = 0;
24854
- for (const char of text) {
25444
+ for (const char of text2) {
24855
25445
  const size = encoder.encode(char).length;
24856
25446
  if (used + size > budget) break;
24857
25447
  out += char;
@@ -24859,8 +25449,8 @@ function truncateBytes(text, maxBytes) {
24859
25449
  }
24860
25450
  return `${out}\u2026`;
24861
25451
  }
24862
- function stripControls(text) {
24863
- return text.replace(/[\u0000-\u001f\u007f-\u009f]+/g, " ").trim();
25452
+ function stripControls(text2) {
25453
+ return text2.replace(/[\u0000-\u001f\u007f-\u009f]+/g, " ").trim();
24864
25454
  }
24865
25455
  function buildNtfyPayload(notification, config) {
24866
25456
  const title = truncateBytes(stripControls(notification.title), TITLE_MAX_BYTES) || "Cogpit";
@@ -24879,7 +25469,7 @@ async function sendPushNotification(notification, config = getPushConfig()) {
24879
25469
  method: "POST",
24880
25470
  headers,
24881
25471
  body: JSON.stringify(buildNtfyPayload(notification, config)),
24882
- signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
25472
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2),
24883
25473
  redirect: "error"
24884
25474
  });
24885
25475
  if (!response.ok) {
@@ -24893,14 +25483,14 @@ async function sendPushNotification(notification, config = getPushConfig()) {
24893
25483
  return false;
24894
25484
  }
24895
25485
  }
24896
- var MESSAGE_MAX_BYTES, TITLE_MAX_BYTES, REQUEST_TIMEOUT_MS, encoder;
25486
+ var MESSAGE_MAX_BYTES, TITLE_MAX_BYTES, REQUEST_TIMEOUT_MS2, encoder;
24897
25487
  var init_pushNotify = __esm({
24898
25488
  "../../server/lib/pushNotify.ts"() {
24899
25489
  init_notifications2();
24900
25490
  init_pushConfig();
24901
25491
  MESSAGE_MAX_BYTES = 1024;
24902
25492
  TITLE_MAX_BYTES = 256;
24903
- REQUEST_TIMEOUT_MS = 5e3;
25493
+ REQUEST_TIMEOUT_MS2 = 5e3;
24904
25494
  encoder = new TextEncoder();
24905
25495
  }
24906
25496
  });
@@ -25703,8 +26293,8 @@ var init_ports2 = __esm({
25703
26293
 
25704
26294
  // ../../server/routes/project-file.ts
25705
26295
  import { randomUUID as randomUUID5 } from "node:crypto";
25706
- import { readFile as readFile19, realpath as realpath11, rename as rename3, stat as stat16, unlink as unlink6, writeFile as writeFile6 } from "node:fs/promises";
25707
- import { dirname as dirname10, isAbsolute as isAbsolute11, resolve as resolve17 } from "node:path";
26296
+ import { readFile as readFile20, realpath as realpath11, rename as rename3, stat as stat16, unlink as unlink6, writeFile as writeFile6 } from "node:fs/promises";
26297
+ import { dirname as dirname11, isAbsolute as isAbsolute11, resolve as resolve17 } from "node:path";
25708
26298
  function readBody(req) {
25709
26299
  return new Promise((resolveBody, reject) => {
25710
26300
  let body = "";
@@ -25765,7 +26355,7 @@ async function writeAtomically(absolutePath, content, mode, expectedMtimeMs) {
25765
26355
  if (latest.mtimeMs !== expectedMtimeMs) {
25766
26356
  throw new ProjectFileError(409, "File changed on disk. Reload it before saving.");
25767
26357
  }
25768
- const temporaryPath = resolve17(dirname10(absolutePath), `.${randomUUID5()}.cogpit-save`);
26358
+ const temporaryPath = resolve17(dirname11(absolutePath), `.${randomUUID5()}.cogpit-save`);
25769
26359
  try {
25770
26360
  await writeFile6(temporaryPath, content, { encoding: "utf-8", mode });
25771
26361
  const beforeRename = await stat16(absolutePath);
@@ -25785,7 +26375,7 @@ function registerProjectFileContentRoutes(use) {
25785
26375
  const filePath = url.searchParams.get("path") ?? "";
25786
26376
  try {
25787
26377
  const file = await resolveProjectFile(cwd, filePath);
25788
- const buffer = await readFile19(file.absolutePath);
26378
+ const buffer = await readFile20(file.absolutePath);
25789
26379
  return sendJson(res, 200, {
25790
26380
  content: decodeTextFile(buffer),
25791
26381
  mtimeMs: file.info.mtimeMs,
@@ -25915,30 +26505,77 @@ async function listProjectFiles(root, { skipCache = false } = {}) {
25915
26505
  fileCache.set(root, { expiresAt: Date.now() + CACHE_TTL_MS3, files });
25916
26506
  return files;
25917
26507
  }
26508
+ function listDirectoryEntries(files, directory) {
26509
+ const prefix = directory ? `${directory.replace(/\/+$/, "")}/` : "";
26510
+ const children = directChildren(files, prefix);
26511
+ return [
26512
+ ...children.directories.map((name) => ({ name: compactChain(files, prefix, name), type: "directory" })),
26513
+ ...children.files.map((name) => ({ name, type: "file" }))
26514
+ ];
26515
+ }
26516
+ function directChildren(files, prefix) {
26517
+ const directories = /* @__PURE__ */ new Set();
26518
+ const plainFiles = /* @__PURE__ */ new Set();
26519
+ for (const file of files) {
26520
+ if (!file.startsWith(prefix)) continue;
26521
+ const rest = file.slice(prefix.length);
26522
+ const slash = rest.indexOf("/");
26523
+ if (slash === -1) plainFiles.add(rest);
26524
+ else directories.add(rest.slice(0, slash));
26525
+ }
26526
+ const byName = (a, b) => a.localeCompare(b);
26527
+ return { directories: [...directories].sort(byName), files: [...plainFiles].sort(byName) };
26528
+ }
26529
+ function compactChain(files, prefix, name) {
26530
+ let chain = name;
26531
+ for (; ; ) {
26532
+ const children = directChildren(files, `${prefix}${chain}/`);
26533
+ if (children.files.length > 0 || children.directories.length !== 1) return chain;
26534
+ chain = `${chain}/${children.directories[0]}`;
26535
+ }
26536
+ }
26537
+ async function resolveProjectRoot(cwd) {
26538
+ if (!isAbsolute12(cwd)) return { error: "cwd must be an absolute path", status: 400 };
26539
+ try {
26540
+ const root = resolve18(cwd);
26541
+ const info = await stat17(root);
26542
+ if (!info.isDirectory()) return { error: "cwd must be a directory", status: 400 };
26543
+ return { root: await realpath12(root) };
26544
+ } catch {
26545
+ return { error: "Project directory not found", status: 404 };
26546
+ }
26547
+ }
25918
26548
  function registerProjectFileRoutes(use) {
26549
+ use("/api/project-files/tree", async (req, res, next) => {
26550
+ if (req.method !== "GET") return next();
26551
+ const url = new URL(req.url || "", "http://localhost");
26552
+ const directory = (url.searchParams.get("dir") ?? "").replace(/^\/+|\/+$/g, "");
26553
+ if (directory.split("/").some((segment) => segment === "..")) {
26554
+ return sendJson(res, 400, { error: "dir must stay inside the project" });
26555
+ }
26556
+ const resolved = await resolveProjectRoot(url.searchParams.get("cwd") ?? "");
26557
+ if ("error" in resolved) return sendJson(res, resolved.status, { error: resolved.error });
26558
+ const files = await listProjectFiles(resolved.root, { skipCache: url.searchParams.get("refresh") === "1" });
26559
+ return sendJson(res, 200, {
26560
+ entries: listDirectoryEntries(files, directory),
26561
+ scanLimited: files.length >= MAX_FILES
26562
+ });
26563
+ });
25919
26564
  use("/api/project-files", async (req, res, next) => {
25920
26565
  if (req.method !== "GET") return next();
25921
26566
  const url = new URL(req.url || "", "http://localhost");
25922
- const cwd = url.searchParams.get("cwd") ?? "";
25923
26567
  const query4 = url.searchParams.get("q") ?? "";
25924
26568
  const limit = Math.min(Math.max(Number(url.searchParams.get("limit")) || 30, 1), 100);
25925
26569
  const skipCache = url.searchParams.get("refresh") === "1";
25926
- if (!isAbsolute12(cwd)) return sendJson(res, 400, { error: "cwd must be an absolute path" });
25927
- let root = resolve18(cwd);
25928
- try {
25929
- const info = await stat17(root);
25930
- if (!info.isDirectory()) return sendJson(res, 400, { error: "cwd must be a directory" });
25931
- root = await realpath12(root);
25932
- const files = await listProjectFiles(root, { skipCache });
25933
- const ranked = rankProjectFiles(files, query4, limit);
25934
- return sendJson(res, 200, {
25935
- files: ranked.files,
25936
- totalMatches: ranked.totalMatches,
25937
- scanLimited: files.length >= MAX_FILES
25938
- });
25939
- } catch {
25940
- return sendJson(res, 404, { error: "Project directory not found" });
25941
- }
26570
+ const resolved = await resolveProjectRoot(url.searchParams.get("cwd") ?? "");
26571
+ if ("error" in resolved) return sendJson(res, resolved.status, { error: resolved.error });
26572
+ const files = await listProjectFiles(resolved.root, { skipCache });
26573
+ const ranked = rankProjectFiles(files, query4, limit);
26574
+ return sendJson(res, 200, {
26575
+ files: ranked.files,
26576
+ totalMatches: ranked.totalMatches,
26577
+ scanLimited: files.length >= MAX_FILES
26578
+ });
25942
26579
  });
25943
26580
  }
25944
26581
  var MAX_FILES, CACHE_TTL_MS3, IGNORED_DIRECTORIES, fileCache, execFile8;
@@ -26066,7 +26703,7 @@ var init_sessionSearch = __esm({
26066
26703
 
26067
26704
  // ../../server/lib/projectNames.ts
26068
26705
  import { basename as basename10 } from "node:path";
26069
- import { homedir as homedir10 } from "node:os";
26706
+ import { homedir as homedir11 } from "node:os";
26070
26707
  function shortNameFromPath(path) {
26071
26708
  const trimmed = path.replace(/[\\/]+$/, "");
26072
26709
  return basename10(trimmed) || trimmed || path;
@@ -26102,7 +26739,7 @@ var HOME_PREFIX;
26102
26739
  var init_projectNames = __esm({
26103
26740
  "../../server/lib/projectNames.ts"() {
26104
26741
  init_agent_descriptors();
26105
- HOME_PREFIX = descriptorFor("claude").dirName.encode(homedir10()).replace(/^-/, "").toLowerCase();
26742
+ HOME_PREFIX = descriptorFor("claude").dirName.encode(homedir11()).replace(/^-/, "").toLowerCase();
26106
26743
  }
26107
26744
  });
26108
26745
 
@@ -26214,8 +26851,8 @@ async function handleActiveSessions(req, res, next) {
26214
26851
  const resolveTeamLead = (teamName) => {
26215
26852
  let cached = teamLeadCache.get(teamName);
26216
26853
  if (!cached) {
26217
- const configPath = join11(dirs.TEAMS_DIR, teamName, "config.json");
26218
- cached = isWithinDir(dirs.TEAMS_DIR, configPath) ? readFile9(configPath, "utf-8").then((raw) => {
26854
+ const configPath2 = join11(dirs.TEAMS_DIR, teamName, "config.json");
26855
+ cached = isWithinDir(dirs.TEAMS_DIR, configPath2) ? readFile9(configPath2, "utf-8").then((raw) => {
26219
26856
  const lead = JSON.parse(String(raw)).leadSessionId;
26220
26857
  return typeof lead === "string" && lead ? lead : null;
26221
26858
  }).catch(() => null) : Promise.resolve(null);
@@ -26425,18 +27062,18 @@ async function readSessionHeader(filePath) {
26425
27062
  try {
26426
27063
  const fileStat = await fh.stat();
26427
27064
  let readLen = Math.min(HEADER_BYTES, fileStat.size);
26428
- let text = "";
27065
+ let text2 = "";
26429
27066
  let bytesRead = 0;
26430
27067
  for (; ; ) {
26431
27068
  const buf = Buffer.allocUnsafe(readLen);
26432
27069
  const result = await fh.read(buf, 0, readLen, 0);
26433
27070
  bytesRead = result.bytesRead;
26434
- text = buf.subarray(0, bytesRead).toString("utf-8");
27071
+ text2 = buf.subarray(0, bytesRead).toString("utf-8");
26435
27072
  const isWholeFile = bytesRead >= fileStat.size;
26436
- if (isWholeFile || text.includes("\n") || readLen >= MAX_HEADER_BYTES) break;
27073
+ if (isWholeFile || text2.includes("\n") || readLen >= MAX_HEADER_BYTES) break;
26437
27074
  readLen = Math.min(readLen * 4, Math.min(fileStat.size, MAX_HEADER_BYTES));
26438
27075
  }
26439
- const parts = text.split("\n").filter((l) => l.trim().length > 0);
27076
+ const parts = text2.split("\n").filter((l) => l.trim().length > 0);
26440
27077
  if (bytesRead < fileStat.size && parts.length > 0) {
26441
27078
  parts.pop();
26442
27079
  }
@@ -26900,8 +27537,8 @@ function getProviderUpdates() {
26900
27537
  function isProviderUpdateId(value) {
26901
27538
  return typeof value === "string" && AGENT_KINDS.includes(value);
26902
27539
  }
26903
- function truncate2(text) {
26904
- const trimmed = text.trim();
27540
+ function truncate2(text2) {
27541
+ const trimmed = text2.trim();
26905
27542
  if (!trimmed) return null;
26906
27543
  return trimmed.length <= CLI_OUTPUT_MAX_CHARS ? trimmed : trimmed.slice(0, CLI_OUTPUT_MAX_CHARS);
26907
27544
  }
@@ -27049,12 +27686,189 @@ var init_agent_executable = __esm({
27049
27686
  }
27050
27687
  });
27051
27688
 
27689
+ // ../../server/agents/claudeSwap.ts
27690
+ function asRow(value) {
27691
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
27692
+ }
27693
+ function asString2(value) {
27694
+ return typeof value === "string" && value.trim() ? value : null;
27695
+ }
27696
+ function asSlot(value) {
27697
+ return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : null;
27698
+ }
27699
+ function parseWindow(value) {
27700
+ const row = asRow(value);
27701
+ if (!row || typeof row.pct !== "number" || !Number.isFinite(row.pct)) return null;
27702
+ return {
27703
+ pct: Math.min(100, Math.max(0, row.pct)),
27704
+ resetsIn: asString2(row.countdown),
27705
+ resetsAt: asString2(row.resetsAt)
27706
+ };
27707
+ }
27708
+ function parseUsage2(value) {
27709
+ const row = asRow(value);
27710
+ if (!row) return null;
27711
+ return { fiveHour: parseWindow(row.fiveHour), sevenDay: parseWindow(row.sevenDay) };
27712
+ }
27713
+ function parseAccount(value) {
27714
+ const row = asRow(value);
27715
+ if (!row) return null;
27716
+ const slot = asSlot(row.number);
27717
+ const email = asString2(row.email);
27718
+ if (slot === null || email === null) return null;
27719
+ return {
27720
+ slot,
27721
+ alias: asString2(row.alias),
27722
+ email,
27723
+ organization: asString2(row.organizationName),
27724
+ active: row.active === true,
27725
+ disabled: row.disabled === true,
27726
+ usageStatus: asString2(row.usageStatus) ?? "unavailable",
27727
+ usage: parseUsage2(row.usage)
27728
+ };
27729
+ }
27730
+ function parseJson(stdout) {
27731
+ try {
27732
+ return asRow(JSON.parse(stdout));
27733
+ } catch {
27734
+ return null;
27735
+ }
27736
+ }
27737
+ function parseAccountList(stdout) {
27738
+ const payload = parseJson(stdout);
27739
+ if (!payload || !Array.isArray(payload.accounts)) return null;
27740
+ return {
27741
+ activeSlot: asSlot(payload.activeAccountNumber),
27742
+ accounts: payload.accounts.map(parseAccount).filter((account) => account !== null)
27743
+ };
27744
+ }
27745
+ function parseSwitchResult(stdout) {
27746
+ const payload = parseJson(stdout);
27747
+ if (!payload) return null;
27748
+ const error = switcherError(payload);
27749
+ if (error) return { error };
27750
+ if (typeof payload.switched !== "boolean") return null;
27751
+ return {
27752
+ switched: payload.switched,
27753
+ message: asString2(payload.message) ?? (payload.switched ? "Switched account." : "Account unchanged."),
27754
+ warnings: Array.isArray(payload.warnings) ? payload.warnings.filter((w) => typeof w === "string") : []
27755
+ };
27756
+ }
27757
+ function switcherError(payload) {
27758
+ return asString2(asRow(payload.error)?.message);
27759
+ }
27760
+ function failureMessage(run2, fallback) {
27761
+ if (run2.timedOut) return `${CSWAP_BIN} timed out`;
27762
+ const envelope = parseJson(run2.stdout);
27763
+ return envelope && switcherError(envelope) || run2.stderr.trim() || fallback;
27764
+ }
27765
+ function isClaudeSwapInstalled() {
27766
+ return findExecutableOnPath(CSWAP_BIN) !== void 0;
27767
+ }
27768
+ async function describeClaudeAccounts() {
27769
+ if (!isClaudeSwapInstalled()) return { status: "missing" };
27770
+ const [version, list] = await Promise.all([
27771
+ runCli(CSWAP_BIN, ["--version"], DEFAULT_PROBE_TIMEOUT_MS),
27772
+ runCli(CSWAP_BIN, ["list", "--json"], LIST_TIMEOUT_MS)
27773
+ ]);
27774
+ if (list.code !== 0) {
27775
+ return { status: "error", error: failureMessage(list, `${CSWAP_BIN} list failed`) };
27776
+ }
27777
+ const parsed = parseAccountList(list.stdout);
27778
+ if (!parsed) return { status: "error", error: `${CSWAP_BIN} list returned unexpected output` };
27779
+ return { status: "ok", tool: TOOL_NAME, version: extractVersion(version.stdout), ...parsed };
27780
+ }
27781
+ async function switchClaudeAccount(slot) {
27782
+ if (asSlot(slot) === null) throw new Error("slot must be a positive integer");
27783
+ const run2 = await runCli(CSWAP_BIN, ["switch", String(slot), "--json"], SWITCH_TIMEOUT_MS);
27784
+ const parsed = run2.code === 0 ? parseSwitchResult(run2.stdout) : null;
27785
+ if (!parsed) throw new Error(failureMessage(run2, `${CSWAP_BIN} switch failed`));
27786
+ if ("error" in parsed) throw new Error(parsed.error);
27787
+ return { ...parsed, credentialStore: process.platform === "darwin" ? "keychain" : "file" };
27788
+ }
27789
+ var CSWAP_BIN, TOOL_NAME, LIST_TIMEOUT_MS, SWITCH_TIMEOUT_MS;
27790
+ var init_claudeSwap = __esm({
27791
+ "../../server/agents/claudeSwap.ts"() {
27792
+ init_versions();
27793
+ init_binaryResolver();
27794
+ init_cliProcess();
27795
+ CSWAP_BIN = "cswap";
27796
+ TOOL_NAME = "claude-swap";
27797
+ LIST_TIMEOUT_MS = 3e4;
27798
+ SWITCH_TIMEOUT_MS = 3e4;
27799
+ }
27800
+ });
27801
+
27802
+ // ../../server/agents/accounts.ts
27803
+ function accountSwitcherFor(kind) {
27804
+ return kind === "claude" ? claudeAccounts : null;
27805
+ }
27806
+ var claudeAccounts;
27807
+ var init_accounts = __esm({
27808
+ "../../server/agents/accounts.ts"() {
27809
+ init_claudeSwap();
27810
+ claudeAccounts = {
27811
+ describe: describeClaudeAccounts,
27812
+ switchTo: switchClaudeAccount
27813
+ };
27814
+ }
27815
+ });
27816
+
27817
+ // ../../server/routes/agent-accounts.ts
27818
+ function registerAgentAccountRoutes(use) {
27819
+ use("/api/agent-accounts", async (req, res, next) => {
27820
+ const segments2 = new URL(req.url || "/", "http://localhost").pathname.split("/").filter(Boolean);
27821
+ const [kind, action, ...rest] = segments2;
27822
+ if (!AGENT_KINDS.includes(kind ?? "") || rest.length > 0) return next();
27823
+ const switcher = accountSwitcherFor(kind);
27824
+ if (action === void 0 && req.method === "GET") {
27825
+ if (!switcher) {
27826
+ sendJson(res, 404, { error: `${kind} has no account switcher` });
27827
+ return;
27828
+ }
27829
+ try {
27830
+ sendJson(res, 200, await switcher.describe());
27831
+ } catch (err) {
27832
+ sendJson(res, 500, { error: String(err) });
27833
+ }
27834
+ return;
27835
+ }
27836
+ if (action === "switch" && req.method === "POST") {
27837
+ if (!switcher) {
27838
+ sendJson(res, 404, { error: `${kind} has no account switcher` });
27839
+ return;
27840
+ }
27841
+ withJsonBody(req, res, async (body) => {
27842
+ const slot = body?.slot;
27843
+ if (typeof slot !== "number" || !Number.isInteger(slot) || slot <= 0) {
27844
+ sendJson(res, 400, { error: "slot must be a positive integer" });
27845
+ return;
27846
+ }
27847
+ try {
27848
+ sendJson(res, 200, await switcher.switchTo(slot));
27849
+ } catch (err) {
27850
+ sendJson(res, 500, { error: err instanceof Error ? err.message : String(err) });
27851
+ }
27852
+ });
27853
+ return;
27854
+ }
27855
+ next();
27856
+ });
27857
+ }
27858
+ var init_agent_accounts = __esm({
27859
+ "../../server/routes/agent-accounts.ts"() {
27860
+ init_agent_descriptors();
27861
+ init_accounts();
27862
+ init_http();
27863
+ }
27864
+ });
27865
+
27052
27866
  // ../../server/routes/scripts/discovery.ts
27053
- import { readdir as readdir12, readFile as readFile20 } from "node:fs/promises";
27054
- import { join as join26, relative as relative10 } from "node:path";
27867
+ import { readdir as readdir12, readFile as readFile21 } from "node:fs/promises";
27868
+ import { join as join27, relative as relative10 } from "node:path";
27055
27869
  async function extractScripts(dir, dirLabel) {
27056
27870
  try {
27057
- const raw = await readFile20(join26(dir, "package.json"), "utf-8");
27871
+ const raw = await readFile21(join27(dir, "package.json"), "utf-8");
27058
27872
  const pkg = JSON.parse(raw);
27059
27873
  const scripts = pkg.scripts;
27060
27874
  if (!scripts || typeof scripts !== "object") return [];
@@ -27080,7 +27894,7 @@ async function discoverScripts(projectDir) {
27080
27894
  );
27081
27895
  const childResults = await Promise.all(
27082
27896
  childDirs.map(async (entry) => {
27083
- const childPath = join26(projectDir, entry.name);
27897
+ const childPath = join27(projectDir, entry.name);
27084
27898
  const label = relative10(projectDir, childPath) + "/";
27085
27899
  return extractScripts(childPath, label);
27086
27900
  })
@@ -27266,12 +28080,12 @@ var init_session_config = __esm({
27266
28080
 
27267
28081
  // ../../server/lib/agentTeamIdentity.ts
27268
28082
  import { open as open9, readdir as readdir13 } from "node:fs/promises";
27269
- import { join as join27 } from "node:path";
28083
+ import { join as join28 } from "node:path";
27270
28084
  async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
27271
28085
  const entries3 = await readdir13(dirs.PROJECTS_DIR, { withFileTypes: true });
27272
28086
  for (const entry of entries3) {
27273
28087
  if (!entry.isDirectory() || entry.name === "memory") continue;
27274
- const filePath = join27(
28088
+ const filePath = join28(
27275
28089
  dirs.PROJECTS_DIR,
27276
28090
  entry.name,
27277
28091
  leadSessionId,
@@ -27312,8 +28126,8 @@ async function readSessionTeamTags(filePath) {
27312
28126
  try {
27313
28127
  const buf = Buffer.alloc(32768);
27314
28128
  const { bytesRead } = await fh.read(buf, 0, 32768, 0);
27315
- const text = buf.subarray(0, bytesRead).toString("utf-8");
27316
- const lines = text.split("\n");
28129
+ const text2 = buf.subarray(0, bytesRead).toString("utf-8");
28130
+ const lines = text2.split("\n");
27317
28131
  const complete = bytesRead === 32768 ? lines.slice(0, -1) : lines;
27318
28132
  for (const line of complete.slice(0, 40)) {
27319
28133
  if (!line || !line.includes('"teamName"')) continue;
@@ -27479,8 +28293,8 @@ function mapToolCall(tc) {
27479
28293
  function mapContentBlock(block) {
27480
28294
  switch (block.kind) {
27481
28295
  case "thinking": {
27482
- const text = block.blocks.filter((b) => b.thinking.length > 0).map((b) => b.thinking).join("\n\n");
27483
- return { kind: "thinking", text, timestamp: block.timestamp ?? null };
28296
+ const text2 = block.blocks.filter((b) => b.thinking.length > 0).map((b) => b.thinking).join("\n\n");
28297
+ return { kind: "thinking", text: text2, timestamp: block.timestamp ?? null };
27484
28298
  }
27485
28299
  case "text":
27486
28300
  return { kind: "text", text: block.text.join("\n\n"), timestamp: block.timestamp ?? null };
@@ -27548,9 +28362,9 @@ async function findTeamContext(sessionId, subagentFileName) {
27548
28362
  const teamEntries = await readdir6(dirs.TEAMS_DIR, { withFileTypes: true });
27549
28363
  for (const entry of teamEntries) {
27550
28364
  if (!entry.isDirectory()) continue;
27551
- const configPath = join11(dirs.TEAMS_DIR, entry.name, "config.json");
28365
+ const configPath2 = join11(dirs.TEAMS_DIR, entry.name, "config.json");
27552
28366
  try {
27553
- const raw = await readFile9(configPath, "utf-8");
28367
+ const raw = await readFile9(configPath2, "utf-8");
27554
28368
  const config = JSON.parse(raw);
27555
28369
  if (config.leadSessionId !== sessionId) continue;
27556
28370
  const members = config.members ?? [];
@@ -27786,14 +28600,14 @@ function cdTarget(segment, cwd) {
27786
28600
  if (!m) return null;
27787
28601
  return resolvePath(m[1] ?? m[2] ?? m[3] ?? "", cwd);
27788
28602
  }
27789
- function writeTarget(text) {
27790
- const tee = text.match(/^tee\s+(?:(-a)\s+)?(?:"([^"]+)"|'([^']+)'|([^\s<>|;&]+))/);
28603
+ function writeTarget(text2) {
28604
+ const tee = text2.match(/^tee\s+(?:(-a)\s+)?(?:"([^"]+)"|'([^']+)'|([^\s<>|;&]+))/);
27791
28605
  if (tee) {
27792
28606
  if (tee[1]) return null;
27793
28607
  return tee[2] ?? tee[3] ?? tee[4] ?? null;
27794
28608
  }
27795
- if (!/^cat\b/.test(text)) return null;
27796
- const redirect = text.match(/(>>?)\s*(?:"([^"]+)"|'([^']+)'|([^\s<>|;&]+))/);
28609
+ if (!/^cat\b/.test(text2)) return null;
28610
+ const redirect = text2.match(/(>>?)\s*(?:"([^"]+)"|'([^']+)'|([^\s<>|;&]+))/);
27797
28611
  if (!redirect || redirect[1] === ">>") return null;
27798
28612
  return redirect[2] ?? redirect[3] ?? redirect[4] ?? null;
27799
28613
  }
@@ -27964,7 +28778,7 @@ function normalizeCopilotFileChangeEvents(jsonlContent) {
27964
28778
  }
27965
28779
  });
27966
28780
  }
27967
- return records.map((record4) => JSON.stringify(record4)).join("\n");
28781
+ return records.map((record5) => JSON.stringify(record5)).join("\n");
27968
28782
  }
27969
28783
  async function parseSessionFileChanges(jsonlContent, includeContent) {
27970
28784
  if (formatForText(jsonlContent).kind === "copilot") {
@@ -28034,8 +28848,8 @@ async function parseSessionFileChanges(jsonlContent, includeContent) {
28034
28848
  if (payload.type === "custom_tool_call_output" && typeof payload.call_id === "string") {
28035
28849
  const patchCalls = patchCallIds.get(payload.call_id);
28036
28850
  if (patchCalls) {
28037
- const { text, isError: wrapperIsError } = parseCustomToolOutput(payload.output);
28038
- const failedIds = patchCalls.direct && wrapperIsError ? new Set(patchCalls.calls.map((call) => call.id)) : findFailedNestedPatchCallIds(text, wrapperIsError, patchCalls.calls);
28851
+ const { text: text2, isError: wrapperIsError } = parseCustomToolOutput(payload.output);
28852
+ const failedIds = patchCalls.direct && wrapperIsError ? new Set(patchCalls.calls.map((call) => call.id)) : findFailedNestedPatchCallIds(text2, wrapperIsError, patchCalls.calls);
28039
28853
  for (const call of patchCalls.calls) resultMap.set(call.id, failedIds.has(call.id));
28040
28854
  }
28041
28855
  }
@@ -28272,7 +29086,7 @@ var init_session_status = __esm({
28272
29086
  });
28273
29087
 
28274
29088
  // ../../server/routes/shares.ts
28275
- import { basename as basename11, dirname as dirname11 } from "node:path";
29089
+ import { basename as basename11, dirname as dirname12 } from "node:path";
28276
29090
  function remoteAccessEnabled() {
28277
29091
  return isTeamEdition() || getConfig()?.networkAccess === true;
28278
29092
  }
@@ -28287,7 +29101,7 @@ async function resolveShareTarget(sessionId) {
28287
29101
  if (agentKind === "codex" || agentKind === "copilot") {
28288
29102
  return { shareable: false, reason: agentKind };
28289
29103
  }
28290
- const dirName = basename11(dirname11(filePath));
29104
+ const dirName = basename11(dirname12(filePath));
28291
29105
  const fileName = basename11(filePath);
28292
29106
  const resolved = await resolveSessionFilePath(dirName, fileName);
28293
29107
  if (resolved !== filePath) return { shareable: false, reason: "not-found" };
@@ -28693,7 +29507,7 @@ async function readBodyOrRespond(req, res) {
28693
29507
  return null;
28694
29508
  }
28695
29509
  }
28696
- function asString2(value) {
29510
+ function asString3(value) {
28697
29511
  return typeof value === "string" ? value : "";
28698
29512
  }
28699
29513
  function enqueueBootstrap(operation) {
@@ -28754,8 +29568,8 @@ function registerTeamAdminRoutes(use) {
28754
29568
  }
28755
29569
  try {
28756
29570
  const user = await createUser({
28757
- username: asString2(body.username),
28758
- password: asString2(body.password),
29571
+ username: asString3(body.username),
29572
+ password: asString3(body.password),
28759
29573
  displayName: typeof body.displayName === "string" ? body.displayName : void 0,
28760
29574
  role: "admin"
28761
29575
  });
@@ -28787,10 +29601,10 @@ function registerTeamAdminRoutes(use) {
28787
29601
  if (body === null) return;
28788
29602
  try {
28789
29603
  const user = await createUser({
28790
- username: asString2(body.username),
28791
- password: asString2(body.password),
29604
+ username: asString3(body.username),
29605
+ password: asString3(body.password),
28792
29606
  displayName: typeof body.displayName === "string" ? body.displayName : void 0,
28793
- role: asString2(body.role)
29607
+ role: asString3(body.role)
28794
29608
  });
28795
29609
  return sendJson(res, 200, { user });
28796
29610
  } catch (error) {
@@ -28883,10 +29697,10 @@ async function detectTeamFromSessionFile(sessionId, dirNameHint) {
28883
29697
  if (!isWithinDir(dirs.PROJECTS_DIR, filePath)) continue;
28884
29698
  const tags = await readSessionTeamTags(filePath);
28885
29699
  if (!tags.teamName) continue;
28886
- const configPath = join11(dirs.TEAMS_DIR, tags.teamName, "config.json");
28887
- if (!isWithinDir(dirs.TEAMS_DIR, configPath)) continue;
29700
+ const configPath2 = join11(dirs.TEAMS_DIR, tags.teamName, "config.json");
29701
+ if (!isWithinDir(dirs.TEAMS_DIR, configPath2)) continue;
28888
29702
  try {
28889
- const config = JSON.parse(await readFile9(configPath, "utf-8"));
29703
+ const config = JSON.parse(await readFile9(configPath2, "utf-8"));
28890
29704
  return {
28891
29705
  teamName: tags.teamName,
28892
29706
  config,
@@ -28965,8 +29779,8 @@ function registerTeamSessionRoutes(use) {
28965
29779
  let bestMatch = null;
28966
29780
  for (const teamName of teamDirs) {
28967
29781
  try {
28968
- const configPath = join11(dirs.TEAMS_DIR, teamName, "config.json");
28969
- const configRaw = await readFile9(configPath, "utf-8");
29782
+ const configPath2 = join11(dirs.TEAMS_DIR, teamName, "config.json");
29783
+ const configRaw = await readFile9(configPath2, "utf-8");
28970
29784
  const config = JSON.parse(configRaw);
28971
29785
  if (config.leadSessionId !== leadSessionId) continue;
28972
29786
  const createdAt = config.createdAt ?? 0;
@@ -29020,8 +29834,8 @@ function registerTeamSessionRoutes(use) {
29020
29834
  const teamName = decodeURIComponent(parts[0]);
29021
29835
  const memberName = decodeURIComponent(parts[1]);
29022
29836
  try {
29023
- const configPath = join11(dirs.TEAMS_DIR, teamName, "config.json");
29024
- const configRaw = await readFile9(configPath, "utf-8");
29837
+ const configPath2 = join11(dirs.TEAMS_DIR, teamName, "config.json");
29838
+ const configRaw = await readFile9(configPath2, "utf-8");
29025
29839
  const config = JSON.parse(configRaw);
29026
29840
  const leadSessionId = config.leadSessionId;
29027
29841
  if (!leadSessionId) {
@@ -29152,8 +29966,8 @@ function registerTeamRoutes(use) {
29152
29966
  const teams = [];
29153
29967
  for (const teamName of teamDirs) {
29154
29968
  try {
29155
- const configPath = join11(dirs.TEAMS_DIR, teamName, "config.json");
29156
- const configRaw = await readFile9(configPath, "utf-8");
29969
+ const configPath2 = join11(dirs.TEAMS_DIR, teamName, "config.json");
29970
+ const configRaw = await readFile9(configPath2, "utf-8");
29157
29971
  const config = JSON.parse(configRaw);
29158
29972
  const taskSummary = { total: 0, completed: 0, inProgress: 0, pending: 0 };
29159
29973
  try {
@@ -29352,7 +30166,7 @@ var init_teams = __esm({
29352
30166
  });
29353
30167
 
29354
30168
  // ../../server/routes/undo/paths.ts
29355
- import { dirname as dirname12 } from "node:path";
30169
+ import { dirname as dirname13 } from "node:path";
29356
30170
  function isOpaqueFileName(value) {
29357
30171
  return value.length > 0 && !value.includes("/") && !value.includes("\\") && !value.includes("\0");
29358
30172
  }
@@ -29360,7 +30174,7 @@ function resolveUndoStatePath(sessionId) {
29360
30174
  if (!isOpaqueFileName(sessionId)) return null;
29361
30175
  const undoRoot = resolve7(dirs.UNDO_DIR);
29362
30176
  const filePath = resolve7(undoRoot, `${sessionId}.json`);
29363
- return isWithinDir(undoRoot, filePath) && dirname12(filePath) === undoRoot ? filePath : null;
30177
+ return isWithinDir(undoRoot, filePath) && dirname13(filePath) === undoRoot ? filePath : null;
29364
30178
  }
29365
30179
  function resolveEncodedUndoStatePath(encodedSessionId) {
29366
30180
  try {
@@ -29384,7 +30198,7 @@ var init_paths = __esm({
29384
30198
  });
29385
30199
 
29386
30200
  // ../../server/routes/undo/fileOperations.ts
29387
- import { basename as basename12, dirname as dirname13, isAbsolute as isAbsolute13 } from "node:path";
30201
+ import { basename as basename12, dirname as dirname14, isAbsolute as isAbsolute13 } from "node:path";
29388
30202
  import { lstat as lstat6, realpath as realpath13 } from "node:fs/promises";
29389
30203
  function hasTraversalSegment(filePath) {
29390
30204
  return filePath.split(/[\\/]+/).includes("..");
@@ -29409,7 +30223,7 @@ async function resolveSafeOperationPath(filePath, home, canonicalHome) {
29409
30223
  } catch (error) {
29410
30224
  if (!isMissingPathError(error)) return null;
29411
30225
  try {
29412
- const canonicalParent = await realpath13(dirname13(resolved));
30226
+ const canonicalParent = await realpath13(dirname14(resolved));
29413
30227
  const canonicalTarget = join11(canonicalParent, basename12(resolved));
29414
30228
  return isWithinDir(canonicalHome, canonicalTarget) && !isForbiddenPath(canonicalTarget) ? canonicalTarget : null;
29415
30229
  } catch {
@@ -30044,25 +30858,25 @@ function aggregateSessionUsage(scopedRecords, rates2) {
30044
30858
  let providerReportedRecords = 0;
30045
30859
  let modelPricedRecords = 0;
30046
30860
  let unpricedRecords = 0;
30047
- for (const { record: record4, isSubagent } of scopedRecords) {
30048
- if (record4.dedupeKey !== null) {
30049
- if (seen.has(record4.dedupeKey)) continue;
30050
- seen.add(record4.dedupeKey);
30051
- }
30052
- const priced = priceUsage(rates2, record4.model, record4.totals, record4.reportedCostUsd, record4.speed);
30053
- const recordSavings = cacheSavingsUsd(rates2, record4.model, record4.totals, record4.speed);
30054
- const calculated = usageCostBreakdown(rates2, record4.model, record4.totals, record4.speed);
30055
- totals = addUsageCostTotals(totals, record4.totals);
30861
+ for (const { record: record5, isSubagent } of scopedRecords) {
30862
+ if (record5.dedupeKey !== null) {
30863
+ if (seen.has(record5.dedupeKey)) continue;
30864
+ seen.add(record5.dedupeKey);
30865
+ }
30866
+ const priced = priceUsage(rates2, record5.model, record5.totals, record5.reportedCostUsd, record5.speed);
30867
+ const recordSavings = cacheSavingsUsd(rates2, record5.model, record5.totals, record5.speed);
30868
+ const calculated = usageCostBreakdown(rates2, record5.model, record5.totals, record5.speed);
30869
+ totals = addUsageCostTotals(totals, record5.totals);
30056
30870
  costUsd += priced.costUsd;
30057
30871
  cacheSavings += recordSavings;
30058
30872
  addRecordCostBreakdown(breakdown, calculated, priced.costUsd);
30059
30873
  if (priced.costSource === "providerReported") providerReportedRecords += 1;
30060
30874
  else if (priced.costSource === "modelPriced") modelPricedRecords += 1;
30061
30875
  else unpricedRecords += 1;
30062
- let model = models.get(record4.model);
30876
+ let model = models.get(record5.model);
30063
30877
  if (!model) {
30064
30878
  model = {
30065
- model: record4.model,
30879
+ model: record5.model,
30066
30880
  totals: emptyUsageCostTotals(),
30067
30881
  costUsd: 0,
30068
30882
  cacheSavingsUsd: 0,
@@ -30070,18 +30884,18 @@ function aggregateSessionUsage(scopedRecords, rates2) {
30070
30884
  providerReportedRecords: 0,
30071
30885
  unpricedRecords: 0
30072
30886
  };
30073
- models.set(record4.model, model);
30887
+ models.set(record5.model, model);
30074
30888
  }
30075
- model.totals = addUsageCostTotals(model.totals, record4.totals);
30889
+ model.totals = addUsageCostTotals(model.totals, record5.totals);
30076
30890
  model.costUsd += priced.costUsd;
30077
30891
  model.cacheSavingsUsd += recordSavings;
30078
30892
  model.records += 1;
30079
30893
  if (priced.costSource === "providerReported") model.providerReportedRecords += 1;
30080
30894
  if (priced.costSource === "unpriced") model.unpricedRecords += 1;
30081
30895
  calls.push({
30082
- timestamp: new Date(record4.timestampMs).toISOString(),
30083
- model: record4.model,
30084
- totals: record4.totals,
30896
+ timestamp: new Date(record5.timestampMs).toISOString(),
30897
+ model: record5.model,
30898
+ totals: record5.totals,
30085
30899
  costUsd: priced.costUsd,
30086
30900
  costSource: priced.costSource,
30087
30901
  isSubagent
@@ -30126,20 +30940,20 @@ var init_aggregate = __esm({
30126
30940
  this.#toDay = makeDayFormatter(options.timeZone);
30127
30941
  }
30128
30942
  /** Folds one record in; returns whether it actually contributed. */
30129
- add(record4) {
30130
- if (record4.dedupeKey !== null) {
30131
- if (this.#seen.has(record4.dedupeKey)) return false;
30132
- this.#seen.add(record4.dedupeKey);
30943
+ add(record5) {
30944
+ if (record5.dedupeKey !== null) {
30945
+ if (this.#seen.has(record5.dedupeKey)) return false;
30946
+ this.#seen.add(record5.dedupeKey);
30133
30947
  }
30134
- const day = this.#toDay(record4.timestampMs);
30948
+ const day = this.#toDay(record5.timestampMs);
30135
30949
  if (day < this.#options.sinceDay || day > this.#options.untilDay) return false;
30136
- const key2 = [day, record4.provider, record4.model].join(KEY_SEPARATOR);
30950
+ const key2 = [day, record5.provider, record5.model].join(KEY_SEPARATOR);
30137
30951
  let bucket = this.#buckets.get(key2);
30138
30952
  if (bucket === void 0) {
30139
30953
  bucket = {
30140
30954
  day,
30141
- provider: record4.provider,
30142
- model: record4.model,
30955
+ provider: record5.provider,
30956
+ model: record5.model,
30143
30957
  totals: emptyUsageCostTotals(),
30144
30958
  costUsd: 0,
30145
30959
  cacheSavingsUsd: 0,
@@ -30152,25 +30966,25 @@ var init_aggregate = __esm({
30152
30966
  }
30153
30967
  const priced = priceUsage(
30154
30968
  this.#options.rates,
30155
- record4.model,
30156
- record4.totals,
30157
- record4.reportedCostUsd,
30158
- record4.speed
30969
+ record5.model,
30970
+ record5.totals,
30971
+ record5.reportedCostUsd,
30972
+ record5.speed
30159
30973
  );
30160
- bucket.totals = addUsageCostTotals(bucket.totals, record4.totals);
30974
+ bucket.totals = addUsageCostTotals(bucket.totals, record5.totals);
30161
30975
  bucket.costUsd += priced.costUsd;
30162
30976
  bucket.cacheSavingsUsd += cacheSavingsUsd(
30163
30977
  this.#options.rates,
30164
- record4.model,
30165
- record4.totals,
30166
- record4.speed
30978
+ record5.model,
30979
+ record5.totals,
30980
+ record5.speed
30167
30981
  );
30168
30982
  bucket.records += 1;
30169
30983
  if (priced.costSource === "unpriced") bucket.unpricedRecords += 1;
30170
30984
  if (priced.costSource === "providerReported") bucket.providerReportedRecords += 1;
30171
- if (record4.sessionId.length > 0) {
30172
- bucket.sessions.add(record4.sessionId);
30173
- this.#sessions.add(record4.sessionId);
30985
+ if (record5.sessionId.length > 0) {
30986
+ bucket.sessions.add(record5.sessionId);
30987
+ this.#sessions.add(record5.sessionId);
30174
30988
  }
30175
30989
  return true;
30176
30990
  }
@@ -30201,7 +31015,7 @@ var init_aggregate = __esm({
30201
31015
  // ../../server/lib/usageCost/reader.ts
30202
31016
  import { createReadStream as createReadStream3 } from "node:fs";
30203
31017
  import { readdir as readdir14, stat as stat19 } from "node:fs/promises";
30204
- import { join as join28 } from "node:path";
31018
+ import { join as join29 } from "node:path";
30205
31019
  import { createInterface as createInterface3 } from "node:readline";
30206
31020
  async function listTranscriptFiles(root, sinceMs) {
30207
31021
  const found = [];
@@ -30213,7 +31027,7 @@ async function listTranscriptFiles(root, sinceMs) {
30213
31027
  return;
30214
31028
  }
30215
31029
  for (const entry of entries3) {
30216
- const child = join28(dir, entry.name);
31030
+ const child = join29(dir, entry.name);
30217
31031
  if (entry.isDirectory()) {
30218
31032
  await walk2(child);
30219
31033
  continue;
@@ -30251,17 +31065,17 @@ async function readTranscriptRecords(filePath, provider) {
30251
31065
  function dedupeWithinFile(records) {
30252
31066
  const slotByKey = /* @__PURE__ */ new Map();
30253
31067
  const kept = [];
30254
- for (const record4 of records) {
30255
- if (record4.dedupeKey === null) {
30256
- kept.push(record4);
31068
+ for (const record5 of records) {
31069
+ if (record5.dedupeKey === null) {
31070
+ kept.push(record5);
30257
31071
  continue;
30258
31072
  }
30259
- const slot = slotByKey.get(record4.dedupeKey);
31073
+ const slot = slotByKey.get(record5.dedupeKey);
30260
31074
  if (slot === void 0) {
30261
- slotByKey.set(record4.dedupeKey, kept.push(record4) - 1);
31075
+ slotByKey.set(record5.dedupeKey, kept.push(record5) - 1);
30262
31076
  continue;
30263
31077
  }
30264
- if (record4.totals.outputTokens > kept[slot].totals.outputTokens) kept[slot] = record4;
31078
+ if (record5.totals.outputTokens > kept[slot].totals.outputTokens) kept[slot] = record5;
30265
31079
  }
30266
31080
  return kept;
30267
31081
  }
@@ -30272,10 +31086,10 @@ var init_reader = __esm({
30272
31086
  });
30273
31087
 
30274
31088
  // ../../server/lib/usageCost/service.ts
30275
- import { readFile as readFile21, stat as stat20, writeFile as writeFile7 } from "node:fs/promises";
30276
- import { join as join29 } from "node:path";
31089
+ import { readFile as readFile22, stat as stat20, writeFile as writeFile7 } from "node:fs/promises";
31090
+ import { join as join30 } from "node:path";
30277
31091
  function ratesCachePath() {
30278
- return join29(getDataRoot(), "usage-model-rates.json");
31092
+ return join30(getDataRoot(), "usage-model-rates.json");
30279
31093
  }
30280
31094
  function ratesFetchedAt() {
30281
31095
  return ratesFetchedAtMs === null ? null : new Date(ratesFetchedAtMs).toISOString();
@@ -30285,7 +31099,7 @@ async function ensureRatesInner() {
30285
31099
  if (ratesFetchedAtMs !== null && now - ratesFetchedAtMs < RATES_TTL_MS) return;
30286
31100
  if (ratesFetchedAtMs === null) {
30287
31101
  try {
30288
- const raw = JSON.parse(await readFile21(ratesCachePath(), "utf8"));
31102
+ const raw = JSON.parse(await readFile22(ratesCachePath(), "utf8"));
30289
31103
  if (typeof raw.fetchedAtMs === "number") {
30290
31104
  const parsed2 = parseRateTable(raw.document);
30291
31105
  if (parsed2.size > 0) {
@@ -30341,13 +31155,13 @@ async function readFileRecords(file, provider) {
30341
31155
  fileCache2.set(file.path, { size: file.size, mtimeMs: file.mtimeMs, provider, records });
30342
31156
  return records;
30343
31157
  }
30344
- function addCountedUsage(counted, record4) {
30345
- const byModel = counted.get(record4.sessionId) ?? /* @__PURE__ */ new Map();
31158
+ function addCountedUsage(counted, record5) {
31159
+ const byModel = counted.get(record5.sessionId) ?? /* @__PURE__ */ new Map();
30346
31160
  byModel.set(
30347
- record4.model,
30348
- addUsageCostTotals(byModel.get(record4.model) ?? emptyUsageCostTotals(), record4.totals)
31161
+ record5.model,
31162
+ addUsageCostTotals(byModel.get(record5.model) ?? emptyUsageCostTotals(), record5.totals)
30349
31163
  );
30350
- counted.set(record4.sessionId, byModel);
31164
+ counted.set(record5.sessionId, byModel);
30351
31165
  }
30352
31166
  function makeWindow(days, timeZone, nowMs = Date.now()) {
30353
31167
  const toDay = makeDayFormatter(timeZone);
@@ -30378,14 +31192,14 @@ async function readUsageCostSummary(input) {
30378
31192
  for (const file of files) {
30379
31193
  const records = await readFileRecords(file, provider);
30380
31194
  scannedFiles += 1;
30381
- for (const record4 of records) {
30382
- aggregator.add(record4);
30383
- if (liveSessionIds.has(record4.sessionId)) addCountedUsage(durableTotals, record4);
31195
+ for (const record5 of records) {
31196
+ aggregator.add(record5);
31197
+ if (liveSessionIds.has(record5.sessionId)) addCountedUsage(durableTotals, record5);
30384
31198
  }
30385
31199
  }
30386
31200
  }
30387
31201
  for (const runtime of runtimes2) {
30388
- for (const record4 of await runtime.liveUsageRecords(durableTotals)) aggregator.add(record4);
31202
+ for (const record5 of await runtime.liveUsageRecords(durableTotals)) aggregator.add(record5);
30389
31203
  }
30390
31204
  const retentionCutoffMs = startedAtMs - 90 * 24 * 60 * 60 * 1e3;
30391
31205
  for (const [path, entry] of fileCache2) {
@@ -30450,8 +31264,8 @@ async function childTranscripts(dirName, rootSessionId, provider) {
30450
31264
  }
30451
31265
  function countedUsageBySession(scopedRecords) {
30452
31266
  const counted = /* @__PURE__ */ new Map();
30453
- for (const { record: record4 } of scopedRecords) {
30454
- if (record4.sessionId) addCountedUsage(counted, record4);
31267
+ for (const { record: record5 } of scopedRecords) {
31268
+ if (record5.sessionId) addCountedUsage(counted, record5);
30455
31269
  }
30456
31270
  return counted;
30457
31271
  }
@@ -30465,7 +31279,7 @@ async function readSessionUsageCostSummary(input) {
30465
31279
  const store = storeForDirName(input.dirName);
30466
31280
  const provider = store.kind;
30467
31281
  const directRecords = await readFileRecords(directFile, provider);
30468
- const sessionId = store.descriptor.sessionFile.sessionId(input.fileName) ?? directRecords.find((record4) => record4.sessionId.length > 0)?.sessionId ?? "";
31282
+ const sessionId = store.descriptor.sessionFile.sessionId(input.fileName) ?? directRecords.find((record5) => record5.sessionId.length > 0)?.sessionId ?? "";
30469
31283
  const files = [
30470
31284
  { file: directFile, isSubagent: isSubagentAddress(input.fileName) }
30471
31285
  ];
@@ -30479,19 +31293,19 @@ async function readSessionUsageCostSummary(input) {
30479
31293
  records: await readFileRecords(file, provider)
30480
31294
  })));
30481
31295
  const scopedRecords = recordsByFile.flatMap(
30482
- ({ records, isSubagent }) => records.map((record4) => ({ record: record4, isSubagent }))
31296
+ ({ records, isSubagent }) => records.map((record5) => ({ record: record5, isSubagent }))
30483
31297
  );
30484
31298
  const sessionIds = /* @__PURE__ */ new Set();
30485
- for (const { record: record4 } of scopedRecords) {
30486
- if (record4.sessionId) sessionIds.add(record4.sessionId);
31299
+ for (const { record: record5 } of scopedRecords) {
31300
+ if (record5.sessionId) sessionIds.add(record5.sessionId);
30487
31301
  }
30488
31302
  if (sessionId) sessionIds.add(sessionId);
30489
31303
  const runtime = runtimeFor(provider);
30490
31304
  if ([...sessionIds].some((id) => runtime.hasSession(id))) {
30491
31305
  const liveRecords = await runtime.liveUsageRecords(countedUsageBySession(scopedRecords));
30492
- for (const record4 of liveRecords) {
30493
- if (!sessionIds.has(record4.sessionId)) continue;
30494
- scopedRecords.push({ record: record4, isSubagent: record4.sessionId !== sessionId });
31306
+ for (const record5 of liveRecords) {
31307
+ if (!sessionIds.has(record5.sessionId)) continue;
31308
+ scopedRecords.push({ record: record5, isSubagent: record5.sessionId !== sessionId });
30495
31309
  }
30496
31310
  }
30497
31311
  const aggregated = aggregateSessionUsage(scopedRecords, rates);
@@ -31286,7 +32100,7 @@ var init_worktreeIo = __esm({
31286
32100
  });
31287
32101
 
31288
32102
  // ../../server/routes/worktrees/worktreeUtils.ts
31289
- import { resolve as resolve20, dirname as dirname14 } from "node:path";
32103
+ import { resolve as resolve20, dirname as dirname15 } from "node:path";
31290
32104
  function isValidWorktreeName(name) {
31291
32105
  return /^[a-zA-Z0-9._-]+$/.test(name) && name.length <= 40;
31292
32106
  }
@@ -31322,7 +32136,7 @@ async function readFirstJsonLine(filePath) {
31322
32136
  await fileHandle.close();
31323
32137
  }
31324
32138
  }
31325
- async function resolveProjectPath2(projectDir, dirName) {
32139
+ async function resolveProjectPath3(projectDir, dirName) {
31326
32140
  try {
31327
32141
  const files = await readdir6(projectDir);
31328
32142
  const sessionFiles = files.filter((file) => file.endsWith(".jsonl"));
@@ -31349,7 +32163,7 @@ async function getMainWorktreeRoot(projectPath) {
31349
32163
  const commonDir = (await runWorktreeCommand("git", ["rev-parse", "--git-common-dir"], {
31350
32164
  cwd: projectPath
31351
32165
  })).trim();
31352
- return dirname14(resolve20(projectPath, commonDir));
32166
+ return dirname15(resolve20(projectPath, commonDir));
31353
32167
  } catch {
31354
32168
  return null;
31355
32169
  }
@@ -31512,7 +32326,7 @@ async function handleWorktreeList(dirName, res) {
31512
32326
  res.end(JSON.stringify({ error: "Access denied" }));
31513
32327
  return;
31514
32328
  }
31515
- const projectPath = await resolveProjectPath2(projectDir, dirName);
32329
+ const projectPath = await resolveProjectPath3(projectDir, dirName);
31516
32330
  const gitRoot = await getMainWorktreeRoot(projectPath);
31517
32331
  if (!gitRoot) {
31518
32332
  res.setHeader("Content-Type", "application/json");
@@ -31601,7 +32415,7 @@ function requireProjectDir(dirName, res) {
31601
32415
  return projectDir;
31602
32416
  }
31603
32417
  async function requireGitRoot(projectDir, dirName, res) {
31604
- const projectPath = await resolveProjectPath2(projectDir, dirName);
32418
+ const projectPath = await resolveProjectPath3(projectDir, dirName);
31605
32419
  const gitRoot = await getMainWorktreeRoot(projectPath);
31606
32420
  if (!gitRoot) {
31607
32421
  res.statusCode = 400;
@@ -31834,8 +32648,8 @@ function apiRoute(id, register) {
31834
32648
  function registerApiRoutes(use, context) {
31835
32649
  const safeUse = (path, handler) => use(path, catchAsyncErrors(handler));
31836
32650
  safeUse("/api", compressionMiddleware);
31837
- for (const route of API_ROUTE_REGISTRY) {
31838
- route.register(safeUse, context);
32651
+ for (const route2 of API_ROUTE_REGISTRY) {
32652
+ route2.register(safeUse, context);
31839
32653
  }
31840
32654
  }
31841
32655
  var API_ROUTE_REGISTRY;
@@ -31863,6 +32677,7 @@ var init_api_routes = __esm({
31863
32677
  init_git_status();
31864
32678
  init_github();
31865
32679
  init_vercel_deployments();
32680
+ init_clickup();
31866
32681
  init_project_icon();
31867
32682
  init_hello();
31868
32683
  init_local_file();
@@ -31878,6 +32693,7 @@ var init_api_routes = __esm({
31878
32693
  init_projects2();
31879
32694
  init_provider_updates();
31880
32695
  init_agent_executable();
32696
+ init_agent_accounts();
31881
32697
  init_scripts();
31882
32698
  init_session_config();
31883
32699
  init_session_context();
@@ -31934,6 +32750,7 @@ var init_api_routes = __esm({
31934
32750
  apiRoute("git-status", registerGitStatusRoutes),
31935
32751
  apiRoute("github", registerGitHubRoutes),
31936
32752
  apiRoute("vercel-deployments", registerVercelDeploymentRoutes),
32753
+ apiRoute("clickup", registerClickUpRoutes),
31937
32754
  apiRoute("project-icon", registerProjectIconRoutes),
31938
32755
  apiRoute("git-diff", registerGitDiffRoutes),
31939
32756
  apiRoute("mcp", registerMcpRoutes),
@@ -31948,7 +32765,8 @@ var init_api_routes = __esm({
31948
32765
  apiRoute("codex-threads", registerCodexThreadRoutes),
31949
32766
  apiRoute("agent-runtime", registerAgentRuntimeRoutes),
31950
32767
  apiRoute("provider-updates", registerProviderUpdateRoutes),
31951
- apiRoute("agent-executable", registerAgentExecutableRoutes)
32768
+ apiRoute("agent-executable", registerAgentExecutableRoutes),
32769
+ apiRoute("agent-accounts", registerAgentAccountRoutes)
31952
32770
  ];
31953
32771
  }
31954
32772
  });
@@ -31992,7 +32810,7 @@ import { WebSocket } from "ws";
31992
32810
  import { spawn as ptySpawn } from "node-pty";
31993
32811
  import { execFileSync as execFileSync2 } from "node:child_process";
31994
32812
  import { randomUUID as randomUUID6 } from "node:crypto";
31995
- import { homedir as homedir11 } from "node:os";
32813
+ import { homedir as homedir12 } from "node:os";
31996
32814
  function defaultShell() {
31997
32815
  if (process.platform === "win32") return process.env.COMSPEC ?? "powershell.exe";
31998
32816
  return process.env.SHELL ?? "/bin/zsh";
@@ -32106,7 +32924,7 @@ var init_pty_server = __esm({
32106
32924
  return;
32107
32925
  }
32108
32926
  const name = msg.name || `Terminal ${this.sessions.size + 1}`;
32109
- const cwd = msg.cwd || homedir11();
32927
+ const cwd = msg.cwd || homedir12();
32110
32928
  const cols = msg.cols || 80;
32111
32929
  const rows = msg.rows || 24;
32112
32930
  const command = msg.command || defaultShell();
@@ -32364,18 +33182,18 @@ var init_pty_authorization = __esm({
32364
33182
  // ../../server/app-server.ts
32365
33183
  import express from "express";
32366
33184
  import { createServer, request as httpRequest2 } from "node:http";
32367
- import { join as join30 } from "node:path";
33185
+ import { join as join31 } from "node:path";
32368
33186
  import { WebSocketServer as WebSocketServer2 } from "ws";
32369
33187
  async function createServerComposition(staticDir, userDataDir, environment) {
32370
33188
  setDataRoot(userDataDir);
32371
- setConfigPath(join30(userDataDir, "config.local.json"));
33189
+ setConfigPath(join31(userDataDir, "config.local.json"));
32372
33190
  await loadConfig();
32373
33191
  const configEdition = getConfiguredEditionValue();
32374
33192
  initEdition({ shell: environment.mode, configEdition });
32375
33193
  const suppression = describeEditionSuppression(process.env, configEdition, environment.mode);
32376
33194
  if (suppression) console.warn(suppression);
32377
33195
  if (isTeamEdition()) {
32378
- const teamDir = join30(getDataRoot(), "team");
33196
+ const teamDir = join31(getDataRoot(), "team");
32379
33197
  await initUsersStore(teamDir);
32380
33198
  await initSessionPersistence(teamDir);
32381
33199
  initializeBootstrapToken(userCount());
@@ -32545,11 +33363,11 @@ var init_standalone_app_server = __esm({
32545
33363
 
32546
33364
  // ../../server/lib/portFile.ts
32547
33365
  import { mkdirSync as mkdirSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
32548
- import { homedir as homedir12 } from "node:os";
32549
- import { dirname as dirname15, join as join31 } from "node:path";
33366
+ import { homedir as homedir13 } from "node:os";
33367
+ import { dirname as dirname16, join as join32 } from "node:path";
32550
33368
  function writePortFile(port) {
32551
33369
  try {
32552
- mkdirSync2(dirname15(PORT_FILE), { recursive: true });
33370
+ mkdirSync2(dirname16(PORT_FILE), { recursive: true });
32553
33371
  writeFileSync2(PORT_FILE, `${port}
32554
33372
  `, { mode: 384 });
32555
33373
  } catch (err) {
@@ -32566,7 +33384,7 @@ function removePortFile() {
32566
33384
  var PORT_FILE;
32567
33385
  var init_portFile = __esm({
32568
33386
  "../../server/lib/portFile.ts"() {
32569
- PORT_FILE = join31(homedir12(), ".cogpit", "port");
33387
+ PORT_FILE = join32(homedir13(), ".cogpit", "port");
32570
33388
  }
32571
33389
  });
32572
33390
 
@@ -32814,8 +33632,8 @@ __export(standalone_runtime_exports, {
32814
33632
  startStandaloneServer: () => startStandaloneServer
32815
33633
  });
32816
33634
  import { existsSync, mkdirSync as mkdirSync3 } from "node:fs";
32817
- import { homedir as homedir13 } from "node:os";
32818
- import { join as join32 } from "node:path";
33635
+ import { homedir as homedir14 } from "node:os";
33636
+ import { join as join33 } from "node:path";
32819
33637
  function listen(server, port, host) {
32820
33638
  return new Promise((resolve22, reject) => {
32821
33639
  const onError = (error) => reject(error);
@@ -32833,23 +33651,23 @@ function listen(server, port, host) {
32833
33651
  }
32834
33652
  async function startStandaloneServer({
32835
33653
  staticDir,
32836
- dataDir = join32(homedir13(), ".config", "cogpit"),
33654
+ dataDir = join33(homedir14(), ".config", "cogpit"),
32837
33655
  host = "127.0.0.1",
32838
33656
  port = 19384,
32839
33657
  env = process.env,
32840
33658
  publishPort = false
32841
33659
  }) {
32842
33660
  mkdirSync3(dataDir, { recursive: true });
32843
- const configPath = join32(dataDir, "config.local.json");
32844
- setConfigPath(configPath);
32845
- const configExisted = existsSync(configPath);
33661
+ const configPath2 = join33(dataDir, "config.local.json");
33662
+ setConfigPath(configPath2);
33663
+ const configExisted = existsSync(configPath2);
32846
33664
  await loadConfig();
32847
33665
  let createdConfig;
32848
33666
  if (!configExisted) {
32849
- const claudeDir = join32(homedir13(), ".claude");
32850
- if (existsSync(join32(claudeDir, "projects"))) {
33667
+ const claudeDir = join33(homedir14(), ".claude");
33668
+ if (existsSync(join33(claudeDir, "projects"))) {
32851
33669
  await saveConfig({ claudeDir });
32852
- createdConfig = `${configPath} for ${claudeDir}`;
33670
+ createdConfig = `${configPath2} for ${claudeDir}`;
32853
33671
  }
32854
33672
  }
32855
33673
  initEdition({ shell: "standalone", configEdition: getConfiguredEditionValue() });
@@ -32919,8 +33737,8 @@ var init_standalone_runtime = __esm({
32919
33737
 
32920
33738
  // src/index.ts
32921
33739
  import { spawn as spawn4 } from "node:child_process";
32922
- import { homedir as homedir14 } from "node:os";
32923
- import { join as join33, resolve as resolve21 } from "node:path";
33740
+ import { homedir as homedir15 } from "node:os";
33741
+ import { join as join34, resolve as resolve21 } from "node:path";
32924
33742
  var SESSION_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/;
32925
33743
  var USAGE = `Cogpit
32926
33744
 
@@ -33029,8 +33847,8 @@ async function openExternalUrl(url) {
33029
33847
  async function startPackagedServer(options) {
33030
33848
  const { startStandaloneServer: startStandaloneServer2 } = await Promise.resolve().then(() => (init_standalone_runtime(), standalone_runtime_exports));
33031
33849
  return startStandaloneServer2({
33032
- staticDir: join33(import.meta.dirname, "web"),
33033
- dataDir: options.dataDir ?? join33(homedir14(), ".config", "cogpit"),
33850
+ staticDir: join34(import.meta.dirname, "web"),
33851
+ dataDir: options.dataDir ?? join34(homedir15(), ".config", "cogpit"),
33034
33852
  host: "127.0.0.1",
33035
33853
  port: options.port,
33036
33854
  publishPort: false
@@ -33046,7 +33864,7 @@ async function waitForShutdownSignal() {
33046
33864
  for (const signal of signals) process.once(signal, done);
33047
33865
  });
33048
33866
  }
33049
- var defaultDependencies3 = {
33867
+ var defaultDependencies4 = {
33050
33868
  fetch,
33051
33869
  openUrl: openExternalUrl,
33052
33870
  startServer: startPackagedServer,
@@ -33073,7 +33891,7 @@ async function verifyServer(server, command, deps) {
33073
33891
  }
33074
33892
  }
33075
33893
  async function run(argv, overrides = {}) {
33076
- const deps = { ...defaultDependencies3, ...overrides };
33894
+ const deps = { ...defaultDependencies4, ...overrides };
33077
33895
  let command;
33078
33896
  try {
33079
33897
  command = parseArgs(argv);