cogpit 2.4.0 → 2.4.2
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 +1104 -489
- package/dist/web/assets/{CommandPaletteHost-DU1jhhYG.js → CommandPaletteHost-DJghey7B.js} +1 -1
- package/dist/web/assets/{ConfigBrowser-CTZR8nw6.js → ConfigBrowser-x0UdXG0K.js} +1 -1
- package/dist/web/assets/{HighlightedEditor-CNTtimUO.js → HighlightedEditor-D0TDZx8S.js} +1 -1
- package/dist/web/assets/{KeyboardShortcutsDialog-DtTE4xjZ.js → KeyboardShortcutsDialog-2606YXAx.js} +1 -1
- package/dist/web/assets/{MobileFileChanges-DaJh6sQ7.js → MobileFileChanges-B4dwGXMS.js} +1 -1
- package/dist/web/assets/{PreviewPanel-BOL9gNaQ.js → PreviewPanel-CJdf-VLC.js} +1 -1
- package/dist/web/assets/{ProjectFilesPanel-CBFFT9qJ.js → ProjectFilesPanel-3GzuQyp3.js} +1 -1
- package/dist/web/assets/{ProjectSwitcherModal-UUQMoktd.js → ProjectSwitcherModal-D8boI2Qx.js} +1 -1
- package/dist/web/assets/{TerminalOutput-T82q4Tf9.js → TerminalOutput-C-6RWc6C.js} +1 -1
- package/dist/web/assets/{ThemeSelectorModal-rFVnzZuC.js → ThemeSelectorModal-DZ9JuT6j.js} +1 -1
- package/dist/web/assets/{WorkflowsPanel-COZwo8h-.js → WorkflowsPanel-i3GanFyN.js} +1 -1
- package/dist/web/assets/{WorktreePanel-DvZNvNhH.js → WorktreePanel-D-BUTFL2.js} +1 -1
- package/dist/web/assets/{index-CpHg1sRc.js → index-BBKPLXTq.js} +1 -1
- package/dist/web/assets/index-CMQcske6.js +1 -0
- package/dist/web/assets/index-C_0XOtqJ.css +1 -0
- package/dist/web/assets/index-D6p4gVB_.js +154 -0
- package/dist/web/assets/{index-BhjwMUil.js → index-ztb2qsgi.js} +1 -1
- package/dist/web/assets/{session-parser.worker-QY58jiXs.js → session-parser.worker-D3MwyNH5.js} +1 -1
- package/dist/web/assets/{vendor-ui-B9m2oOMV.js → vendor-ui-RwWl1mlR.js} +175 -160
- package/dist/web/index.html +3 -3
- package/package.json +1 -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/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"() {
|
|
@@ -8541,10 +8549,10 @@ function parseCustomToolOutput(output) {
|
|
|
8541
8549
|
if (!rawOutput) return { text: "", isError: false };
|
|
8542
8550
|
try {
|
|
8543
8551
|
const parsed = JSON.parse(rawOutput);
|
|
8544
|
-
const
|
|
8552
|
+
const text2 = typeof parsed.output === "string" ? parsed.output : rawOutput;
|
|
8545
8553
|
const meta = isObject(parsed.metadata) ? parsed.metadata : null;
|
|
8546
|
-
const isError = meta ? meta.exit_code !== 0 && meta.exit_code !== void 0 : inferToolError(
|
|
8547
|
-
return { text, isError };
|
|
8554
|
+
const isError = meta ? meta.exit_code !== 0 && meta.exit_code !== void 0 : inferToolError(text2);
|
|
8555
|
+
return { text: text2, isError };
|
|
8548
8556
|
} catch {
|
|
8549
8557
|
return { text: rawOutput, isError: inferToolError(rawOutput) };
|
|
8550
8558
|
}
|
|
@@ -8583,9 +8591,9 @@ function safeParseLine(line) {
|
|
|
8583
8591
|
function isObject2(value) {
|
|
8584
8592
|
return typeof value === "object" && value !== null;
|
|
8585
8593
|
}
|
|
8586
|
-
function isCodexRecord(
|
|
8587
|
-
if (!
|
|
8588
|
-
return
|
|
8594
|
+
function isCodexRecord(record5) {
|
|
8595
|
+
if (!record5 || typeof record5.type !== "string") return false;
|
|
8596
|
+
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
8597
|
}
|
|
8590
8598
|
function extractMessageText(payload, blockType) {
|
|
8591
8599
|
const content = payload?.content;
|
|
@@ -8641,12 +8649,12 @@ function buildCodexUserContent(message, images, audio = [], localImages = [], lo
|
|
|
8641
8649
|
...localAudio.map((path) => `
|
|
8642
8650
|
[audio attachment](<${path}>)`)
|
|
8643
8651
|
].join("");
|
|
8644
|
-
const
|
|
8645
|
-
if (images.length === 0 && audio.length === 0) return
|
|
8652
|
+
const text2 = message + attachmentSuffix;
|
|
8653
|
+
if (images.length === 0 && audio.length === 0) return text2;
|
|
8646
8654
|
return [
|
|
8647
8655
|
...images,
|
|
8648
8656
|
...audio,
|
|
8649
|
-
...
|
|
8657
|
+
...text2 ? [{ type: "text", text: text2 }] : []
|
|
8650
8658
|
];
|
|
8651
8659
|
}
|
|
8652
8660
|
function extractInterAgentMessage(payload) {
|
|
@@ -8658,8 +8666,8 @@ function extractInterAgentMessage(payload) {
|
|
|
8658
8666
|
}
|
|
8659
8667
|
const header = rawText.slice(0, headerEnd.index);
|
|
8660
8668
|
const messageType = header.match(/^Message Type:\s*([^\r\n]+)/)?.[1]?.trim().toUpperCase() ?? null;
|
|
8661
|
-
const
|
|
8662
|
-
return { messageType, text };
|
|
8669
|
+
const text2 = rawText.slice(headerEnd.index + headerEnd[0].length).trim();
|
|
8670
|
+
return { messageType, text: text2 };
|
|
8663
8671
|
}
|
|
8664
8672
|
function agentNameFromPath(agentPath) {
|
|
8665
8673
|
const segments2 = agentPath.split(/[\\/]/).filter(Boolean);
|
|
@@ -8671,8 +8679,8 @@ function readableAgentPrompt(value) {
|
|
|
8671
8679
|
if (/^gAAAAA[A-Za-z0-9_-]+$/.test(prompt)) return "";
|
|
8672
8680
|
return prompt;
|
|
8673
8681
|
}
|
|
8674
|
-
function normalizePromptText(
|
|
8675
|
-
const trimmed =
|
|
8682
|
+
function normalizePromptText(text2) {
|
|
8683
|
+
const trimmed = text2.trim();
|
|
8676
8684
|
if (!trimmed) return "";
|
|
8677
8685
|
if (SKIP_PROMPT_PREFIXES.some((prefix) => trimmed.startsWith(prefix))) return "";
|
|
8678
8686
|
return trimmed;
|
|
@@ -8702,9 +8710,9 @@ function parseTokenUsage(value) {
|
|
|
8702
8710
|
cache_read_input_tokens: cacheRead
|
|
8703
8711
|
};
|
|
8704
8712
|
}
|
|
8705
|
-
function appendThinking(turn,
|
|
8706
|
-
if (!
|
|
8707
|
-
const block = { type: "thinking", thinking:
|
|
8713
|
+
function appendThinking(turn, text2, timestamp2) {
|
|
8714
|
+
if (!text2) return;
|
|
8715
|
+
const block = { type: "thinking", thinking: text2, signature: "" };
|
|
8708
8716
|
turn.thinking.push(block);
|
|
8709
8717
|
const last = turn.contentBlocks[turn.contentBlocks.length - 1];
|
|
8710
8718
|
if (last && last.kind === "thinking") {
|
|
@@ -8765,9 +8773,9 @@ function parseMcpEventResult(value) {
|
|
|
8765
8773
|
const ok = isObject2(value.Ok) ? value.Ok : null;
|
|
8766
8774
|
if (!ok) return { text: safeStringify(value), isError: false };
|
|
8767
8775
|
const parsedContent = parseCustomToolOutput(ok.content);
|
|
8768
|
-
const
|
|
8776
|
+
const text2 = parsedContent.text || (ok.structuredContent !== void 0 ? safeStringify(ok.structuredContent) : safeStringify(ok));
|
|
8769
8777
|
return {
|
|
8770
|
-
text,
|
|
8778
|
+
text: text2,
|
|
8771
8779
|
isError: ok.isError === true || parsedContent.isError
|
|
8772
8780
|
};
|
|
8773
8781
|
}
|
|
@@ -8786,22 +8794,22 @@ function createTurn(turnId, timestamp2, model) {
|
|
|
8786
8794
|
model
|
|
8787
8795
|
};
|
|
8788
8796
|
}
|
|
8789
|
-
function extractPromptFromRecord(
|
|
8790
|
-
if (
|
|
8791
|
-
return normalizePromptText(
|
|
8797
|
+
function extractPromptFromRecord(record5) {
|
|
8798
|
+
if (record5.type === "event_msg" && isObject2(record5.payload) && record5.payload.type === "user_message" && typeof record5.payload.message === "string") {
|
|
8799
|
+
return normalizePromptText(record5.payload.message);
|
|
8792
8800
|
}
|
|
8793
|
-
if (
|
|
8794
|
-
return normalizePromptText(extractMessageText(
|
|
8801
|
+
if (record5.type === "response_item" && isObject2(record5.payload) && record5.payload.type === "message" && record5.payload.role === "user") {
|
|
8802
|
+
return normalizePromptText(extractMessageText(record5.payload, "input_text"));
|
|
8795
8803
|
}
|
|
8796
8804
|
return "";
|
|
8797
8805
|
}
|
|
8798
|
-
function recordOpensTurn(
|
|
8799
|
-
if (
|
|
8800
|
-
if (
|
|
8801
|
-
if (
|
|
8806
|
+
function recordOpensTurn(record5, payload) {
|
|
8807
|
+
if (record5.type === "session_meta") return false;
|
|
8808
|
+
if (record5.type === "event_msg" && payload?.type === "task_started") return false;
|
|
8809
|
+
if (record5.type === "response_item" && payload?.type === "message") {
|
|
8802
8810
|
if (payload.role === "developer" || payload.role === "system") return false;
|
|
8803
8811
|
if (payload.role === "user") {
|
|
8804
|
-
return extractPromptFromRecord(
|
|
8812
|
+
return extractPromptFromRecord(record5) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
|
|
8805
8813
|
}
|
|
8806
8814
|
}
|
|
8807
8815
|
return true;
|
|
@@ -8822,22 +8830,22 @@ function extractMetadataFromRecords(records) {
|
|
|
8822
8830
|
let parentSessionId = null;
|
|
8823
8831
|
let agentPath = "/root";
|
|
8824
8832
|
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
|
|
8833
|
+
for (const record5 of records) {
|
|
8834
|
+
if (!isObject2(record5.payload)) continue;
|
|
8835
|
+
if (record5.type === "session_meta") {
|
|
8836
|
+
sessionId ||= typeof record5.payload.id === "string" ? record5.payload.id : "";
|
|
8837
|
+
version ||= typeof record5.payload.cli_version === "string" ? record5.payload.cli_version : "";
|
|
8838
|
+
cwd ||= typeof record5.payload.cwd === "string" ? record5.payload.cwd : "";
|
|
8839
|
+
if (!branchedFrom && isObject2(record5.payload.branchedFrom)) {
|
|
8840
|
+
const sourceId = typeof record5.payload.branchedFrom.sessionId === "string" ? record5.payload.branchedFrom.sessionId : "";
|
|
8833
8841
|
if (sourceId) {
|
|
8834
8842
|
branchedFrom = {
|
|
8835
8843
|
sessionId: sourceId,
|
|
8836
|
-
turnIndex: typeof
|
|
8844
|
+
turnIndex: typeof record5.payload.branchedFrom.turnIndex === "number" ? record5.payload.branchedFrom.turnIndex : null
|
|
8837
8845
|
};
|
|
8838
8846
|
}
|
|
8839
8847
|
}
|
|
8840
|
-
const source = isObject2(
|
|
8848
|
+
const source = isObject2(record5.payload.source) ? record5.payload.source : null;
|
|
8841
8849
|
if (source && isObject2(source.subagent)) {
|
|
8842
8850
|
isSubagent = true;
|
|
8843
8851
|
const threadSpawn = isObject2(source.subagent.thread_spawn) ? source.subagent.thread_spawn : null;
|
|
@@ -8845,25 +8853,25 @@ function extractMetadataFromRecords(records) {
|
|
|
8845
8853
|
agentPath = threadSpawn.agent_path;
|
|
8846
8854
|
}
|
|
8847
8855
|
}
|
|
8848
|
-
if (typeof
|
|
8849
|
-
parentSessionId =
|
|
8856
|
+
if (typeof record5.payload.forked_from_id === "string" && record5.payload.forked_from_id) {
|
|
8857
|
+
parentSessionId = record5.payload.forked_from_id;
|
|
8850
8858
|
}
|
|
8851
|
-
const git = isObject2(
|
|
8859
|
+
const git = isObject2(record5.payload.git) ? record5.payload.git : null;
|
|
8852
8860
|
gitBranch ||= git && typeof git.branch === "string" ? git.branch : "";
|
|
8853
8861
|
}
|
|
8854
|
-
if (
|
|
8855
|
-
model ||= typeof
|
|
8856
|
-
cwd ||= typeof
|
|
8862
|
+
if (record5.type === "turn_context") {
|
|
8863
|
+
model ||= typeof record5.payload.model === "string" ? record5.payload.model : "";
|
|
8864
|
+
cwd ||= typeof record5.payload.cwd === "string" ? record5.payload.cwd : "";
|
|
8857
8865
|
}
|
|
8858
|
-
const prompt = extractPromptFromRecord(
|
|
8866
|
+
const prompt = extractPromptFromRecord(record5);
|
|
8859
8867
|
if (!prompt) continue;
|
|
8860
8868
|
if (prompt === previousPrompt) continue;
|
|
8861
8869
|
if (!firstUserMessage) firstUserMessage = prompt;
|
|
8862
8870
|
lastUserMessage = prompt;
|
|
8863
8871
|
previousPrompt = prompt;
|
|
8864
8872
|
turnCount++;
|
|
8865
|
-
if (!timestamp2) timestamp2 =
|
|
8866
|
-
lastTimestamp =
|
|
8873
|
+
if (!timestamp2) timestamp2 = record5.timestamp ?? "";
|
|
8874
|
+
lastTimestamp = record5.timestamp ?? lastTimestamp;
|
|
8867
8875
|
}
|
|
8868
8876
|
if (lastTimestamp === "") lastTimestamp = timestamp2;
|
|
8869
8877
|
return {
|
|
@@ -9021,19 +9029,19 @@ function walkCodexRecords(records, options) {
|
|
|
9021
9029
|
appendToolCall(targetTurn, toolCall, timestamp2);
|
|
9022
9030
|
}
|
|
9023
9031
|
for (let index = 0; index < records.length; index++) {
|
|
9024
|
-
const
|
|
9025
|
-
if (!isCodexRecord(
|
|
9032
|
+
const record5 = records[index];
|
|
9033
|
+
if (!isCodexRecord(record5)) continue;
|
|
9026
9034
|
recordIndex = index;
|
|
9027
|
-
const payload = isObject2(
|
|
9028
|
-
const timestamp2 =
|
|
9029
|
-
if (
|
|
9035
|
+
const payload = isObject2(record5.payload) ? record5.payload : void 0;
|
|
9036
|
+
const timestamp2 = record5.timestamp ?? "";
|
|
9037
|
+
if (record5.type === "compacted") {
|
|
9030
9038
|
current = commitTurn(current);
|
|
9031
9039
|
pendingCompaction = "Conversation compacted";
|
|
9032
9040
|
lastTurnTimestamp = timestamp2;
|
|
9033
9041
|
continue;
|
|
9034
9042
|
}
|
|
9035
|
-
if (
|
|
9036
|
-
if (
|
|
9043
|
+
if (record5.type === "world_state") continue;
|
|
9044
|
+
if (record5.type === "turn_context") {
|
|
9037
9045
|
current = commitTurn(current);
|
|
9038
9046
|
pendingContextIndex = index;
|
|
9039
9047
|
currentTurnId = typeof payload?.turn_id === "string" ? payload.turn_id : null;
|
|
@@ -9042,7 +9050,7 @@ function walkCodexRecords(records, options) {
|
|
|
9042
9050
|
sawTurnStart = true;
|
|
9043
9051
|
continue;
|
|
9044
9052
|
}
|
|
9045
|
-
if (
|
|
9053
|
+
if (record5.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
|
|
9046
9054
|
if (current && (current.assistantText.length > 0 || current.toolCalls.length > 0 || current.thinking.length > 0)) {
|
|
9047
9055
|
current = commitTurn(current);
|
|
9048
9056
|
}
|
|
@@ -9066,12 +9074,12 @@ function walkCodexRecords(records, options) {
|
|
|
9066
9074
|
lastTurnTimestamp = timestamp2;
|
|
9067
9075
|
continue;
|
|
9068
9076
|
}
|
|
9069
|
-
if (!current && !recordOpensTurn(
|
|
9077
|
+
if (!current && !recordOpensTurn(record5, payload)) continue;
|
|
9070
9078
|
current ??= createActiveTurn(currentTurnId, timestamp2, currentModel);
|
|
9071
9079
|
if (!current.model && currentModel) current.model = currentModel;
|
|
9072
9080
|
if (!current.timestamp) current.timestamp = timestamp2;
|
|
9073
9081
|
if (timestamp2) lastTurnTimestamp = timestamp2;
|
|
9074
|
-
if (
|
|
9082
|
+
if (record5.type === "event_msg" && payload?.type === "token_count") {
|
|
9075
9083
|
const info = isObject2(payload.info) ? payload.info : null;
|
|
9076
9084
|
const lastUsage = info ? parseTokenUsage(info.last_token_usage) : null;
|
|
9077
9085
|
if (lastUsage) {
|
|
@@ -9079,14 +9087,14 @@ function walkCodexRecords(records, options) {
|
|
|
9079
9087
|
}
|
|
9080
9088
|
continue;
|
|
9081
9089
|
}
|
|
9082
|
-
if (
|
|
9090
|
+
if (record5.type === "event_msg" && payload?.type === "web_search_end" && typeof payload.call_id === "string") {
|
|
9083
9091
|
const input = {};
|
|
9084
9092
|
if (typeof payload.query === "string" && payload.query) input.query = payload.query;
|
|
9085
9093
|
if (isObject2(payload.action)) input.action = payload.action;
|
|
9086
9094
|
upsertWebSearchCall(current, payload.call_id, input, "completed", timestamp2);
|
|
9087
9095
|
continue;
|
|
9088
9096
|
}
|
|
9089
|
-
if (
|
|
9097
|
+
if (record5.type === "event_msg" && payload?.type === "mcp_tool_call_end" && typeof payload.call_id === "string" && isObject2(payload.invocation)) {
|
|
9090
9098
|
const invocation = payload.invocation;
|
|
9091
9099
|
const server = typeof invocation.server === "string" ? invocation.server : "mcp";
|
|
9092
9100
|
const tool = typeof invocation.tool === "string" ? invocation.tool : "tool";
|
|
@@ -9109,7 +9117,7 @@ function walkCodexRecords(records, options) {
|
|
|
9109
9117
|
}
|
|
9110
9118
|
continue;
|
|
9111
9119
|
}
|
|
9112
|
-
if (
|
|
9120
|
+
if (record5.type === "event_msg" && payload?.type === "sub_agent_activity" && typeof payload.agent_thread_id === "string" && typeof payload.agent_path === "string") {
|
|
9113
9121
|
const agentId = payload.agent_thread_id;
|
|
9114
9122
|
const eventId2 = typeof payload.event_id === "string" ? payload.event_id : "";
|
|
9115
9123
|
const kind = typeof payload.kind === "string" ? payload.kind : "started";
|
|
@@ -9143,7 +9151,7 @@ function walkCodexRecords(records, options) {
|
|
|
9143
9151
|
upsertAgentMessage(agentId, current, timestamp2, { status });
|
|
9144
9152
|
continue;
|
|
9145
9153
|
}
|
|
9146
|
-
if (
|
|
9154
|
+
if (record5.type !== "response_item" || !payload) continue;
|
|
9147
9155
|
if (payload.type === "reasoning") {
|
|
9148
9156
|
const summary = Array.isArray(payload.summary) ? payload.summary.filter((item) => typeof item === "string").join("\n") : "";
|
|
9149
9157
|
appendThinking(current, summary.trim(), timestamp2);
|
|
@@ -9154,11 +9162,11 @@ function walkCodexRecords(records, options) {
|
|
|
9154
9162
|
continue;
|
|
9155
9163
|
}
|
|
9156
9164
|
if (payload.type === "message" && payload.role === "user" && current.userMessage === null) {
|
|
9157
|
-
const
|
|
9165
|
+
const text2 = normalizePromptText(extractMessageText(payload, "input_text"));
|
|
9158
9166
|
const images = extractResponseMessageImages(payload);
|
|
9159
9167
|
const audio = extractResponseMessageAudio(payload);
|
|
9160
|
-
if (
|
|
9161
|
-
current.userMessage = buildCodexUserContent(
|
|
9168
|
+
if (text2 || images.length > 0 || audio.length > 0) {
|
|
9169
|
+
current.userMessage = buildCodexUserContent(text2, images, audio);
|
|
9162
9170
|
current.isFragment = false;
|
|
9163
9171
|
sawTurnStart = true;
|
|
9164
9172
|
}
|
|
@@ -9364,14 +9372,14 @@ function walkCodexRecords(records, options) {
|
|
|
9364
9372
|
}
|
|
9365
9373
|
if (payload.type === "custom_tool_call_output" && typeof payload.call_id === "string") {
|
|
9366
9374
|
const callId = payload.call_id;
|
|
9367
|
-
const { text, isError } = parseCustomToolOutput(payload.output);
|
|
9375
|
+
const { text: text2, isError } = parseCustomToolOutput(payload.output);
|
|
9368
9376
|
const patchCalls = patchCallIds.get(callId);
|
|
9369
9377
|
if (patchCalls) {
|
|
9370
|
-
const failedIds = patchCalls.direct && isError ? new Set(patchCalls.calls.map((call) => call.id)) : findFailedNestedPatchCallIds(
|
|
9378
|
+
const failedIds = patchCalls.direct && isError ? new Set(patchCalls.calls.map((call) => call.id)) : findFailedNestedPatchCallIds(text2, isError, patchCalls.calls);
|
|
9371
9379
|
for (const patchCall of patchCalls.calls) {
|
|
9372
9380
|
const tc = pendingToolCalls.get(patchCall.id);
|
|
9373
9381
|
if (tc) {
|
|
9374
|
-
tc.result =
|
|
9382
|
+
tc.result = text2;
|
|
9375
9383
|
tc.isError = failedIds.has(tc.id);
|
|
9376
9384
|
pendingToolCalls.delete(tc.id);
|
|
9377
9385
|
}
|
|
@@ -9380,7 +9388,7 @@ function walkCodexRecords(records, options) {
|
|
|
9380
9388
|
}
|
|
9381
9389
|
const toolCall = pendingToolCalls.get(callId);
|
|
9382
9390
|
if (toolCall) {
|
|
9383
|
-
toolCall.result =
|
|
9391
|
+
toolCall.result = text2;
|
|
9384
9392
|
toolCall.isError = isError;
|
|
9385
9393
|
pendingToolCalls.delete(callId);
|
|
9386
9394
|
}
|
|
@@ -9413,7 +9421,7 @@ function parseCodexSession(jsonlText, options) {
|
|
|
9413
9421
|
return session;
|
|
9414
9422
|
}
|
|
9415
9423
|
function appendCodexSession(existing, newJsonlText) {
|
|
9416
|
-
const prefix = existing.rawMessages.map((
|
|
9424
|
+
const prefix = existing.rawMessages.map((record5) => JSON.stringify(record5)).join("\n");
|
|
9417
9425
|
return parseCodexSession(prefix ? `${prefix}
|
|
9418
9426
|
${newJsonlText}` : newJsonlText);
|
|
9419
9427
|
}
|
|
@@ -9513,8 +9521,8 @@ function collectCodexPendingAgents(rawMessages) {
|
|
|
9513
9521
|
continue;
|
|
9514
9522
|
}
|
|
9515
9523
|
if (payload.type === "agent_message" && typeof payload.author === "string") {
|
|
9516
|
-
const
|
|
9517
|
-
const messageType =
|
|
9524
|
+
const text2 = codexPayloadText(payload);
|
|
9525
|
+
const messageType = text2.match(/^Message Type:\s*([^\r\n]+)/)?.[1]?.trim().toUpperCase() ?? "";
|
|
9518
9526
|
if (!TERMINAL_INTER_AGENT_TYPES.has(messageType)) continue;
|
|
9519
9527
|
const agentId = agentIdByPath.get(payload.author) ?? payload.author;
|
|
9520
9528
|
done.add(agentId);
|
|
@@ -9608,16 +9616,16 @@ async function readCodexSessionIdentity(filePath) {
|
|
|
9608
9616
|
let parentSessionId = null;
|
|
9609
9617
|
let sawSessionMeta = false;
|
|
9610
9618
|
for (const line of await readHeadLines(filePath, HEAD_BYTES)) {
|
|
9611
|
-
let
|
|
9619
|
+
let record5;
|
|
9612
9620
|
try {
|
|
9613
|
-
|
|
9621
|
+
record5 = JSON.parse(line);
|
|
9614
9622
|
} catch {
|
|
9615
9623
|
continue;
|
|
9616
9624
|
}
|
|
9617
|
-
if (!isRecord2(
|
|
9618
|
-
if (
|
|
9625
|
+
if (!isRecord2(record5) || !isRecord2(record5.payload)) continue;
|
|
9626
|
+
if (record5.type === "session_meta") {
|
|
9619
9627
|
sawSessionMeta = true;
|
|
9620
|
-
const payload =
|
|
9628
|
+
const payload = record5.payload;
|
|
9621
9629
|
if (!sessionId && typeof payload.id === "string") sessionId = payload.id;
|
|
9622
9630
|
if (!cwd && typeof payload.cwd === "string") cwd = payload.cwd;
|
|
9623
9631
|
if (!parentSessionId && typeof payload.forked_from_id === "string") {
|
|
@@ -9627,8 +9635,8 @@ async function readCodexSessionIdentity(filePath) {
|
|
|
9627
9635
|
if (source && isRecord2(source.subagent)) isSubagent = true;
|
|
9628
9636
|
const git = isRecord2(payload.git) ? payload.git : null;
|
|
9629
9637
|
if (!gitBranch && git && typeof git.branch === "string") gitBranch = git.branch;
|
|
9630
|
-
} else if (
|
|
9631
|
-
if (!cwd && typeof
|
|
9638
|
+
} else if (record5.type === "turn_context") {
|
|
9639
|
+
if (!cwd && typeof record5.payload.cwd === "string") cwd = record5.payload.cwd;
|
|
9632
9640
|
}
|
|
9633
9641
|
}
|
|
9634
9642
|
if (!sawSessionMeta || !cwd) return null;
|
|
@@ -10028,8 +10036,8 @@ function textFromValue(value) {
|
|
|
10028
10036
|
if (typeof value === "string") return value;
|
|
10029
10037
|
if (!Array.isArray(value)) return "";
|
|
10030
10038
|
return value.flatMap((part) => {
|
|
10031
|
-
const
|
|
10032
|
-
return
|
|
10039
|
+
const text2 = typeof part === "string" ? part : isObject3(part) ? readString(part.text, part.content) : "";
|
|
10040
|
+
return text2 ? [text2] : [];
|
|
10033
10041
|
}).join("\n");
|
|
10034
10042
|
}
|
|
10035
10043
|
function collectBinaryAssets(events) {
|
|
@@ -10069,10 +10077,10 @@ function extractImages(values, assets) {
|
|
|
10069
10077
|
return images;
|
|
10070
10078
|
}
|
|
10071
10079
|
function buildUserContent(data, assets) {
|
|
10072
|
-
const
|
|
10080
|
+
const text2 = readString(data.content);
|
|
10073
10081
|
const images = extractImages(data.attachments, assets);
|
|
10074
|
-
if (images.length === 0) return
|
|
10075
|
-
return [...images, ...
|
|
10082
|
+
if (images.length === 0) return text2;
|
|
10083
|
+
return [...images, ...text2 ? [{ type: "text", text: text2 }] : []];
|
|
10076
10084
|
}
|
|
10077
10085
|
function extractToolResultImages(data, assets) {
|
|
10078
10086
|
if (!isObject3(data.result)) return [];
|
|
@@ -10201,17 +10209,17 @@ function extractToolResult(data) {
|
|
|
10201
10209
|
if (typeof result.content === "string") return result.content;
|
|
10202
10210
|
if (Array.isArray(result.contents)) {
|
|
10203
10211
|
const content = result.contents.flatMap((part) => {
|
|
10204
|
-
const
|
|
10205
|
-
return
|
|
10212
|
+
const text2 = typeof part === "string" ? part : isObject3(part) ? readString(part.text, part.content, part.output) : "";
|
|
10213
|
+
return text2 ? [text2] : [];
|
|
10206
10214
|
}).join("\n");
|
|
10207
10215
|
if (content) return content;
|
|
10208
10216
|
}
|
|
10209
10217
|
if (result.structuredContent !== void 0) return safeStringify2(result.structuredContent);
|
|
10210
10218
|
return safeStringify2(result);
|
|
10211
10219
|
}
|
|
10212
|
-
function appendThinking2(turn,
|
|
10213
|
-
if (!
|
|
10214
|
-
const block = { type: "thinking", thinking:
|
|
10220
|
+
function appendThinking2(turn, text2, timestamp2, signature) {
|
|
10221
|
+
if (!text2 || turn.thinking.some((block2) => block2.thinking === text2)) return;
|
|
10222
|
+
const block = { type: "thinking", thinking: text2, signature };
|
|
10215
10223
|
turn.thinking.push(block);
|
|
10216
10224
|
const last = turn.contentBlocks[turn.contentBlocks.length - 1];
|
|
10217
10225
|
if (last?.kind === "thinking") {
|
|
@@ -10389,8 +10397,8 @@ function parseCopilotSession(jsonlText, options) {
|
|
|
10389
10397
|
message.model = readString(data.model) || message.model;
|
|
10390
10398
|
const reasoning = readString(data.reasoningText);
|
|
10391
10399
|
if (reasoning && !message.thinking.includes(reasoning)) message.thinking.push(reasoning);
|
|
10392
|
-
const
|
|
10393
|
-
if (
|
|
10400
|
+
const text2 = textFromValue(data.content);
|
|
10401
|
+
if (text2 && !message.text.includes(text2)) message.text.push(text2);
|
|
10394
10402
|
for (const call of toolCallsFromRequests(
|
|
10395
10403
|
data.toolRequests,
|
|
10396
10404
|
timestamp2,
|
|
@@ -10645,7 +10653,7 @@ function parseCopilotSession(jsonlText, options) {
|
|
|
10645
10653
|
};
|
|
10646
10654
|
}
|
|
10647
10655
|
function appendCopilotSession(existing, newJsonlText) {
|
|
10648
|
-
const prefix = existing.rawMessages.map((
|
|
10656
|
+
const prefix = existing.rawMessages.map((record5) => JSON.stringify(record5)).join("\n");
|
|
10649
10657
|
return parseCopilotSession(prefix ? `${prefix}
|
|
10650
10658
|
${newJsonlText}` : newJsonlText);
|
|
10651
10659
|
}
|
|
@@ -10753,11 +10761,11 @@ function brandCopilotBranch() {
|
|
|
10753
10761
|
function copilotTurnBoundaries(records) {
|
|
10754
10762
|
const boundaries = [];
|
|
10755
10763
|
for (let index = 0; index < records.length; index++) {
|
|
10756
|
-
const
|
|
10757
|
-
if (
|
|
10758
|
-
const data =
|
|
10764
|
+
const record5 = records[index];
|
|
10765
|
+
if (record5.type !== "user.message" || typeof record5.agentId === "string") continue;
|
|
10766
|
+
const data = record5.data;
|
|
10759
10767
|
if (!data || typeof data !== "object" || Array.isArray(data)) continue;
|
|
10760
|
-
if (typeof
|
|
10768
|
+
if (typeof record5.id !== "string" || !record5.id) continue;
|
|
10761
10769
|
boundaries.push(index);
|
|
10762
10770
|
}
|
|
10763
10771
|
return boundaries;
|
|
@@ -10814,14 +10822,14 @@ async function readCopilotSessionIdentity(filePath) {
|
|
|
10814
10822
|
let cwd = "";
|
|
10815
10823
|
let gitBranch = "";
|
|
10816
10824
|
for (const line of await readHeadLines(filePath, HEAD_BYTES)) {
|
|
10817
|
-
let
|
|
10825
|
+
let record5;
|
|
10818
10826
|
try {
|
|
10819
|
-
|
|
10827
|
+
record5 = JSON.parse(line);
|
|
10820
10828
|
} catch {
|
|
10821
10829
|
continue;
|
|
10822
10830
|
}
|
|
10823
|
-
if (!isRecord3(
|
|
10824
|
-
const data = isRecord3(
|
|
10831
|
+
if (!isRecord3(record5) || record5.type !== "session.start" && record5.type !== "session.resume") continue;
|
|
10832
|
+
const data = isRecord3(record5.data) ? record5.data : null;
|
|
10825
10833
|
if (!data) continue;
|
|
10826
10834
|
if (typeof data.sessionId === "string" && data.sessionId) sessionId = data.sessionId;
|
|
10827
10835
|
const context = isRecord3(data.context) ? data.context : null;
|
|
@@ -11013,15 +11021,15 @@ function readSender(attrs) {
|
|
|
11013
11021
|
}
|
|
11014
11022
|
return null;
|
|
11015
11023
|
}
|
|
11016
|
-
function parseAgentEnvelope(
|
|
11024
|
+
function parseAgentEnvelope(text2) {
|
|
11017
11025
|
let sender = null;
|
|
11018
11026
|
let matched = false;
|
|
11019
|
-
const unwrapped =
|
|
11027
|
+
const unwrapped = text2.replace(ENVELOPE_RE, (_full, _tag, attrs, inner) => {
|
|
11020
11028
|
matched = true;
|
|
11021
11029
|
if (sender === null) sender = readSender(attrs);
|
|
11022
11030
|
return inner.trim();
|
|
11023
11031
|
});
|
|
11024
|
-
return { sender, matched, body: matched ? unwrapped.trim() :
|
|
11032
|
+
return { sender, matched, body: matched ? unwrapped.trim() : text2 };
|
|
11025
11033
|
}
|
|
11026
11034
|
var ENVELOPE_RE, SENDER_PATTERNS;
|
|
11027
11035
|
var init_agentEnvelope = __esm({
|
|
@@ -11055,9 +11063,9 @@ function isVisibleQueuedPrompt(content) {
|
|
|
11055
11063
|
}
|
|
11056
11064
|
function isTaskNotificationRecord(msg) {
|
|
11057
11065
|
if (msg.origin?.kind === "task-notification") return true;
|
|
11058
|
-
const
|
|
11059
|
-
if (!
|
|
11060
|
-
return
|
|
11066
|
+
const text2 = extractTextFromContent(msg.message.content);
|
|
11067
|
+
if (!text2.includes("<task-notification>")) return false;
|
|
11068
|
+
return text2.replace(TASK_NOTIFICATION_BLOCK_RE, "").replace(ANY_TAG_RE, "").trim() === "";
|
|
11061
11069
|
}
|
|
11062
11070
|
function queuedCommandPrompt(msg) {
|
|
11063
11071
|
if (!isAttachmentMessage(msg)) return null;
|
|
@@ -11109,8 +11117,8 @@ function mergeTokenUsage3(existing, incoming) {
|
|
|
11109
11117
|
};
|
|
11110
11118
|
}
|
|
11111
11119
|
function extractCompactionSummary(content) {
|
|
11112
|
-
const
|
|
11113
|
-
return
|
|
11120
|
+
const text2 = extractTextFromContent(content).trim();
|
|
11121
|
+
return text2.replace(RESUME_PREAMBLE_RE, "").replace(RESUME_INSTRUCTIONS_RE, "").trim();
|
|
11114
11122
|
}
|
|
11115
11123
|
function normalizeCompactionMeta(meta) {
|
|
11116
11124
|
if (!meta) return void 0;
|
|
@@ -11891,13 +11899,13 @@ function collectClaudeBackgroundWork(rawMessages) {
|
|
|
11891
11899
|
const resolved = /* @__PURE__ */ new Set();
|
|
11892
11900
|
const queuedIds = /* @__PURE__ */ new Set();
|
|
11893
11901
|
const deliveredIds = /* @__PURE__ */ new Set();
|
|
11894
|
-
function noteNotifications(
|
|
11895
|
-
if (!
|
|
11896
|
-
for (const match of
|
|
11902
|
+
function noteNotifications(text2, sink) {
|
|
11903
|
+
if (!text2.includes(TASK_NOTIFICATION_MARKER)) return;
|
|
11904
|
+
for (const match of text2.matchAll(TASK_ID_RE)) {
|
|
11897
11905
|
resolved.add(match[1]);
|
|
11898
11906
|
sink?.add(match[1]);
|
|
11899
11907
|
}
|
|
11900
|
-
for (const match of
|
|
11908
|
+
for (const match of text2.matchAll(TOOL_USE_ID_RE)) {
|
|
11901
11909
|
resolved.add(match[1]);
|
|
11902
11910
|
sink?.add(match[1]);
|
|
11903
11911
|
}
|
|
@@ -11913,7 +11921,7 @@ function collectClaudeBackgroundWork(rawMessages) {
|
|
|
11913
11921
|
const description = [toolUseResult.description, toolUseResult.workflowName, toolUseResult.summary].find((value) => typeof value === "string" && value.length > 0) ?? "";
|
|
11914
11922
|
if (ids.length > 0) launches.push({ ids, description });
|
|
11915
11923
|
}
|
|
11916
|
-
for (const
|
|
11924
|
+
for (const text2 of userMessageTexts(msg)) noteNotifications(text2, deliveredIds);
|
|
11917
11925
|
continue;
|
|
11918
11926
|
}
|
|
11919
11927
|
if (msg.type === "assistant") {
|
|
@@ -12181,12 +12189,12 @@ function isRecord4(value) {
|
|
|
12181
12189
|
function nonEmpty(value) {
|
|
12182
12190
|
return typeof value === "string" && value ? value : null;
|
|
12183
12191
|
}
|
|
12184
|
-
function stripTaggedBlocks(
|
|
12185
|
-
return
|
|
12192
|
+
function stripTaggedBlocks(text2) {
|
|
12193
|
+
return text2.replace(/<[^>]+>[\s\S]*?<\/[^>]+>/g, "").trim();
|
|
12186
12194
|
}
|
|
12187
|
-
function effortFromRecord(
|
|
12195
|
+
function effortFromRecord(record5) {
|
|
12188
12196
|
for (const kind of AGENT_KINDS) {
|
|
12189
|
-
const effort = READERS[kind].effort(
|
|
12197
|
+
const effort = READERS[kind].effort(record5);
|
|
12190
12198
|
if (effort) return effort;
|
|
12191
12199
|
}
|
|
12192
12200
|
return null;
|
|
@@ -12196,16 +12204,16 @@ function userMessageTextFromLine(line) {
|
|
|
12196
12204
|
(kind) => READERS[kind].userMessageMarkers.some((marker) => line.includes(marker))
|
|
12197
12205
|
);
|
|
12198
12206
|
if (candidates.length === 0) return null;
|
|
12199
|
-
let
|
|
12207
|
+
let record5;
|
|
12200
12208
|
try {
|
|
12201
|
-
|
|
12209
|
+
record5 = JSON.parse(line);
|
|
12202
12210
|
} catch {
|
|
12203
12211
|
return null;
|
|
12204
12212
|
}
|
|
12205
|
-
if (!isRecord4(
|
|
12213
|
+
if (!isRecord4(record5)) return null;
|
|
12206
12214
|
for (const kind of candidates) {
|
|
12207
|
-
const
|
|
12208
|
-
if (
|
|
12215
|
+
const text2 = READERS[kind].userMessageText(record5);
|
|
12216
|
+
if (text2 !== null) return text2;
|
|
12209
12217
|
}
|
|
12210
12218
|
return null;
|
|
12211
12219
|
}
|
|
@@ -12216,51 +12224,51 @@ var init_recordReaders = __esm({
|
|
|
12216
12224
|
claudeReader = {
|
|
12217
12225
|
kind: "claude",
|
|
12218
12226
|
// Every assistant record is tagged with the effort that turn ran at.
|
|
12219
|
-
effort: (
|
|
12227
|
+
effort: (record5) => record5.type === "assistant" ? nonEmpty(record5.effort) : null,
|
|
12220
12228
|
userMessageMarkers: ['"user"'],
|
|
12221
|
-
userMessageText(
|
|
12222
|
-
if (
|
|
12223
|
-
const content = isRecord4(
|
|
12229
|
+
userMessageText(record5) {
|
|
12230
|
+
if (record5.type !== "user" || record5.isMeta) return null;
|
|
12231
|
+
const content = isRecord4(record5.message) ? record5.message.content : void 0;
|
|
12224
12232
|
if (typeof content === "string") return stripTaggedBlocks(content);
|
|
12225
12233
|
if (!Array.isArray(content)) return "";
|
|
12226
|
-
let
|
|
12234
|
+
let text2 = "";
|
|
12227
12235
|
for (const block of content) {
|
|
12228
12236
|
if (isRecord4(block) && block.type === "text" && typeof block.text === "string") {
|
|
12229
|
-
|
|
12237
|
+
text2 += stripTaggedBlocks(block.text) + " ";
|
|
12230
12238
|
}
|
|
12231
12239
|
}
|
|
12232
|
-
return
|
|
12240
|
+
return text2.trim();
|
|
12233
12241
|
}
|
|
12234
12242
|
};
|
|
12235
12243
|
codexReader = {
|
|
12236
12244
|
kind: "codex",
|
|
12237
12245
|
// Effort is recorded per turn; newer CLI versions moved it under `thread_settings`.
|
|
12238
|
-
effort(
|
|
12239
|
-
if (
|
|
12240
|
-
const { payload } =
|
|
12246
|
+
effort(record5) {
|
|
12247
|
+
if (record5.type !== "turn_context" || !isRecord4(record5.payload)) return null;
|
|
12248
|
+
const { payload } = record5;
|
|
12241
12249
|
const direct = nonEmpty(payload.effort);
|
|
12242
12250
|
if (direct) return direct;
|
|
12243
12251
|
const settings = isRecord4(payload.thread_settings) ? payload.thread_settings : null;
|
|
12244
12252
|
return nonEmpty(settings?.reasoning_effort);
|
|
12245
12253
|
},
|
|
12246
12254
|
userMessageMarkers: ['"event_msg"'],
|
|
12247
|
-
userMessageText(
|
|
12248
|
-
if (
|
|
12249
|
-
const { payload } =
|
|
12255
|
+
userMessageText(record5) {
|
|
12256
|
+
if (record5.type !== "event_msg" || !isRecord4(record5.payload)) return null;
|
|
12257
|
+
const { payload } = record5;
|
|
12250
12258
|
return payload.type === "user_message" && typeof payload.message === "string" ? payload.message.trim() : null;
|
|
12251
12259
|
}
|
|
12252
12260
|
};
|
|
12253
12261
|
copilotReader = {
|
|
12254
12262
|
kind: "copilot",
|
|
12255
|
-
effort(
|
|
12256
|
-
if (
|
|
12257
|
-
return nonEmpty(
|
|
12263
|
+
effort(record5) {
|
|
12264
|
+
if (record5.type !== "session.start" && record5.type !== "session.resume" && record5.type !== "session.model_change" || !isRecord4(record5.data)) return null;
|
|
12265
|
+
return nonEmpty(record5.data.reasoningEffort ?? record5.data.effort);
|
|
12258
12266
|
},
|
|
12259
12267
|
userMessageMarkers: ['"user.message"'],
|
|
12260
|
-
userMessageText(
|
|
12261
|
-
if (
|
|
12262
|
-
if (typeof
|
|
12263
|
-
const data = isRecord4(
|
|
12268
|
+
userMessageText(record5) {
|
|
12269
|
+
if (record5.type !== "user.message") return null;
|
|
12270
|
+
if (typeof record5.agentId === "string" && record5.agentId) return null;
|
|
12271
|
+
const data = isRecord4(record5.data) ? record5.data : null;
|
|
12264
12272
|
return typeof data?.content === "string" ? data.content.trim() : "";
|
|
12265
12273
|
}
|
|
12266
12274
|
};
|
|
@@ -12273,16 +12281,16 @@ var init_recordReaders = __esm({
|
|
|
12273
12281
|
});
|
|
12274
12282
|
|
|
12275
12283
|
// ../../server/agents/tailRecords.ts
|
|
12276
|
-
function isSubagentLifecycle(
|
|
12277
|
-
return
|
|
12284
|
+
function isSubagentLifecycle(record5) {
|
|
12285
|
+
return record5.type.startsWith("subagent.") && typeof record5.agentId === "string" && record5.agentId.length > 0;
|
|
12278
12286
|
}
|
|
12279
|
-
function isSubagentNoise(
|
|
12280
|
-
return typeof
|
|
12287
|
+
function isSubagentNoise(record5) {
|
|
12288
|
+
return typeof record5.agentId === "string" && record5.agentId.length > 0;
|
|
12281
12289
|
}
|
|
12282
|
-
function classifyTailRecord(
|
|
12290
|
+
function classifyTailRecord(record5) {
|
|
12283
12291
|
for (const kind of AGENT_KINDS) {
|
|
12284
12292
|
const format = TAIL_FORMATS[kind];
|
|
12285
|
-
const verdict = format.classify(
|
|
12293
|
+
const verdict = format.classify(record5);
|
|
12286
12294
|
if (verdict.kind !== "ignore") return { format, verdict };
|
|
12287
12295
|
}
|
|
12288
12296
|
return null;
|
|
@@ -12299,31 +12307,31 @@ var init_tailRecords = __esm({
|
|
|
12299
12307
|
// Background agent/workflow launches, task notifications and TaskStop calls
|
|
12300
12308
|
// can all still change a verdict that a turn-ending line looked to settle.
|
|
12301
12309
|
markers: ["async_launched", "task-notification", '"TaskStop"'],
|
|
12302
|
-
classify(
|
|
12303
|
-
if (
|
|
12304
|
-
const reason =
|
|
12310
|
+
classify(record5) {
|
|
12311
|
+
if (record5.type === "system" && record5.subtype === "terminal_reason") {
|
|
12312
|
+
const reason = record5.reason;
|
|
12305
12313
|
return reason ? { kind: "final", status: { status: "completed", terminalReason: reason } } : IGNORE;
|
|
12306
12314
|
}
|
|
12307
|
-
if (
|
|
12308
|
-
const data =
|
|
12315
|
+
if (record5.type === "progress") {
|
|
12316
|
+
const data = record5.data;
|
|
12309
12317
|
if (data?.type !== "hook_progress") return IGNORE;
|
|
12310
12318
|
const decision = data.decision ?? data.hookSpecificOutput?.permissionDecision;
|
|
12311
12319
|
return decision === "defer" ? ANSWER : IGNORE;
|
|
12312
12320
|
}
|
|
12313
|
-
if (
|
|
12314
|
-
if (
|
|
12315
|
-
const stopReason =
|
|
12316
|
-
if (
|
|
12321
|
+
if (record5.type === "attachment") return KEEP;
|
|
12322
|
+
if (record5.type === "assistant" || record5.type === "user" || record5.type === "queue-operation") {
|
|
12323
|
+
const stopReason = record5.message?.stop_reason;
|
|
12324
|
+
if (record5.type === "assistant" && stopReason === "end_turn") {
|
|
12317
12325
|
return { kind: "turn-end", awaitUserActivity: true };
|
|
12318
12326
|
}
|
|
12319
|
-
const canDerive =
|
|
12327
|
+
const canDerive = record5.type === "assistant" || record5.type === "user" && !record5.isMeta;
|
|
12320
12328
|
return canDerive ? ANSWER : KEEP;
|
|
12321
12329
|
}
|
|
12322
12330
|
return IGNORE;
|
|
12323
12331
|
},
|
|
12324
|
-
classifyAfterTurnEnd(
|
|
12325
|
-
if (
|
|
12326
|
-
const isRealUserTurn =
|
|
12332
|
+
classifyAfterTurnEnd(record5) {
|
|
12333
|
+
if (record5.type !== "user" && record5.type !== "assistant" && record5.type !== "queue-operation" && record5.type !== "attachment") return IGNORE;
|
|
12334
|
+
const isRealUserTurn = record5.type === "user" && !record5.isMeta;
|
|
12327
12335
|
return { kind: "keep", sawUserActivity: isRealUserTurn };
|
|
12328
12336
|
}
|
|
12329
12337
|
};
|
|
@@ -12342,9 +12350,9 @@ var init_tailRecords = __esm({
|
|
|
12342
12350
|
"agent_message",
|
|
12343
12351
|
"function_call_output"
|
|
12344
12352
|
],
|
|
12345
|
-
classify(
|
|
12346
|
-
if (
|
|
12347
|
-
const payload =
|
|
12353
|
+
classify(record5) {
|
|
12354
|
+
if (record5.type === "event_msg") {
|
|
12355
|
+
const payload = record5.payload;
|
|
12348
12356
|
switch (payload?.type) {
|
|
12349
12357
|
case "task_complete":
|
|
12350
12358
|
return { kind: "turn-end" };
|
|
@@ -12356,32 +12364,32 @@ var init_tailRecords = __esm({
|
|
|
12356
12364
|
return IGNORE;
|
|
12357
12365
|
}
|
|
12358
12366
|
}
|
|
12359
|
-
if (
|
|
12360
|
-
const payload =
|
|
12367
|
+
if (record5.type === "response_item") {
|
|
12368
|
+
const payload = record5.payload;
|
|
12361
12369
|
const decides = payload?.type === "function_call" || payload?.type === "message" && (payload.role === "assistant" || payload.role === "user");
|
|
12362
12370
|
return decides ? ANSWER : IGNORE;
|
|
12363
12371
|
}
|
|
12364
12372
|
return IGNORE;
|
|
12365
12373
|
},
|
|
12366
|
-
classifyAfterTurnEnd(
|
|
12367
|
-
return
|
|
12374
|
+
classifyAfterTurnEnd(record5) {
|
|
12375
|
+
return record5.type === "event_msg" || record5.type === "response_item" ? KEEP : IGNORE;
|
|
12368
12376
|
}
|
|
12369
12377
|
};
|
|
12370
12378
|
copilotTail = {
|
|
12371
12379
|
kind: "copilot",
|
|
12372
12380
|
markers: ['"abort"', '"assistant.message"', '"user.message"', '"subagent.'],
|
|
12373
|
-
classify(
|
|
12374
|
-
if (isSubagentLifecycle(
|
|
12375
|
-
const decidable =
|
|
12376
|
-
if (!decidable || isSubagentNoise(
|
|
12377
|
-
if (
|
|
12378
|
-
if (
|
|
12381
|
+
classify(record5) {
|
|
12382
|
+
if (isSubagentLifecycle(record5)) return KEEP;
|
|
12383
|
+
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.");
|
|
12384
|
+
if (!decidable || isSubagentNoise(record5)) return IGNORE;
|
|
12385
|
+
if (record5.type === "assistant.turn_end") return { kind: "turn-end" };
|
|
12386
|
+
if (record5.type === "session.start" || record5.type === "session.resume") return ANSWER;
|
|
12379
12387
|
return { kind: "answer-if-active" };
|
|
12380
12388
|
},
|
|
12381
|
-
classifyAfterTurnEnd(
|
|
12382
|
-
if (isSubagentLifecycle(
|
|
12383
|
-
if (isSubagentNoise(
|
|
12384
|
-
const decides =
|
|
12389
|
+
classifyAfterTurnEnd(record5) {
|
|
12390
|
+
if (isSubagentLifecycle(record5)) return KEEP;
|
|
12391
|
+
if (isSubagentNoise(record5)) return IGNORE;
|
|
12392
|
+
const decides = record5.type === "abort" || record5.type === "assistant.message" || record5.type === "user.message";
|
|
12385
12393
|
return decides ? ANSWER : IGNORE;
|
|
12386
12394
|
}
|
|
12387
12395
|
};
|
|
@@ -12436,14 +12444,14 @@ async function readTranscriptEffort(filePath) {
|
|
|
12436
12444
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
12437
12445
|
const line = lines[i];
|
|
12438
12446
|
if (!line || !line.includes("effort") && !line.includes("Effort")) continue;
|
|
12439
|
-
let
|
|
12447
|
+
let record5;
|
|
12440
12448
|
try {
|
|
12441
|
-
|
|
12449
|
+
record5 = JSON.parse(line);
|
|
12442
12450
|
} catch {
|
|
12443
12451
|
continue;
|
|
12444
12452
|
}
|
|
12445
|
-
if (typeof
|
|
12446
|
-
const effort = effortFromRecord(
|
|
12453
|
+
if (typeof record5 !== "object" || record5 === null) continue;
|
|
12454
|
+
const effort = effortFromRecord(record5);
|
|
12447
12455
|
if (effort) return effort;
|
|
12448
12456
|
}
|
|
12449
12457
|
}
|
|
@@ -12471,22 +12479,22 @@ async function getSessionStatus(filePath) {
|
|
|
12471
12479
|
cursor -= readSize;
|
|
12472
12480
|
const buf = Buffer.alloc(readSize);
|
|
12473
12481
|
const { bytesRead } = await fh.read(buf, 0, readSize, cursor);
|
|
12474
|
-
const
|
|
12475
|
-
const lines =
|
|
12482
|
+
const text2 = buf.subarray(0, bytesRead).toString("utf-8") + leftover;
|
|
12483
|
+
const lines = text2.split("\n");
|
|
12476
12484
|
leftover = cursor > 0 ? lines[0] : "";
|
|
12477
12485
|
const startIdx = cursor > 0 ? 1 : 0;
|
|
12478
12486
|
for (let i = lines.length - 1; i >= startIdx; i--) {
|
|
12479
12487
|
const line = lines[i];
|
|
12480
12488
|
if (!line) continue;
|
|
12481
12489
|
if (turnEnded && !isTailCandidate(line, turnEnded)) continue;
|
|
12482
|
-
let
|
|
12490
|
+
let record5;
|
|
12483
12491
|
try {
|
|
12484
|
-
|
|
12492
|
+
record5 = JSON.parse(line);
|
|
12485
12493
|
} catch {
|
|
12486
12494
|
continue;
|
|
12487
12495
|
}
|
|
12488
|
-
if (typeof
|
|
12489
|
-
const match = turnEnded ? { format: turnEnded, verdict: turnEnded.classifyAfterTurnEnd(
|
|
12496
|
+
if (typeof record5?.type !== "string") continue;
|
|
12497
|
+
const match = turnEnded ? { format: turnEnded, verdict: turnEnded.classifyAfterTurnEnd(record5) } : classifyTailRecord(record5);
|
|
12490
12498
|
if (!match) continue;
|
|
12491
12499
|
const { verdict } = match;
|
|
12492
12500
|
switch (verdict.kind) {
|
|
@@ -12495,20 +12503,20 @@ async function getSessionStatus(filePath) {
|
|
|
12495
12503
|
case "final":
|
|
12496
12504
|
return verdict.status;
|
|
12497
12505
|
case "keep":
|
|
12498
|
-
meaningful.unshift(
|
|
12506
|
+
meaningful.unshift(record5);
|
|
12499
12507
|
if (verdict.sawUserActivity) needUserActivity = false;
|
|
12500
12508
|
continue;
|
|
12501
12509
|
case "answer":
|
|
12502
|
-
meaningful.unshift(
|
|
12510
|
+
meaningful.unshift(record5);
|
|
12503
12511
|
return deriveSessionStatus(meaningful);
|
|
12504
12512
|
case "answer-if-active": {
|
|
12505
|
-
meaningful.unshift(
|
|
12513
|
+
meaningful.unshift(record5);
|
|
12506
12514
|
const status = deriveSessionStatus(meaningful);
|
|
12507
12515
|
if (status.status !== "idle") return status;
|
|
12508
12516
|
continue;
|
|
12509
12517
|
}
|
|
12510
12518
|
case "turn-end":
|
|
12511
|
-
meaningful.unshift(
|
|
12519
|
+
meaningful.unshift(record5);
|
|
12512
12520
|
turnEnded = match.format;
|
|
12513
12521
|
needUserActivity = verdict.awaitUserActivity === true;
|
|
12514
12522
|
continue;
|
|
@@ -12523,12 +12531,12 @@ async function getSessionStatus(filePath) {
|
|
|
12523
12531
|
return { status: "idle" };
|
|
12524
12532
|
}
|
|
12525
12533
|
}
|
|
12526
|
-
function snippetAround(
|
|
12527
|
-
const lower =
|
|
12534
|
+
function snippetAround(text2, query4) {
|
|
12535
|
+
const lower = text2.toLowerCase();
|
|
12528
12536
|
const idx = lower.indexOf(query4.toLowerCase());
|
|
12529
12537
|
const start = Math.max(0, idx - 30);
|
|
12530
|
-
const end = Math.min(
|
|
12531
|
-
const snippet = (start > 0 ? "..." : "") +
|
|
12538
|
+
const end = Math.min(text2.length, idx + query4.length + 70);
|
|
12539
|
+
const snippet = (start > 0 ? "..." : "") + text2.slice(start, end).trim() + (end < text2.length ? "..." : "");
|
|
12532
12540
|
return snippet.slice(0, 150);
|
|
12533
12541
|
}
|
|
12534
12542
|
async function searchSessionMessages(filePath, query4) {
|
|
@@ -12540,8 +12548,8 @@ async function searchSessionMessages(filePath, query4) {
|
|
|
12540
12548
|
return null;
|
|
12541
12549
|
}
|
|
12542
12550
|
for (const line of content.split("\n")) {
|
|
12543
|
-
const
|
|
12544
|
-
if (
|
|
12551
|
+
const text2 = userMessageTextFromLine(line);
|
|
12552
|
+
if (text2 !== null && text2.toLowerCase().includes(q)) return snippetAround(text2, query4);
|
|
12545
12553
|
}
|
|
12546
12554
|
return null;
|
|
12547
12555
|
}
|
|
@@ -12847,10 +12855,10 @@ function transcriptPath2(dirName, sessionId) {
|
|
|
12847
12855
|
}
|
|
12848
12856
|
function turnResultFrom(result) {
|
|
12849
12857
|
if (!result.is_error) return { isError: false };
|
|
12850
|
-
const { result:
|
|
12858
|
+
const { result: text2, subtype } = result;
|
|
12851
12859
|
return {
|
|
12852
12860
|
isError: true,
|
|
12853
|
-
message:
|
|
12861
|
+
message: text2 != null ? String(text2) : `Claude returned an error${subtype ? ` (${subtype})` : ""}`
|
|
12854
12862
|
};
|
|
12855
12863
|
}
|
|
12856
12864
|
async function awaitTranscript(filePath, isSettled) {
|
|
@@ -13200,7 +13208,7 @@ var init_package = __esm({
|
|
|
13200
13208
|
package_default = {
|
|
13201
13209
|
name: "cogpit",
|
|
13202
13210
|
private: true,
|
|
13203
|
-
version: "2.4.
|
|
13211
|
+
version: "2.4.2",
|
|
13204
13212
|
description: "Control center for Claude Code, OpenAI Codex, and GitHub Copilot CLI sessions",
|
|
13205
13213
|
license: "MIT",
|
|
13206
13214
|
author: {
|
|
@@ -16209,17 +16217,17 @@ function parseJsonRecord(line) {
|
|
|
16209
16217
|
}
|
|
16210
16218
|
}
|
|
16211
16219
|
function parseClaudeUsageLine(line) {
|
|
16212
|
-
const
|
|
16213
|
-
if (!
|
|
16214
|
-
const message = asRecord3(
|
|
16220
|
+
const record5 = parseJsonRecord(line);
|
|
16221
|
+
if (!record5 || record5.type !== "assistant") return null;
|
|
16222
|
+
const message = asRecord3(record5.message);
|
|
16215
16223
|
const usage = message ? asRecord3(message.usage) : null;
|
|
16216
16224
|
if (!message || !usage) return null;
|
|
16217
|
-
const timestampMs = parseTimestampMs(
|
|
16225
|
+
const timestampMs = parseTimestampMs(record5.timestamp);
|
|
16218
16226
|
if (timestampMs === null) return null;
|
|
16219
16227
|
const model = typeof message.model === "string" ? message.model : "";
|
|
16220
16228
|
if (model.length === 0) return null;
|
|
16221
16229
|
const messageId = typeof message.id === "string" ? message.id : null;
|
|
16222
|
-
const requestId = typeof
|
|
16230
|
+
const requestId = typeof record5.requestId === "string" ? record5.requestId : null;
|
|
16223
16231
|
const dedupeKey = messageId === null && requestId === null ? null : `${messageId ?? ""}:${requestId ?? ""}`;
|
|
16224
16232
|
const cacheCreationTokens = int(usage.cache_creation_input_tokens);
|
|
16225
16233
|
const byTtl = asRecord3(usage.cache_creation);
|
|
@@ -16238,12 +16246,12 @@ function parseClaudeUsageLine(line) {
|
|
|
16238
16246
|
reasoningTokens: 0
|
|
16239
16247
|
};
|
|
16240
16248
|
if (totalUsageCostTokens(totals) === 0) return null;
|
|
16241
|
-
const cost =
|
|
16249
|
+
const cost = record5.costUSD;
|
|
16242
16250
|
return {
|
|
16243
16251
|
provider: "claude",
|
|
16244
16252
|
timestampMs,
|
|
16245
16253
|
model,
|
|
16246
|
-
sessionId: typeof
|
|
16254
|
+
sessionId: typeof record5.sessionId === "string" ? record5.sessionId : "",
|
|
16247
16255
|
totals,
|
|
16248
16256
|
reportedCostUsd: typeof cost === "number" && Number.isFinite(cost) ? cost : null,
|
|
16249
16257
|
speed: requestSpeed(usage.speed ?? usage.service_tier),
|
|
@@ -16267,23 +16275,23 @@ function isForkedSessionMeta(payload) {
|
|
|
16267
16275
|
return typeof spawn5?.parent_thread_id === "string";
|
|
16268
16276
|
}
|
|
16269
16277
|
function parseCodexUsageLine(line, state) {
|
|
16270
|
-
const
|
|
16271
|
-
if (!
|
|
16272
|
-
const payload = asRecord3(
|
|
16278
|
+
const record5 = parseJsonRecord(line);
|
|
16279
|
+
if (!record5) return null;
|
|
16280
|
+
const payload = asRecord3(record5.payload);
|
|
16273
16281
|
if (!payload) return null;
|
|
16274
|
-
if (
|
|
16282
|
+
if (record5.type === "session_meta") {
|
|
16275
16283
|
if (state.sawSessionMeta) return null;
|
|
16276
16284
|
state.sawSessionMeta = true;
|
|
16277
16285
|
const id = payload.id ?? payload.session_id;
|
|
16278
16286
|
if (typeof id === "string") state.sessionId = id;
|
|
16279
|
-
const metaTimestampMs = parseTimestampMs(
|
|
16287
|
+
const metaTimestampMs = parseTimestampMs(record5.timestamp);
|
|
16280
16288
|
if (metaTimestampMs !== null && isForkedSessionMeta(payload)) {
|
|
16281
16289
|
state.suppressingForkCopies = true;
|
|
16282
16290
|
state.forkCopyAnchorMs = metaTimestampMs;
|
|
16283
16291
|
}
|
|
16284
16292
|
return null;
|
|
16285
16293
|
}
|
|
16286
|
-
if (
|
|
16294
|
+
if (record5.type === "turn_context") {
|
|
16287
16295
|
if (typeof payload.model === "string") state.model = payload.model;
|
|
16288
16296
|
return null;
|
|
16289
16297
|
}
|
|
@@ -16297,7 +16305,7 @@ function parseCodexUsageLine(line, state) {
|
|
|
16297
16305
|
if (payload.type !== "token_count") return null;
|
|
16298
16306
|
const last = asRecord3(asRecord3(payload.info)?.last_token_usage);
|
|
16299
16307
|
if (!last) return null;
|
|
16300
|
-
const timestampMs = parseTimestampMs(
|
|
16308
|
+
const timestampMs = parseTimestampMs(record5.timestamp);
|
|
16301
16309
|
if (timestampMs === null) return null;
|
|
16302
16310
|
if (state.model.length === 0) return null;
|
|
16303
16311
|
const signature = JSON.stringify(last);
|
|
@@ -16398,17 +16406,17 @@ function parseCopilotUsageMetrics(value, state, timestampMs) {
|
|
|
16398
16406
|
return records;
|
|
16399
16407
|
}
|
|
16400
16408
|
function parseCopilotUsageLine(line, state) {
|
|
16401
|
-
const
|
|
16402
|
-
if (!
|
|
16403
|
-
const data = asRecord3(
|
|
16409
|
+
const record5 = parseJsonRecord(line);
|
|
16410
|
+
if (!record5 || typeof record5.agentId === "string" && record5.agentId.length > 0) return [];
|
|
16411
|
+
const data = asRecord3(record5.data);
|
|
16404
16412
|
if (!data) return [];
|
|
16405
|
-
if (
|
|
16413
|
+
if (record5.type === "session.start") {
|
|
16406
16414
|
const sessionId = data.sessionId;
|
|
16407
16415
|
if (typeof sessionId === "string" && sessionId.length > 0) state.sessionId = sessionId;
|
|
16408
16416
|
return [];
|
|
16409
16417
|
}
|
|
16410
|
-
if (
|
|
16411
|
-
const timestampMs = parseTimestampMs(
|
|
16418
|
+
if (record5.type !== "session.shutdown") return [];
|
|
16419
|
+
const timestampMs = parseTimestampMs(record5.timestamp);
|
|
16412
16420
|
return timestampMs === null ? [] : parseCopilotUsageMetrics(data, state, timestampMs);
|
|
16413
16421
|
}
|
|
16414
16422
|
function createUsageScanner(provider, filePath) {
|
|
@@ -16425,8 +16433,8 @@ var init_usageScanners = __esm({
|
|
|
16425
16433
|
// object, so a line is either self-contained or of no interest.
|
|
16426
16434
|
wantsLine: (line) => line.includes('"usage"'),
|
|
16427
16435
|
accept: (line) => {
|
|
16428
|
-
const
|
|
16429
|
-
return
|
|
16436
|
+
const record5 = parseClaudeUsageLine(line);
|
|
16437
|
+
return record5 === null ? [] : [record5];
|
|
16430
16438
|
}
|
|
16431
16439
|
}),
|
|
16432
16440
|
codex: () => {
|
|
@@ -16437,8 +16445,8 @@ var init_usageScanners = __esm({
|
|
|
16437
16445
|
// at all but still have to reach the reducer.
|
|
16438
16446
|
wantsLine: (line) => line.includes('"token_count"') || line.includes('"turn_context"') || line.includes('"session_meta"') || line.includes('"thread_settings_applied"'),
|
|
16439
16447
|
accept: (line) => {
|
|
16440
|
-
const
|
|
16441
|
-
return
|
|
16448
|
+
const record5 = parseCodexUsageLine(line, state);
|
|
16449
|
+
return record5 === null ? [] : [record5];
|
|
16442
16450
|
}
|
|
16443
16451
|
};
|
|
16444
16452
|
},
|
|
@@ -17161,7 +17169,7 @@ async function releaseInspectedSession(sessionId, state, runtime) {
|
|
|
17161
17169
|
});
|
|
17162
17170
|
}
|
|
17163
17171
|
}
|
|
17164
|
-
async function respondFromInspectedSession(res, sessionId, runtime,
|
|
17172
|
+
async function respondFromInspectedSession(res, sessionId, runtime, failureMessage2, operation) {
|
|
17165
17173
|
let state = null;
|
|
17166
17174
|
try {
|
|
17167
17175
|
state = await ensureCopilotSession(sessionId, runtime);
|
|
@@ -17172,7 +17180,7 @@ async function respondFromInspectedSession(res, sessionId, runtime, failureMessa
|
|
|
17172
17180
|
sendJson(res, 200, await operation());
|
|
17173
17181
|
} catch (error) {
|
|
17174
17182
|
sendJson(res, 502, {
|
|
17175
|
-
error: error instanceof Error ? error.message :
|
|
17183
|
+
error: error instanceof Error ? error.message : failureMessage2
|
|
17176
17184
|
});
|
|
17177
17185
|
} finally {
|
|
17178
17186
|
await releaseInspectedSession(sessionId, state, runtime);
|
|
@@ -17687,12 +17695,12 @@ function registerBranchSessionRoute(use) {
|
|
|
17687
17695
|
}
|
|
17688
17696
|
}
|
|
17689
17697
|
const newSessionId = randomUUID2();
|
|
17690
|
-
const { record:
|
|
17698
|
+
const { record: record5, originalId } = format.brandBranch(
|
|
17691
17699
|
JSON.parse(lines[0]),
|
|
17692
17700
|
newSessionId,
|
|
17693
17701
|
turnIndex ?? null
|
|
17694
17702
|
);
|
|
17695
|
-
lines[0] = JSON.stringify(
|
|
17703
|
+
lines[0] = JSON.stringify(record5);
|
|
17696
17704
|
const target = storeForDirName(dirName).transcriptPath(dirName, newSessionId);
|
|
17697
17705
|
if (!target) {
|
|
17698
17706
|
res.statusCode = 500;
|
|
@@ -20656,9 +20664,9 @@ function registerFileWatchRoutes(use) {
|
|
|
20656
20664
|
if (bytesRead <= 0) return;
|
|
20657
20665
|
offset += bytesRead;
|
|
20658
20666
|
recordActivity("Task output reads", { bytes: bytesRead });
|
|
20659
|
-
const
|
|
20660
|
-
if (
|
|
20661
|
-
res.write(`data: ${JSON.stringify({ type: "output", text })}
|
|
20667
|
+
const text2 = decoder.write(buf.subarray(0, bytesRead));
|
|
20668
|
+
if (text2) {
|
|
20669
|
+
res.write(`data: ${JSON.stringify({ type: "output", text: text2 })}
|
|
20662
20670
|
|
|
20663
20671
|
`);
|
|
20664
20672
|
}
|
|
@@ -21262,11 +21270,11 @@ function parseGitStatus(output) {
|
|
|
21262
21270
|
const branch = parseBranchHeader(header);
|
|
21263
21271
|
const files = [];
|
|
21264
21272
|
for (let index = 0; index < records.length; index += 1) {
|
|
21265
|
-
const
|
|
21266
|
-
if (!
|
|
21267
|
-
const indexStatus =
|
|
21268
|
-
const workTreeStatus =
|
|
21269
|
-
const path =
|
|
21273
|
+
const record5 = records[index];
|
|
21274
|
+
if (!record5 || record5.length < 3) continue;
|
|
21275
|
+
const indexStatus = record5[0];
|
|
21276
|
+
const workTreeStatus = record5[1];
|
|
21277
|
+
const path = record5.slice(3);
|
|
21270
21278
|
const renamedOrCopied = /[RC]/.test(`${indexStatus}${workTreeStatus}`);
|
|
21271
21279
|
const originalPath = renamedOrCopied ? records[index += 1] || void 0 : void 0;
|
|
21272
21280
|
files.push({ path, originalPath, indexStatus, workTreeStatus });
|
|
@@ -21482,12 +21490,12 @@ function createPullRequestScanner() {
|
|
|
21482
21490
|
const command = findCreateCommand(input);
|
|
21483
21491
|
if (command) openCreates.set(id, { command, timestamp: timestamp2 });
|
|
21484
21492
|
}
|
|
21485
|
-
function recordPrLink(
|
|
21486
|
-
const url =
|
|
21487
|
-
const number =
|
|
21493
|
+
function recordPrLink(record5, timestamp2) {
|
|
21494
|
+
const url = record5.prUrl;
|
|
21495
|
+
const number = record5.prNumber;
|
|
21488
21496
|
if (typeof url !== "string" || !url) return;
|
|
21489
21497
|
if (typeof number !== "number" || !Number.isInteger(number) || number <= 0) return;
|
|
21490
|
-
const repo = typeof
|
|
21498
|
+
const repo = typeof record5.prRepository === "string" ? record5.prRepository : "";
|
|
21491
21499
|
collector.add({
|
|
21492
21500
|
url,
|
|
21493
21501
|
number,
|
|
@@ -21503,9 +21511,9 @@ function createPullRequestScanner() {
|
|
|
21503
21511
|
if (typeof id !== "string") return;
|
|
21504
21512
|
const create = openCreates.get(id);
|
|
21505
21513
|
if (!create || isError) return;
|
|
21506
|
-
const
|
|
21507
|
-
collector.record(
|
|
21508
|
-
const match = PR_URL.exec(
|
|
21514
|
+
const text2 = resultText(output);
|
|
21515
|
+
collector.record(text2, create.command, id, create.timestamp);
|
|
21516
|
+
const match = PR_URL.exec(text2);
|
|
21509
21517
|
if (match) recordReference({ number: Number(match[3]), repo: `${match[1]}/${match[2]}` });
|
|
21510
21518
|
}
|
|
21511
21519
|
function parseArgs2(raw) {
|
|
@@ -21522,19 +21530,19 @@ function createPullRequestScanner() {
|
|
|
21522
21530
|
if (!line.includes(GH_PR_HINT) && !line.includes(URL_HINT) && !line.includes(PR_LINK_HINT)) {
|
|
21523
21531
|
return;
|
|
21524
21532
|
}
|
|
21525
|
-
let
|
|
21533
|
+
let record5;
|
|
21526
21534
|
try {
|
|
21527
|
-
|
|
21535
|
+
record5 = JSON.parse(line);
|
|
21528
21536
|
} catch {
|
|
21529
21537
|
return;
|
|
21530
21538
|
}
|
|
21531
|
-
if (!isRecord5(
|
|
21532
|
-
const timestamp2 = typeof
|
|
21533
|
-
if (
|
|
21534
|
-
recordPrLink(
|
|
21539
|
+
if (!isRecord5(record5)) return;
|
|
21540
|
+
const timestamp2 = typeof record5.timestamp === "string" ? record5.timestamp : "";
|
|
21541
|
+
if (record5.type === "pr-link") {
|
|
21542
|
+
recordPrLink(record5, timestamp2);
|
|
21535
21543
|
return;
|
|
21536
21544
|
}
|
|
21537
|
-
const payload =
|
|
21545
|
+
const payload = record5.payload;
|
|
21538
21546
|
if (isRecord5(payload)) {
|
|
21539
21547
|
const type = payload.type;
|
|
21540
21548
|
if (type === "function_call" || type === "custom_tool_call") {
|
|
@@ -21544,15 +21552,15 @@ function createPullRequestScanner() {
|
|
|
21544
21552
|
}
|
|
21545
21553
|
return;
|
|
21546
21554
|
}
|
|
21547
|
-
const data =
|
|
21555
|
+
const data = record5.data;
|
|
21548
21556
|
if (isRecord5(data)) {
|
|
21549
|
-
if (
|
|
21557
|
+
if (record5.type === "tool.execution_start") {
|
|
21550
21558
|
recordToolCall(
|
|
21551
21559
|
data.toolCallId,
|
|
21552
21560
|
parseArgs2(data.arguments ?? data.input),
|
|
21553
21561
|
timestamp2
|
|
21554
21562
|
);
|
|
21555
|
-
} else if (
|
|
21563
|
+
} else if (record5.type === "tool.execution_complete") {
|
|
21556
21564
|
recordResult(
|
|
21557
21565
|
data.toolCallId,
|
|
21558
21566
|
data.result ?? data.output ?? data.error,
|
|
@@ -21561,7 +21569,7 @@ function createPullRequestScanner() {
|
|
|
21561
21569
|
}
|
|
21562
21570
|
return;
|
|
21563
21571
|
}
|
|
21564
|
-
const message =
|
|
21572
|
+
const message = record5.message;
|
|
21565
21573
|
if (!isRecord5(message) || !Array.isArray(message.content)) return;
|
|
21566
21574
|
for (const block of message.content) {
|
|
21567
21575
|
if (!isRecord5(block)) continue;
|
|
@@ -22438,9 +22446,9 @@ function deploymentState(value) {
|
|
|
22438
22446
|
return typeof value === "string" && DEPLOYMENT_STATES.has(value) ? value : "QUEUED";
|
|
22439
22447
|
}
|
|
22440
22448
|
function httpsUrl(value, hostnameOnly = false) {
|
|
22441
|
-
const
|
|
22442
|
-
if (!
|
|
22443
|
-
const candidate = hostnameOnly && !
|
|
22449
|
+
const text2 = stringValue2(value);
|
|
22450
|
+
if (!text2) return null;
|
|
22451
|
+
const candidate = hostnameOnly && !text2.includes("://") ? `https://${text2}` : text2;
|
|
22444
22452
|
try {
|
|
22445
22453
|
const url = new URL(candidate);
|
|
22446
22454
|
return url.protocol === "https:" ? url.toString().replace(/\/$/, "") : null;
|
|
@@ -22516,13 +22524,13 @@ function parseBuildLog(value) {
|
|
|
22516
22524
|
const source = record3(value);
|
|
22517
22525
|
if (!source) return null;
|
|
22518
22526
|
const createdAt = timestamp(source.created) ?? timestamp(source.date);
|
|
22519
|
-
const
|
|
22520
|
-
if (createdAt === null || !
|
|
22527
|
+
const text2 = stringValue2(source.text);
|
|
22528
|
+
if (createdAt === null || !text2) return null;
|
|
22521
22529
|
return {
|
|
22522
|
-
id: stringValue2(source.id, `${createdAt}-${
|
|
22530
|
+
id: stringValue2(source.id, `${createdAt}-${text2}`),
|
|
22523
22531
|
createdAt,
|
|
22524
22532
|
type: stringValue2(source.type, "stdout"),
|
|
22525
|
-
text
|
|
22533
|
+
text: text2
|
|
22526
22534
|
};
|
|
22527
22535
|
}
|
|
22528
22536
|
function parseBuildLogsResponse(value) {
|
|
@@ -22759,14 +22767,440 @@ var init_vercel_deployments = __esm({
|
|
|
22759
22767
|
}
|
|
22760
22768
|
});
|
|
22761
22769
|
|
|
22770
|
+
// ../../server/lib/clickupConfig.ts
|
|
22771
|
+
import { mkdir as mkdir6, readFile as readFile17 } from "node:fs/promises";
|
|
22772
|
+
import { homedir as homedir7 } from "node:os";
|
|
22773
|
+
import { dirname as dirname9, join as join22 } from "node:path";
|
|
22774
|
+
function isClickUpToken(value) {
|
|
22775
|
+
return typeof value === "string" && TOKEN_PATTERN.test(value);
|
|
22776
|
+
}
|
|
22777
|
+
async function readStored() {
|
|
22778
|
+
let raw;
|
|
22779
|
+
try {
|
|
22780
|
+
raw = await readFile17(configPath, "utf8");
|
|
22781
|
+
} catch {
|
|
22782
|
+
return {};
|
|
22783
|
+
}
|
|
22784
|
+
try {
|
|
22785
|
+
const parsed = JSON.parse(raw);
|
|
22786
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
|
|
22787
|
+
const source = parsed;
|
|
22788
|
+
const projects = {};
|
|
22789
|
+
const storedProjects = source.projects;
|
|
22790
|
+
if (typeof storedProjects === "object" && storedProjects !== null) {
|
|
22791
|
+
for (const [path, listId] of Object.entries(storedProjects)) {
|
|
22792
|
+
if (typeof listId === "string" && /^\d+$/.test(listId)) projects[path] = listId;
|
|
22793
|
+
}
|
|
22794
|
+
}
|
|
22795
|
+
return { token: isClickUpToken(source.token) ? source.token : void 0, projects };
|
|
22796
|
+
} catch {
|
|
22797
|
+
return {};
|
|
22798
|
+
}
|
|
22799
|
+
}
|
|
22800
|
+
async function loadClickUpConfig() {
|
|
22801
|
+
const stored = await readStored();
|
|
22802
|
+
const envToken = TOKEN_ENV_VARS.map((name) => process.env[name]?.trim()).find(isClickUpToken);
|
|
22803
|
+
if (envToken) {
|
|
22804
|
+
return { token: envToken, tokenFromEnv: true, projects: stored.projects ?? {} };
|
|
22805
|
+
}
|
|
22806
|
+
return { token: stored.token ?? null, tokenFromEnv: false, projects: stored.projects ?? {} };
|
|
22807
|
+
}
|
|
22808
|
+
async function writeStored(next) {
|
|
22809
|
+
await mkdir6(dirname9(configPath), { recursive: true });
|
|
22810
|
+
const file = { projects: next.projects ?? {} };
|
|
22811
|
+
if (next.token) file.token = next.token;
|
|
22812
|
+
await writeOwnerOnlyJson(configPath, file);
|
|
22813
|
+
}
|
|
22814
|
+
async function saveClickUpToken(token) {
|
|
22815
|
+
const stored = await readStored();
|
|
22816
|
+
await writeStored({ ...stored, token: token ?? void 0 });
|
|
22817
|
+
}
|
|
22818
|
+
async function saveClickUpProjectLink(projectPath, listId) {
|
|
22819
|
+
const stored = await readStored();
|
|
22820
|
+
const projects = { ...stored.projects };
|
|
22821
|
+
if (listId === null) delete projects[projectPath];
|
|
22822
|
+
else projects[projectPath] = listId;
|
|
22823
|
+
await writeStored({ ...stored, projects });
|
|
22824
|
+
}
|
|
22825
|
+
var CLICKUP_CONFIG_FILE, TOKEN_PATTERN, configPath, TOKEN_ENV_VARS;
|
|
22826
|
+
var init_clickupConfig = __esm({
|
|
22827
|
+
"../../server/lib/clickupConfig.ts"() {
|
|
22828
|
+
init_atomicJsonFile();
|
|
22829
|
+
CLICKUP_CONFIG_FILE = join22(homedir7(), ".cogpit", "clickup.json");
|
|
22830
|
+
TOKEN_PATTERN = /^pk_[A-Za-z0-9_]{8,}$/;
|
|
22831
|
+
configPath = CLICKUP_CONFIG_FILE;
|
|
22832
|
+
TOKEN_ENV_VARS = ["COGPIT_CLICKUP_TOKEN", "CLICKUP_API_TOKEN"];
|
|
22833
|
+
}
|
|
22834
|
+
});
|
|
22835
|
+
|
|
22836
|
+
// ../../server/routes/clickup.ts
|
|
22837
|
+
function record4(value) {
|
|
22838
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
22839
|
+
}
|
|
22840
|
+
function text(value, fallback = "") {
|
|
22841
|
+
return typeof value === "string" ? value : fallback;
|
|
22842
|
+
}
|
|
22843
|
+
function idText(value) {
|
|
22844
|
+
if (typeof value === "number") return String(value);
|
|
22845
|
+
return text(value);
|
|
22846
|
+
}
|
|
22847
|
+
function epoch(value) {
|
|
22848
|
+
const parsed = typeof value === "string" ? Number(value) : value;
|
|
22849
|
+
return typeof parsed === "number" && Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
22850
|
+
}
|
|
22851
|
+
function folderNameOf(value) {
|
|
22852
|
+
const folder = record4(value);
|
|
22853
|
+
return folder && folder.hidden !== true ? text(folder.name) || null : null;
|
|
22854
|
+
}
|
|
22855
|
+
function invalid(what) {
|
|
22856
|
+
return new ClickUpRouteError(502, "invalid_response", `ClickUp returned an invalid ${what} response`);
|
|
22857
|
+
}
|
|
22858
|
+
function parseUser(value) {
|
|
22859
|
+
const source = record4(value);
|
|
22860
|
+
if (!source || typeof source.id !== "number") return null;
|
|
22861
|
+
const username = text(source.username) || text(source.email);
|
|
22862
|
+
return {
|
|
22863
|
+
id: source.id,
|
|
22864
|
+
username,
|
|
22865
|
+
initials: text(source.initials) || username.slice(0, 2).toUpperCase(),
|
|
22866
|
+
color: text(source.color) || null
|
|
22867
|
+
};
|
|
22868
|
+
}
|
|
22869
|
+
function parseViewerResponse(value) {
|
|
22870
|
+
const viewer = parseUser(record4(value)?.user);
|
|
22871
|
+
if (!viewer) throw invalid("user");
|
|
22872
|
+
return viewer;
|
|
22873
|
+
}
|
|
22874
|
+
function parseNamedEntities(entries3, fallbackName) {
|
|
22875
|
+
return entries3.flatMap((entry) => {
|
|
22876
|
+
const source = record4(entry);
|
|
22877
|
+
const id = idText(source?.id);
|
|
22878
|
+
return source && NUMERIC_ID.test(id) ? [{ id, name: text(source.name, fallbackName) }] : [];
|
|
22879
|
+
});
|
|
22880
|
+
}
|
|
22881
|
+
function parseWorkspacesResponse(value) {
|
|
22882
|
+
const teams = record4(value)?.teams;
|
|
22883
|
+
if (!Array.isArray(teams)) throw invalid("workspace");
|
|
22884
|
+
return parseNamedEntities(teams, "Workspace");
|
|
22885
|
+
}
|
|
22886
|
+
function parseStatus(value) {
|
|
22887
|
+
const source = record4(value);
|
|
22888
|
+
if (!source) return null;
|
|
22889
|
+
const name = text(source.status);
|
|
22890
|
+
if (!name) return null;
|
|
22891
|
+
const type = text(source.type);
|
|
22892
|
+
return {
|
|
22893
|
+
name,
|
|
22894
|
+
type: STATUS_TYPES.has(type) ? type : "custom",
|
|
22895
|
+
color: text(source.color, "#d3d3d3"),
|
|
22896
|
+
order: typeof source.orderindex === "number" ? source.orderindex : 0
|
|
22897
|
+
};
|
|
22898
|
+
}
|
|
22899
|
+
function parseTag(value) {
|
|
22900
|
+
const source = record4(value);
|
|
22901
|
+
const name = text(source?.name);
|
|
22902
|
+
return name ? { name, background: text(source?.tag_bg) || null } : null;
|
|
22903
|
+
}
|
|
22904
|
+
function parsePriority(value) {
|
|
22905
|
+
const name = text(record4(value)?.priority);
|
|
22906
|
+
return PRIORITIES.has(name) ? name : null;
|
|
22907
|
+
}
|
|
22908
|
+
function parseTask(value) {
|
|
22909
|
+
const source = record4(value);
|
|
22910
|
+
if (!source) return null;
|
|
22911
|
+
const id = text(source.id);
|
|
22912
|
+
const status = parseStatus(source.status);
|
|
22913
|
+
const list = record4(source.list);
|
|
22914
|
+
if (!id || !status || !list) return null;
|
|
22915
|
+
const customId = text(source.custom_id);
|
|
22916
|
+
return {
|
|
22917
|
+
id,
|
|
22918
|
+
customId: customId || null,
|
|
22919
|
+
name: text(source.name, "Untitled task"),
|
|
22920
|
+
description: text(source.markdown_description) || text(source.description),
|
|
22921
|
+
status,
|
|
22922
|
+
priority: parsePriority(source.priority),
|
|
22923
|
+
url: text(source.url) || `https://app.clickup.com/t/${id}`,
|
|
22924
|
+
assignees: Array.isArray(source.assignees) ? source.assignees.map(parseUser).filter((user) => user !== null) : [],
|
|
22925
|
+
tags: Array.isArray(source.tags) ? source.tags.map(parseTag).filter((tag) => tag !== null) : [],
|
|
22926
|
+
parentId: text(source.parent) || null,
|
|
22927
|
+
listId: idText(list.id),
|
|
22928
|
+
listName: text(list.name, "List"),
|
|
22929
|
+
folderName: folderNameOf(source.folder),
|
|
22930
|
+
spaceId: idText(record4(source.space)?.id),
|
|
22931
|
+
createdAt: epoch(source.date_created) ?? 0,
|
|
22932
|
+
updatedAt: epoch(source.date_updated) ?? epoch(source.date_created) ?? 0,
|
|
22933
|
+
dueAt: epoch(source.due_date),
|
|
22934
|
+
startAt: epoch(source.start_date),
|
|
22935
|
+
closedAt: epoch(source.date_closed) ?? epoch(source.date_done)
|
|
22936
|
+
};
|
|
22937
|
+
}
|
|
22938
|
+
function parseTasksPage(value) {
|
|
22939
|
+
const source = record4(value);
|
|
22940
|
+
if (!source || !Array.isArray(source.tasks)) throw invalid("task list");
|
|
22941
|
+
return {
|
|
22942
|
+
tasks: source.tasks.map(parseTask).filter((task) => task !== null),
|
|
22943
|
+
lastPage: source.last_page !== false
|
|
22944
|
+
};
|
|
22945
|
+
}
|
|
22946
|
+
function parseListResponse(value) {
|
|
22947
|
+
const source = record4(value);
|
|
22948
|
+
const id = idText(source?.id);
|
|
22949
|
+
if (!source || !NUMERIC_ID.test(id)) throw invalid("list");
|
|
22950
|
+
const statuses = Array.isArray(source.statuses) ? source.statuses.map(parseStatus).filter((status) => status !== null) : [];
|
|
22951
|
+
return {
|
|
22952
|
+
id,
|
|
22953
|
+
name: text(source.name, "List"),
|
|
22954
|
+
folderName: folderNameOf(source.folder),
|
|
22955
|
+
spaceId: idText(record4(source.space)?.id),
|
|
22956
|
+
statuses: statuses.sort((left, right) => left.order - right.order),
|
|
22957
|
+
url: `https://app.clickup.com/v/li/${id}`
|
|
22958
|
+
};
|
|
22959
|
+
}
|
|
22960
|
+
function parseSpacesResponse(value) {
|
|
22961
|
+
const spaces = record4(value)?.spaces;
|
|
22962
|
+
if (!Array.isArray(spaces)) throw invalid("space");
|
|
22963
|
+
return parseNamedEntities(spaces, "Space");
|
|
22964
|
+
}
|
|
22965
|
+
function parseListOptions(value, folderName) {
|
|
22966
|
+
if (!Array.isArray(value)) return [];
|
|
22967
|
+
return parseNamedEntities(value, "List").map((list) => ({ ...list, folderName }));
|
|
22968
|
+
}
|
|
22969
|
+
function parseFoldersResponse(value) {
|
|
22970
|
+
const folders = record4(value)?.folders;
|
|
22971
|
+
if (!Array.isArray(folders)) throw invalid("folder");
|
|
22972
|
+
return folders.flatMap((folder) => {
|
|
22973
|
+
const source = record4(folder);
|
|
22974
|
+
return source ? parseListOptions(source.lists, text(source.name) || null) : [];
|
|
22975
|
+
});
|
|
22976
|
+
}
|
|
22977
|
+
function parseFolderlessListsResponse(value) {
|
|
22978
|
+
const source = record4(value);
|
|
22979
|
+
if (!source || !Array.isArray(source.lists)) throw invalid("list");
|
|
22980
|
+
return parseListOptions(source.lists, null);
|
|
22981
|
+
}
|
|
22982
|
+
async function runClickUpApi(token, path) {
|
|
22983
|
+
let response;
|
|
22984
|
+
try {
|
|
22985
|
+
response = await fetch(`${API_BASE}${path}`, {
|
|
22986
|
+
headers: { Authorization: token, Accept: "application/json" },
|
|
22987
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
22988
|
+
});
|
|
22989
|
+
} catch {
|
|
22990
|
+
throw new ClickUpRouteError(502, "clickup_api_failed", "ClickUp is unreachable");
|
|
22991
|
+
}
|
|
22992
|
+
if (response.status === 401) {
|
|
22993
|
+
throw new ClickUpRouteError(401, "clickup_auth_failed", "ClickUp rejected the API token");
|
|
22994
|
+
}
|
|
22995
|
+
if (response.status === 429) {
|
|
22996
|
+
throw new ClickUpRouteError(429, "clickup_rate_limited", "ClickUp rate limit reached; try again in a minute");
|
|
22997
|
+
}
|
|
22998
|
+
if (!response.ok) {
|
|
22999
|
+
throw new ClickUpRouteError(502, "clickup_api_failed", `ClickUp request failed (${response.status})`);
|
|
23000
|
+
}
|
|
23001
|
+
try {
|
|
23002
|
+
return await response.json();
|
|
23003
|
+
} catch {
|
|
23004
|
+
throw invalid("JSON");
|
|
23005
|
+
}
|
|
23006
|
+
}
|
|
23007
|
+
function identityFor(token, deps) {
|
|
23008
|
+
let cached = identityCache.get(token);
|
|
23009
|
+
if (!cached) {
|
|
23010
|
+
cached = (async () => {
|
|
23011
|
+
const [viewer, workspaces] = await Promise.all([
|
|
23012
|
+
deps.api(token, "/user").then(parseViewerResponse),
|
|
23013
|
+
deps.api(token, "/team").then(parseWorkspacesResponse)
|
|
23014
|
+
]);
|
|
23015
|
+
const workspace = workspaces[0];
|
|
23016
|
+
if (!workspace) throw new ClickUpRouteError(502, "clickup_api_failed", "The token belongs to no ClickUp workspace");
|
|
23017
|
+
return { token, viewer, workspace };
|
|
23018
|
+
})();
|
|
23019
|
+
identityCache.set(token, cached);
|
|
23020
|
+
cached.catch(() => identityCache.delete(token));
|
|
23021
|
+
}
|
|
23022
|
+
return cached;
|
|
23023
|
+
}
|
|
23024
|
+
async function requireIdentity(deps) {
|
|
23025
|
+
const config = await deps.loadConfig();
|
|
23026
|
+
if (!config.token) {
|
|
23027
|
+
throw new ClickUpRouteError(503, "clickup_not_configured", "Add a ClickUp API token to view your tasks");
|
|
23028
|
+
}
|
|
23029
|
+
return { ...await identityFor(config.token, deps), config };
|
|
23030
|
+
}
|
|
23031
|
+
async function statusFor(config, deps) {
|
|
23032
|
+
if (!config.token) return { configured: false, tokenFromEnv: false, viewer: null, workspace: null };
|
|
23033
|
+
const identity = await identityFor(config.token, deps);
|
|
23034
|
+
return { configured: true, tokenFromEnv: config.tokenFromEnv, viewer: identity.viewer, workspace: identity.workspace };
|
|
23035
|
+
}
|
|
23036
|
+
async function fetchTaskPages(token, path, deps, maxPages = MAX_TASK_PAGES) {
|
|
23037
|
+
const tasks = [];
|
|
23038
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
23039
|
+
const result = parseTasksPage(await deps.api(token, `${path}&page=${page}`));
|
|
23040
|
+
tasks.push(...result.tasks);
|
|
23041
|
+
if (result.lastPage) return { tasks, truncated: false };
|
|
23042
|
+
}
|
|
23043
|
+
return { tasks, truncated: true };
|
|
23044
|
+
}
|
|
23045
|
+
async function resolveProjectPath2(cwd, deps) {
|
|
23046
|
+
const project = await deps.resolveProject(cwd);
|
|
23047
|
+
if (!project.ok) throw new ClickUpRouteError(project.status, "clickup_api_failed", project.error);
|
|
23048
|
+
return project.projectPath;
|
|
23049
|
+
}
|
|
23050
|
+
function sendRouteError4(res, error) {
|
|
23051
|
+
if (error instanceof ClickUpRouteError) {
|
|
23052
|
+
sendJson(res, error.status, { error: error.message, code: error.code });
|
|
23053
|
+
return;
|
|
23054
|
+
}
|
|
23055
|
+
sendJson(res, 500, { error: "Unable to load ClickUp data", code: "clickup_api_failed" });
|
|
23056
|
+
}
|
|
23057
|
+
function route(use, path, methods, handler) {
|
|
23058
|
+
use(path, async (req, res, next) => {
|
|
23059
|
+
if (!methods.includes(req.method ?? "")) return next();
|
|
23060
|
+
const url = new URL(req.url || "", "http://localhost");
|
|
23061
|
+
if (url.pathname !== "/" && url.pathname !== "") return next();
|
|
23062
|
+
try {
|
|
23063
|
+
const result = await handler(req, url);
|
|
23064
|
+
sendJson(res, result.status, result.body);
|
|
23065
|
+
} catch (error) {
|
|
23066
|
+
sendRouteError4(res, error);
|
|
23067
|
+
}
|
|
23068
|
+
});
|
|
23069
|
+
}
|
|
23070
|
+
function registerClickUpRoutes(use, deps = defaultDependencies3) {
|
|
23071
|
+
route(use, "/api/clickup/status", ["GET"], async () => ({
|
|
23072
|
+
status: 200,
|
|
23073
|
+
body: await statusFor(await deps.loadConfig(), deps)
|
|
23074
|
+
}));
|
|
23075
|
+
route(use, "/api/clickup/token", ["POST", "DELETE"], async (req) => {
|
|
23076
|
+
const current = await deps.loadConfig();
|
|
23077
|
+
if (current.tokenFromEnv) {
|
|
23078
|
+
throw new ClickUpRouteError(409, "clickup_api_failed", "The ClickUp token comes from the server environment; change it there");
|
|
23079
|
+
}
|
|
23080
|
+
if (current.token) identityCache.delete(current.token);
|
|
23081
|
+
if (req.method === "DELETE") {
|
|
23082
|
+
await deps.saveToken(null);
|
|
23083
|
+
return { status: 200, body: await statusFor({ ...current, token: null }, deps) };
|
|
23084
|
+
}
|
|
23085
|
+
const { token } = await readJsonBody(req);
|
|
23086
|
+
const candidate = typeof token === "string" ? token.trim() : "";
|
|
23087
|
+
if (!isClickUpToken(candidate)) {
|
|
23088
|
+
throw new ClickUpRouteError(400, "clickup_auth_failed", "That does not look like a ClickUp personal API token (pk_\u2026)");
|
|
23089
|
+
}
|
|
23090
|
+
await identityFor(candidate, deps);
|
|
23091
|
+
await deps.saveToken(candidate);
|
|
23092
|
+
return { status: 200, body: await statusFor({ ...current, token: candidate }, deps) };
|
|
23093
|
+
});
|
|
23094
|
+
route(use, "/api/clickup/tasks/mine", ["GET"], async () => {
|
|
23095
|
+
const { token, viewer, workspace } = await requireIdentity(deps);
|
|
23096
|
+
const path = `/team/${workspace.id}/task?assignees[]=${viewer.id}&include_closed=false&subtasks=true&order_by=due_date&reverse=true`;
|
|
23097
|
+
const { tasks, truncated } = await fetchTaskPages(token, path, deps);
|
|
23098
|
+
const body = { workspace, viewer, tasks, truncated };
|
|
23099
|
+
return { status: 200, body };
|
|
23100
|
+
});
|
|
23101
|
+
route(use, "/api/clickup/tasks/list", ["GET"], async (_req, url) => {
|
|
23102
|
+
const projectPath = await resolveProjectPath2(url.searchParams.get("cwd") ?? "", deps);
|
|
23103
|
+
const { token, viewer, workspace, config } = await requireIdentity(deps);
|
|
23104
|
+
const listId = config.projects[projectPath];
|
|
23105
|
+
if (!listId) throw new ClickUpRouteError(404, "project_unlinked", "This project is not linked to a ClickUp list");
|
|
23106
|
+
const since = deps.now() - CLOSED_WINDOW_MS;
|
|
23107
|
+
const [list, open10, closed] = await Promise.all([
|
|
23108
|
+
deps.api(token, `/list/${listId}`).then(parseListResponse),
|
|
23109
|
+
fetchTaskPages(token, `/list/${listId}/task?include_closed=false&subtasks=true&order_by=updated`, deps),
|
|
23110
|
+
fetchTaskPages(token, `/list/${listId}/task?include_closed=true&subtasks=true&order_by=updated&date_updated_gt=${since}`, deps, 1)
|
|
23111
|
+
]);
|
|
23112
|
+
const seen = new Set(open10.tasks.map((task) => task.id));
|
|
23113
|
+
const recentlyClosed = closed.tasks.filter((task) => !seen.has(task.id) && task.status.type === "closed");
|
|
23114
|
+
const body = {
|
|
23115
|
+
workspace,
|
|
23116
|
+
viewer,
|
|
23117
|
+
list,
|
|
23118
|
+
tasks: [...open10.tasks, ...recentlyClosed],
|
|
23119
|
+
truncated: open10.truncated
|
|
23120
|
+
};
|
|
23121
|
+
return { status: 200, body };
|
|
23122
|
+
});
|
|
23123
|
+
route(use, "/api/clickup/spaces", ["GET"], async () => {
|
|
23124
|
+
const { token, workspace } = await requireIdentity(deps);
|
|
23125
|
+
const spaces = parseSpacesResponse(await deps.api(token, `/team/${workspace.id}/space?archived=false`));
|
|
23126
|
+
const body = { workspace, spaces };
|
|
23127
|
+
return { status: 200, body };
|
|
23128
|
+
});
|
|
23129
|
+
route(use, "/api/clickup/lists", ["GET"], async (_req, url) => {
|
|
23130
|
+
const spaceId = url.searchParams.get("spaceId") ?? "";
|
|
23131
|
+
if (!NUMERIC_ID.test(spaceId)) {
|
|
23132
|
+
throw new ClickUpRouteError(400, "clickup_api_failed", "spaceId must be a ClickUp space id");
|
|
23133
|
+
}
|
|
23134
|
+
const { token } = await requireIdentity(deps);
|
|
23135
|
+
const [inFolders, folderless] = await Promise.all([
|
|
23136
|
+
deps.api(token, `/space/${spaceId}/folder?archived=false`).then(parseFoldersResponse),
|
|
23137
|
+
deps.api(token, `/space/${spaceId}/list?archived=false`).then(parseFolderlessListsResponse)
|
|
23138
|
+
]);
|
|
23139
|
+
const body = { spaceId, lists: [...folderless, ...inFolders] };
|
|
23140
|
+
return { status: 200, body };
|
|
23141
|
+
});
|
|
23142
|
+
route(use, "/api/clickup/project-list", ["GET", "PUT"], async (req, url) => {
|
|
23143
|
+
if (req.method === "GET") {
|
|
23144
|
+
const projectPath2 = await resolveProjectPath2(url.searchParams.get("cwd") ?? "", deps);
|
|
23145
|
+
const config = await deps.loadConfig();
|
|
23146
|
+
const body2 = { cwd: projectPath2, listId: config.projects[projectPath2] ?? null };
|
|
23147
|
+
return { status: 200, body: body2 };
|
|
23148
|
+
}
|
|
23149
|
+
const request = await readJsonBody(req);
|
|
23150
|
+
const projectPath = await resolveProjectPath2(typeof request.cwd === "string" ? request.cwd : "", deps);
|
|
23151
|
+
const listId = request.listId === null || request.listId === void 0 ? null : String(request.listId);
|
|
23152
|
+
if (listId !== null && !NUMERIC_ID.test(listId)) {
|
|
23153
|
+
throw new ClickUpRouteError(400, "clickup_api_failed", "listId must be a ClickUp list id");
|
|
23154
|
+
}
|
|
23155
|
+
if (listId !== null) {
|
|
23156
|
+
const { token } = await requireIdentity(deps);
|
|
23157
|
+
parseListResponse(await deps.api(token, `/list/${listId}`));
|
|
23158
|
+
}
|
|
23159
|
+
await deps.saveProjectLink(projectPath, listId);
|
|
23160
|
+
const body = { cwd: projectPath, listId };
|
|
23161
|
+
return { status: 200, body };
|
|
23162
|
+
});
|
|
23163
|
+
}
|
|
23164
|
+
var API_BASE, REQUEST_TIMEOUT_MS, MAX_TASK_PAGES, CLOSED_WINDOW_MS, NUMERIC_ID, STATUS_TYPES, PRIORITIES, ClickUpRouteError, defaultDependencies3, identityCache;
|
|
23165
|
+
var init_clickup = __esm({
|
|
23166
|
+
"../../server/routes/clickup.ts"() {
|
|
23167
|
+
init_http();
|
|
23168
|
+
init_clickupConfig();
|
|
23169
|
+
init_gitProject();
|
|
23170
|
+
API_BASE = "https://api.clickup.com/api/v2";
|
|
23171
|
+
REQUEST_TIMEOUT_MS = 2e4;
|
|
23172
|
+
MAX_TASK_PAGES = 3;
|
|
23173
|
+
CLOSED_WINDOW_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
23174
|
+
NUMERIC_ID = /^\d+$/;
|
|
23175
|
+
STATUS_TYPES = /* @__PURE__ */ new Set(["open", "custom", "closed", "done"]);
|
|
23176
|
+
PRIORITIES = /* @__PURE__ */ new Set(["urgent", "high", "normal", "low"]);
|
|
23177
|
+
ClickUpRouteError = class extends Error {
|
|
23178
|
+
constructor(status, code, message) {
|
|
23179
|
+
super(message);
|
|
23180
|
+
this.status = status;
|
|
23181
|
+
this.code = code;
|
|
23182
|
+
}
|
|
23183
|
+
};
|
|
23184
|
+
defaultDependencies3 = {
|
|
23185
|
+
api: runClickUpApi,
|
|
23186
|
+
loadConfig: loadClickUpConfig,
|
|
23187
|
+
saveToken: saveClickUpToken,
|
|
23188
|
+
saveProjectLink: saveClickUpProjectLink,
|
|
23189
|
+
resolveProject: resolveGitProject,
|
|
23190
|
+
now: () => Date.now()
|
|
23191
|
+
};
|
|
23192
|
+
identityCache = /* @__PURE__ */ new Map();
|
|
23193
|
+
}
|
|
23194
|
+
});
|
|
23195
|
+
|
|
22762
23196
|
// ../../server/lib/projectIcon.ts
|
|
22763
23197
|
import { realpath as realpath10, stat as stat14 } from "node:fs/promises";
|
|
22764
|
-
import { basename as basename9, extname, join as
|
|
23198
|
+
import { basename as basename9, extname, join as join23, relative as relative8, sep as sep10 } from "node:path";
|
|
22765
23199
|
function namedIconCandidates(root) {
|
|
22766
23200
|
const name = basename9(root);
|
|
22767
23201
|
if (!name || name.startsWith(".")) return [];
|
|
22768
23202
|
return ["public", "assets", "static", "."].flatMap(
|
|
22769
|
-
(dir) => NAMED_ICON_EXTENSIONS.map((ext) =>
|
|
23203
|
+
(dir) => NAMED_ICON_EXTENSIONS.map((ext) => join23(dir, `${name}${ext}`))
|
|
22770
23204
|
);
|
|
22771
23205
|
}
|
|
22772
23206
|
function iconContentType(path) {
|
|
@@ -22789,7 +23223,7 @@ async function resolveProjectIcon(projectPath) {
|
|
|
22789
23223
|
...PROJECT_ICON_CANDIDATES.slice(6)
|
|
22790
23224
|
];
|
|
22791
23225
|
for (const candidate of candidates) {
|
|
22792
|
-
const guess =
|
|
23226
|
+
const guess = join23(root, candidate);
|
|
22793
23227
|
try {
|
|
22794
23228
|
const resolved = await realpath10(guess);
|
|
22795
23229
|
if (!isInside(root, resolved)) continue;
|
|
@@ -22943,13 +23377,13 @@ var init_local_file = __esm({
|
|
|
22943
23377
|
|
|
22944
23378
|
// ../../server/routes/mcp.ts
|
|
22945
23379
|
import { execFile as execFile5 } from "node:child_process";
|
|
22946
|
-
import { isAbsolute as isAbsolute10, join as
|
|
22947
|
-
import { readFile as
|
|
22948
|
-
import { homedir as
|
|
23380
|
+
import { isAbsolute as isAbsolute10, join as join24 } from "node:path";
|
|
23381
|
+
import { readFile as readFile18 } from "node:fs/promises";
|
|
23382
|
+
import { homedir as homedir8 } from "node:os";
|
|
22949
23383
|
async function readMcpConfigs(cwd) {
|
|
22950
23384
|
const configs = {};
|
|
22951
23385
|
try {
|
|
22952
|
-
const raw = await
|
|
23386
|
+
const raw = await readFile18(join24(homedir8(), ".claude.json"), "utf-8");
|
|
22953
23387
|
const parsed = JSON.parse(raw);
|
|
22954
23388
|
if (parsed.mcpServers && typeof parsed.mcpServers === "object") {
|
|
22955
23389
|
Object.assign(configs, parsed.mcpServers);
|
|
@@ -22967,16 +23401,16 @@ async function readMcpConfigs(cwd) {
|
|
|
22967
23401
|
} catch {
|
|
22968
23402
|
}
|
|
22969
23403
|
const otherSources = [
|
|
22970
|
-
|
|
23404
|
+
join24(homedir8(), ".claude", "settings.json"),
|
|
22971
23405
|
// global settings
|
|
22972
|
-
|
|
23406
|
+
join24(cwd, ".mcp.json"),
|
|
22973
23407
|
// project
|
|
22974
|
-
|
|
23408
|
+
join24(cwd, ".claude", "settings.local.json")
|
|
22975
23409
|
// project local
|
|
22976
23410
|
];
|
|
22977
23411
|
for (const path of otherSources) {
|
|
22978
23412
|
try {
|
|
22979
|
-
const raw = await
|
|
23413
|
+
const raw = await readFile18(path, "utf-8");
|
|
22980
23414
|
const parsed = JSON.parse(raw);
|
|
22981
23415
|
if (parsed.mcpServers && typeof parsed.mcpServers === "object") {
|
|
22982
23416
|
Object.assign(configs, parsed.mcpServers);
|
|
@@ -23187,8 +23621,8 @@ function humanizeIdentifier(value, titleCase = false) {
|
|
|
23187
23621
|
return titleCase ? lower[0].toUpperCase() + lower.slice(1) : lower;
|
|
23188
23622
|
});
|
|
23189
23623
|
if (words.length === 0) return "Tool";
|
|
23190
|
-
const
|
|
23191
|
-
return
|
|
23624
|
+
const text2 = words.join(" ");
|
|
23625
|
+
return text2[0].toUpperCase() + text2.slice(1);
|
|
23192
23626
|
}
|
|
23193
23627
|
function stringExpression(source) {
|
|
23194
23628
|
if (!source) return null;
|
|
@@ -23718,8 +24152,8 @@ function foldFileEdit(acc, name, input) {
|
|
|
23718
24152
|
}
|
|
23719
24153
|
return true;
|
|
23720
24154
|
}
|
|
23721
|
-
function notePreview(acc,
|
|
23722
|
-
const trimmed =
|
|
24155
|
+
function notePreview(acc, text2) {
|
|
24156
|
+
const trimmed = text2.trim();
|
|
23723
24157
|
if (trimmed) acc.lastAssistantText = trimmed.slice(0, PREVIEW_LIMIT);
|
|
23724
24158
|
}
|
|
23725
24159
|
var TRAIL_LENGTH, PREVIEW_LIMIT;
|
|
@@ -23822,9 +24256,9 @@ function copilotText(value) {
|
|
|
23822
24256
|
if (!Array.isArray(value)) return "";
|
|
23823
24257
|
return value.flatMap((part) => {
|
|
23824
24258
|
if (typeof part === "string") return part ? [part] : [];
|
|
23825
|
-
const
|
|
23826
|
-
const
|
|
23827
|
-
return
|
|
24259
|
+
const record5 = asRecord5(part);
|
|
24260
|
+
const text2 = str(record5.text) || str(record5.content);
|
|
24261
|
+
return text2 ? [text2] : [];
|
|
23828
24262
|
}).join("\n");
|
|
23829
24263
|
}
|
|
23830
24264
|
function normalizeCopilotToolName(name) {
|
|
@@ -24387,14 +24821,14 @@ var init_models = __esm({
|
|
|
24387
24821
|
});
|
|
24388
24822
|
|
|
24389
24823
|
// ../../server/lib/notificationHistory.ts
|
|
24390
|
-
import { mkdir as
|
|
24824
|
+
import { mkdir as mkdir7, readFile as readFile19 } from "node:fs/promises";
|
|
24391
24825
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
24392
|
-
import { homedir as
|
|
24393
|
-
import { dirname as
|
|
24826
|
+
import { homedir as homedir9 } from "node:os";
|
|
24827
|
+
import { dirname as dirname10, join as join25 } from "node:path";
|
|
24394
24828
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
24395
24829
|
async function load() {
|
|
24396
24830
|
if (entries2) return entries2;
|
|
24397
|
-
loadPromise ??=
|
|
24831
|
+
loadPromise ??= readFile19(NOTIFICATION_HISTORY_FILE, "utf-8").then((raw) => {
|
|
24398
24832
|
const parsed = JSON.parse(raw);
|
|
24399
24833
|
return Array.isArray(parsed) ? parsed.filter(isEntry) : [];
|
|
24400
24834
|
}).catch(() => []).then((loaded2) => {
|
|
@@ -24420,7 +24854,7 @@ function schedulePersist2() {
|
|
|
24420
24854
|
const snapshot = entries2;
|
|
24421
24855
|
if (!snapshot) return;
|
|
24422
24856
|
dirty = false;
|
|
24423
|
-
void
|
|
24857
|
+
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
24858
|
}, PERSIST_DEBOUNCE_MS);
|
|
24425
24859
|
persistTimer.unref?.();
|
|
24426
24860
|
}
|
|
@@ -24428,7 +24862,7 @@ function flushSync() {
|
|
|
24428
24862
|
if (!dirty || !entries2) return;
|
|
24429
24863
|
dirty = false;
|
|
24430
24864
|
try {
|
|
24431
|
-
mkdirSync(
|
|
24865
|
+
mkdirSync(dirname10(NOTIFICATION_HISTORY_FILE), { recursive: true });
|
|
24432
24866
|
writeFileSync(NOTIFICATION_HISTORY_FILE, JSON.stringify(entries2, null, 2), { mode: 384 });
|
|
24433
24867
|
} catch {
|
|
24434
24868
|
}
|
|
@@ -24478,7 +24912,7 @@ var NOTIFICATION_HISTORY_FILE, MAX_ENTRIES3, PERSIST_DEBOUNCE_MS, entries2, load
|
|
|
24478
24912
|
var init_notificationHistory = __esm({
|
|
24479
24913
|
"../../server/lib/notificationHistory.ts"() {
|
|
24480
24914
|
init_atomicJsonFile();
|
|
24481
|
-
NOTIFICATION_HISTORY_FILE =
|
|
24915
|
+
NOTIFICATION_HISTORY_FILE = join25(homedir9(), ".cogpit", "notifications.json");
|
|
24482
24916
|
MAX_ENTRIES3 = 200;
|
|
24483
24917
|
PERSIST_DEBOUNCE_MS = 500;
|
|
24484
24918
|
entries2 = null;
|
|
@@ -24533,9 +24967,9 @@ function parseEtimeSeconds(etime) {
|
|
|
24533
24967
|
const [, days, hours, minutes, seconds] = match;
|
|
24534
24968
|
return Number(days ?? 0) * 86400 + Number(hours ?? 0) * 3600 + Number(minutes) * 60 + Number(seconds);
|
|
24535
24969
|
}
|
|
24536
|
-
function parsePsOutput(
|
|
24970
|
+
function parsePsOutput(text2) {
|
|
24537
24971
|
const rows = [];
|
|
24538
|
-
for (const line of
|
|
24972
|
+
for (const line of text2.split("\n")) {
|
|
24539
24973
|
const match = /^\s*(\d+)\s+(\d+)\s+([\d.]+)\s+(\d+)\s+(\S+)\s+(.*\S)/.exec(line);
|
|
24540
24974
|
if (!match) continue;
|
|
24541
24975
|
rows.push({
|
|
@@ -24741,8 +25175,8 @@ var init_notifications2 = __esm({
|
|
|
24741
25175
|
|
|
24742
25176
|
// ../../server/lib/pushConfig.ts
|
|
24743
25177
|
import { readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
|
|
24744
|
-
import { homedir as
|
|
24745
|
-
import { join as
|
|
25178
|
+
import { homedir as homedir10 } from "node:os";
|
|
25179
|
+
import { join as join26 } from "node:path";
|
|
24746
25180
|
function warnOnce(message) {
|
|
24747
25181
|
if (lastWarning === message) return;
|
|
24748
25182
|
lastWarning = message;
|
|
@@ -24837,7 +25271,7 @@ function getPushConfig(path = PUSH_CONFIG_FILE) {
|
|
|
24837
25271
|
var PUSH_CONFIG_FILE, DEFAULT_NTFY_URL, TOPIC_PATTERN, cache5, lastWarning;
|
|
24838
25272
|
var init_pushConfig = __esm({
|
|
24839
25273
|
"../../server/lib/pushConfig.ts"() {
|
|
24840
|
-
PUSH_CONFIG_FILE =
|
|
25274
|
+
PUSH_CONFIG_FILE = join26(homedir10(), ".cogpit", "push.json");
|
|
24841
25275
|
DEFAULT_NTFY_URL = "https://ntfy.sh";
|
|
24842
25276
|
TOPIC_PATTERN = /^[-_A-Za-z0-9]{1,64}$/;
|
|
24843
25277
|
cache5 = null;
|
|
@@ -24846,12 +25280,12 @@ var init_pushConfig = __esm({
|
|
|
24846
25280
|
});
|
|
24847
25281
|
|
|
24848
25282
|
// ../../server/lib/pushNotify.ts
|
|
24849
|
-
function truncateBytes(
|
|
24850
|
-
if (encoder.encode(
|
|
25283
|
+
function truncateBytes(text2, maxBytes) {
|
|
25284
|
+
if (encoder.encode(text2).length <= maxBytes) return text2;
|
|
24851
25285
|
const budget = maxBytes - 3;
|
|
24852
25286
|
let out = "";
|
|
24853
25287
|
let used = 0;
|
|
24854
|
-
for (const char of
|
|
25288
|
+
for (const char of text2) {
|
|
24855
25289
|
const size = encoder.encode(char).length;
|
|
24856
25290
|
if (used + size > budget) break;
|
|
24857
25291
|
out += char;
|
|
@@ -24859,8 +25293,8 @@ function truncateBytes(text, maxBytes) {
|
|
|
24859
25293
|
}
|
|
24860
25294
|
return `${out}\u2026`;
|
|
24861
25295
|
}
|
|
24862
|
-
function stripControls(
|
|
24863
|
-
return
|
|
25296
|
+
function stripControls(text2) {
|
|
25297
|
+
return text2.replace(/[\u0000-\u001f\u007f-\u009f]+/g, " ").trim();
|
|
24864
25298
|
}
|
|
24865
25299
|
function buildNtfyPayload(notification, config) {
|
|
24866
25300
|
const title = truncateBytes(stripControls(notification.title), TITLE_MAX_BYTES) || "Cogpit";
|
|
@@ -24879,7 +25313,7 @@ async function sendPushNotification(notification, config = getPushConfig()) {
|
|
|
24879
25313
|
method: "POST",
|
|
24880
25314
|
headers,
|
|
24881
25315
|
body: JSON.stringify(buildNtfyPayload(notification, config)),
|
|
24882
|
-
signal: AbortSignal.timeout(
|
|
25316
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS2),
|
|
24883
25317
|
redirect: "error"
|
|
24884
25318
|
});
|
|
24885
25319
|
if (!response.ok) {
|
|
@@ -24893,14 +25327,14 @@ async function sendPushNotification(notification, config = getPushConfig()) {
|
|
|
24893
25327
|
return false;
|
|
24894
25328
|
}
|
|
24895
25329
|
}
|
|
24896
|
-
var MESSAGE_MAX_BYTES, TITLE_MAX_BYTES,
|
|
25330
|
+
var MESSAGE_MAX_BYTES, TITLE_MAX_BYTES, REQUEST_TIMEOUT_MS2, encoder;
|
|
24897
25331
|
var init_pushNotify = __esm({
|
|
24898
25332
|
"../../server/lib/pushNotify.ts"() {
|
|
24899
25333
|
init_notifications2();
|
|
24900
25334
|
init_pushConfig();
|
|
24901
25335
|
MESSAGE_MAX_BYTES = 1024;
|
|
24902
25336
|
TITLE_MAX_BYTES = 256;
|
|
24903
|
-
|
|
25337
|
+
REQUEST_TIMEOUT_MS2 = 5e3;
|
|
24904
25338
|
encoder = new TextEncoder();
|
|
24905
25339
|
}
|
|
24906
25340
|
});
|
|
@@ -25703,8 +26137,8 @@ var init_ports2 = __esm({
|
|
|
25703
26137
|
|
|
25704
26138
|
// ../../server/routes/project-file.ts
|
|
25705
26139
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
25706
|
-
import { readFile as
|
|
25707
|
-
import { dirname as
|
|
26140
|
+
import { readFile as readFile20, realpath as realpath11, rename as rename3, stat as stat16, unlink as unlink6, writeFile as writeFile6 } from "node:fs/promises";
|
|
26141
|
+
import { dirname as dirname11, isAbsolute as isAbsolute11, resolve as resolve17 } from "node:path";
|
|
25708
26142
|
function readBody(req) {
|
|
25709
26143
|
return new Promise((resolveBody, reject) => {
|
|
25710
26144
|
let body = "";
|
|
@@ -25765,7 +26199,7 @@ async function writeAtomically(absolutePath, content, mode, expectedMtimeMs) {
|
|
|
25765
26199
|
if (latest.mtimeMs !== expectedMtimeMs) {
|
|
25766
26200
|
throw new ProjectFileError(409, "File changed on disk. Reload it before saving.");
|
|
25767
26201
|
}
|
|
25768
|
-
const temporaryPath = resolve17(
|
|
26202
|
+
const temporaryPath = resolve17(dirname11(absolutePath), `.${randomUUID5()}.cogpit-save`);
|
|
25769
26203
|
try {
|
|
25770
26204
|
await writeFile6(temporaryPath, content, { encoding: "utf-8", mode });
|
|
25771
26205
|
const beforeRename = await stat16(absolutePath);
|
|
@@ -25785,7 +26219,7 @@ function registerProjectFileContentRoutes(use) {
|
|
|
25785
26219
|
const filePath = url.searchParams.get("path") ?? "";
|
|
25786
26220
|
try {
|
|
25787
26221
|
const file = await resolveProjectFile(cwd, filePath);
|
|
25788
|
-
const buffer = await
|
|
26222
|
+
const buffer = await readFile20(file.absolutePath);
|
|
25789
26223
|
return sendJson(res, 200, {
|
|
25790
26224
|
content: decodeTextFile(buffer),
|
|
25791
26225
|
mtimeMs: file.info.mtimeMs,
|
|
@@ -26066,7 +26500,7 @@ var init_sessionSearch = __esm({
|
|
|
26066
26500
|
|
|
26067
26501
|
// ../../server/lib/projectNames.ts
|
|
26068
26502
|
import { basename as basename10 } from "node:path";
|
|
26069
|
-
import { homedir as
|
|
26503
|
+
import { homedir as homedir11 } from "node:os";
|
|
26070
26504
|
function shortNameFromPath(path) {
|
|
26071
26505
|
const trimmed = path.replace(/[\\/]+$/, "");
|
|
26072
26506
|
return basename10(trimmed) || trimmed || path;
|
|
@@ -26102,7 +26536,7 @@ var HOME_PREFIX;
|
|
|
26102
26536
|
var init_projectNames = __esm({
|
|
26103
26537
|
"../../server/lib/projectNames.ts"() {
|
|
26104
26538
|
init_agent_descriptors();
|
|
26105
|
-
HOME_PREFIX = descriptorFor("claude").dirName.encode(
|
|
26539
|
+
HOME_PREFIX = descriptorFor("claude").dirName.encode(homedir11()).replace(/^-/, "").toLowerCase();
|
|
26106
26540
|
}
|
|
26107
26541
|
});
|
|
26108
26542
|
|
|
@@ -26214,8 +26648,8 @@ async function handleActiveSessions(req, res, next) {
|
|
|
26214
26648
|
const resolveTeamLead = (teamName) => {
|
|
26215
26649
|
let cached = teamLeadCache.get(teamName);
|
|
26216
26650
|
if (!cached) {
|
|
26217
|
-
const
|
|
26218
|
-
cached = isWithinDir(dirs.TEAMS_DIR,
|
|
26651
|
+
const configPath2 = join11(dirs.TEAMS_DIR, teamName, "config.json");
|
|
26652
|
+
cached = isWithinDir(dirs.TEAMS_DIR, configPath2) ? readFile9(configPath2, "utf-8").then((raw) => {
|
|
26219
26653
|
const lead = JSON.parse(String(raw)).leadSessionId;
|
|
26220
26654
|
return typeof lead === "string" && lead ? lead : null;
|
|
26221
26655
|
}).catch(() => null) : Promise.resolve(null);
|
|
@@ -26425,18 +26859,18 @@ async function readSessionHeader(filePath) {
|
|
|
26425
26859
|
try {
|
|
26426
26860
|
const fileStat = await fh.stat();
|
|
26427
26861
|
let readLen = Math.min(HEADER_BYTES, fileStat.size);
|
|
26428
|
-
let
|
|
26862
|
+
let text2 = "";
|
|
26429
26863
|
let bytesRead = 0;
|
|
26430
26864
|
for (; ; ) {
|
|
26431
26865
|
const buf = Buffer.allocUnsafe(readLen);
|
|
26432
26866
|
const result = await fh.read(buf, 0, readLen, 0);
|
|
26433
26867
|
bytesRead = result.bytesRead;
|
|
26434
|
-
|
|
26868
|
+
text2 = buf.subarray(0, bytesRead).toString("utf-8");
|
|
26435
26869
|
const isWholeFile = bytesRead >= fileStat.size;
|
|
26436
|
-
if (isWholeFile ||
|
|
26870
|
+
if (isWholeFile || text2.includes("\n") || readLen >= MAX_HEADER_BYTES) break;
|
|
26437
26871
|
readLen = Math.min(readLen * 4, Math.min(fileStat.size, MAX_HEADER_BYTES));
|
|
26438
26872
|
}
|
|
26439
|
-
const parts =
|
|
26873
|
+
const parts = text2.split("\n").filter((l) => l.trim().length > 0);
|
|
26440
26874
|
if (bytesRead < fileStat.size && parts.length > 0) {
|
|
26441
26875
|
parts.pop();
|
|
26442
26876
|
}
|
|
@@ -26900,8 +27334,8 @@ function getProviderUpdates() {
|
|
|
26900
27334
|
function isProviderUpdateId(value) {
|
|
26901
27335
|
return typeof value === "string" && AGENT_KINDS.includes(value);
|
|
26902
27336
|
}
|
|
26903
|
-
function truncate2(
|
|
26904
|
-
const trimmed =
|
|
27337
|
+
function truncate2(text2) {
|
|
27338
|
+
const trimmed = text2.trim();
|
|
26905
27339
|
if (!trimmed) return null;
|
|
26906
27340
|
return trimmed.length <= CLI_OUTPUT_MAX_CHARS ? trimmed : trimmed.slice(0, CLI_OUTPUT_MAX_CHARS);
|
|
26907
27341
|
}
|
|
@@ -27049,12 +27483,189 @@ var init_agent_executable = __esm({
|
|
|
27049
27483
|
}
|
|
27050
27484
|
});
|
|
27051
27485
|
|
|
27486
|
+
// ../../server/agents/claudeSwap.ts
|
|
27487
|
+
function asRow(value) {
|
|
27488
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
27489
|
+
}
|
|
27490
|
+
function asString2(value) {
|
|
27491
|
+
return typeof value === "string" && value.trim() ? value : null;
|
|
27492
|
+
}
|
|
27493
|
+
function asSlot(value) {
|
|
27494
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : null;
|
|
27495
|
+
}
|
|
27496
|
+
function parseWindow(value) {
|
|
27497
|
+
const row = asRow(value);
|
|
27498
|
+
if (!row || typeof row.pct !== "number" || !Number.isFinite(row.pct)) return null;
|
|
27499
|
+
return {
|
|
27500
|
+
pct: Math.min(100, Math.max(0, row.pct)),
|
|
27501
|
+
resetsIn: asString2(row.countdown),
|
|
27502
|
+
resetsAt: asString2(row.resetsAt)
|
|
27503
|
+
};
|
|
27504
|
+
}
|
|
27505
|
+
function parseUsage2(value) {
|
|
27506
|
+
const row = asRow(value);
|
|
27507
|
+
if (!row) return null;
|
|
27508
|
+
return { fiveHour: parseWindow(row.fiveHour), sevenDay: parseWindow(row.sevenDay) };
|
|
27509
|
+
}
|
|
27510
|
+
function parseAccount(value) {
|
|
27511
|
+
const row = asRow(value);
|
|
27512
|
+
if (!row) return null;
|
|
27513
|
+
const slot = asSlot(row.number);
|
|
27514
|
+
const email = asString2(row.email);
|
|
27515
|
+
if (slot === null || email === null) return null;
|
|
27516
|
+
return {
|
|
27517
|
+
slot,
|
|
27518
|
+
alias: asString2(row.alias),
|
|
27519
|
+
email,
|
|
27520
|
+
organization: asString2(row.organizationName),
|
|
27521
|
+
active: row.active === true,
|
|
27522
|
+
disabled: row.disabled === true,
|
|
27523
|
+
usageStatus: asString2(row.usageStatus) ?? "unavailable",
|
|
27524
|
+
usage: parseUsage2(row.usage)
|
|
27525
|
+
};
|
|
27526
|
+
}
|
|
27527
|
+
function parseJson(stdout) {
|
|
27528
|
+
try {
|
|
27529
|
+
return asRow(JSON.parse(stdout));
|
|
27530
|
+
} catch {
|
|
27531
|
+
return null;
|
|
27532
|
+
}
|
|
27533
|
+
}
|
|
27534
|
+
function parseAccountList(stdout) {
|
|
27535
|
+
const payload = parseJson(stdout);
|
|
27536
|
+
if (!payload || !Array.isArray(payload.accounts)) return null;
|
|
27537
|
+
return {
|
|
27538
|
+
activeSlot: asSlot(payload.activeAccountNumber),
|
|
27539
|
+
accounts: payload.accounts.map(parseAccount).filter((account) => account !== null)
|
|
27540
|
+
};
|
|
27541
|
+
}
|
|
27542
|
+
function parseSwitchResult(stdout) {
|
|
27543
|
+
const payload = parseJson(stdout);
|
|
27544
|
+
if (!payload) return null;
|
|
27545
|
+
const error = switcherError(payload);
|
|
27546
|
+
if (error) return { error };
|
|
27547
|
+
if (typeof payload.switched !== "boolean") return null;
|
|
27548
|
+
return {
|
|
27549
|
+
switched: payload.switched,
|
|
27550
|
+
message: asString2(payload.message) ?? (payload.switched ? "Switched account." : "Account unchanged."),
|
|
27551
|
+
warnings: Array.isArray(payload.warnings) ? payload.warnings.filter((w) => typeof w === "string") : []
|
|
27552
|
+
};
|
|
27553
|
+
}
|
|
27554
|
+
function switcherError(payload) {
|
|
27555
|
+
return asString2(asRow(payload.error)?.message);
|
|
27556
|
+
}
|
|
27557
|
+
function failureMessage(run2, fallback) {
|
|
27558
|
+
if (run2.timedOut) return `${CSWAP_BIN} timed out`;
|
|
27559
|
+
const envelope = parseJson(run2.stdout);
|
|
27560
|
+
return envelope && switcherError(envelope) || run2.stderr.trim() || fallback;
|
|
27561
|
+
}
|
|
27562
|
+
function isClaudeSwapInstalled() {
|
|
27563
|
+
return findExecutableOnPath(CSWAP_BIN) !== void 0;
|
|
27564
|
+
}
|
|
27565
|
+
async function describeClaudeAccounts() {
|
|
27566
|
+
if (!isClaudeSwapInstalled()) return { status: "missing" };
|
|
27567
|
+
const [version, list] = await Promise.all([
|
|
27568
|
+
runCli(CSWAP_BIN, ["--version"], DEFAULT_PROBE_TIMEOUT_MS),
|
|
27569
|
+
runCli(CSWAP_BIN, ["list", "--json"], LIST_TIMEOUT_MS)
|
|
27570
|
+
]);
|
|
27571
|
+
if (list.code !== 0) {
|
|
27572
|
+
return { status: "error", error: failureMessage(list, `${CSWAP_BIN} list failed`) };
|
|
27573
|
+
}
|
|
27574
|
+
const parsed = parseAccountList(list.stdout);
|
|
27575
|
+
if (!parsed) return { status: "error", error: `${CSWAP_BIN} list returned unexpected output` };
|
|
27576
|
+
return { status: "ok", tool: TOOL_NAME, version: extractVersion(version.stdout), ...parsed };
|
|
27577
|
+
}
|
|
27578
|
+
async function switchClaudeAccount(slot) {
|
|
27579
|
+
if (asSlot(slot) === null) throw new Error("slot must be a positive integer");
|
|
27580
|
+
const run2 = await runCli(CSWAP_BIN, ["switch", String(slot), "--json"], SWITCH_TIMEOUT_MS);
|
|
27581
|
+
const parsed = run2.code === 0 ? parseSwitchResult(run2.stdout) : null;
|
|
27582
|
+
if (!parsed) throw new Error(failureMessage(run2, `${CSWAP_BIN} switch failed`));
|
|
27583
|
+
if ("error" in parsed) throw new Error(parsed.error);
|
|
27584
|
+
return { ...parsed, credentialStore: process.platform === "darwin" ? "keychain" : "file" };
|
|
27585
|
+
}
|
|
27586
|
+
var CSWAP_BIN, TOOL_NAME, LIST_TIMEOUT_MS, SWITCH_TIMEOUT_MS;
|
|
27587
|
+
var init_claudeSwap = __esm({
|
|
27588
|
+
"../../server/agents/claudeSwap.ts"() {
|
|
27589
|
+
init_versions();
|
|
27590
|
+
init_binaryResolver();
|
|
27591
|
+
init_cliProcess();
|
|
27592
|
+
CSWAP_BIN = "cswap";
|
|
27593
|
+
TOOL_NAME = "claude-swap";
|
|
27594
|
+
LIST_TIMEOUT_MS = 3e4;
|
|
27595
|
+
SWITCH_TIMEOUT_MS = 3e4;
|
|
27596
|
+
}
|
|
27597
|
+
});
|
|
27598
|
+
|
|
27599
|
+
// ../../server/agents/accounts.ts
|
|
27600
|
+
function accountSwitcherFor(kind) {
|
|
27601
|
+
return kind === "claude" ? claudeAccounts : null;
|
|
27602
|
+
}
|
|
27603
|
+
var claudeAccounts;
|
|
27604
|
+
var init_accounts = __esm({
|
|
27605
|
+
"../../server/agents/accounts.ts"() {
|
|
27606
|
+
init_claudeSwap();
|
|
27607
|
+
claudeAccounts = {
|
|
27608
|
+
describe: describeClaudeAccounts,
|
|
27609
|
+
switchTo: switchClaudeAccount
|
|
27610
|
+
};
|
|
27611
|
+
}
|
|
27612
|
+
});
|
|
27613
|
+
|
|
27614
|
+
// ../../server/routes/agent-accounts.ts
|
|
27615
|
+
function registerAgentAccountRoutes(use) {
|
|
27616
|
+
use("/api/agent-accounts", async (req, res, next) => {
|
|
27617
|
+
const segments2 = new URL(req.url || "/", "http://localhost").pathname.split("/").filter(Boolean);
|
|
27618
|
+
const [kind, action, ...rest] = segments2;
|
|
27619
|
+
if (!AGENT_KINDS.includes(kind ?? "") || rest.length > 0) return next();
|
|
27620
|
+
const switcher = accountSwitcherFor(kind);
|
|
27621
|
+
if (action === void 0 && req.method === "GET") {
|
|
27622
|
+
if (!switcher) {
|
|
27623
|
+
sendJson(res, 404, { error: `${kind} has no account switcher` });
|
|
27624
|
+
return;
|
|
27625
|
+
}
|
|
27626
|
+
try {
|
|
27627
|
+
sendJson(res, 200, await switcher.describe());
|
|
27628
|
+
} catch (err) {
|
|
27629
|
+
sendJson(res, 500, { error: String(err) });
|
|
27630
|
+
}
|
|
27631
|
+
return;
|
|
27632
|
+
}
|
|
27633
|
+
if (action === "switch" && req.method === "POST") {
|
|
27634
|
+
if (!switcher) {
|
|
27635
|
+
sendJson(res, 404, { error: `${kind} has no account switcher` });
|
|
27636
|
+
return;
|
|
27637
|
+
}
|
|
27638
|
+
withJsonBody(req, res, async (body) => {
|
|
27639
|
+
const slot = body?.slot;
|
|
27640
|
+
if (typeof slot !== "number" || !Number.isInteger(slot) || slot <= 0) {
|
|
27641
|
+
sendJson(res, 400, { error: "slot must be a positive integer" });
|
|
27642
|
+
return;
|
|
27643
|
+
}
|
|
27644
|
+
try {
|
|
27645
|
+
sendJson(res, 200, await switcher.switchTo(slot));
|
|
27646
|
+
} catch (err) {
|
|
27647
|
+
sendJson(res, 500, { error: err instanceof Error ? err.message : String(err) });
|
|
27648
|
+
}
|
|
27649
|
+
});
|
|
27650
|
+
return;
|
|
27651
|
+
}
|
|
27652
|
+
next();
|
|
27653
|
+
});
|
|
27654
|
+
}
|
|
27655
|
+
var init_agent_accounts = __esm({
|
|
27656
|
+
"../../server/routes/agent-accounts.ts"() {
|
|
27657
|
+
init_agent_descriptors();
|
|
27658
|
+
init_accounts();
|
|
27659
|
+
init_http();
|
|
27660
|
+
}
|
|
27661
|
+
});
|
|
27662
|
+
|
|
27052
27663
|
// ../../server/routes/scripts/discovery.ts
|
|
27053
|
-
import { readdir as readdir12, readFile as
|
|
27054
|
-
import { join as
|
|
27664
|
+
import { readdir as readdir12, readFile as readFile21 } from "node:fs/promises";
|
|
27665
|
+
import { join as join27, relative as relative10 } from "node:path";
|
|
27055
27666
|
async function extractScripts(dir, dirLabel) {
|
|
27056
27667
|
try {
|
|
27057
|
-
const raw = await
|
|
27668
|
+
const raw = await readFile21(join27(dir, "package.json"), "utf-8");
|
|
27058
27669
|
const pkg = JSON.parse(raw);
|
|
27059
27670
|
const scripts = pkg.scripts;
|
|
27060
27671
|
if (!scripts || typeof scripts !== "object") return [];
|
|
@@ -27080,7 +27691,7 @@ async function discoverScripts(projectDir) {
|
|
|
27080
27691
|
);
|
|
27081
27692
|
const childResults = await Promise.all(
|
|
27082
27693
|
childDirs.map(async (entry) => {
|
|
27083
|
-
const childPath =
|
|
27694
|
+
const childPath = join27(projectDir, entry.name);
|
|
27084
27695
|
const label = relative10(projectDir, childPath) + "/";
|
|
27085
27696
|
return extractScripts(childPath, label);
|
|
27086
27697
|
})
|
|
@@ -27266,12 +27877,12 @@ var init_session_config = __esm({
|
|
|
27266
27877
|
|
|
27267
27878
|
// ../../server/lib/agentTeamIdentity.ts
|
|
27268
27879
|
import { open as open9, readdir as readdir13 } from "node:fs/promises";
|
|
27269
|
-
import { join as
|
|
27880
|
+
import { join as join28 } from "node:path";
|
|
27270
27881
|
async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
|
|
27271
27882
|
const entries3 = await readdir13(dirs.PROJECTS_DIR, { withFileTypes: true });
|
|
27272
27883
|
for (const entry of entries3) {
|
|
27273
27884
|
if (!entry.isDirectory() || entry.name === "memory") continue;
|
|
27274
|
-
const filePath =
|
|
27885
|
+
const filePath = join28(
|
|
27275
27886
|
dirs.PROJECTS_DIR,
|
|
27276
27887
|
entry.name,
|
|
27277
27888
|
leadSessionId,
|
|
@@ -27312,8 +27923,8 @@ async function readSessionTeamTags(filePath) {
|
|
|
27312
27923
|
try {
|
|
27313
27924
|
const buf = Buffer.alloc(32768);
|
|
27314
27925
|
const { bytesRead } = await fh.read(buf, 0, 32768, 0);
|
|
27315
|
-
const
|
|
27316
|
-
const lines =
|
|
27926
|
+
const text2 = buf.subarray(0, bytesRead).toString("utf-8");
|
|
27927
|
+
const lines = text2.split("\n");
|
|
27317
27928
|
const complete = bytesRead === 32768 ? lines.slice(0, -1) : lines;
|
|
27318
27929
|
for (const line of complete.slice(0, 40)) {
|
|
27319
27930
|
if (!line || !line.includes('"teamName"')) continue;
|
|
@@ -27479,8 +28090,8 @@ function mapToolCall(tc) {
|
|
|
27479
28090
|
function mapContentBlock(block) {
|
|
27480
28091
|
switch (block.kind) {
|
|
27481
28092
|
case "thinking": {
|
|
27482
|
-
const
|
|
27483
|
-
return { kind: "thinking", text, timestamp: block.timestamp ?? null };
|
|
28093
|
+
const text2 = block.blocks.filter((b) => b.thinking.length > 0).map((b) => b.thinking).join("\n\n");
|
|
28094
|
+
return { kind: "thinking", text: text2, timestamp: block.timestamp ?? null };
|
|
27484
28095
|
}
|
|
27485
28096
|
case "text":
|
|
27486
28097
|
return { kind: "text", text: block.text.join("\n\n"), timestamp: block.timestamp ?? null };
|
|
@@ -27548,9 +28159,9 @@ async function findTeamContext(sessionId, subagentFileName) {
|
|
|
27548
28159
|
const teamEntries = await readdir6(dirs.TEAMS_DIR, { withFileTypes: true });
|
|
27549
28160
|
for (const entry of teamEntries) {
|
|
27550
28161
|
if (!entry.isDirectory()) continue;
|
|
27551
|
-
const
|
|
28162
|
+
const configPath2 = join11(dirs.TEAMS_DIR, entry.name, "config.json");
|
|
27552
28163
|
try {
|
|
27553
|
-
const raw = await readFile9(
|
|
28164
|
+
const raw = await readFile9(configPath2, "utf-8");
|
|
27554
28165
|
const config = JSON.parse(raw);
|
|
27555
28166
|
if (config.leadSessionId !== sessionId) continue;
|
|
27556
28167
|
const members = config.members ?? [];
|
|
@@ -27786,14 +28397,14 @@ function cdTarget(segment, cwd) {
|
|
|
27786
28397
|
if (!m) return null;
|
|
27787
28398
|
return resolvePath(m[1] ?? m[2] ?? m[3] ?? "", cwd);
|
|
27788
28399
|
}
|
|
27789
|
-
function writeTarget(
|
|
27790
|
-
const tee =
|
|
28400
|
+
function writeTarget(text2) {
|
|
28401
|
+
const tee = text2.match(/^tee\s+(?:(-a)\s+)?(?:"([^"]+)"|'([^']+)'|([^\s<>|;&]+))/);
|
|
27791
28402
|
if (tee) {
|
|
27792
28403
|
if (tee[1]) return null;
|
|
27793
28404
|
return tee[2] ?? tee[3] ?? tee[4] ?? null;
|
|
27794
28405
|
}
|
|
27795
|
-
if (!/^cat\b/.test(
|
|
27796
|
-
const redirect =
|
|
28406
|
+
if (!/^cat\b/.test(text2)) return null;
|
|
28407
|
+
const redirect = text2.match(/(>>?)\s*(?:"([^"]+)"|'([^']+)'|([^\s<>|;&]+))/);
|
|
27797
28408
|
if (!redirect || redirect[1] === ">>") return null;
|
|
27798
28409
|
return redirect[2] ?? redirect[3] ?? redirect[4] ?? null;
|
|
27799
28410
|
}
|
|
@@ -27964,7 +28575,7 @@ function normalizeCopilotFileChangeEvents(jsonlContent) {
|
|
|
27964
28575
|
}
|
|
27965
28576
|
});
|
|
27966
28577
|
}
|
|
27967
|
-
return records.map((
|
|
28578
|
+
return records.map((record5) => JSON.stringify(record5)).join("\n");
|
|
27968
28579
|
}
|
|
27969
28580
|
async function parseSessionFileChanges(jsonlContent, includeContent) {
|
|
27970
28581
|
if (formatForText(jsonlContent).kind === "copilot") {
|
|
@@ -28034,8 +28645,8 @@ async function parseSessionFileChanges(jsonlContent, includeContent) {
|
|
|
28034
28645
|
if (payload.type === "custom_tool_call_output" && typeof payload.call_id === "string") {
|
|
28035
28646
|
const patchCalls = patchCallIds.get(payload.call_id);
|
|
28036
28647
|
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(
|
|
28648
|
+
const { text: text2, isError: wrapperIsError } = parseCustomToolOutput(payload.output);
|
|
28649
|
+
const failedIds = patchCalls.direct && wrapperIsError ? new Set(patchCalls.calls.map((call) => call.id)) : findFailedNestedPatchCallIds(text2, wrapperIsError, patchCalls.calls);
|
|
28039
28650
|
for (const call of patchCalls.calls) resultMap.set(call.id, failedIds.has(call.id));
|
|
28040
28651
|
}
|
|
28041
28652
|
}
|
|
@@ -28272,7 +28883,7 @@ var init_session_status = __esm({
|
|
|
28272
28883
|
});
|
|
28273
28884
|
|
|
28274
28885
|
// ../../server/routes/shares.ts
|
|
28275
|
-
import { basename as basename11, dirname as
|
|
28886
|
+
import { basename as basename11, dirname as dirname12 } from "node:path";
|
|
28276
28887
|
function remoteAccessEnabled() {
|
|
28277
28888
|
return isTeamEdition() || getConfig()?.networkAccess === true;
|
|
28278
28889
|
}
|
|
@@ -28287,7 +28898,7 @@ async function resolveShareTarget(sessionId) {
|
|
|
28287
28898
|
if (agentKind === "codex" || agentKind === "copilot") {
|
|
28288
28899
|
return { shareable: false, reason: agentKind };
|
|
28289
28900
|
}
|
|
28290
|
-
const dirName = basename11(
|
|
28901
|
+
const dirName = basename11(dirname12(filePath));
|
|
28291
28902
|
const fileName = basename11(filePath);
|
|
28292
28903
|
const resolved = await resolveSessionFilePath(dirName, fileName);
|
|
28293
28904
|
if (resolved !== filePath) return { shareable: false, reason: "not-found" };
|
|
@@ -28693,7 +29304,7 @@ async function readBodyOrRespond(req, res) {
|
|
|
28693
29304
|
return null;
|
|
28694
29305
|
}
|
|
28695
29306
|
}
|
|
28696
|
-
function
|
|
29307
|
+
function asString3(value) {
|
|
28697
29308
|
return typeof value === "string" ? value : "";
|
|
28698
29309
|
}
|
|
28699
29310
|
function enqueueBootstrap(operation) {
|
|
@@ -28754,8 +29365,8 @@ function registerTeamAdminRoutes(use) {
|
|
|
28754
29365
|
}
|
|
28755
29366
|
try {
|
|
28756
29367
|
const user = await createUser({
|
|
28757
|
-
username:
|
|
28758
|
-
password:
|
|
29368
|
+
username: asString3(body.username),
|
|
29369
|
+
password: asString3(body.password),
|
|
28759
29370
|
displayName: typeof body.displayName === "string" ? body.displayName : void 0,
|
|
28760
29371
|
role: "admin"
|
|
28761
29372
|
});
|
|
@@ -28787,10 +29398,10 @@ function registerTeamAdminRoutes(use) {
|
|
|
28787
29398
|
if (body === null) return;
|
|
28788
29399
|
try {
|
|
28789
29400
|
const user = await createUser({
|
|
28790
|
-
username:
|
|
28791
|
-
password:
|
|
29401
|
+
username: asString3(body.username),
|
|
29402
|
+
password: asString3(body.password),
|
|
28792
29403
|
displayName: typeof body.displayName === "string" ? body.displayName : void 0,
|
|
28793
|
-
role:
|
|
29404
|
+
role: asString3(body.role)
|
|
28794
29405
|
});
|
|
28795
29406
|
return sendJson(res, 200, { user });
|
|
28796
29407
|
} catch (error) {
|
|
@@ -28883,10 +29494,10 @@ async function detectTeamFromSessionFile(sessionId, dirNameHint) {
|
|
|
28883
29494
|
if (!isWithinDir(dirs.PROJECTS_DIR, filePath)) continue;
|
|
28884
29495
|
const tags = await readSessionTeamTags(filePath);
|
|
28885
29496
|
if (!tags.teamName) continue;
|
|
28886
|
-
const
|
|
28887
|
-
if (!isWithinDir(dirs.TEAMS_DIR,
|
|
29497
|
+
const configPath2 = join11(dirs.TEAMS_DIR, tags.teamName, "config.json");
|
|
29498
|
+
if (!isWithinDir(dirs.TEAMS_DIR, configPath2)) continue;
|
|
28888
29499
|
try {
|
|
28889
|
-
const config = JSON.parse(await readFile9(
|
|
29500
|
+
const config = JSON.parse(await readFile9(configPath2, "utf-8"));
|
|
28890
29501
|
return {
|
|
28891
29502
|
teamName: tags.teamName,
|
|
28892
29503
|
config,
|
|
@@ -28965,8 +29576,8 @@ function registerTeamSessionRoutes(use) {
|
|
|
28965
29576
|
let bestMatch = null;
|
|
28966
29577
|
for (const teamName of teamDirs) {
|
|
28967
29578
|
try {
|
|
28968
|
-
const
|
|
28969
|
-
const configRaw = await readFile9(
|
|
29579
|
+
const configPath2 = join11(dirs.TEAMS_DIR, teamName, "config.json");
|
|
29580
|
+
const configRaw = await readFile9(configPath2, "utf-8");
|
|
28970
29581
|
const config = JSON.parse(configRaw);
|
|
28971
29582
|
if (config.leadSessionId !== leadSessionId) continue;
|
|
28972
29583
|
const createdAt = config.createdAt ?? 0;
|
|
@@ -29020,8 +29631,8 @@ function registerTeamSessionRoutes(use) {
|
|
|
29020
29631
|
const teamName = decodeURIComponent(parts[0]);
|
|
29021
29632
|
const memberName = decodeURIComponent(parts[1]);
|
|
29022
29633
|
try {
|
|
29023
|
-
const
|
|
29024
|
-
const configRaw = await readFile9(
|
|
29634
|
+
const configPath2 = join11(dirs.TEAMS_DIR, teamName, "config.json");
|
|
29635
|
+
const configRaw = await readFile9(configPath2, "utf-8");
|
|
29025
29636
|
const config = JSON.parse(configRaw);
|
|
29026
29637
|
const leadSessionId = config.leadSessionId;
|
|
29027
29638
|
if (!leadSessionId) {
|
|
@@ -29152,8 +29763,8 @@ function registerTeamRoutes(use) {
|
|
|
29152
29763
|
const teams = [];
|
|
29153
29764
|
for (const teamName of teamDirs) {
|
|
29154
29765
|
try {
|
|
29155
|
-
const
|
|
29156
|
-
const configRaw = await readFile9(
|
|
29766
|
+
const configPath2 = join11(dirs.TEAMS_DIR, teamName, "config.json");
|
|
29767
|
+
const configRaw = await readFile9(configPath2, "utf-8");
|
|
29157
29768
|
const config = JSON.parse(configRaw);
|
|
29158
29769
|
const taskSummary = { total: 0, completed: 0, inProgress: 0, pending: 0 };
|
|
29159
29770
|
try {
|
|
@@ -29352,7 +29963,7 @@ var init_teams = __esm({
|
|
|
29352
29963
|
});
|
|
29353
29964
|
|
|
29354
29965
|
// ../../server/routes/undo/paths.ts
|
|
29355
|
-
import { dirname as
|
|
29966
|
+
import { dirname as dirname13 } from "node:path";
|
|
29356
29967
|
function isOpaqueFileName(value) {
|
|
29357
29968
|
return value.length > 0 && !value.includes("/") && !value.includes("\\") && !value.includes("\0");
|
|
29358
29969
|
}
|
|
@@ -29360,7 +29971,7 @@ function resolveUndoStatePath(sessionId) {
|
|
|
29360
29971
|
if (!isOpaqueFileName(sessionId)) return null;
|
|
29361
29972
|
const undoRoot = resolve7(dirs.UNDO_DIR);
|
|
29362
29973
|
const filePath = resolve7(undoRoot, `${sessionId}.json`);
|
|
29363
|
-
return isWithinDir(undoRoot, filePath) &&
|
|
29974
|
+
return isWithinDir(undoRoot, filePath) && dirname13(filePath) === undoRoot ? filePath : null;
|
|
29364
29975
|
}
|
|
29365
29976
|
function resolveEncodedUndoStatePath(encodedSessionId) {
|
|
29366
29977
|
try {
|
|
@@ -29384,7 +29995,7 @@ var init_paths = __esm({
|
|
|
29384
29995
|
});
|
|
29385
29996
|
|
|
29386
29997
|
// ../../server/routes/undo/fileOperations.ts
|
|
29387
|
-
import { basename as basename12, dirname as
|
|
29998
|
+
import { basename as basename12, dirname as dirname14, isAbsolute as isAbsolute13 } from "node:path";
|
|
29388
29999
|
import { lstat as lstat6, realpath as realpath13 } from "node:fs/promises";
|
|
29389
30000
|
function hasTraversalSegment(filePath) {
|
|
29390
30001
|
return filePath.split(/[\\/]+/).includes("..");
|
|
@@ -29409,7 +30020,7 @@ async function resolveSafeOperationPath(filePath, home, canonicalHome) {
|
|
|
29409
30020
|
} catch (error) {
|
|
29410
30021
|
if (!isMissingPathError(error)) return null;
|
|
29411
30022
|
try {
|
|
29412
|
-
const canonicalParent = await realpath13(
|
|
30023
|
+
const canonicalParent = await realpath13(dirname14(resolved));
|
|
29413
30024
|
const canonicalTarget = join11(canonicalParent, basename12(resolved));
|
|
29414
30025
|
return isWithinDir(canonicalHome, canonicalTarget) && !isForbiddenPath(canonicalTarget) ? canonicalTarget : null;
|
|
29415
30026
|
} catch {
|
|
@@ -30044,25 +30655,25 @@ function aggregateSessionUsage(scopedRecords, rates2) {
|
|
|
30044
30655
|
let providerReportedRecords = 0;
|
|
30045
30656
|
let modelPricedRecords = 0;
|
|
30046
30657
|
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,
|
|
30658
|
+
for (const { record: record5, isSubagent } of scopedRecords) {
|
|
30659
|
+
if (record5.dedupeKey !== null) {
|
|
30660
|
+
if (seen.has(record5.dedupeKey)) continue;
|
|
30661
|
+
seen.add(record5.dedupeKey);
|
|
30662
|
+
}
|
|
30663
|
+
const priced = priceUsage(rates2, record5.model, record5.totals, record5.reportedCostUsd, record5.speed);
|
|
30664
|
+
const recordSavings = cacheSavingsUsd(rates2, record5.model, record5.totals, record5.speed);
|
|
30665
|
+
const calculated = usageCostBreakdown(rates2, record5.model, record5.totals, record5.speed);
|
|
30666
|
+
totals = addUsageCostTotals(totals, record5.totals);
|
|
30056
30667
|
costUsd += priced.costUsd;
|
|
30057
30668
|
cacheSavings += recordSavings;
|
|
30058
30669
|
addRecordCostBreakdown(breakdown, calculated, priced.costUsd);
|
|
30059
30670
|
if (priced.costSource === "providerReported") providerReportedRecords += 1;
|
|
30060
30671
|
else if (priced.costSource === "modelPriced") modelPricedRecords += 1;
|
|
30061
30672
|
else unpricedRecords += 1;
|
|
30062
|
-
let model = models.get(
|
|
30673
|
+
let model = models.get(record5.model);
|
|
30063
30674
|
if (!model) {
|
|
30064
30675
|
model = {
|
|
30065
|
-
model:
|
|
30676
|
+
model: record5.model,
|
|
30066
30677
|
totals: emptyUsageCostTotals(),
|
|
30067
30678
|
costUsd: 0,
|
|
30068
30679
|
cacheSavingsUsd: 0,
|
|
@@ -30070,18 +30681,18 @@ function aggregateSessionUsage(scopedRecords, rates2) {
|
|
|
30070
30681
|
providerReportedRecords: 0,
|
|
30071
30682
|
unpricedRecords: 0
|
|
30072
30683
|
};
|
|
30073
|
-
models.set(
|
|
30684
|
+
models.set(record5.model, model);
|
|
30074
30685
|
}
|
|
30075
|
-
model.totals = addUsageCostTotals(model.totals,
|
|
30686
|
+
model.totals = addUsageCostTotals(model.totals, record5.totals);
|
|
30076
30687
|
model.costUsd += priced.costUsd;
|
|
30077
30688
|
model.cacheSavingsUsd += recordSavings;
|
|
30078
30689
|
model.records += 1;
|
|
30079
30690
|
if (priced.costSource === "providerReported") model.providerReportedRecords += 1;
|
|
30080
30691
|
if (priced.costSource === "unpriced") model.unpricedRecords += 1;
|
|
30081
30692
|
calls.push({
|
|
30082
|
-
timestamp: new Date(
|
|
30083
|
-
model:
|
|
30084
|
-
totals:
|
|
30693
|
+
timestamp: new Date(record5.timestampMs).toISOString(),
|
|
30694
|
+
model: record5.model,
|
|
30695
|
+
totals: record5.totals,
|
|
30085
30696
|
costUsd: priced.costUsd,
|
|
30086
30697
|
costSource: priced.costSource,
|
|
30087
30698
|
isSubagent
|
|
@@ -30126,20 +30737,20 @@ var init_aggregate = __esm({
|
|
|
30126
30737
|
this.#toDay = makeDayFormatter(options.timeZone);
|
|
30127
30738
|
}
|
|
30128
30739
|
/** Folds one record in; returns whether it actually contributed. */
|
|
30129
|
-
add(
|
|
30130
|
-
if (
|
|
30131
|
-
if (this.#seen.has(
|
|
30132
|
-
this.#seen.add(
|
|
30740
|
+
add(record5) {
|
|
30741
|
+
if (record5.dedupeKey !== null) {
|
|
30742
|
+
if (this.#seen.has(record5.dedupeKey)) return false;
|
|
30743
|
+
this.#seen.add(record5.dedupeKey);
|
|
30133
30744
|
}
|
|
30134
|
-
const day = this.#toDay(
|
|
30745
|
+
const day = this.#toDay(record5.timestampMs);
|
|
30135
30746
|
if (day < this.#options.sinceDay || day > this.#options.untilDay) return false;
|
|
30136
|
-
const key2 = [day,
|
|
30747
|
+
const key2 = [day, record5.provider, record5.model].join(KEY_SEPARATOR);
|
|
30137
30748
|
let bucket = this.#buckets.get(key2);
|
|
30138
30749
|
if (bucket === void 0) {
|
|
30139
30750
|
bucket = {
|
|
30140
30751
|
day,
|
|
30141
|
-
provider:
|
|
30142
|
-
model:
|
|
30752
|
+
provider: record5.provider,
|
|
30753
|
+
model: record5.model,
|
|
30143
30754
|
totals: emptyUsageCostTotals(),
|
|
30144
30755
|
costUsd: 0,
|
|
30145
30756
|
cacheSavingsUsd: 0,
|
|
@@ -30152,25 +30763,25 @@ var init_aggregate = __esm({
|
|
|
30152
30763
|
}
|
|
30153
30764
|
const priced = priceUsage(
|
|
30154
30765
|
this.#options.rates,
|
|
30155
|
-
|
|
30156
|
-
|
|
30157
|
-
|
|
30158
|
-
|
|
30766
|
+
record5.model,
|
|
30767
|
+
record5.totals,
|
|
30768
|
+
record5.reportedCostUsd,
|
|
30769
|
+
record5.speed
|
|
30159
30770
|
);
|
|
30160
|
-
bucket.totals = addUsageCostTotals(bucket.totals,
|
|
30771
|
+
bucket.totals = addUsageCostTotals(bucket.totals, record5.totals);
|
|
30161
30772
|
bucket.costUsd += priced.costUsd;
|
|
30162
30773
|
bucket.cacheSavingsUsd += cacheSavingsUsd(
|
|
30163
30774
|
this.#options.rates,
|
|
30164
|
-
|
|
30165
|
-
|
|
30166
|
-
|
|
30775
|
+
record5.model,
|
|
30776
|
+
record5.totals,
|
|
30777
|
+
record5.speed
|
|
30167
30778
|
);
|
|
30168
30779
|
bucket.records += 1;
|
|
30169
30780
|
if (priced.costSource === "unpriced") bucket.unpricedRecords += 1;
|
|
30170
30781
|
if (priced.costSource === "providerReported") bucket.providerReportedRecords += 1;
|
|
30171
|
-
if (
|
|
30172
|
-
bucket.sessions.add(
|
|
30173
|
-
this.#sessions.add(
|
|
30782
|
+
if (record5.sessionId.length > 0) {
|
|
30783
|
+
bucket.sessions.add(record5.sessionId);
|
|
30784
|
+
this.#sessions.add(record5.sessionId);
|
|
30174
30785
|
}
|
|
30175
30786
|
return true;
|
|
30176
30787
|
}
|
|
@@ -30201,7 +30812,7 @@ var init_aggregate = __esm({
|
|
|
30201
30812
|
// ../../server/lib/usageCost/reader.ts
|
|
30202
30813
|
import { createReadStream as createReadStream3 } from "node:fs";
|
|
30203
30814
|
import { readdir as readdir14, stat as stat19 } from "node:fs/promises";
|
|
30204
|
-
import { join as
|
|
30815
|
+
import { join as join29 } from "node:path";
|
|
30205
30816
|
import { createInterface as createInterface3 } from "node:readline";
|
|
30206
30817
|
async function listTranscriptFiles(root, sinceMs) {
|
|
30207
30818
|
const found = [];
|
|
@@ -30213,7 +30824,7 @@ async function listTranscriptFiles(root, sinceMs) {
|
|
|
30213
30824
|
return;
|
|
30214
30825
|
}
|
|
30215
30826
|
for (const entry of entries3) {
|
|
30216
|
-
const child =
|
|
30827
|
+
const child = join29(dir, entry.name);
|
|
30217
30828
|
if (entry.isDirectory()) {
|
|
30218
30829
|
await walk2(child);
|
|
30219
30830
|
continue;
|
|
@@ -30251,17 +30862,17 @@ async function readTranscriptRecords(filePath, provider) {
|
|
|
30251
30862
|
function dedupeWithinFile(records) {
|
|
30252
30863
|
const slotByKey = /* @__PURE__ */ new Map();
|
|
30253
30864
|
const kept = [];
|
|
30254
|
-
for (const
|
|
30255
|
-
if (
|
|
30256
|
-
kept.push(
|
|
30865
|
+
for (const record5 of records) {
|
|
30866
|
+
if (record5.dedupeKey === null) {
|
|
30867
|
+
kept.push(record5);
|
|
30257
30868
|
continue;
|
|
30258
30869
|
}
|
|
30259
|
-
const slot = slotByKey.get(
|
|
30870
|
+
const slot = slotByKey.get(record5.dedupeKey);
|
|
30260
30871
|
if (slot === void 0) {
|
|
30261
|
-
slotByKey.set(
|
|
30872
|
+
slotByKey.set(record5.dedupeKey, kept.push(record5) - 1);
|
|
30262
30873
|
continue;
|
|
30263
30874
|
}
|
|
30264
|
-
if (
|
|
30875
|
+
if (record5.totals.outputTokens > kept[slot].totals.outputTokens) kept[slot] = record5;
|
|
30265
30876
|
}
|
|
30266
30877
|
return kept;
|
|
30267
30878
|
}
|
|
@@ -30272,10 +30883,10 @@ var init_reader = __esm({
|
|
|
30272
30883
|
});
|
|
30273
30884
|
|
|
30274
30885
|
// ../../server/lib/usageCost/service.ts
|
|
30275
|
-
import { readFile as
|
|
30276
|
-
import { join as
|
|
30886
|
+
import { readFile as readFile22, stat as stat20, writeFile as writeFile7 } from "node:fs/promises";
|
|
30887
|
+
import { join as join30 } from "node:path";
|
|
30277
30888
|
function ratesCachePath() {
|
|
30278
|
-
return
|
|
30889
|
+
return join30(getDataRoot(), "usage-model-rates.json");
|
|
30279
30890
|
}
|
|
30280
30891
|
function ratesFetchedAt() {
|
|
30281
30892
|
return ratesFetchedAtMs === null ? null : new Date(ratesFetchedAtMs).toISOString();
|
|
@@ -30285,7 +30896,7 @@ async function ensureRatesInner() {
|
|
|
30285
30896
|
if (ratesFetchedAtMs !== null && now - ratesFetchedAtMs < RATES_TTL_MS) return;
|
|
30286
30897
|
if (ratesFetchedAtMs === null) {
|
|
30287
30898
|
try {
|
|
30288
|
-
const raw = JSON.parse(await
|
|
30899
|
+
const raw = JSON.parse(await readFile22(ratesCachePath(), "utf8"));
|
|
30289
30900
|
if (typeof raw.fetchedAtMs === "number") {
|
|
30290
30901
|
const parsed2 = parseRateTable(raw.document);
|
|
30291
30902
|
if (parsed2.size > 0) {
|
|
@@ -30341,13 +30952,13 @@ async function readFileRecords(file, provider) {
|
|
|
30341
30952
|
fileCache2.set(file.path, { size: file.size, mtimeMs: file.mtimeMs, provider, records });
|
|
30342
30953
|
return records;
|
|
30343
30954
|
}
|
|
30344
|
-
function addCountedUsage(counted,
|
|
30345
|
-
const byModel = counted.get(
|
|
30955
|
+
function addCountedUsage(counted, record5) {
|
|
30956
|
+
const byModel = counted.get(record5.sessionId) ?? /* @__PURE__ */ new Map();
|
|
30346
30957
|
byModel.set(
|
|
30347
|
-
|
|
30348
|
-
addUsageCostTotals(byModel.get(
|
|
30958
|
+
record5.model,
|
|
30959
|
+
addUsageCostTotals(byModel.get(record5.model) ?? emptyUsageCostTotals(), record5.totals)
|
|
30349
30960
|
);
|
|
30350
|
-
counted.set(
|
|
30961
|
+
counted.set(record5.sessionId, byModel);
|
|
30351
30962
|
}
|
|
30352
30963
|
function makeWindow(days, timeZone, nowMs = Date.now()) {
|
|
30353
30964
|
const toDay = makeDayFormatter(timeZone);
|
|
@@ -30378,14 +30989,14 @@ async function readUsageCostSummary(input) {
|
|
|
30378
30989
|
for (const file of files) {
|
|
30379
30990
|
const records = await readFileRecords(file, provider);
|
|
30380
30991
|
scannedFiles += 1;
|
|
30381
|
-
for (const
|
|
30382
|
-
aggregator.add(
|
|
30383
|
-
if (liveSessionIds.has(
|
|
30992
|
+
for (const record5 of records) {
|
|
30993
|
+
aggregator.add(record5);
|
|
30994
|
+
if (liveSessionIds.has(record5.sessionId)) addCountedUsage(durableTotals, record5);
|
|
30384
30995
|
}
|
|
30385
30996
|
}
|
|
30386
30997
|
}
|
|
30387
30998
|
for (const runtime of runtimes2) {
|
|
30388
|
-
for (const
|
|
30999
|
+
for (const record5 of await runtime.liveUsageRecords(durableTotals)) aggregator.add(record5);
|
|
30389
31000
|
}
|
|
30390
31001
|
const retentionCutoffMs = startedAtMs - 90 * 24 * 60 * 60 * 1e3;
|
|
30391
31002
|
for (const [path, entry] of fileCache2) {
|
|
@@ -30450,8 +31061,8 @@ async function childTranscripts(dirName, rootSessionId, provider) {
|
|
|
30450
31061
|
}
|
|
30451
31062
|
function countedUsageBySession(scopedRecords) {
|
|
30452
31063
|
const counted = /* @__PURE__ */ new Map();
|
|
30453
|
-
for (const { record:
|
|
30454
|
-
if (
|
|
31064
|
+
for (const { record: record5 } of scopedRecords) {
|
|
31065
|
+
if (record5.sessionId) addCountedUsage(counted, record5);
|
|
30455
31066
|
}
|
|
30456
31067
|
return counted;
|
|
30457
31068
|
}
|
|
@@ -30465,7 +31076,7 @@ async function readSessionUsageCostSummary(input) {
|
|
|
30465
31076
|
const store = storeForDirName(input.dirName);
|
|
30466
31077
|
const provider = store.kind;
|
|
30467
31078
|
const directRecords = await readFileRecords(directFile, provider);
|
|
30468
|
-
const sessionId = store.descriptor.sessionFile.sessionId(input.fileName) ?? directRecords.find((
|
|
31079
|
+
const sessionId = store.descriptor.sessionFile.sessionId(input.fileName) ?? directRecords.find((record5) => record5.sessionId.length > 0)?.sessionId ?? "";
|
|
30469
31080
|
const files = [
|
|
30470
31081
|
{ file: directFile, isSubagent: isSubagentAddress(input.fileName) }
|
|
30471
31082
|
];
|
|
@@ -30479,19 +31090,19 @@ async function readSessionUsageCostSummary(input) {
|
|
|
30479
31090
|
records: await readFileRecords(file, provider)
|
|
30480
31091
|
})));
|
|
30481
31092
|
const scopedRecords = recordsByFile.flatMap(
|
|
30482
|
-
({ records, isSubagent }) => records.map((
|
|
31093
|
+
({ records, isSubagent }) => records.map((record5) => ({ record: record5, isSubagent }))
|
|
30483
31094
|
);
|
|
30484
31095
|
const sessionIds = /* @__PURE__ */ new Set();
|
|
30485
|
-
for (const { record:
|
|
30486
|
-
if (
|
|
31096
|
+
for (const { record: record5 } of scopedRecords) {
|
|
31097
|
+
if (record5.sessionId) sessionIds.add(record5.sessionId);
|
|
30487
31098
|
}
|
|
30488
31099
|
if (sessionId) sessionIds.add(sessionId);
|
|
30489
31100
|
const runtime = runtimeFor(provider);
|
|
30490
31101
|
if ([...sessionIds].some((id) => runtime.hasSession(id))) {
|
|
30491
31102
|
const liveRecords = await runtime.liveUsageRecords(countedUsageBySession(scopedRecords));
|
|
30492
|
-
for (const
|
|
30493
|
-
if (!sessionIds.has(
|
|
30494
|
-
scopedRecords.push({ record:
|
|
31103
|
+
for (const record5 of liveRecords) {
|
|
31104
|
+
if (!sessionIds.has(record5.sessionId)) continue;
|
|
31105
|
+
scopedRecords.push({ record: record5, isSubagent: record5.sessionId !== sessionId });
|
|
30495
31106
|
}
|
|
30496
31107
|
}
|
|
30497
31108
|
const aggregated = aggregateSessionUsage(scopedRecords, rates);
|
|
@@ -31286,7 +31897,7 @@ var init_worktreeIo = __esm({
|
|
|
31286
31897
|
});
|
|
31287
31898
|
|
|
31288
31899
|
// ../../server/routes/worktrees/worktreeUtils.ts
|
|
31289
|
-
import { resolve as resolve20, dirname as
|
|
31900
|
+
import { resolve as resolve20, dirname as dirname15 } from "node:path";
|
|
31290
31901
|
function isValidWorktreeName(name) {
|
|
31291
31902
|
return /^[a-zA-Z0-9._-]+$/.test(name) && name.length <= 40;
|
|
31292
31903
|
}
|
|
@@ -31322,7 +31933,7 @@ async function readFirstJsonLine(filePath) {
|
|
|
31322
31933
|
await fileHandle.close();
|
|
31323
31934
|
}
|
|
31324
31935
|
}
|
|
31325
|
-
async function
|
|
31936
|
+
async function resolveProjectPath3(projectDir, dirName) {
|
|
31326
31937
|
try {
|
|
31327
31938
|
const files = await readdir6(projectDir);
|
|
31328
31939
|
const sessionFiles = files.filter((file) => file.endsWith(".jsonl"));
|
|
@@ -31349,7 +31960,7 @@ async function getMainWorktreeRoot(projectPath) {
|
|
|
31349
31960
|
const commonDir = (await runWorktreeCommand("git", ["rev-parse", "--git-common-dir"], {
|
|
31350
31961
|
cwd: projectPath
|
|
31351
31962
|
})).trim();
|
|
31352
|
-
return
|
|
31963
|
+
return dirname15(resolve20(projectPath, commonDir));
|
|
31353
31964
|
} catch {
|
|
31354
31965
|
return null;
|
|
31355
31966
|
}
|
|
@@ -31512,7 +32123,7 @@ async function handleWorktreeList(dirName, res) {
|
|
|
31512
32123
|
res.end(JSON.stringify({ error: "Access denied" }));
|
|
31513
32124
|
return;
|
|
31514
32125
|
}
|
|
31515
|
-
const projectPath = await
|
|
32126
|
+
const projectPath = await resolveProjectPath3(projectDir, dirName);
|
|
31516
32127
|
const gitRoot = await getMainWorktreeRoot(projectPath);
|
|
31517
32128
|
if (!gitRoot) {
|
|
31518
32129
|
res.setHeader("Content-Type", "application/json");
|
|
@@ -31601,7 +32212,7 @@ function requireProjectDir(dirName, res) {
|
|
|
31601
32212
|
return projectDir;
|
|
31602
32213
|
}
|
|
31603
32214
|
async function requireGitRoot(projectDir, dirName, res) {
|
|
31604
|
-
const projectPath = await
|
|
32215
|
+
const projectPath = await resolveProjectPath3(projectDir, dirName);
|
|
31605
32216
|
const gitRoot = await getMainWorktreeRoot(projectPath);
|
|
31606
32217
|
if (!gitRoot) {
|
|
31607
32218
|
res.statusCode = 400;
|
|
@@ -31834,8 +32445,8 @@ function apiRoute(id, register) {
|
|
|
31834
32445
|
function registerApiRoutes(use, context) {
|
|
31835
32446
|
const safeUse = (path, handler) => use(path, catchAsyncErrors(handler));
|
|
31836
32447
|
safeUse("/api", compressionMiddleware);
|
|
31837
|
-
for (const
|
|
31838
|
-
|
|
32448
|
+
for (const route2 of API_ROUTE_REGISTRY) {
|
|
32449
|
+
route2.register(safeUse, context);
|
|
31839
32450
|
}
|
|
31840
32451
|
}
|
|
31841
32452
|
var API_ROUTE_REGISTRY;
|
|
@@ -31863,6 +32474,7 @@ var init_api_routes = __esm({
|
|
|
31863
32474
|
init_git_status();
|
|
31864
32475
|
init_github();
|
|
31865
32476
|
init_vercel_deployments();
|
|
32477
|
+
init_clickup();
|
|
31866
32478
|
init_project_icon();
|
|
31867
32479
|
init_hello();
|
|
31868
32480
|
init_local_file();
|
|
@@ -31878,6 +32490,7 @@ var init_api_routes = __esm({
|
|
|
31878
32490
|
init_projects2();
|
|
31879
32491
|
init_provider_updates();
|
|
31880
32492
|
init_agent_executable();
|
|
32493
|
+
init_agent_accounts();
|
|
31881
32494
|
init_scripts();
|
|
31882
32495
|
init_session_config();
|
|
31883
32496
|
init_session_context();
|
|
@@ -31934,6 +32547,7 @@ var init_api_routes = __esm({
|
|
|
31934
32547
|
apiRoute("git-status", registerGitStatusRoutes),
|
|
31935
32548
|
apiRoute("github", registerGitHubRoutes),
|
|
31936
32549
|
apiRoute("vercel-deployments", registerVercelDeploymentRoutes),
|
|
32550
|
+
apiRoute("clickup", registerClickUpRoutes),
|
|
31937
32551
|
apiRoute("project-icon", registerProjectIconRoutes),
|
|
31938
32552
|
apiRoute("git-diff", registerGitDiffRoutes),
|
|
31939
32553
|
apiRoute("mcp", registerMcpRoutes),
|
|
@@ -31948,7 +32562,8 @@ var init_api_routes = __esm({
|
|
|
31948
32562
|
apiRoute("codex-threads", registerCodexThreadRoutes),
|
|
31949
32563
|
apiRoute("agent-runtime", registerAgentRuntimeRoutes),
|
|
31950
32564
|
apiRoute("provider-updates", registerProviderUpdateRoutes),
|
|
31951
|
-
apiRoute("agent-executable", registerAgentExecutableRoutes)
|
|
32565
|
+
apiRoute("agent-executable", registerAgentExecutableRoutes),
|
|
32566
|
+
apiRoute("agent-accounts", registerAgentAccountRoutes)
|
|
31952
32567
|
];
|
|
31953
32568
|
}
|
|
31954
32569
|
});
|
|
@@ -31992,7 +32607,7 @@ import { WebSocket } from "ws";
|
|
|
31992
32607
|
import { spawn as ptySpawn } from "node-pty";
|
|
31993
32608
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
31994
32609
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
31995
|
-
import { homedir as
|
|
32610
|
+
import { homedir as homedir12 } from "node:os";
|
|
31996
32611
|
function defaultShell() {
|
|
31997
32612
|
if (process.platform === "win32") return process.env.COMSPEC ?? "powershell.exe";
|
|
31998
32613
|
return process.env.SHELL ?? "/bin/zsh";
|
|
@@ -32106,7 +32721,7 @@ var init_pty_server = __esm({
|
|
|
32106
32721
|
return;
|
|
32107
32722
|
}
|
|
32108
32723
|
const name = msg.name || `Terminal ${this.sessions.size + 1}`;
|
|
32109
|
-
const cwd = msg.cwd ||
|
|
32724
|
+
const cwd = msg.cwd || homedir12();
|
|
32110
32725
|
const cols = msg.cols || 80;
|
|
32111
32726
|
const rows = msg.rows || 24;
|
|
32112
32727
|
const command = msg.command || defaultShell();
|
|
@@ -32364,18 +32979,18 @@ var init_pty_authorization = __esm({
|
|
|
32364
32979
|
// ../../server/app-server.ts
|
|
32365
32980
|
import express from "express";
|
|
32366
32981
|
import { createServer, request as httpRequest2 } from "node:http";
|
|
32367
|
-
import { join as
|
|
32982
|
+
import { join as join31 } from "node:path";
|
|
32368
32983
|
import { WebSocketServer as WebSocketServer2 } from "ws";
|
|
32369
32984
|
async function createServerComposition(staticDir, userDataDir, environment) {
|
|
32370
32985
|
setDataRoot(userDataDir);
|
|
32371
|
-
setConfigPath(
|
|
32986
|
+
setConfigPath(join31(userDataDir, "config.local.json"));
|
|
32372
32987
|
await loadConfig();
|
|
32373
32988
|
const configEdition = getConfiguredEditionValue();
|
|
32374
32989
|
initEdition({ shell: environment.mode, configEdition });
|
|
32375
32990
|
const suppression = describeEditionSuppression(process.env, configEdition, environment.mode);
|
|
32376
32991
|
if (suppression) console.warn(suppression);
|
|
32377
32992
|
if (isTeamEdition()) {
|
|
32378
|
-
const teamDir =
|
|
32993
|
+
const teamDir = join31(getDataRoot(), "team");
|
|
32379
32994
|
await initUsersStore(teamDir);
|
|
32380
32995
|
await initSessionPersistence(teamDir);
|
|
32381
32996
|
initializeBootstrapToken(userCount());
|
|
@@ -32545,11 +33160,11 @@ var init_standalone_app_server = __esm({
|
|
|
32545
33160
|
|
|
32546
33161
|
// ../../server/lib/portFile.ts
|
|
32547
33162
|
import { mkdirSync as mkdirSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
32548
|
-
import { homedir as
|
|
32549
|
-
import { dirname as
|
|
33163
|
+
import { homedir as homedir13 } from "node:os";
|
|
33164
|
+
import { dirname as dirname16, join as join32 } from "node:path";
|
|
32550
33165
|
function writePortFile(port) {
|
|
32551
33166
|
try {
|
|
32552
|
-
mkdirSync2(
|
|
33167
|
+
mkdirSync2(dirname16(PORT_FILE), { recursive: true });
|
|
32553
33168
|
writeFileSync2(PORT_FILE, `${port}
|
|
32554
33169
|
`, { mode: 384 });
|
|
32555
33170
|
} catch (err) {
|
|
@@ -32566,7 +33181,7 @@ function removePortFile() {
|
|
|
32566
33181
|
var PORT_FILE;
|
|
32567
33182
|
var init_portFile = __esm({
|
|
32568
33183
|
"../../server/lib/portFile.ts"() {
|
|
32569
|
-
PORT_FILE =
|
|
33184
|
+
PORT_FILE = join32(homedir13(), ".cogpit", "port");
|
|
32570
33185
|
}
|
|
32571
33186
|
});
|
|
32572
33187
|
|
|
@@ -32814,8 +33429,8 @@ __export(standalone_runtime_exports, {
|
|
|
32814
33429
|
startStandaloneServer: () => startStandaloneServer
|
|
32815
33430
|
});
|
|
32816
33431
|
import { existsSync, mkdirSync as mkdirSync3 } from "node:fs";
|
|
32817
|
-
import { homedir as
|
|
32818
|
-
import { join as
|
|
33432
|
+
import { homedir as homedir14 } from "node:os";
|
|
33433
|
+
import { join as join33 } from "node:path";
|
|
32819
33434
|
function listen(server, port, host) {
|
|
32820
33435
|
return new Promise((resolve22, reject) => {
|
|
32821
33436
|
const onError = (error) => reject(error);
|
|
@@ -32833,23 +33448,23 @@ function listen(server, port, host) {
|
|
|
32833
33448
|
}
|
|
32834
33449
|
async function startStandaloneServer({
|
|
32835
33450
|
staticDir,
|
|
32836
|
-
dataDir =
|
|
33451
|
+
dataDir = join33(homedir14(), ".config", "cogpit"),
|
|
32837
33452
|
host = "127.0.0.1",
|
|
32838
33453
|
port = 19384,
|
|
32839
33454
|
env = process.env,
|
|
32840
33455
|
publishPort = false
|
|
32841
33456
|
}) {
|
|
32842
33457
|
mkdirSync3(dataDir, { recursive: true });
|
|
32843
|
-
const
|
|
32844
|
-
setConfigPath(
|
|
32845
|
-
const configExisted = existsSync(
|
|
33458
|
+
const configPath2 = join33(dataDir, "config.local.json");
|
|
33459
|
+
setConfigPath(configPath2);
|
|
33460
|
+
const configExisted = existsSync(configPath2);
|
|
32846
33461
|
await loadConfig();
|
|
32847
33462
|
let createdConfig;
|
|
32848
33463
|
if (!configExisted) {
|
|
32849
|
-
const claudeDir =
|
|
32850
|
-
if (existsSync(
|
|
33464
|
+
const claudeDir = join33(homedir14(), ".claude");
|
|
33465
|
+
if (existsSync(join33(claudeDir, "projects"))) {
|
|
32851
33466
|
await saveConfig({ claudeDir });
|
|
32852
|
-
createdConfig = `${
|
|
33467
|
+
createdConfig = `${configPath2} for ${claudeDir}`;
|
|
32853
33468
|
}
|
|
32854
33469
|
}
|
|
32855
33470
|
initEdition({ shell: "standalone", configEdition: getConfiguredEditionValue() });
|
|
@@ -32919,8 +33534,8 @@ var init_standalone_runtime = __esm({
|
|
|
32919
33534
|
|
|
32920
33535
|
// src/index.ts
|
|
32921
33536
|
import { spawn as spawn4 } from "node:child_process";
|
|
32922
|
-
import { homedir as
|
|
32923
|
-
import { join as
|
|
33537
|
+
import { homedir as homedir15 } from "node:os";
|
|
33538
|
+
import { join as join34, resolve as resolve21 } from "node:path";
|
|
32924
33539
|
var SESSION_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/;
|
|
32925
33540
|
var USAGE = `Cogpit
|
|
32926
33541
|
|
|
@@ -33029,8 +33644,8 @@ async function openExternalUrl(url) {
|
|
|
33029
33644
|
async function startPackagedServer(options) {
|
|
33030
33645
|
const { startStandaloneServer: startStandaloneServer2 } = await Promise.resolve().then(() => (init_standalone_runtime(), standalone_runtime_exports));
|
|
33031
33646
|
return startStandaloneServer2({
|
|
33032
|
-
staticDir:
|
|
33033
|
-
dataDir: options.dataDir ??
|
|
33647
|
+
staticDir: join34(import.meta.dirname, "web"),
|
|
33648
|
+
dataDir: options.dataDir ?? join34(homedir15(), ".config", "cogpit"),
|
|
33034
33649
|
host: "127.0.0.1",
|
|
33035
33650
|
port: options.port,
|
|
33036
33651
|
publishPort: false
|
|
@@ -33046,7 +33661,7 @@ async function waitForShutdownSignal() {
|
|
|
33046
33661
|
for (const signal of signals) process.once(signal, done);
|
|
33047
33662
|
});
|
|
33048
33663
|
}
|
|
33049
|
-
var
|
|
33664
|
+
var defaultDependencies4 = {
|
|
33050
33665
|
fetch,
|
|
33051
33666
|
openUrl: openExternalUrl,
|
|
33052
33667
|
startServer: startPackagedServer,
|
|
@@ -33073,7 +33688,7 @@ async function verifyServer(server, command, deps) {
|
|
|
33073
33688
|
}
|
|
33074
33689
|
}
|
|
33075
33690
|
async function run(argv, overrides = {}) {
|
|
33076
|
-
const deps = { ...
|
|
33691
|
+
const deps = { ...defaultDependencies4, ...overrides };
|
|
33077
33692
|
let command;
|
|
33078
33693
|
try {
|
|
33079
33694
|
command = parseArgs(argv);
|