cogpit-memory 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +363 -179
- package/dist/index.js +358 -174
- package/dist/lib/agent-descriptors.d.ts +4 -0
- package/dist/lib/agents.d.ts +14 -0
- package/dist/lib/backgroundAgents.d.ts +16 -0
- package/dist/lib/claude.d.ts +10 -0
- package/dist/lib/codex.d.ts +25 -0
- package/dist/lib/transcriptFile.d.ts +22 -0
- package/dist/lib/types.d.ts +118 -2
- package/package.json +1 -1
- package/skill/SKILL.md +26 -346
package/dist/index.js
CHANGED
|
@@ -54,7 +54,7 @@ var import_better_sqlite3 = __toESM(require("better-sqlite3"));
|
|
|
54
54
|
var Database = import_better_sqlite3.default;
|
|
55
55
|
|
|
56
56
|
// src/lib/search-index.ts
|
|
57
|
-
var
|
|
57
|
+
var import_node_fs3 = require("node:fs");
|
|
58
58
|
|
|
59
59
|
// src/lib/types.ts
|
|
60
60
|
var AGENT_KINDS = ["acp", "codex", "copilot", "claude"];
|
|
@@ -122,7 +122,7 @@ function base64DirNameCodec(prefix) {
|
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
124
|
function sessionIdFromJsonlName(fileName) {
|
|
125
|
-
const match = new RegExp(`(${SESSION_UUID})\\.jsonl
|
|
125
|
+
const match = new RegExp(`(${SESSION_UUID})\\.jsonl(?:\\.zst)?$`, "i").exec(fileName);
|
|
126
126
|
return match ? match[1] : null;
|
|
127
127
|
}
|
|
128
128
|
function ownTranscriptRoot(sessionId) {
|
|
@@ -292,7 +292,8 @@ var claude = {
|
|
|
292
292
|
fastTier: true,
|
|
293
293
|
lowPriorityInTerminal: true,
|
|
294
294
|
imageInput: true,
|
|
295
|
-
midTurnSteering:
|
|
295
|
+
midTurnSteering: true,
|
|
296
|
+
activeNotifications: true,
|
|
296
297
|
stopSession: true,
|
|
297
298
|
ultracode: true,
|
|
298
299
|
contextWindow: true,
|
|
@@ -378,6 +379,7 @@ var codex = {
|
|
|
378
379
|
bundledBySdk: false,
|
|
379
380
|
homeDirName: ".codex",
|
|
380
381
|
homeEnvVar: "CODEX_HOME",
|
|
382
|
+
sessionIdEnvVar: "CODEX_THREAD_ID",
|
|
381
383
|
installMarker: "",
|
|
382
384
|
homeIsDiscoverable: true,
|
|
383
385
|
process: {
|
|
@@ -428,6 +430,7 @@ var codex = {
|
|
|
428
430
|
lowPriorityInTerminal: false,
|
|
429
431
|
imageInput: true,
|
|
430
432
|
midTurnSteering: true,
|
|
433
|
+
activeNotifications: true,
|
|
431
434
|
stopSession: false,
|
|
432
435
|
ultracode: false,
|
|
433
436
|
contextWindow: false,
|
|
@@ -549,6 +552,7 @@ var copilot = {
|
|
|
549
552
|
lowPriorityInTerminal: false,
|
|
550
553
|
imageInput: false,
|
|
551
554
|
midTurnSteering: true,
|
|
555
|
+
activeNotifications: true,
|
|
552
556
|
stopSession: true,
|
|
553
557
|
ultracode: false,
|
|
554
558
|
contextWindow: false,
|
|
@@ -578,7 +582,7 @@ var acp = {
|
|
|
578
582
|
launchArgs: { permissions: () => [], model: () => [], effort: () => [], fastTier: () => [] },
|
|
579
583
|
cli: { ...copilot.cli, packageName: "", homebrew: null, wingetId: null, selfUpdate: null, requiresConfiguration: true, homeDirName: ".cogpit-acp", homeEnvVar: "COGPIT_ACP_HOME", homeIsDiscoverable: true, installMarker: "projects" },
|
|
580
584
|
config: { ...copilot.config, rootDirName: ".cogpit-acp", instructions: [], settings: [], skillsDir: null },
|
|
581
|
-
capabilities: { ...copilot.capabilities, undo: false, redo: false, nativeRewind: false, nativeFork: false, midTurnSteering: false, externalProcesses: false, autoPermissionMode: "never", toolPermissionRules: false, namedSessions: false }
|
|
585
|
+
capabilities: { ...copilot.capabilities, undo: false, redo: false, nativeRewind: false, nativeFork: false, midTurnSteering: false, activeNotifications: false, externalProcesses: false, autoPermissionMode: "never", toolPermissionRules: false, namedSessions: false }
|
|
582
586
|
};
|
|
583
587
|
var DESCRIPTORS = Object.freeze({
|
|
584
588
|
claude,
|
|
@@ -682,6 +686,27 @@ function readJsStringLiteral(source, startIndex) {
|
|
|
682
686
|
return null;
|
|
683
687
|
}
|
|
684
688
|
|
|
689
|
+
// src/lib/backgroundAgents.ts
|
|
690
|
+
function awaitingAgentsStatus(launches, pendingQueue = 0) {
|
|
691
|
+
if (!launches.some((launch) => launch.endedAt === void 0)) return null;
|
|
692
|
+
const ordered = [...launches].sort((a, b) => a.launchedAt - b.launchedAt);
|
|
693
|
+
let batchStart = 0;
|
|
694
|
+
let busyUntil = -Infinity;
|
|
695
|
+
ordered.forEach((launch, index) => {
|
|
696
|
+
if (busyUntil < launch.launchedAt) batchStart = index;
|
|
697
|
+
busyUntil = Math.max(busyUntil, launch.endedAt ?? Infinity);
|
|
698
|
+
});
|
|
699
|
+
const batch = ordered.slice(batchStart).map(({ agent, endedAt }) => ({ ...agent, done: endedAt !== void 0 }));
|
|
700
|
+
const running = batch.filter((agent) => !agent.done);
|
|
701
|
+
return {
|
|
702
|
+
status: "awaiting_agents",
|
|
703
|
+
pendingQueue,
|
|
704
|
+
pendingAgents: running.length,
|
|
705
|
+
pendingAgentDescriptions: running.map((agent) => agent.description).filter((description) => description.length > 0),
|
|
706
|
+
backgroundAgents: batch
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
|
|
685
710
|
// src/lib/messageTypeGuards.ts
|
|
686
711
|
function isUserMessage(msg) {
|
|
687
712
|
return msg.type === "user";
|
|
@@ -846,6 +871,17 @@ function isTaskNotificationRecord(msg) {
|
|
|
846
871
|
if (!text.includes("<task-notification>")) return false;
|
|
847
872
|
return text.replace(TASK_NOTIFICATION_BLOCK_RE, "").replace(ANY_TAG_RE, "").trim() === "";
|
|
848
873
|
}
|
|
874
|
+
function isTaskToolName(name) {
|
|
875
|
+
return name === "Task" || name === "Agent";
|
|
876
|
+
}
|
|
877
|
+
function readTaskMeta(input) {
|
|
878
|
+
const effort = input.effort;
|
|
879
|
+
return {
|
|
880
|
+
name: typeof input.name === "string" ? input.name : null,
|
|
881
|
+
subagentType: typeof input.subagent_type === "string" ? input.subagent_type : null,
|
|
882
|
+
effort: typeof effort === "string" || typeof effort === "number" ? String(effort) : null
|
|
883
|
+
};
|
|
884
|
+
}
|
|
849
885
|
function queuedCommandPrompt(msg) {
|
|
850
886
|
if (!isAttachmentMessage(msg)) return null;
|
|
851
887
|
const attachment = msg.attachment;
|
|
@@ -1187,7 +1223,13 @@ function buildTurnsWithStarts(messages) {
|
|
|
1187
1223
|
continue;
|
|
1188
1224
|
}
|
|
1189
1225
|
if (isSystemMessage(msg) && msg.subtype === "local_command" && msg.content) {
|
|
1190
|
-
current?.contentBlocks.push({
|
|
1226
|
+
current?.contentBlocks.push({
|
|
1227
|
+
kind: "local_command",
|
|
1228
|
+
content: msg.content,
|
|
1229
|
+
timestamp: msg.timestamp,
|
|
1230
|
+
...msg.contextUsage ? { contextUsage: msg.contextUsage } : {},
|
|
1231
|
+
...msg.usageReport ? { usageReport: msg.usageReport } : {}
|
|
1232
|
+
});
|
|
1191
1233
|
continue;
|
|
1192
1234
|
}
|
|
1193
1235
|
if (isQueueOperationMessage(msg)) {
|
|
@@ -1263,6 +1305,7 @@ function buildTurnsWithStarts(messages) {
|
|
|
1263
1305
|
parentToolUseId: toolUseId || void 0,
|
|
1264
1306
|
agentName: taskMeta?.name ?? null,
|
|
1265
1307
|
subagentType: taskMeta?.subagentType ?? null,
|
|
1308
|
+
...taskMeta?.effort ? { effort: taskMeta.effort } : {},
|
|
1266
1309
|
type: "assistant",
|
|
1267
1310
|
content: toolUseResult.content,
|
|
1268
1311
|
toolCalls: [],
|
|
@@ -1401,15 +1444,12 @@ function buildTurnsWithStarts(messages) {
|
|
|
1401
1444
|
current.toolCalls.push(tc);
|
|
1402
1445
|
msgToolCalls.push(tc);
|
|
1403
1446
|
pendingToolUses.set(block.id, { turn: current, index: idx });
|
|
1404
|
-
if (block.name
|
|
1447
|
+
if (isTaskToolName(block.name)) {
|
|
1405
1448
|
const input = block.input;
|
|
1406
1449
|
if (input.run_in_background === true) {
|
|
1407
1450
|
backgroundAgentParentIds.add(block.id);
|
|
1408
1451
|
}
|
|
1409
|
-
taskMetaMap.set(block.id,
|
|
1410
|
-
name: input.name ?? null,
|
|
1411
|
-
subagentType: input.subagent_type ?? null
|
|
1412
|
-
});
|
|
1452
|
+
taskMetaMap.set(block.id, readTaskMeta(input));
|
|
1413
1453
|
}
|
|
1414
1454
|
}
|
|
1415
1455
|
}
|
|
@@ -1420,6 +1460,7 @@ function buildTurnsWithStarts(messages) {
|
|
|
1420
1460
|
if (isProgressMessage(msg) && msg.data.type === "agent_progress") {
|
|
1421
1461
|
const data = msg.data;
|
|
1422
1462
|
const parentId = msg.parentToolUseID ?? "";
|
|
1463
|
+
const ownToolUseId = data.toolUseId ?? parentId;
|
|
1423
1464
|
let subAgentUsage = null;
|
|
1424
1465
|
if (data.message.type === "assistant") {
|
|
1425
1466
|
const innerMsg = data.message.message;
|
|
@@ -1436,12 +1477,14 @@ function buildTurnsWithStarts(messages) {
|
|
|
1436
1477
|
}
|
|
1437
1478
|
}
|
|
1438
1479
|
const innerModel = data.message.type === "assistant" ? data.message.message.model ?? null : null;
|
|
1439
|
-
const taskMeta = taskMetaMap.get(
|
|
1480
|
+
const taskMeta = taskMetaMap.get(ownToolUseId);
|
|
1440
1481
|
const agentMsg = {
|
|
1441
1482
|
agentId: data.agentId,
|
|
1442
|
-
parentToolUseId:
|
|
1483
|
+
parentToolUseId: ownToolUseId || void 0,
|
|
1484
|
+
...data.parentAgentId ? { parentAgentId: data.parentAgentId } : {},
|
|
1485
|
+
...taskMeta?.effort ? { effort: taskMeta.effort } : {},
|
|
1443
1486
|
agentName: taskMeta?.name ?? null,
|
|
1444
|
-
subagentType: taskMeta?.subagentType ?? null,
|
|
1487
|
+
subagentType: taskMeta?.subagentType ?? data.subagentType ?? null,
|
|
1445
1488
|
type: data.message.type,
|
|
1446
1489
|
content: data.message.message.content,
|
|
1447
1490
|
toolCalls: [],
|
|
@@ -1461,6 +1504,7 @@ function buildTurnsWithStarts(messages) {
|
|
|
1461
1504
|
} else if (block.type === "text") {
|
|
1462
1505
|
agentMsg.text.push(block.text);
|
|
1463
1506
|
} else if (block.type === "tool_use") {
|
|
1507
|
+
if (isTaskToolName(block.name)) taskMetaMap.set(block.id, readTaskMeta(block.input));
|
|
1464
1508
|
agentMsg.toolCalls.push({
|
|
1465
1509
|
id: block.id,
|
|
1466
1510
|
name: block.name,
|
|
@@ -1553,11 +1597,19 @@ function buildTurns(messages) {
|
|
|
1553
1597
|
function isClaudeSessionText() {
|
|
1554
1598
|
return true;
|
|
1555
1599
|
}
|
|
1600
|
+
var API_REQUEST_TYPE = '"type":"api-request';
|
|
1601
|
+
var RECORD_TYPE_WINDOW = 256;
|
|
1602
|
+
function isClaudeNoiseLine(line) {
|
|
1603
|
+
if (line.startsWith(`{${API_REQUEST_TYPE}`)) return true;
|
|
1604
|
+
const head = line.slice(0, RECORD_TYPE_WINDOW);
|
|
1605
|
+
const at = head.indexOf(API_REQUEST_TYPE);
|
|
1606
|
+
return at > 0 && head.lastIndexOf("{", at) === 0;
|
|
1607
|
+
}
|
|
1556
1608
|
function parseRecords(lines) {
|
|
1557
1609
|
const messages = [];
|
|
1558
1610
|
for (const line of lines) {
|
|
1559
1611
|
const trimmed = line.trim();
|
|
1560
|
-
if (!trimmed) continue;
|
|
1612
|
+
if (!trimmed || isClaudeNoiseLine(trimmed)) continue;
|
|
1561
1613
|
try {
|
|
1562
1614
|
messages.push(JSON.parse(trimmed));
|
|
1563
1615
|
} catch {
|
|
@@ -1662,21 +1714,24 @@ function userMessageTexts(msg) {
|
|
|
1662
1714
|
}
|
|
1663
1715
|
function collectClaudeBackgroundWork(rawMessages) {
|
|
1664
1716
|
const launches = [];
|
|
1665
|
-
const
|
|
1717
|
+
const resolvedAt = /* @__PURE__ */ new Map();
|
|
1666
1718
|
const queuedIds = /* @__PURE__ */ new Set();
|
|
1667
1719
|
const deliveredIds = /* @__PURE__ */ new Set();
|
|
1668
|
-
function
|
|
1720
|
+
function resolve2(id, index) {
|
|
1721
|
+
if (!resolvedAt.has(id)) resolvedAt.set(id, index);
|
|
1722
|
+
}
|
|
1723
|
+
function noteNotifications(text, index, sink) {
|
|
1669
1724
|
if (!text.includes(TASK_NOTIFICATION_MARKER)) return;
|
|
1670
1725
|
for (const match of text.matchAll(TASK_ID_RE)) {
|
|
1671
|
-
|
|
1726
|
+
resolve2(match[1], index);
|
|
1672
1727
|
sink?.add(match[1]);
|
|
1673
1728
|
}
|
|
1674
1729
|
for (const match of text.matchAll(TOOL_USE_ID_RE)) {
|
|
1675
|
-
|
|
1730
|
+
resolve2(match[1], index);
|
|
1676
1731
|
sink?.add(match[1]);
|
|
1677
1732
|
}
|
|
1678
1733
|
}
|
|
1679
|
-
for (const msg of rawMessages) {
|
|
1734
|
+
for (const [index, msg] of rawMessages.entries()) {
|
|
1680
1735
|
if (msg.type === "user") {
|
|
1681
1736
|
const toolUseResult = isObject(msg.toolUseResult) ? msg.toolUseResult : null;
|
|
1682
1737
|
if (toolUseResult?.status === "async_launched") {
|
|
@@ -1685,9 +1740,11 @@ function collectClaudeBackgroundWork(rawMessages) {
|
|
|
1685
1740
|
const toolUseIds = blocks.filter((block) => isObject(block) && block.type === "tool_result").map((block) => block.tool_use_id);
|
|
1686
1741
|
const ids = [toolUseResult.agentId, toolUseResult.taskId, ...toolUseIds].filter((id) => typeof id === "string" && id.length > 0);
|
|
1687
1742
|
const description = [toolUseResult.description, toolUseResult.workflowName, toolUseResult.summary].find((value) => typeof value === "string" && value.length > 0) ?? "";
|
|
1688
|
-
|
|
1743
|
+
const toolUseId = toolUseIds.find((id) => typeof id === "string" && id.length > 0);
|
|
1744
|
+
const startedAt = typeof msg.timestamp === "string" ? msg.timestamp : void 0;
|
|
1745
|
+
if (ids.length > 0) launches.push({ ids, launch: { agent: { description, startedAt, toolUseId }, launchedAt: index } });
|
|
1689
1746
|
}
|
|
1690
|
-
for (const text of userMessageTexts(msg)) noteNotifications(text, deliveredIds);
|
|
1747
|
+
for (const text of userMessageTexts(msg)) noteNotifications(text, index, deliveredIds);
|
|
1691
1748
|
continue;
|
|
1692
1749
|
}
|
|
1693
1750
|
if (msg.type === "assistant") {
|
|
@@ -1697,33 +1754,28 @@ function collectClaudeBackgroundWork(rawMessages) {
|
|
|
1697
1754
|
if (!isObject(block) || block.type !== "tool_use" || block.name !== "TaskStop") continue;
|
|
1698
1755
|
const input = isObject(block.input) ? block.input : null;
|
|
1699
1756
|
const taskId = input?.task_id ?? input?.shell_id;
|
|
1700
|
-
if (typeof taskId === "string")
|
|
1757
|
+
if (typeof taskId === "string") resolve2(taskId, index);
|
|
1701
1758
|
}
|
|
1702
1759
|
continue;
|
|
1703
1760
|
}
|
|
1704
1761
|
if (msg.type === "attachment") {
|
|
1705
1762
|
const attachment = isObject(msg.attachment) ? msg.attachment : null;
|
|
1706
|
-
if (typeof attachment?.prompt === "string") noteNotifications(attachment.prompt, deliveredIds);
|
|
1763
|
+
if (typeof attachment?.prompt === "string") noteNotifications(attachment.prompt, index, deliveredIds);
|
|
1707
1764
|
continue;
|
|
1708
1765
|
}
|
|
1709
1766
|
if (msg.type === "queue-operation" && typeof msg.content === "string") {
|
|
1710
1767
|
const op = msg.operation;
|
|
1711
|
-
noteNotifications(msg.content, op === "enqueue" ? queuedIds : deliveredIds);
|
|
1768
|
+
noteNotifications(msg.content, index, op === "enqueue" ? queuedIds : deliveredIds);
|
|
1712
1769
|
}
|
|
1713
1770
|
}
|
|
1714
1771
|
return {
|
|
1715
|
-
|
|
1772
|
+
launches: launches.map(({ ids, launch }) => {
|
|
1773
|
+
const ends = ids.flatMap((id) => resolvedAt.get(id) ?? []);
|
|
1774
|
+
return ends.length > 0 ? { ...launch, endedAt: Math.min(...ends) } : launch;
|
|
1775
|
+
}),
|
|
1716
1776
|
undeliveredNotifications: [...queuedIds].filter((id) => !deliveredIds.has(id)).length
|
|
1717
1777
|
};
|
|
1718
1778
|
}
|
|
1719
|
-
function awaitingAgentsResult(pendingDescriptions, pendingQueue) {
|
|
1720
|
-
return {
|
|
1721
|
-
status: "awaiting_agents",
|
|
1722
|
-
pendingQueue,
|
|
1723
|
-
pendingAgents: pendingDescriptions.length,
|
|
1724
|
-
pendingAgentDescriptions: pendingDescriptions.filter((description) => description.length > 0)
|
|
1725
|
-
};
|
|
1726
|
-
}
|
|
1727
1779
|
function deriveClaudeSessionStatus(rawMessages) {
|
|
1728
1780
|
let pendingEnqueues = 0;
|
|
1729
1781
|
let backgroundWork = null;
|
|
@@ -1769,9 +1821,8 @@ function deriveClaudeSessionStatus(rawMessages) {
|
|
|
1769
1821
|
if (stopReason === "end_turn") {
|
|
1770
1822
|
const work = getBackgroundWork();
|
|
1771
1823
|
if (deliveringNotification || work.undeliveredNotifications > 0) return result("processing");
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
}
|
|
1824
|
+
const awaiting = awaitingAgentsStatus(work.launches, Math.max(0, pendingEnqueues));
|
|
1825
|
+
if (awaiting) return awaiting;
|
|
1775
1826
|
let hasActivity = false;
|
|
1776
1827
|
for (let j = i - 1; j >= 0; j--) {
|
|
1777
1828
|
const m = rawMessages[j];
|
|
@@ -2168,6 +2219,48 @@ function codexParentId(payload) {
|
|
|
2168
2219
|
}
|
|
2169
2220
|
return null;
|
|
2170
2221
|
}
|
|
2222
|
+
function inheritedHistoryFilter(records) {
|
|
2223
|
+
const meta = records.find((record2) => record2?.type === "session_meta");
|
|
2224
|
+
const start = meta?.payload?.subagent_history_start_ordinal;
|
|
2225
|
+
if (typeof start !== "number") return null;
|
|
2226
|
+
const reachesPast = (ordinal) => typeof ordinal === "number" && ordinal >= start;
|
|
2227
|
+
if (!reachesPast(meta?.rolloutLastOrdinal) && !records.some((record2) => reachesPast(record2?.ordinal))) return null;
|
|
2228
|
+
return (record2) => typeof record2.ordinal === "number" && record2.ordinal > 0 && record2.ordinal < start;
|
|
2229
|
+
}
|
|
2230
|
+
async function codexPageHeaderLine(firstLine, lastLines) {
|
|
2231
|
+
if (!firstLine.includes('"subagent_history_start_ordinal"')) return firstLine;
|
|
2232
|
+
const meta = safeParseLine(firstLine);
|
|
2233
|
+
if (meta?.type !== "session_meta") return firstLine;
|
|
2234
|
+
const lines = await lastLines();
|
|
2235
|
+
for (let index = lines.length - 1; index >= 0; index--) {
|
|
2236
|
+
const ordinal = safeParseLine(lines[index])?.ordinal;
|
|
2237
|
+
if (typeof ordinal === "number") return JSON.stringify({ ...meta, rolloutLastOrdinal: ordinal });
|
|
2238
|
+
}
|
|
2239
|
+
return firstLine;
|
|
2240
|
+
}
|
|
2241
|
+
function subAgentActivitySource(record2) {
|
|
2242
|
+
const payload = record2.payload;
|
|
2243
|
+
if (record2.type !== "event_msg" || !isObject3(payload)) return null;
|
|
2244
|
+
if (payload.type === "sub_agent_activity") return payload;
|
|
2245
|
+
if (payload.type === "item_completed" && isObject3(payload.item) && payload.item.type === "SubAgentActivity") return payload.item;
|
|
2246
|
+
return null;
|
|
2247
|
+
}
|
|
2248
|
+
function readSubAgentActivity(record2) {
|
|
2249
|
+
const source = subAgentActivitySource(record2);
|
|
2250
|
+
if (!source || typeof source.agent_thread_id !== "string" || typeof source.agent_path !== "string") return null;
|
|
2251
|
+
return {
|
|
2252
|
+
agentId: source.agent_thread_id,
|
|
2253
|
+
agentPath: source.agent_path,
|
|
2254
|
+
kind: typeof source.kind === "string" ? source.kind : "started",
|
|
2255
|
+
eventId: findString(source.event_id, source.id) ?? "",
|
|
2256
|
+
model: findString(source.model) || null,
|
|
2257
|
+
effort: findString(source.reasoning_effort) || null
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
function turnErrorMessage(payload) {
|
|
2261
|
+
if (payload.type !== "task_complete" || !isObject3(payload.error)) return "";
|
|
2262
|
+
return typeof payload.error.message === "string" ? payload.error.message.trim() : "";
|
|
2263
|
+
}
|
|
2171
2264
|
function isCodexRecord(record2) {
|
|
2172
2265
|
if (!record2 || typeof record2.type !== "string") return false;
|
|
2173
2266
|
return record2.type === "session_meta" || record2.type === "turn_context" || record2.type === "event_msg" || record2.type === "response_item" || record2.type === "inter_agent_communication_metadata" || record2.type === "compacted" || record2.type === "world_state";
|
|
@@ -2365,22 +2458,39 @@ function createTurn2(turnId, timestamp, model) {
|
|
|
2365
2458
|
model
|
|
2366
2459
|
};
|
|
2367
2460
|
}
|
|
2368
|
-
function
|
|
2369
|
-
|
|
2370
|
-
|
|
2461
|
+
function codexPromptText(record2) {
|
|
2462
|
+
const payload = isObject3(record2.payload) ? record2.payload : null;
|
|
2463
|
+
if (record2.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
|
|
2464
|
+
return normalizePromptText(payload.message);
|
|
2371
2465
|
}
|
|
2372
|
-
if (record2.type === "response_item" &&
|
|
2373
|
-
return normalizePromptText(extractMessageText(
|
|
2466
|
+
if (record2.type === "response_item" && payload?.type === "message" && payload.role === "user") {
|
|
2467
|
+
return normalizePromptText(extractMessageText(payload, "input_text"));
|
|
2374
2468
|
}
|
|
2375
2469
|
return "";
|
|
2376
2470
|
}
|
|
2471
|
+
function createCodexPromptReader() {
|
|
2472
|
+
let echoPending = false;
|
|
2473
|
+
return (record2) => {
|
|
2474
|
+
const payload = isObject3(record2.payload) ? record2.payload : null;
|
|
2475
|
+
if (record2.type === "event_msg" && payload?.type === "user_message") {
|
|
2476
|
+
const isEcho = echoPending;
|
|
2477
|
+
echoPending = false;
|
|
2478
|
+
return isEcho ? "" : codexPromptText(record2);
|
|
2479
|
+
}
|
|
2480
|
+
if (record2.type !== "response_item") return "";
|
|
2481
|
+
const prompt = codexPromptText(record2);
|
|
2482
|
+
if (prompt) echoPending = true;
|
|
2483
|
+
else if (payload?.type !== "message" || payload.role !== "user") echoPending = false;
|
|
2484
|
+
return prompt;
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2377
2487
|
function recordOpensTurn(record2, payload) {
|
|
2378
2488
|
if (record2.type === "session_meta") return false;
|
|
2379
2489
|
if (record2.type === "event_msg" && payload?.type === "task_started") return false;
|
|
2380
2490
|
if (record2.type === "response_item" && payload?.type === "message") {
|
|
2381
2491
|
if (payload.role === "developer" || payload.role === "system") return false;
|
|
2382
2492
|
if (payload.role === "user") {
|
|
2383
|
-
return
|
|
2493
|
+
return codexPromptText(record2) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
|
|
2384
2494
|
}
|
|
2385
2495
|
}
|
|
2386
2496
|
return true;
|
|
@@ -2400,9 +2510,10 @@ function extractMetadataFromRecords(records) {
|
|
|
2400
2510
|
let isSubagent = false;
|
|
2401
2511
|
let parentSessionId = null;
|
|
2402
2512
|
let agentPath = "/root";
|
|
2403
|
-
|
|
2513
|
+
const readPrompt = createCodexPromptReader();
|
|
2514
|
+
const isInherited = inheritedHistoryFilter(records);
|
|
2404
2515
|
for (const record2 of records) {
|
|
2405
|
-
if (!isObject3(record2.payload)) continue;
|
|
2516
|
+
if (!isObject3(record2.payload) || isInherited?.(record2)) continue;
|
|
2406
2517
|
if (record2.type === "session_meta") {
|
|
2407
2518
|
sessionId ||= typeof record2.payload.id === "string" ? record2.payload.id : "";
|
|
2408
2519
|
version ||= typeof record2.payload.cli_version === "string" ? record2.payload.cli_version : "";
|
|
@@ -2432,12 +2543,10 @@ function extractMetadataFromRecords(records) {
|
|
|
2432
2543
|
model ||= typeof record2.payload.model === "string" ? record2.payload.model : "";
|
|
2433
2544
|
cwd ||= typeof record2.payload.cwd === "string" ? record2.payload.cwd : "";
|
|
2434
2545
|
}
|
|
2435
|
-
const prompt =
|
|
2546
|
+
const prompt = readPrompt(record2);
|
|
2436
2547
|
if (!prompt) continue;
|
|
2437
|
-
if (prompt === previousPrompt) continue;
|
|
2438
2548
|
if (!firstUserMessage) firstUserMessage = prompt;
|
|
2439
2549
|
lastUserMessage = prompt;
|
|
2440
|
-
previousPrompt = prompt;
|
|
2441
2550
|
turnCount++;
|
|
2442
2551
|
if (!timestamp) timestamp = record2.timestamp ?? "";
|
|
2443
2552
|
lastTimestamp = record2.timestamp ?? lastTimestamp;
|
|
@@ -2507,6 +2616,7 @@ function walkCodexRecords(records, options) {
|
|
|
2507
2616
|
timestamp: info?.timestamp ?? eventTimestamp2,
|
|
2508
2617
|
tokenUsage: null,
|
|
2509
2618
|
model: info?.model ?? null,
|
|
2619
|
+
...info?.effort ? { effort: info.effort } : {},
|
|
2510
2620
|
isBackground: false,
|
|
2511
2621
|
prompt: info?.message || void 0,
|
|
2512
2622
|
status: update.status ?? "running"
|
|
@@ -2527,6 +2637,7 @@ function walkCodexRecords(records, options) {
|
|
|
2527
2637
|
agentMessage.agentName = info.nickname ?? (info.agentPath ? agentNameFromPath(info.agentPath) : agentMessage.agentName);
|
|
2528
2638
|
agentMessage.subagentType = info.agentType;
|
|
2529
2639
|
agentMessage.model = info.model;
|
|
2640
|
+
if (info.effort) agentMessage.effort = info.effort;
|
|
2530
2641
|
agentMessage.prompt = info.message || agentMessage.prompt;
|
|
2531
2642
|
}
|
|
2532
2643
|
if (update.text && !agentMessage.text.includes(update.text)) {
|
|
@@ -2597,9 +2708,10 @@ function walkCodexRecords(records, options) {
|
|
|
2597
2708
|
webSearchCalls.set(id, toolCall);
|
|
2598
2709
|
appendToolCall(targetTurn, toolCall, timestamp);
|
|
2599
2710
|
}
|
|
2711
|
+
const isInherited = inheritedHistoryFilter(records);
|
|
2600
2712
|
for (let index = 0; index < records.length; index++) {
|
|
2601
2713
|
const record2 = records[index];
|
|
2602
|
-
if (!isCodexRecord(record2)) continue;
|
|
2714
|
+
if (!isCodexRecord(record2) || isInherited?.(record2)) continue;
|
|
2603
2715
|
recordIndex = index;
|
|
2604
2716
|
const payload = isObject3(record2.payload) ? record2.payload : void 0;
|
|
2605
2717
|
const timestamp = record2.timestamp ?? "";
|
|
@@ -2688,12 +2800,18 @@ function walkCodexRecords(records, options) {
|
|
|
2688
2800
|
}
|
|
2689
2801
|
continue;
|
|
2690
2802
|
}
|
|
2691
|
-
if (record2.type === "event_msg" && payload
|
|
2692
|
-
const
|
|
2693
|
-
|
|
2694
|
-
|
|
2803
|
+
if (record2.type === "event_msg" && payload) {
|
|
2804
|
+
const turnError = turnErrorMessage(payload);
|
|
2805
|
+
if (turnError) {
|
|
2806
|
+
appendAssistantText(current, turnError, timestamp);
|
|
2807
|
+
continue;
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
const activity = readSubAgentActivity(record2);
|
|
2811
|
+
if (activity) {
|
|
2812
|
+
const { agentId, agentPath, eventId: eventId2, kind } = activity;
|
|
2695
2813
|
const spawnInfo = eventId2 ? spawnAgentCalls.get(eventId2) : void 0;
|
|
2696
|
-
const existingId = agentIdByPath.get(
|
|
2814
|
+
const existingId = agentIdByPath.get(agentPath);
|
|
2697
2815
|
const existing = agentRegistry.get(agentId) ?? (existingId ? agentRegistry.get(existingId) : void 0);
|
|
2698
2816
|
if (kind !== "started" && !existing && !spawnInfo) continue;
|
|
2699
2817
|
if (existingId && existingId !== agentId && !agentMessages.has(agentId)) {
|
|
@@ -2707,18 +2825,19 @@ function walkCodexRecords(records, options) {
|
|
|
2707
2825
|
}
|
|
2708
2826
|
const info = {
|
|
2709
2827
|
agentId,
|
|
2710
|
-
nickname: existing?.nickname ?? agentNameFromPath(
|
|
2711
|
-
agentPath
|
|
2828
|
+
nickname: existing?.nickname ?? agentNameFromPath(agentPath) ?? spawnInfo?.taskName ?? null,
|
|
2829
|
+
agentPath,
|
|
2712
2830
|
message: existing?.message ?? spawnInfo?.message ?? "",
|
|
2713
|
-
model: existing?.model ?? spawnInfo?.model ?? null,
|
|
2831
|
+
model: activity.model ?? existing?.model ?? spawnInfo?.model ?? null,
|
|
2832
|
+
effort: activity.effort ?? existing?.effort ?? null,
|
|
2714
2833
|
agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
|
|
2715
2834
|
timestamp: existing?.timestamp ?? (timestamp || spawnInfo?.timestamp || ""),
|
|
2716
2835
|
parentToolCallId: existing?.parentToolCallId ?? eventId2
|
|
2717
2836
|
};
|
|
2718
2837
|
agentRegistry.set(agentId, info);
|
|
2719
|
-
agentIdByPath.set(
|
|
2838
|
+
agentIdByPath.set(agentPath, agentId);
|
|
2720
2839
|
if (eventId2 && (kind === "started" || spawnInfo)) agentIdBySpawnCall.set(eventId2, agentId);
|
|
2721
|
-
const status = kind === "interrupted"
|
|
2840
|
+
const status = kind === "interrupted" || kind === "completed" ? kind : "running";
|
|
2722
2841
|
upsertAgentMessage(agentId, current, timestamp, { status });
|
|
2723
2842
|
continue;
|
|
2724
2843
|
}
|
|
@@ -2874,6 +2993,7 @@ function walkCodexRecords(records, options) {
|
|
|
2874
2993
|
agentPath: agentPath ?? existing?.agentPath ?? null,
|
|
2875
2994
|
message: existing?.message ?? spawnInfo?.message ?? "",
|
|
2876
2995
|
model: existing?.model ?? spawnInfo?.model ?? null,
|
|
2996
|
+
effort: existing?.effort ?? null,
|
|
2877
2997
|
agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
|
|
2878
2998
|
timestamp: existing?.timestamp ?? spawnInfo?.timestamp ?? timestamp,
|
|
2879
2999
|
parentToolCallId: existing?.parentToolCallId ?? toolCall.id
|
|
@@ -2992,8 +3112,10 @@ function walkCodexRecords(records, options) {
|
|
|
2992
3112
|
}
|
|
2993
3113
|
function parseCodexSession(jsonlText, options) {
|
|
2994
3114
|
const records = jsonlText.split("\n").map((line) => line.trim()).filter(Boolean).map(safeParseLine).filter(isCodexRecord);
|
|
3115
|
+
const isInherited = inheritedHistoryFilter(records);
|
|
3116
|
+
const ownRecords = isInherited ? records.filter((record2) => !isInherited(record2)) : records;
|
|
2995
3117
|
const { turnStartIndices: _starts, ...session } = walkCodexRecords(
|
|
2996
|
-
|
|
3118
|
+
ownRecords,
|
|
2997
3119
|
options
|
|
2998
3120
|
);
|
|
2999
3121
|
return session;
|
|
@@ -3018,40 +3140,48 @@ function parseJsonObject(value) {
|
|
|
3018
3140
|
return null;
|
|
3019
3141
|
}
|
|
3020
3142
|
}
|
|
3021
|
-
function
|
|
3022
|
-
const
|
|
3023
|
-
const
|
|
3143
|
+
function collectCodexBackgroundAgents(rawMessages) {
|
|
3144
|
+
const launched = /* @__PURE__ */ new Map();
|
|
3145
|
+
const alive = /* @__PURE__ */ new Set();
|
|
3146
|
+
const endedAt = /* @__PURE__ */ new Map();
|
|
3024
3147
|
const agentIdByPath = /* @__PURE__ */ new Map();
|
|
3025
3148
|
const spawnCalls = /* @__PURE__ */ new Map();
|
|
3026
3149
|
const waitCalls = /* @__PURE__ */ new Set();
|
|
3027
3150
|
const interruptCalls = /* @__PURE__ */ new Map();
|
|
3028
|
-
function markAlive(agentId, description) {
|
|
3029
|
-
if (
|
|
3030
|
-
|
|
3031
|
-
|
|
3151
|
+
function markAlive(agentId, description, index, startedAt) {
|
|
3152
|
+
if (endedAt.has(agentId)) return;
|
|
3153
|
+
alive.add(agentId);
|
|
3154
|
+
const launch = launched.get(agentId);
|
|
3155
|
+
if (!launch) launched.set(agentId, { launchedAt: index, description, startedAt });
|
|
3156
|
+
else if (!launch.description) launch.description = description;
|
|
3157
|
+
}
|
|
3158
|
+
function markEnded(agentId, index) {
|
|
3159
|
+
if (!endedAt.has(agentId)) endedAt.set(agentId, index);
|
|
3160
|
+
alive.delete(agentId);
|
|
3161
|
+
}
|
|
3162
|
+
for (const [index, msg] of rawMessages.entries()) {
|
|
3032
3163
|
const payload = isObject3(msg.payload) ? msg.payload : null;
|
|
3033
3164
|
if (!payload) continue;
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
const
|
|
3038
|
-
const existingId = agentIdByPath.get(
|
|
3039
|
-
const known = alive.has(agentId) ||
|
|
3165
|
+
const timestamp = typeof msg.timestamp === "string" ? msg.timestamp : void 0;
|
|
3166
|
+
const activity = readSubAgentActivity(msg);
|
|
3167
|
+
if (activity) {
|
|
3168
|
+
const { agentId, agentPath, kind, eventId: eventId2 } = activity;
|
|
3169
|
+
const existingId = agentIdByPath.get(agentPath);
|
|
3170
|
+
const known = alive.has(agentId) || endedAt.has(agentId) || existingId !== void 0 || spawnCalls.has(eventId2);
|
|
3040
3171
|
if (kind !== "started" && !known) continue;
|
|
3041
3172
|
if (existingId && existingId !== agentId) {
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
if (
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
done.add(agentId);
|
|
3051
|
-
alive.delete(agentId);
|
|
3052
|
-
} else {
|
|
3053
|
-
markAlive(agentId, spawnCalls.get(eventId2) ?? "");
|
|
3173
|
+
const prior = launched.get(existingId);
|
|
3174
|
+
launched.delete(existingId);
|
|
3175
|
+
const current = launched.get(agentId);
|
|
3176
|
+
if (prior && !current) launched.set(agentId, prior);
|
|
3177
|
+
else if (prior && current && !current.description) current.description = prior.description;
|
|
3178
|
+
if (alive.delete(existingId)) markAlive(agentId, "", index, timestamp);
|
|
3179
|
+
const priorEnd = endedAt.get(existingId);
|
|
3180
|
+
if (priorEnd !== void 0) markEnded(agentId, priorEnd);
|
|
3054
3181
|
}
|
|
3182
|
+
agentIdByPath.set(agentPath, agentId);
|
|
3183
|
+
if (kind === "interrupted" || kind === "completed") markEnded(agentId, index);
|
|
3184
|
+
else markAlive(agentId, spawnCalls.get(eventId2) ?? "", index, timestamp);
|
|
3055
3185
|
continue;
|
|
3056
3186
|
}
|
|
3057
3187
|
if (msg.type !== "response_item") continue;
|
|
@@ -3075,7 +3205,7 @@ function collectCodexPendingAgents(rawMessages) {
|
|
|
3075
3205
|
const output = parseJsonObject(payload.output);
|
|
3076
3206
|
const agentId = typeof output?.agent_id === "string" ? output.agent_id : "";
|
|
3077
3207
|
if (agentId) {
|
|
3078
|
-
markAlive(agentId, spawnCalls.get(callId) ?? "");
|
|
3208
|
+
markAlive(agentId, spawnCalls.get(callId) ?? "", index, timestamp);
|
|
3079
3209
|
const agentPath = typeof output?.task_name === "string" ? output.task_name : "";
|
|
3080
3210
|
if (agentPath && !agentIdByPath.has(agentPath)) agentIdByPath.set(agentPath, agentId);
|
|
3081
3211
|
}
|
|
@@ -3086,16 +3216,10 @@ function collectCodexPendingAgents(rawMessages) {
|
|
|
3086
3216
|
const statusValue = isObject3(status) ? status : {};
|
|
3087
3217
|
const lifecycle = typeof statusValue.status === "string" ? statusValue.status : "";
|
|
3088
3218
|
const isTerminal = typeof statusValue.completed === "string" || typeof statusValue.failed === "string" || typeof statusValue.error === "string" || typeof statusValue.interrupted === "string" || lifecycle === "completed" || lifecycle === "failed" || lifecycle === "interrupted";
|
|
3089
|
-
if (isTerminal)
|
|
3090
|
-
done.add(agentId);
|
|
3091
|
-
alive.delete(agentId);
|
|
3092
|
-
}
|
|
3219
|
+
if (isTerminal) markEnded(agentId, index);
|
|
3093
3220
|
}
|
|
3094
3221
|
} else if (interruptCalls.has(callId)) {
|
|
3095
|
-
for (const agentId of interruptCalls.get(callId) ?? [])
|
|
3096
|
-
done.add(agentId);
|
|
3097
|
-
alive.delete(agentId);
|
|
3098
|
-
}
|
|
3222
|
+
for (const agentId of interruptCalls.get(callId) ?? []) markEnded(agentId, index);
|
|
3099
3223
|
}
|
|
3100
3224
|
continue;
|
|
3101
3225
|
}
|
|
@@ -3103,12 +3227,14 @@ function collectCodexPendingAgents(rawMessages) {
|
|
|
3103
3227
|
const text = codexPayloadText(payload);
|
|
3104
3228
|
const messageType = text.match(/^Message Type:\s*([^\r\n]+)/)?.[1]?.trim().toUpperCase() ?? "";
|
|
3105
3229
|
if (!TERMINAL_INTER_AGENT_TYPES.has(messageType)) continue;
|
|
3106
|
-
|
|
3107
|
-
done.add(agentId);
|
|
3108
|
-
alive.delete(agentId);
|
|
3230
|
+
markEnded(agentIdByPath.get(payload.author) ?? payload.author, index);
|
|
3109
3231
|
}
|
|
3110
3232
|
}
|
|
3111
|
-
return [...
|
|
3233
|
+
return [...launched.entries()].map(([agentId, { description, startedAt, launchedAt }]) => ({
|
|
3234
|
+
agent: { description, startedAt },
|
|
3235
|
+
launchedAt,
|
|
3236
|
+
endedAt: alive.has(agentId) ? void 0 : endedAt.get(agentId) ?? launchedAt
|
|
3237
|
+
}));
|
|
3112
3238
|
}
|
|
3113
3239
|
function deriveCodexSessionStatus(rawMessages) {
|
|
3114
3240
|
for (let i = rawMessages.length - 1; i >= 0; i--) {
|
|
@@ -3117,16 +3243,7 @@ function deriveCodexSessionStatus(rawMessages) {
|
|
|
3117
3243
|
const payload = msg.payload;
|
|
3118
3244
|
switch (payload?.type) {
|
|
3119
3245
|
case "task_complete": {
|
|
3120
|
-
|
|
3121
|
-
if (pending.length > 0) {
|
|
3122
|
-
return {
|
|
3123
|
-
status: "awaiting_agents",
|
|
3124
|
-
pendingQueue: 0,
|
|
3125
|
-
pendingAgents: pending.length,
|
|
3126
|
-
pendingAgentDescriptions: pending.filter((description) => description.length > 0)
|
|
3127
|
-
};
|
|
3128
|
-
}
|
|
3129
|
-
return { status: "completed" };
|
|
3246
|
+
return awaitingAgentsStatus(collectCodexBackgroundAgents(rawMessages)) ?? { status: "completed" };
|
|
3130
3247
|
}
|
|
3131
3248
|
case "task_started":
|
|
3132
3249
|
return { status: "processing" };
|
|
@@ -3924,33 +4041,32 @@ function isCopilotEventType(type) {
|
|
|
3924
4041
|
return typeof type === "string" && (type === "abort" || type === "binary_asset" || type === "user.message" || type.startsWith("assistant.") || type.startsWith("permission.") || type.startsWith("session.") || type.startsWith("subagent.") || type.startsWith("tool.") || type.startsWith("user_input."));
|
|
3925
4042
|
}
|
|
3926
4043
|
function deriveCopilotSessionStatus(rawMessages) {
|
|
3927
|
-
const
|
|
3928
|
-
for (const event of rawMessages) {
|
|
4044
|
+
const agents = /* @__PURE__ */ new Map();
|
|
4045
|
+
for (const [index, event] of rawMessages.entries()) {
|
|
3929
4046
|
const agentId = typeof event.agentId === "string" ? event.agentId : "";
|
|
3930
4047
|
if (!agentId && (event.type === "abort" || event.type === "session.shutdown" || event.type === "session.error")) {
|
|
3931
|
-
|
|
4048
|
+
agents.clear();
|
|
3932
4049
|
continue;
|
|
3933
4050
|
}
|
|
3934
4051
|
if (!agentId || !event.type.startsWith("subagent.")) continue;
|
|
3935
4052
|
const data = isObject4(event.data) ? event.data : {};
|
|
4053
|
+
const launch = agents.get(agentId);
|
|
3936
4054
|
if (event.type === "subagent.completed" || event.type === "subagent.failed") {
|
|
3937
|
-
|
|
4055
|
+
if (launch) launch.endedAt ??= index;
|
|
3938
4056
|
continue;
|
|
3939
4057
|
}
|
|
3940
4058
|
if (event.type === "subagent.started" || event.type === "subagent.configured") {
|
|
3941
4059
|
const description = [data.agentDisplayName, data.description, data.agentName].find((value) => typeof value === "string") ?? "";
|
|
3942
|
-
|
|
4060
|
+
if (!launch || launch.endedAt !== void 0) {
|
|
4061
|
+
const startedAt = typeof event.timestamp === "string" ? event.timestamp : void 0;
|
|
4062
|
+
agents.set(agentId, { agent: { description, startedAt }, launchedAt: index });
|
|
4063
|
+
} else if (description) {
|
|
4064
|
+
launch.agent.description = description;
|
|
4065
|
+
}
|
|
3943
4066
|
}
|
|
3944
4067
|
}
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
return {
|
|
3948
|
-
status: "awaiting_agents",
|
|
3949
|
-
pendingQueue: 0,
|
|
3950
|
-
pendingAgents: descriptions.length,
|
|
3951
|
-
pendingAgentDescriptions: descriptions.filter((description) => description.length > 0)
|
|
3952
|
-
};
|
|
3953
|
-
}
|
|
4068
|
+
const awaiting = awaitingAgentsStatus([...agents.values()]);
|
|
4069
|
+
if (awaiting) return awaiting;
|
|
3954
4070
|
let sawUserActivity = false;
|
|
3955
4071
|
const completedPermissionRequests = /* @__PURE__ */ new Set();
|
|
3956
4072
|
for (let i = rawMessages.length - 1; i >= 0; i--) {
|
|
@@ -4036,6 +4152,7 @@ function copilotTurnBoundaries(records) {
|
|
|
4036
4152
|
|
|
4037
4153
|
// src/lib/agents.ts
|
|
4038
4154
|
var TERMINAL_AGENT_KIND = AGENT_KINDS[AGENT_KINDS.length - 1];
|
|
4155
|
+
var hasNoNoiseLines = () => false;
|
|
4039
4156
|
var codexFormat = {
|
|
4040
4157
|
kind: "codex",
|
|
4041
4158
|
descriptor: descriptorFor("codex"),
|
|
@@ -4045,6 +4162,8 @@ var codexFormat = {
|
|
|
4045
4162
|
append: appendCodexSession,
|
|
4046
4163
|
metadataFromLines: extractCodexMetadataFromLines,
|
|
4047
4164
|
status: deriveCodexSessionStatus,
|
|
4165
|
+
isNoiseLine: hasNoNoiseLines,
|
|
4166
|
+
pageHeaderLine: codexPageHeaderLine,
|
|
4048
4167
|
brandBranch: brandCodexBranch,
|
|
4049
4168
|
turnBoundaries: codexTurnBoundaries
|
|
4050
4169
|
};
|
|
@@ -4057,6 +4176,7 @@ var copilotFormat = {
|
|
|
4057
4176
|
append: appendCopilotSession,
|
|
4058
4177
|
metadataFromLines: extractCopilotMetadataFromLines,
|
|
4059
4178
|
status: deriveCopilotSessionStatus,
|
|
4179
|
+
isNoiseLine: hasNoNoiseLines,
|
|
4060
4180
|
brandBranch: brandCopilotBranch,
|
|
4061
4181
|
turnBoundaries: copilotTurnBoundaries
|
|
4062
4182
|
};
|
|
@@ -4070,6 +4190,7 @@ var claudeFormat = {
|
|
|
4070
4190
|
append: appendClaudeSession,
|
|
4071
4191
|
metadataFromLines: extractClaudeMetadataFromLines,
|
|
4072
4192
|
status: deriveClaudeSessionStatus,
|
|
4193
|
+
isNoiseLine: isClaudeNoiseLine,
|
|
4073
4194
|
brandBranch: brandClaudeBranch,
|
|
4074
4195
|
turnBoundaries: claudeTurnBoundaries
|
|
4075
4196
|
};
|
|
@@ -4099,6 +4220,9 @@ function formatForText(jsonlText) {
|
|
|
4099
4220
|
function formatForRecords(records) {
|
|
4100
4221
|
return firstMatch((format) => format.detectsRecords(records));
|
|
4101
4222
|
}
|
|
4223
|
+
function isAnyAgentNoiseLine(line) {
|
|
4224
|
+
return AGENT_KINDS.some((kind) => FORMATS[kind].isNoiseLine(line));
|
|
4225
|
+
}
|
|
4102
4226
|
|
|
4103
4227
|
// src/lib/parser.ts
|
|
4104
4228
|
function extractTextFromContent2(content) {
|
|
@@ -4124,8 +4248,55 @@ function getUserMessageImages(content) {
|
|
|
4124
4248
|
return content.filter((b) => b.type === "image");
|
|
4125
4249
|
}
|
|
4126
4250
|
|
|
4127
|
-
// src/lib/
|
|
4251
|
+
// src/lib/transcriptFile.ts
|
|
4128
4252
|
var import_node_fs = require("node:fs");
|
|
4253
|
+
var import_promises = require("node:fs/promises");
|
|
4254
|
+
var zlib = __toESM(require("node:zlib"));
|
|
4255
|
+
var COMPRESSED_SUFFIX = ".zst";
|
|
4256
|
+
var canReadCompressedTranscripts = typeof zlib.zstdDecompressSync === "function";
|
|
4257
|
+
function isCompressedTranscript(filePath) {
|
|
4258
|
+
return filePath.endsWith(COMPRESSED_SUFFIX);
|
|
4259
|
+
}
|
|
4260
|
+
function uncompressedTranscriptName(fileName) {
|
|
4261
|
+
return isCompressedTranscript(fileName) ? fileName.slice(0, -COMPRESSED_SUFFIX.length) : fileName;
|
|
4262
|
+
}
|
|
4263
|
+
function isListableTranscript(name, siblings) {
|
|
4264
|
+
const plainName = uncompressedTranscriptName(name);
|
|
4265
|
+
if (!plainName.endsWith(".jsonl")) return false;
|
|
4266
|
+
if (plainName === name) return true;
|
|
4267
|
+
return canReadCompressedTranscripts && !siblings.has(plainName);
|
|
4268
|
+
}
|
|
4269
|
+
function inflate(data) {
|
|
4270
|
+
if (!canReadCompressedTranscripts) {
|
|
4271
|
+
throw new Error("Reading a .jsonl.zst transcript needs Node.js 22.15 or newer, or Bun");
|
|
4272
|
+
}
|
|
4273
|
+
return zlib.zstdDecompressSync(data);
|
|
4274
|
+
}
|
|
4275
|
+
function readTranscriptTextSync(filePath) {
|
|
4276
|
+
const data = (0, import_node_fs.readFileSync)(filePath);
|
|
4277
|
+
return (isCompressedTranscript(filePath) ? inflate(data) : data).toString("utf-8");
|
|
4278
|
+
}
|
|
4279
|
+
async function readTranscriptText(filePath) {
|
|
4280
|
+
const data = await (0, import_promises.readFile)(filePath);
|
|
4281
|
+
return (isCompressedTranscript(filePath) ? inflate(data) : data).toString("utf-8");
|
|
4282
|
+
}
|
|
4283
|
+
async function openTranscript(filePath) {
|
|
4284
|
+
if (!isCompressedTranscript(filePath)) return (0, import_promises.open)(filePath, "r");
|
|
4285
|
+
const [fileStat, compressed] = await Promise.all([(0, import_promises.stat)(filePath), (0, import_promises.readFile)(filePath)]);
|
|
4286
|
+
const data = inflate(compressed);
|
|
4287
|
+
return {
|
|
4288
|
+
async read(buffer, offset, length, position) {
|
|
4289
|
+
const start = Math.min(Math.max(position, 0), data.length);
|
|
4290
|
+
return { bytesRead: data.copy(buffer, offset, start, Math.min(start + length, data.length)) };
|
|
4291
|
+
},
|
|
4292
|
+
stat: async () => ({ size: data.length, mtimeMs: fileStat.mtimeMs }),
|
|
4293
|
+
close: async () => {
|
|
4294
|
+
}
|
|
4295
|
+
};
|
|
4296
|
+
}
|
|
4297
|
+
|
|
4298
|
+
// src/lib/stores.ts
|
|
4299
|
+
var import_node_fs2 = require("node:fs");
|
|
4129
4300
|
var import_node_path2 = require("node:path");
|
|
4130
4301
|
|
|
4131
4302
|
// src/lib/dirs.ts
|
|
@@ -4152,14 +4323,14 @@ var MAX_WALK_DEPTH = 4;
|
|
|
4152
4323
|
var SUBAGENTS_DIR = "subagents";
|
|
4153
4324
|
function mtimeOf(filePath) {
|
|
4154
4325
|
try {
|
|
4155
|
-
return (0,
|
|
4326
|
+
return (0, import_node_fs2.statSync)(filePath).mtimeMs;
|
|
4156
4327
|
} catch {
|
|
4157
4328
|
return null;
|
|
4158
4329
|
}
|
|
4159
4330
|
}
|
|
4160
4331
|
function readDirSafe(dir) {
|
|
4161
4332
|
try {
|
|
4162
|
-
return (0,
|
|
4333
|
+
return (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true });
|
|
4163
4334
|
} catch {
|
|
4164
4335
|
return [];
|
|
4165
4336
|
}
|
|
@@ -4170,8 +4341,8 @@ function isWithin(root, target) {
|
|
|
4170
4341
|
}
|
|
4171
4342
|
function canonicalWithinRoot(root, filePath) {
|
|
4172
4343
|
try {
|
|
4173
|
-
const realRoot = (0,
|
|
4174
|
-
const real = (0,
|
|
4344
|
+
const realRoot = (0, import_node_fs2.realpathSync)(root);
|
|
4345
|
+
const real = (0, import_node_fs2.realpathSync)(filePath);
|
|
4175
4346
|
return isWithin(realRoot, real) ? real : null;
|
|
4176
4347
|
} catch {
|
|
4177
4348
|
return null;
|
|
@@ -4237,13 +4408,15 @@ function walkClaude(root, cutoffMs) {
|
|
|
4237
4408
|
function walkCodex(root, cutoffMs, dir = root, depth = 0) {
|
|
4238
4409
|
if (depth > MAX_WALK_DEPTH) return [];
|
|
4239
4410
|
const found = [];
|
|
4240
|
-
|
|
4411
|
+
const entries = readDirSafe(dir);
|
|
4412
|
+
const names = new Set(entries.map((entry) => entry.name));
|
|
4413
|
+
for (const entry of entries) {
|
|
4241
4414
|
const filePath = (0, import_node_path2.join)(dir, entry.name);
|
|
4242
4415
|
if (entry.isDirectory()) {
|
|
4243
4416
|
found.push(...walkCodex(root, cutoffMs, filePath, depth + 1));
|
|
4244
4417
|
continue;
|
|
4245
4418
|
}
|
|
4246
|
-
if (!entry.name
|
|
4419
|
+
if (!isListableTranscript(entry.name, names)) continue;
|
|
4247
4420
|
const mtimeMs = mtimeOf(filePath);
|
|
4248
4421
|
if (mtimeMs === null || mtimeMs < cutoffMs) continue;
|
|
4249
4422
|
found.push({
|
|
@@ -4304,14 +4477,18 @@ var WALKERS = {
|
|
|
4304
4477
|
find(root, sessionId) {
|
|
4305
4478
|
const walk = (dir, depth) => {
|
|
4306
4479
|
if (depth > MAX_WALK_DEPTH) return null;
|
|
4307
|
-
|
|
4480
|
+
const entries = readDirSafe(dir);
|
|
4481
|
+
const names = new Set(entries.map((entry) => entry.name));
|
|
4482
|
+
for (const entry of entries) {
|
|
4308
4483
|
const filePath = (0, import_node_path2.join)(dir, entry.name);
|
|
4309
4484
|
if (entry.isDirectory()) {
|
|
4310
4485
|
const match = walk(filePath, depth + 1);
|
|
4311
4486
|
if (match) return match;
|
|
4312
4487
|
continue;
|
|
4313
4488
|
}
|
|
4314
|
-
if (entry.name.endsWith(`${sessionId}.jsonl`))
|
|
4489
|
+
if (uncompressedTranscriptName(entry.name).endsWith(`${sessionId}.jsonl`) && isListableTranscript(entry.name, names)) {
|
|
4490
|
+
return filePath;
|
|
4491
|
+
}
|
|
4315
4492
|
}
|
|
4316
4493
|
return null;
|
|
4317
4494
|
};
|
|
@@ -4354,7 +4531,7 @@ function makeStore(kind, home, configuredId) {
|
|
|
4354
4531
|
ownsPath: (filePath) => {
|
|
4355
4532
|
if (isWithin((0, import_node_path2.resolve)(root()), (0, import_node_path2.resolve)(filePath))) return true;
|
|
4356
4533
|
try {
|
|
4357
|
-
return isWithin((0,
|
|
4534
|
+
return isWithin((0, import_node_fs2.realpathSync)(root()), (0, import_node_fs2.realpathSync)(filePath));
|
|
4358
4535
|
} catch {
|
|
4359
4536
|
return false;
|
|
4360
4537
|
}
|
|
@@ -4388,7 +4565,7 @@ function allStores() {
|
|
|
4388
4565
|
if (!entry.isDirectory()) continue;
|
|
4389
4566
|
const home = (0, import_node_path2.join)(root, "provider-instances", entry.name);
|
|
4390
4567
|
try {
|
|
4391
|
-
const config = JSON.parse((0,
|
|
4568
|
+
const config = JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.join)(home, "config.json"), "utf8"));
|
|
4392
4569
|
if (config.providerInstance?.id === entry.name && config.providerInstance.agent && AGENT_KINDS.includes(config.providerInstance.agent)) stores.push(makeStore(config.providerInstance.agent, home, entry.name));
|
|
4393
4570
|
} catch {
|
|
4394
4571
|
}
|
|
@@ -4463,7 +4640,7 @@ var SearchIndex = class {
|
|
|
4463
4640
|
const { count: totalRows } = this.db.prepare("SELECT COUNT(*) as count FROM search_content").get();
|
|
4464
4641
|
let dbSizeBytes = 0;
|
|
4465
4642
|
try {
|
|
4466
|
-
dbSizeBytes = (0,
|
|
4643
|
+
dbSizeBytes = (0, import_node_fs3.statSync)(this.dbPath).size;
|
|
4467
4644
|
} catch {
|
|
4468
4645
|
}
|
|
4469
4646
|
return {
|
|
@@ -4536,9 +4713,9 @@ var SearchIndex = class {
|
|
|
4536
4713
|
indexFile(filePath, sessionId, mtimeMs, opts) {
|
|
4537
4714
|
const resolvedSessionId = sessionId ?? identifyTranscript(filePath).sessionId;
|
|
4538
4715
|
if (mtimeMs == null) {
|
|
4539
|
-
mtimeMs = (0,
|
|
4716
|
+
mtimeMs = (0, import_node_fs3.statSync)(filePath).mtimeMs;
|
|
4540
4717
|
}
|
|
4541
|
-
const content = (
|
|
4718
|
+
const content = readTranscriptTextSync(filePath);
|
|
4542
4719
|
const session = parseSession(content, { skipStats: true });
|
|
4543
4720
|
const isSubagent = opts?.isSubagent ? 1 : 0;
|
|
4544
4721
|
const parentSessionId = opts?.parentSessionId ?? null;
|
|
@@ -4567,7 +4744,7 @@ var SearchIndex = class {
|
|
|
4567
4744
|
const files = this.db.prepare("SELECT file_path FROM indexed_files").all();
|
|
4568
4745
|
const missing = files.filter(({ file_path }) => {
|
|
4569
4746
|
try {
|
|
4570
|
-
(0,
|
|
4747
|
+
(0, import_node_fs3.statSync)(file_path);
|
|
4571
4748
|
return false;
|
|
4572
4749
|
} catch (error) {
|
|
4573
4750
|
const code = error.code;
|
|
@@ -4684,7 +4861,7 @@ var SearchIndex = class {
|
|
|
4684
4861
|
this.db.close();
|
|
4685
4862
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
4686
4863
|
try {
|
|
4687
|
-
(0,
|
|
4864
|
+
(0, import_node_fs3.unlinkSync)(this.dbPath + suffix);
|
|
4688
4865
|
} catch {
|
|
4689
4866
|
}
|
|
4690
4867
|
}
|
|
@@ -4708,7 +4885,7 @@ var SearchIndex = class {
|
|
|
4708
4885
|
const txn = this.db.transaction(() => {
|
|
4709
4886
|
for (const file of files) {
|
|
4710
4887
|
try {
|
|
4711
|
-
const content = (
|
|
4888
|
+
const content = readTranscriptTextSync(file.path);
|
|
4712
4889
|
const session = parseSession(content, { skipStats: true });
|
|
4713
4890
|
this.insertSessionContent(insert, file.sessionId, file.path, session);
|
|
4714
4891
|
insertFile.run(file.path, file.mtimeMs, file.sessionId, file.isSubagent ? 1 : 0, file.parentSessionId);
|
|
@@ -4770,8 +4947,8 @@ var SearchIndex = class {
|
|
|
4770
4947
|
};
|
|
4771
4948
|
|
|
4772
4949
|
// src/commands/search.ts
|
|
4773
|
-
var
|
|
4774
|
-
var
|
|
4950
|
+
var import_node_fs4 = require("node:fs");
|
|
4951
|
+
var import_promises2 = require("node:fs/promises");
|
|
4775
4952
|
var import_node_path3 = require("node:path");
|
|
4776
4953
|
|
|
4777
4954
|
// src/lib/response.ts
|
|
@@ -4809,9 +4986,9 @@ async function searchSessions(query, opts, searchIndex) {
|
|
|
4809
4986
|
let ownedIndex = false;
|
|
4810
4987
|
if (!index && searchIndex === void 0) {
|
|
4811
4988
|
try {
|
|
4812
|
-
const dbExists = (0,
|
|
4989
|
+
const dbExists = (0, import_node_fs4.existsSync)(DEFAULT_DB_PATH);
|
|
4813
4990
|
if (!dbExists) {
|
|
4814
|
-
(0,
|
|
4991
|
+
(0, import_node_fs4.mkdirSync)((0, import_node_path3.dirname)(DEFAULT_DB_PATH), { recursive: true });
|
|
4815
4992
|
}
|
|
4816
4993
|
index = new SearchIndex(DEFAULT_DB_PATH);
|
|
4817
4994
|
ownedIndex = true;
|
|
@@ -4885,7 +5062,7 @@ async function cwdFromFilePath(filePath) {
|
|
|
4885
5062
|
const cached = cwdCache.get(filePath);
|
|
4886
5063
|
if (cached !== void 0) return cached;
|
|
4887
5064
|
try {
|
|
4888
|
-
const fh = await (
|
|
5065
|
+
const fh = await openTranscript(filePath);
|
|
4889
5066
|
try {
|
|
4890
5067
|
const buf = Buffer.alloc(CWD_READ_BYTES);
|
|
4891
5068
|
const { bytesRead } = await fh.read(buf, 0, CWD_READ_BYTES, 0);
|
|
@@ -4943,7 +5120,7 @@ function searchField(text, location, query, caseSensitive, extras) {
|
|
|
4943
5120
|
async function discoverSingleSession(sessionId) {
|
|
4944
5121
|
const jsonlPath = await findSessionFile(sessionId);
|
|
4945
5122
|
if (!jsonlPath) return [];
|
|
4946
|
-
const s = await (0,
|
|
5123
|
+
const s = await (0, import_promises2.stat)(jsonlPath);
|
|
4947
5124
|
return [{ path: jsonlPath, mtimeMs: s.mtimeMs, sessionId }];
|
|
4948
5125
|
}
|
|
4949
5126
|
function discoverAllSessions(maxAgeMs) {
|
|
@@ -4951,7 +5128,7 @@ function discoverAllSessions(maxAgeMs) {
|
|
|
4951
5128
|
}
|
|
4952
5129
|
async function rawTextMatch(filePath, query, caseSensitive) {
|
|
4953
5130
|
try {
|
|
4954
|
-
const content = await (
|
|
5131
|
+
const content = await readTranscriptText(filePath);
|
|
4955
5132
|
const haystack = caseSensitive ? content : content.toLowerCase();
|
|
4956
5133
|
const needle = caseSensitive ? query : query.toLowerCase();
|
|
4957
5134
|
if (haystack.includes(needle)) return content;
|
|
@@ -5026,7 +5203,7 @@ async function walkSubagentFiles(parentJsonlPath, query, caseSensitive, currentD
|
|
|
5026
5203
|
const subDir = parentJsonlPath.replace(/\.jsonl$/, "") + "/subagents";
|
|
5027
5204
|
let files;
|
|
5028
5205
|
try {
|
|
5029
|
-
files = await (0,
|
|
5206
|
+
files = await (0, import_promises2.readdir)(subDir);
|
|
5030
5207
|
} catch {
|
|
5031
5208
|
return [];
|
|
5032
5209
|
}
|
|
@@ -5104,14 +5281,14 @@ async function rawScanSearch(query, sessionId, maxAgeMs, limit, caseSensitive, e
|
|
|
5104
5281
|
}
|
|
5105
5282
|
|
|
5106
5283
|
// src/commands/context.ts
|
|
5107
|
-
var
|
|
5284
|
+
var import_promises4 = require("node:fs/promises");
|
|
5108
5285
|
var import_node_path5 = require("node:path");
|
|
5109
5286
|
|
|
5110
5287
|
// src/lib/helpers.ts
|
|
5111
|
-
var
|
|
5288
|
+
var import_promises3 = require("node:fs/promises");
|
|
5112
5289
|
var import_node_path4 = require("node:path");
|
|
5113
5290
|
async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
|
|
5114
|
-
const entries = await (0,
|
|
5291
|
+
const entries = await (0, import_promises3.readdir)(dirs.PROJECTS_DIR, { withFileTypes: true });
|
|
5115
5292
|
for (const entry of entries) {
|
|
5116
5293
|
if (!entry.isDirectory() || entry.name === "memory") continue;
|
|
5117
5294
|
const filePath = (0, import_node_path4.join)(
|
|
@@ -5122,7 +5299,7 @@ async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
|
|
|
5122
5299
|
subagentFileName
|
|
5123
5300
|
);
|
|
5124
5301
|
try {
|
|
5125
|
-
const fh = await (0,
|
|
5302
|
+
const fh = await (0, import_promises3.open)(filePath, "r");
|
|
5126
5303
|
try {
|
|
5127
5304
|
const buf = Buffer.alloc(16384);
|
|
5128
5305
|
const { bytesRead } = await fh.read(buf, 0, 16384, 0);
|
|
@@ -5317,7 +5494,13 @@ function mapContentBlock(block) {
|
|
|
5317
5494
|
case "task_notification":
|
|
5318
5495
|
return { kind: "task_notification", content: block.content, timestamp: block.timestamp ?? null };
|
|
5319
5496
|
case "local_command":
|
|
5320
|
-
return {
|
|
5497
|
+
return {
|
|
5498
|
+
kind: "local_command",
|
|
5499
|
+
content: block.content,
|
|
5500
|
+
timestamp: block.timestamp ?? null,
|
|
5501
|
+
...block.contextUsage ? { contextUsage: block.contextUsage } : {},
|
|
5502
|
+
...block.usageReport ? { usageReport: block.usageReport } : {}
|
|
5503
|
+
};
|
|
5321
5504
|
default: {
|
|
5322
5505
|
const exhaustive = block;
|
|
5323
5506
|
return exhaustive;
|
|
@@ -5327,7 +5510,7 @@ function mapContentBlock(block) {
|
|
|
5327
5510
|
async function findSubagentFile(parentJsonlPath, agentId) {
|
|
5328
5511
|
const subagentsDir = parentJsonlPath.replace(/\.jsonl$/, "") + "/subagents";
|
|
5329
5512
|
try {
|
|
5330
|
-
const files = await (0,
|
|
5513
|
+
const files = await (0, import_promises4.readdir)(subagentsDir);
|
|
5331
5514
|
for (const f of files) {
|
|
5332
5515
|
if (!f.startsWith("agent-") || !f.endsWith(".jsonl")) continue;
|
|
5333
5516
|
const fileAgentId = f.replace("agent-", "").replace(".jsonl", "");
|
|
@@ -5341,12 +5524,12 @@ async function findSubagentFile(parentJsonlPath, agentId) {
|
|
|
5341
5524
|
}
|
|
5342
5525
|
async function findTeamContext(sessionId, subagentFileName) {
|
|
5343
5526
|
try {
|
|
5344
|
-
const teamEntries = await (0,
|
|
5527
|
+
const teamEntries = await (0, import_promises4.readdir)(dirs.TEAMS_DIR, { withFileTypes: true });
|
|
5345
5528
|
for (const entry of teamEntries) {
|
|
5346
5529
|
if (!entry.isDirectory()) continue;
|
|
5347
5530
|
const configPath = (0, import_node_path5.join)(dirs.TEAMS_DIR, entry.name, "config.json");
|
|
5348
5531
|
try {
|
|
5349
|
-
const raw = await (0,
|
|
5532
|
+
const raw = await (0, import_promises4.readFile)(configPath, "utf-8");
|
|
5350
5533
|
const config = JSON.parse(raw);
|
|
5351
5534
|
if (config.leadSessionId !== sessionId) continue;
|
|
5352
5535
|
const members = config.members ?? [];
|
|
@@ -5355,10 +5538,10 @@ async function findTeamContext(sessionId, subagentFileName) {
|
|
|
5355
5538
|
let currentTask = null;
|
|
5356
5539
|
try {
|
|
5357
5540
|
const taskDir = (0, import_node_path5.join)(dirs.TASKS_DIR, entry.name);
|
|
5358
|
-
const taskFiles = await (0,
|
|
5541
|
+
const taskFiles = await (0, import_promises4.readdir)(taskDir);
|
|
5359
5542
|
for (const tf of taskFiles) {
|
|
5360
5543
|
if (!tf.endsWith(".json")) continue;
|
|
5361
|
-
const taskRaw = await (0,
|
|
5544
|
+
const taskRaw = await (0, import_promises4.readFile)((0, import_node_path5.join)(taskDir, tf), "utf-8");
|
|
5362
5545
|
const task = JSON.parse(taskRaw);
|
|
5363
5546
|
if (task.owner === memberName && task.status === "in_progress") {
|
|
5364
5547
|
currentTask = { id: task.id, subject: task.subject, status: task.status };
|
|
@@ -5406,14 +5589,14 @@ function findAgentMetadata(session, agentId) {
|
|
|
5406
5589
|
async function getSessionOverview(sessionId) {
|
|
5407
5590
|
const jsonlPath = await findSessionFile(sessionId);
|
|
5408
5591
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5409
|
-
const content = await (
|
|
5592
|
+
const content = await readTranscriptText(jsonlPath);
|
|
5410
5593
|
const session = parseTranscript(content, jsonlPath);
|
|
5411
5594
|
return mapSessionToOverview(session);
|
|
5412
5595
|
}
|
|
5413
5596
|
async function getTurnDetail(sessionId, turnIndex) {
|
|
5414
5597
|
const jsonlPath = await findSessionFile(sessionId);
|
|
5415
5598
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5416
|
-
const content = await (
|
|
5599
|
+
const content = await readTranscriptText(jsonlPath);
|
|
5417
5600
|
const session = parseTranscript(content, jsonlPath);
|
|
5418
5601
|
if (turnIndex < 0 || turnIndex >= session.turns.length) return { error: "Turn not found" };
|
|
5419
5602
|
return mapTurnToDetail(session, turnIndex);
|
|
@@ -5421,11 +5604,11 @@ async function getTurnDetail(sessionId, turnIndex) {
|
|
|
5421
5604
|
async function getAgentOverview(sessionId, agentId) {
|
|
5422
5605
|
const jsonlPath = await findSessionFile(sessionId);
|
|
5423
5606
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5424
|
-
const content = await (
|
|
5607
|
+
const content = await readTranscriptText(jsonlPath);
|
|
5425
5608
|
const session = parseTranscript(content, jsonlPath);
|
|
5426
5609
|
const subagentFile = await findSubagentFile(jsonlPath, agentId);
|
|
5427
5610
|
if (!subagentFile) return { error: "Agent not found" };
|
|
5428
|
-
const subagentContent = await (
|
|
5611
|
+
const subagentContent = await readTranscriptText(subagentFile.filePath);
|
|
5429
5612
|
const subagentSession = parseTranscript(subagentContent, subagentFile.filePath);
|
|
5430
5613
|
const metadata = findAgentMetadata(session, agentId);
|
|
5431
5614
|
const parentToolCallId = findParentToolCallId(session, agentId);
|
|
@@ -5446,7 +5629,7 @@ async function getAgentTurnDetail(sessionId, agentId, turnIndex) {
|
|
|
5446
5629
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5447
5630
|
const subagentFile = await findSubagentFile(jsonlPath, agentId);
|
|
5448
5631
|
if (!subagentFile) return { error: "Agent not found" };
|
|
5449
|
-
const subagentContent = await (
|
|
5632
|
+
const subagentContent = await readTranscriptText(subagentFile.filePath);
|
|
5450
5633
|
const subagentSession = parseTranscript(subagentContent, subagentFile.filePath);
|
|
5451
5634
|
if (turnIndex < 0 || turnIndex >= subagentSession.turns.length) return { error: "Turn not found" };
|
|
5452
5635
|
return mapTurnToDetail(subagentSession, turnIndex);
|
|
@@ -5456,7 +5639,7 @@ async function getAgentTurnDetail(sessionId, agentId, turnIndex) {
|
|
|
5456
5639
|
var import_node_path6 = require("node:path");
|
|
5457
5640
|
|
|
5458
5641
|
// src/lib/metadata.ts
|
|
5459
|
-
var
|
|
5642
|
+
var import_promises5 = require("node:fs/promises");
|
|
5460
5643
|
|
|
5461
5644
|
// src/lib/sessionStatus.ts
|
|
5462
5645
|
function deriveSessionStatus(rawMessages) {
|
|
@@ -5481,6 +5664,7 @@ function scanClaudeMessages(lines) {
|
|
|
5481
5664
|
turnCount: 0
|
|
5482
5665
|
};
|
|
5483
5666
|
for (const line of lines) {
|
|
5667
|
+
if (isAnyAgentNoiseLine(line)) continue;
|
|
5484
5668
|
let record2;
|
|
5485
5669
|
try {
|
|
5486
5670
|
record2 = JSON.parse(line);
|
|
@@ -5509,11 +5693,11 @@ function scanClaudeMessages(lines) {
|
|
|
5509
5693
|
return meta;
|
|
5510
5694
|
}
|
|
5511
5695
|
async function readLines(filePath, size) {
|
|
5512
|
-
if (size <= FULL_READ_LIMIT) {
|
|
5513
|
-
const content = await (
|
|
5696
|
+
if (size <= FULL_READ_LIMIT || isCompressedTranscript(filePath)) {
|
|
5697
|
+
const content = await readTranscriptText(filePath);
|
|
5514
5698
|
return { lines: content.split("\n").filter(Boolean), isPartialRead: false };
|
|
5515
5699
|
}
|
|
5516
|
-
const handle = await (0,
|
|
5700
|
+
const handle = await (0, import_promises5.open)(filePath, "r");
|
|
5517
5701
|
try {
|
|
5518
5702
|
const buffer = Buffer.alloc(HEAD_READ_BYTES);
|
|
5519
5703
|
const { bytesRead } = await handle.read(buffer, 0, HEAD_READ_BYTES, 0);
|
|
@@ -5528,11 +5712,11 @@ async function readLines(filePath, size) {
|
|
|
5528
5712
|
}
|
|
5529
5713
|
}
|
|
5530
5714
|
async function getSessionMeta(filePath) {
|
|
5531
|
-
const fileStat = await (0,
|
|
5715
|
+
const fileStat = await (0, import_promises5.stat)(filePath);
|
|
5532
5716
|
let { lines, isPartialRead } = await readLines(filePath, fileStat.size);
|
|
5533
5717
|
const format = formatForText(lines.join("\n"));
|
|
5534
5718
|
if (isPartialRead && !format.descriptor.metadataFromHead) {
|
|
5535
|
-
lines = (await (0,
|
|
5719
|
+
lines = (await (0, import_promises5.readFile)(filePath, "utf-8")).split("\n").filter(Boolean);
|
|
5536
5720
|
isPartialRead = false;
|
|
5537
5721
|
}
|
|
5538
5722
|
const header = readHeader(format, lines);
|
|
@@ -5561,10 +5745,10 @@ async function getSessionStatus(filePath) {
|
|
|
5561
5745
|
const CHUNK = 4096;
|
|
5562
5746
|
const MAX_CHUNKS = 64;
|
|
5563
5747
|
try {
|
|
5564
|
-
const
|
|
5565
|
-
if (fileStat.size === 0) return { status: "idle" };
|
|
5566
|
-
const fh = await (0, import_promises4.open)(filePath, "r");
|
|
5748
|
+
const fh = await openTranscript(filePath);
|
|
5567
5749
|
try {
|
|
5750
|
+
const fileStat = await fh.stat();
|
|
5751
|
+
if (fileStat.size === 0) return { status: "idle" };
|
|
5568
5752
|
const meaningful = [];
|
|
5569
5753
|
let cursor = fileStat.size;
|
|
5570
5754
|
let leftover = "";
|
|
@@ -5580,7 +5764,7 @@ async function getSessionStatus(filePath) {
|
|
|
5580
5764
|
const startIdx = cursor > 0 ? 1 : 0;
|
|
5581
5765
|
for (let i = lines.length - 1; i >= startIdx; i--) {
|
|
5582
5766
|
const line = lines[i];
|
|
5583
|
-
if (!line) continue;
|
|
5767
|
+
if (!line || isAnyAgentNoiseLine(line)) continue;
|
|
5584
5768
|
let obj;
|
|
5585
5769
|
try {
|
|
5586
5770
|
obj = JSON.parse(line);
|
|
@@ -5711,11 +5895,11 @@ async function currentSession(cwd) {
|
|
|
5711
5895
|
}
|
|
5712
5896
|
|
|
5713
5897
|
// src/commands/index-cmd.ts
|
|
5714
|
-
var
|
|
5898
|
+
var import_node_fs5 = require("node:fs");
|
|
5715
5899
|
var import_node_path7 = require("node:path");
|
|
5716
5900
|
async function indexStats(dbPath) {
|
|
5717
5901
|
const path = dbPath ?? DEFAULT_DB_PATH;
|
|
5718
|
-
if (!(0,
|
|
5902
|
+
if (!(0, import_node_fs5.existsSync)(path)) {
|
|
5719
5903
|
return { error: `Database not found at ${path}. Run 'cogpit-memory index rebuild' to create it.` };
|
|
5720
5904
|
}
|
|
5721
5905
|
const index = new SearchIndex(path);
|
|
@@ -5725,7 +5909,7 @@ async function indexStats(dbPath) {
|
|
|
5725
5909
|
}
|
|
5726
5910
|
async function indexRebuild(dbPath) {
|
|
5727
5911
|
const path = dbPath ?? DEFAULT_DB_PATH;
|
|
5728
|
-
(0,
|
|
5912
|
+
(0, import_node_fs5.mkdirSync)((0, import_node_path7.dirname)(path), { recursive: true });
|
|
5729
5913
|
const index = new SearchIndex(path);
|
|
5730
5914
|
index.buildFull();
|
|
5731
5915
|
const stats = index.getStats();
|