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.
- package/dist/cli.js +1374 -556
- package/dist/web/assets/{CommandPaletteHost-DU1jhhYG.js → CommandPaletteHost-D43icOGh.js} +1 -1
- package/dist/web/assets/{ConfigBrowser-CTZR8nw6.js → ConfigBrowser-BailHbYr.js} +1 -1
- package/dist/web/assets/{HighlightedEditor-CNTtimUO.js → HighlightedEditor-Kf1cQYyg.js} +1 -1
- package/dist/web/assets/{KeyboardShortcutsDialog-DtTE4xjZ.js → KeyboardShortcutsDialog-CHb_hQuK.js} +1 -1
- package/dist/web/assets/{MobileFileChanges-DaJh6sQ7.js → MobileFileChanges-C9Xk9gfg.js} +1 -1
- package/dist/web/assets/{PreviewPanel-BOL9gNaQ.js → PreviewPanel-Djv1bZZJ.js} +1 -1
- package/dist/web/assets/ProjectFilesPanel-DuBqjGFA.js +4 -0
- package/dist/web/assets/{ProjectSwitcherModal-UUQMoktd.js → ProjectSwitcherModal-CxQ6p2B4.js} +1 -1
- package/dist/web/assets/{TerminalOutput-T82q4Tf9.js → TerminalOutput-Cm-dLkUR.js} +1 -1
- package/dist/web/assets/ThemeSelectorModal-CTuOdp5Q.js +1 -0
- package/dist/web/assets/WorkflowsPanel-P7HtcaDf.js +1 -0
- package/dist/web/assets/{WorktreePanel-DvZNvNhH.js → WorktreePanel-DcjYVMuA.js} +1 -1
- package/dist/web/assets/index-CEBq1nya.js +1 -0
- package/dist/web/assets/{index-BhjwMUil.js → index-CVfvPIib.js} +4 -4
- package/dist/web/assets/index-CWj7TiFf.css +1 -0
- package/dist/web/assets/{index-CpHg1sRc.js → index-D2LNKOXE.js} +1 -1
- package/dist/web/assets/index-DFiPbdIb.js +153 -0
- package/dist/web/assets/session-parser.worker-SrNyVFwl.js +29 -0
- package/dist/web/assets/{vendor-ui-B9m2oOMV.js → vendor-ui-DUTyrBOX.js} +175 -160
- package/dist/web/index.html +3 -3
- package/package.json +1 -1
- package/dist/web/assets/ProjectFilesPanel-CBFFT9qJ.js +0 -4
- package/dist/web/assets/ThemeSelectorModal-rFVnzZuC.js +0 -1
- package/dist/web/assets/WorkflowsPanel-COZwo8h-.js +0 -1
- package/dist/web/assets/index-CghBqEmp.js +0 -153
- package/dist/web/assets/index-XlQRZ_Un.js +0 -1
- package/dist/web/assets/index-f2DFkgKZ.css +0 -1
- 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
|
|
490
|
-
lastAttempt.set(id,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
1275
|
-
return
|
|
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
|
|
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" && (
|
|
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" && (
|
|
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" &&
|
|
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
|
|
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(
|
|
4015
|
-
return { changed: true, value: toPublicShare(
|
|
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
|
|
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 =
|
|
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
|
|
6043
|
-
if (!
|
|
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 +=
|
|
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:
|
|
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,
|
|
6084
|
-
if (!sessionId || !messageId || !
|
|
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 +=
|
|
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:
|
|
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
|
|
7497
|
+
let text2 = buf.subarray(0, bytesRead).toString("utf-8");
|
|
7490
7498
|
if (bytesRead === byteLimit) {
|
|
7491
|
-
const lastNewline =
|
|
7492
|
-
if (lastNewline >= 0)
|
|
7499
|
+
const lastNewline = text2.lastIndexOf("\n");
|
|
7500
|
+
if (lastNewline >= 0) text2 = text2.slice(0, lastNewline);
|
|
7493
7501
|
}
|
|
7494
|
-
return
|
|
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(
|
|
7540
|
+
function lastRealModel(text2) {
|
|
7533
7541
|
let found = null;
|
|
7534
|
-
for (const match of
|
|
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
|
|
7661
|
+
const text2 = buf.subarray(0, bytesRead).toString("utf-8") + leftover;
|
|
7654
7662
|
if (!foundModel) {
|
|
7655
|
-
const found = lastRealModel(
|
|
7663
|
+
const found = lastRealModel(text2);
|
|
7656
7664
|
if (found) {
|
|
7657
7665
|
model = found;
|
|
7658
7666
|
foundModel = true;
|
|
7659
7667
|
}
|
|
7660
7668
|
}
|
|
7661
|
-
const splitLines =
|
|
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,
|
|
8007
|
-
if (!
|
|
8008
|
-
turn.assistantText.push(
|
|
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(
|
|
8019
|
+
last.text.push(text2);
|
|
8012
8020
|
return;
|
|
8013
8021
|
}
|
|
8014
|
-
turn.contentBlocks.push({ kind: "text", text: [
|
|
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*=`, "
|
|
8147
|
-
|
|
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
|
-
|
|
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
|
|
8535
|
-
if (
|
|
8536
|
-
|
|
8537
|
-
|
|
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
|
|
8541
|
-
|
|
8587
|
+
const original = outputContent(output);
|
|
8588
|
+
let envelope = isObject(output) && !Array.isArray(output) ? output : null;
|
|
8542
8589
|
try {
|
|
8543
|
-
const parsed = JSON.parse(
|
|
8544
|
-
|
|
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(
|
|
8587
|
-
if (!
|
|
8588
|
-
return
|
|
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
|
|
8645
|
-
if (images.length === 0 && audio.length === 0) return
|
|
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
|
-
...
|
|
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
|
|
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(
|
|
8675
|
-
const trimmed =
|
|
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,
|
|
8706
|
-
if (!
|
|
8707
|
-
const block = { type: "thinking", thinking:
|
|
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
|
|
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
|
-
|
|
8771
|
-
|
|
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(
|
|
8790
|
-
if (
|
|
8791
|
-
return normalizePromptText(
|
|
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 (
|
|
8794
|
-
return normalizePromptText(extractMessageText(
|
|
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(
|
|
8799
|
-
if (
|
|
8800
|
-
if (
|
|
8801
|
-
if (
|
|
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(
|
|
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
|
|
8826
|
-
if (!isObject2(
|
|
8827
|
-
if (
|
|
8828
|
-
sessionId ||= typeof
|
|
8829
|
-
version ||= typeof
|
|
8830
|
-
cwd ||= typeof
|
|
8831
|
-
if (!branchedFrom && isObject2(
|
|
8832
|
-
const sourceId = typeof
|
|
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
|
|
8910
|
+
turnIndex: typeof record5.payload.branchedFrom.turnIndex === "number" ? record5.payload.branchedFrom.turnIndex : null
|
|
8837
8911
|
};
|
|
8838
8912
|
}
|
|
8839
8913
|
}
|
|
8840
|
-
const source = isObject2(
|
|
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
|
|
8849
|
-
parentSessionId =
|
|
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(
|
|
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 (
|
|
8855
|
-
model ||= typeof
|
|
8856
|
-
cwd ||= typeof
|
|
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(
|
|
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 =
|
|
8866
|
-
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
|
|
9025
|
-
if (!isCodexRecord(
|
|
9098
|
+
const record5 = records[index];
|
|
9099
|
+
if (!isCodexRecord(record5)) continue;
|
|
9026
9100
|
recordIndex = index;
|
|
9027
|
-
const payload = isObject2(
|
|
9028
|
-
const timestamp2 =
|
|
9029
|
-
if (
|
|
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 (
|
|
9036
|
-
if (
|
|
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 (
|
|
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(
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
|
9233
|
+
const text2 = normalizePromptText(extractMessageText(payload, "input_text"));
|
|
9158
9234
|
const images = extractResponseMessageImages(payload);
|
|
9159
9235
|
const audio = extractResponseMessageAudio(payload);
|
|
9160
|
-
if (
|
|
9161
|
-
current.userMessage = buildCodexUserContent(
|
|
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
|
|
9349
|
+
const parsedOutput = parseCustomToolOutput(payload.output);
|
|
9350
|
+
const output = parsedOutput.text;
|
|
9274
9351
|
toolCall.result = output;
|
|
9275
|
-
toolCall.isError =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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((
|
|
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
|
|
9517
|
-
const messageType =
|
|
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
|
|
9690
|
+
let record5;
|
|
9612
9691
|
try {
|
|
9613
|
-
|
|
9692
|
+
record5 = JSON.parse(line);
|
|
9614
9693
|
} catch {
|
|
9615
9694
|
continue;
|
|
9616
9695
|
}
|
|
9617
|
-
if (!isRecord2(
|
|
9618
|
-
if (
|
|
9696
|
+
if (!isRecord2(record5) || !isRecord2(record5.payload)) continue;
|
|
9697
|
+
if (record5.type === "session_meta") {
|
|
9619
9698
|
sawSessionMeta = true;
|
|
9620
|
-
const 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 (
|
|
9631
|
-
if (!cwd && typeof
|
|
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
|
|
10032
|
-
return
|
|
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
|
|
10151
|
+
const text2 = readString(data.content);
|
|
10073
10152
|
const images = extractImages(data.attachments, assets);
|
|
10074
|
-
if (images.length === 0) return
|
|
10075
|
-
return [...images, ...
|
|
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
|
|
10205
|
-
return
|
|
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,
|
|
10213
|
-
if (!
|
|
10214
|
-
const block = { type: "thinking", thinking:
|
|
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
|
|
10393
|
-
if (
|
|
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((
|
|
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
|
|
10757
|
-
if (
|
|
10758
|
-
const 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
|
|
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
|
|
10896
|
+
let record5;
|
|
10818
10897
|
try {
|
|
10819
|
-
|
|
10898
|
+
record5 = JSON.parse(line);
|
|
10820
10899
|
} catch {
|
|
10821
10900
|
continue;
|
|
10822
10901
|
}
|
|
10823
|
-
if (!isRecord3(
|
|
10824
|
-
const data = isRecord3(
|
|
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(
|
|
11095
|
+
function parseAgentEnvelope(text2) {
|
|
11017
11096
|
let sender = null;
|
|
11018
11097
|
let matched = false;
|
|
11019
|
-
const unwrapped =
|
|
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() :
|
|
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
|
|
11059
|
-
if (!
|
|
11060
|
-
return
|
|
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
|
|
11113
|
-
return
|
|
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(
|
|
11895
|
-
if (!
|
|
11896
|
-
for (const match of
|
|
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
|
|
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
|
|
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(
|
|
12185
|
-
return
|
|
12263
|
+
function stripTaggedBlocks(text2) {
|
|
12264
|
+
return text2.replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g, "").trim();
|
|
12186
12265
|
}
|
|
12187
|
-
function effortFromRecord(
|
|
12266
|
+
function effortFromRecord(record5) {
|
|
12188
12267
|
for (const kind of AGENT_KINDS) {
|
|
12189
|
-
const effort = READERS[kind].effort(
|
|
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
|
|
12278
|
+
let record5;
|
|
12200
12279
|
try {
|
|
12201
|
-
|
|
12280
|
+
record5 = JSON.parse(line);
|
|
12202
12281
|
} catch {
|
|
12203
12282
|
return null;
|
|
12204
12283
|
}
|
|
12205
|
-
if (!isRecord4(
|
|
12284
|
+
if (!isRecord4(record5)) return null;
|
|
12206
12285
|
for (const kind of candidates) {
|
|
12207
|
-
const
|
|
12208
|
-
if (
|
|
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: (
|
|
12298
|
+
effort: (record5) => record5.type === "assistant" ? nonEmpty(record5.effort) : null,
|
|
12220
12299
|
userMessageMarkers: ['"user"'],
|
|
12221
|
-
userMessageText(
|
|
12222
|
-
if (
|
|
12223
|
-
const content = isRecord4(
|
|
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
|
|
12305
|
+
let text2 = "";
|
|
12227
12306
|
for (const block of content) {
|
|
12228
12307
|
if (isRecord4(block) && block.type === "text" && typeof block.text === "string") {
|
|
12229
|
-
|
|
12308
|
+
text2 += stripTaggedBlocks(block.text) + " ";
|
|
12230
12309
|
}
|
|
12231
12310
|
}
|
|
12232
|
-
return
|
|
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(
|
|
12239
|
-
if (
|
|
12240
|
-
const { payload } =
|
|
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(
|
|
12248
|
-
if (
|
|
12249
|
-
const { payload } =
|
|
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(
|
|
12256
|
-
if (
|
|
12257
|
-
return nonEmpty(
|
|
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(
|
|
12261
|
-
if (
|
|
12262
|
-
if (typeof
|
|
12263
|
-
const data = isRecord4(
|
|
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(
|
|
12277
|
-
return
|
|
12355
|
+
function isSubagentLifecycle(record5) {
|
|
12356
|
+
return record5.type.startsWith("subagent.") && typeof record5.agentId === "string" && record5.agentId.length > 0;
|
|
12278
12357
|
}
|
|
12279
|
-
function isSubagentNoise(
|
|
12280
|
-
return typeof
|
|
12358
|
+
function isSubagentNoise(record5) {
|
|
12359
|
+
return typeof record5.agentId === "string" && record5.agentId.length > 0;
|
|
12281
12360
|
}
|
|
12282
|
-
function classifyTailRecord(
|
|
12361
|
+
function classifyTailRecord(record5) {
|
|
12283
12362
|
for (const kind of AGENT_KINDS) {
|
|
12284
12363
|
const format = TAIL_FORMATS[kind];
|
|
12285
|
-
const verdict = format.classify(
|
|
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(
|
|
12303
|
-
if (
|
|
12304
|
-
const 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 (
|
|
12308
|
-
const 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 (
|
|
12314
|
-
if (
|
|
12315
|
-
const stopReason =
|
|
12316
|
-
if (
|
|
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 =
|
|
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(
|
|
12325
|
-
if (
|
|
12326
|
-
const isRealUserTurn =
|
|
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(
|
|
12346
|
-
if (
|
|
12347
|
-
const 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 (
|
|
12360
|
-
const 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(
|
|
12367
|
-
return
|
|
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(
|
|
12374
|
-
if (isSubagentLifecycle(
|
|
12375
|
-
const decidable =
|
|
12376
|
-
if (!decidable || isSubagentNoise(
|
|
12377
|
-
if (
|
|
12378
|
-
if (
|
|
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(
|
|
12382
|
-
if (isSubagentLifecycle(
|
|
12383
|
-
if (isSubagentNoise(
|
|
12384
|
-
const decides =
|
|
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
|
|
12518
|
+
let record5;
|
|
12440
12519
|
try {
|
|
12441
|
-
|
|
12520
|
+
record5 = JSON.parse(line);
|
|
12442
12521
|
} catch {
|
|
12443
12522
|
continue;
|
|
12444
12523
|
}
|
|
12445
|
-
if (typeof
|
|
12446
|
-
const effort = effortFromRecord(
|
|
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
|
|
12475
|
-
const lines =
|
|
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
|
|
12561
|
+
let record5;
|
|
12483
12562
|
try {
|
|
12484
|
-
|
|
12563
|
+
record5 = JSON.parse(line);
|
|
12485
12564
|
} catch {
|
|
12486
12565
|
continue;
|
|
12487
12566
|
}
|
|
12488
|
-
if (typeof
|
|
12489
|
-
const match = turnEnded ? { format: turnEnded, verdict: turnEnded.classifyAfterTurnEnd(
|
|
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(
|
|
12577
|
+
meaningful.unshift(record5);
|
|
12499
12578
|
if (verdict.sawUserActivity) needUserActivity = false;
|
|
12500
12579
|
continue;
|
|
12501
12580
|
case "answer":
|
|
12502
|
-
meaningful.unshift(
|
|
12581
|
+
meaningful.unshift(record5);
|
|
12503
12582
|
return deriveSessionStatus(meaningful);
|
|
12504
12583
|
case "answer-if-active": {
|
|
12505
|
-
meaningful.unshift(
|
|
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(
|
|
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(
|
|
12527
|
-
const lower =
|
|
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(
|
|
12531
|
-
const snippet = (start > 0 ? "..." : "") +
|
|
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
|
|
12544
|
-
if (
|
|
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:
|
|
12929
|
+
const { result: text2, subtype } = result;
|
|
12851
12930
|
return {
|
|
12852
12931
|
isError: true,
|
|
12853
|
-
message:
|
|
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.
|
|
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
|
|
16213
|
-
if (!
|
|
16214
|
-
const message = asRecord3(
|
|
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(
|
|
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
|
|
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 =
|
|
16320
|
+
const cost = record5.costUSD;
|
|
16242
16321
|
return {
|
|
16243
16322
|
provider: "claude",
|
|
16244
16323
|
timestampMs,
|
|
16245
16324
|
model,
|
|
16246
|
-
sessionId: typeof
|
|
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
|
|
16271
|
-
if (!
|
|
16272
|
-
const payload = asRecord3(
|
|
16349
|
+
const record5 = parseJsonRecord(line);
|
|
16350
|
+
if (!record5) return null;
|
|
16351
|
+
const payload = asRecord3(record5.payload);
|
|
16273
16352
|
if (!payload) return null;
|
|
16274
|
-
if (
|
|
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(
|
|
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 (
|
|
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(
|
|
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
|
|
16402
|
-
if (!
|
|
16403
|
-
const data = asRecord3(
|
|
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 (
|
|
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 (
|
|
16411
|
-
const timestampMs = parseTimestampMs(
|
|
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
|
|
16429
|
-
return
|
|
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
|
|
16441
|
-
return
|
|
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,
|
|
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 :
|
|
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:
|
|
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(
|
|
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
|
|
20660
|
-
if (
|
|
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
|
|
21266
|
-
if (!
|
|
21267
|
-
const indexStatus =
|
|
21268
|
-
const workTreeStatus =
|
|
21269
|
-
const path =
|
|
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(
|
|
21486
|
-
const url =
|
|
21487
|
-
const number =
|
|
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
|
|
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
|
|
21507
|
-
collector.record(
|
|
21508
|
-
const match = PR_URL.exec(
|
|
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
|
|
21604
|
+
let record5;
|
|
21526
21605
|
try {
|
|
21527
|
-
|
|
21606
|
+
record5 = JSON.parse(line);
|
|
21528
21607
|
} catch {
|
|
21529
21608
|
return;
|
|
21530
21609
|
}
|
|
21531
|
-
if (!isRecord5(
|
|
21532
|
-
const timestamp2 = typeof
|
|
21533
|
-
if (
|
|
21534
|
-
recordPrLink(
|
|
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 =
|
|
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 =
|
|
21626
|
+
const data = record5.data;
|
|
21548
21627
|
if (isRecord5(data)) {
|
|
21549
|
-
if (
|
|
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 (
|
|
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 =
|
|
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
|
|
22442
|
-
if (!
|
|
22443
|
-
const candidate = hostnameOnly && !
|
|
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
|
|
22520
|
-
if (createdAt === null || !
|
|
22598
|
+
const text2 = stringValue2(source.text);
|
|
22599
|
+
if (createdAt === null || !text2) return null;
|
|
22521
22600
|
return {
|
|
22522
|
-
id: stringValue2(source.id, `${createdAt}-${
|
|
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
|
|
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) =>
|
|
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 =
|
|
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
|
|
22947
|
-
import { readFile as
|
|
22948
|
-
import { homedir as
|
|
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
|
|
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
|
-
|
|
23475
|
+
join24(homedir8(), ".claude", "settings.json"),
|
|
22971
23476
|
// global settings
|
|
22972
|
-
|
|
23477
|
+
join24(cwd, ".mcp.json"),
|
|
22973
23478
|
// project
|
|
22974
|
-
|
|
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
|
|
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
|
|
23191
|
-
return
|
|
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: "
|
|
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
|
-
|
|
23363
|
-
return
|
|
23364
|
-
|
|
23365
|
-
|
|
23366
|
-
|
|
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
|
|
23440
|
-
|
|
23441
|
-
|
|
23442
|
-
|
|
23443
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
23470
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
24136
|
+
const definition = TOOL_LABELS[name];
|
|
23581
24137
|
return {
|
|
23582
|
-
label:
|
|
23583
|
-
summary: defaultToolSummary(tc),
|
|
23584
|
-
styleName:
|
|
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
|
|
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
|
-
|
|
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: "
|
|
23597
|
-
send_message: { label: "Message agent", styleName: "
|
|
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: "
|
|
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: "
|
|
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,
|
|
23722
|
-
const trimmed =
|
|
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
|
|
23826
|
-
const
|
|
23827
|
-
return
|
|
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
|
|
24980
|
+
import { mkdir as mkdir7, readFile as readFile19 } from "node:fs/promises";
|
|
24391
24981
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
24392
|
-
import { homedir as
|
|
24393
|
-
import { dirname as
|
|
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 ??=
|
|
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
|
|
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(
|
|
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 =
|
|
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(
|
|
25126
|
+
function parsePsOutput(text2) {
|
|
24537
25127
|
const rows = [];
|
|
24538
|
-
for (const line of
|
|
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
|
|
24745
|
-
import { join as
|
|
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 =
|
|
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(
|
|
24850
|
-
if (encoder.encode(
|
|
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
|
|
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(
|
|
24863
|
-
return
|
|
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(
|
|
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,
|
|
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
|
-
|
|
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
|
|
25707
|
-
import { dirname as
|
|
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(
|
|
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
|
|
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
|
-
|
|
25927
|
-
|
|
25928
|
-
|
|
25929
|
-
|
|
25930
|
-
|
|
25931
|
-
|
|
25932
|
-
|
|
25933
|
-
|
|
25934
|
-
|
|
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
|
|
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(
|
|
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
|
|
26218
|
-
cached = isWithinDir(dirs.TEAMS_DIR,
|
|
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
|
|
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
|
-
|
|
27071
|
+
text2 = buf.subarray(0, bytesRead).toString("utf-8");
|
|
26435
27072
|
const isWholeFile = bytesRead >= fileStat.size;
|
|
26436
|
-
if (isWholeFile ||
|
|
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 =
|
|
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(
|
|
26904
|
-
const trimmed =
|
|
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
|
|
27054
|
-
import { join as
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
27316
|
-
const lines =
|
|
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
|
|
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
|
|
28365
|
+
const configPath2 = join11(dirs.TEAMS_DIR, entry.name, "config.json");
|
|
27552
28366
|
try {
|
|
27553
|
-
const raw = await readFile9(
|
|
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(
|
|
27790
|
-
const tee =
|
|
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(
|
|
27796
|
-
const redirect =
|
|
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((
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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:
|
|
28758
|
-
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:
|
|
28791
|
-
password:
|
|
29604
|
+
username: asString3(body.username),
|
|
29605
|
+
password: asString3(body.password),
|
|
28792
29606
|
displayName: typeof body.displayName === "string" ? body.displayName : void 0,
|
|
28793
|
-
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
|
|
28887
|
-
if (!isWithinDir(dirs.TEAMS_DIR,
|
|
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(
|
|
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
|
|
28969
|
-
const configRaw = await readFile9(
|
|
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
|
|
29024
|
-
const configRaw = await readFile9(
|
|
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
|
|
29156
|
-
const configRaw = await readFile9(
|
|
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
|
|
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) &&
|
|
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
|
|
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(
|
|
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:
|
|
30048
|
-
if (
|
|
30049
|
-
if (seen.has(
|
|
30050
|
-
seen.add(
|
|
30051
|
-
}
|
|
30052
|
-
const priced = priceUsage(rates2,
|
|
30053
|
-
const recordSavings = cacheSavingsUsd(rates2,
|
|
30054
|
-
const calculated = usageCostBreakdown(rates2,
|
|
30055
|
-
totals = addUsageCostTotals(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(
|
|
30876
|
+
let model = models.get(record5.model);
|
|
30063
30877
|
if (!model) {
|
|
30064
30878
|
model = {
|
|
30065
|
-
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(
|
|
30887
|
+
models.set(record5.model, model);
|
|
30074
30888
|
}
|
|
30075
|
-
model.totals = addUsageCostTotals(model.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(
|
|
30083
|
-
model:
|
|
30084
|
-
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(
|
|
30130
|
-
if (
|
|
30131
|
-
if (this.#seen.has(
|
|
30132
|
-
this.#seen.add(
|
|
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(
|
|
30948
|
+
const day = this.#toDay(record5.timestampMs);
|
|
30135
30949
|
if (day < this.#options.sinceDay || day > this.#options.untilDay) return false;
|
|
30136
|
-
const key2 = [day,
|
|
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:
|
|
30142
|
-
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
|
-
|
|
30156
|
-
|
|
30157
|
-
|
|
30158
|
-
|
|
30969
|
+
record5.model,
|
|
30970
|
+
record5.totals,
|
|
30971
|
+
record5.reportedCostUsd,
|
|
30972
|
+
record5.speed
|
|
30159
30973
|
);
|
|
30160
|
-
bucket.totals = addUsageCostTotals(bucket.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
|
-
|
|
30165
|
-
|
|
30166
|
-
|
|
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 (
|
|
30172
|
-
bucket.sessions.add(
|
|
30173
|
-
this.#sessions.add(
|
|
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
|
|
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 =
|
|
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
|
|
30255
|
-
if (
|
|
30256
|
-
kept.push(
|
|
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(
|
|
31073
|
+
const slot = slotByKey.get(record5.dedupeKey);
|
|
30260
31074
|
if (slot === void 0) {
|
|
30261
|
-
slotByKey.set(
|
|
31075
|
+
slotByKey.set(record5.dedupeKey, kept.push(record5) - 1);
|
|
30262
31076
|
continue;
|
|
30263
31077
|
}
|
|
30264
|
-
if (
|
|
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
|
|
30276
|
-
import { join as
|
|
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
|
|
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
|
|
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,
|
|
30345
|
-
const byModel = counted.get(
|
|
31158
|
+
function addCountedUsage(counted, record5) {
|
|
31159
|
+
const byModel = counted.get(record5.sessionId) ?? /* @__PURE__ */ new Map();
|
|
30346
31160
|
byModel.set(
|
|
30347
|
-
|
|
30348
|
-
addUsageCostTotals(byModel.get(
|
|
31161
|
+
record5.model,
|
|
31162
|
+
addUsageCostTotals(byModel.get(record5.model) ?? emptyUsageCostTotals(), record5.totals)
|
|
30349
31163
|
);
|
|
30350
|
-
counted.set(
|
|
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
|
|
30382
|
-
aggregator.add(
|
|
30383
|
-
if (liveSessionIds.has(
|
|
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
|
|
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:
|
|
30454
|
-
if (
|
|
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((
|
|
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((
|
|
31296
|
+
({ records, isSubagent }) => records.map((record5) => ({ record: record5, isSubagent }))
|
|
30483
31297
|
);
|
|
30484
31298
|
const sessionIds = /* @__PURE__ */ new Set();
|
|
30485
|
-
for (const { record:
|
|
30486
|
-
if (
|
|
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
|
|
30493
|
-
if (!sessionIds.has(
|
|
30494
|
-
scopedRecords.push({ record:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
31838
|
-
|
|
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
|
|
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 ||
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
|
32549
|
-
import { dirname as
|
|
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(
|
|
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 =
|
|
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
|
|
32818
|
-
import { join as
|
|
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 =
|
|
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
|
|
32844
|
-
setConfigPath(
|
|
32845
|
-
const configExisted = existsSync(
|
|
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 =
|
|
32850
|
-
if (existsSync(
|
|
33667
|
+
const claudeDir = join33(homedir14(), ".claude");
|
|
33668
|
+
if (existsSync(join33(claudeDir, "projects"))) {
|
|
32851
33669
|
await saveConfig({ claudeDir });
|
|
32852
|
-
createdConfig = `${
|
|
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
|
|
32923
|
-
import { join as
|
|
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:
|
|
33033
|
-
dataDir: options.dataDir ??
|
|
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
|
|
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 = { ...
|
|
33894
|
+
const deps = { ...defaultDependencies4, ...overrides };
|
|
33077
33895
|
let command;
|
|
33078
33896
|
try {
|
|
33079
33897
|
command = parseArgs(argv);
|