cogpit-memory 0.4.0 → 0.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 +438 -182
- package/dist/index.js +433 -177
- package/dist/lib/agent-descriptors.d.ts +4 -0
- package/dist/lib/agents.d.ts +14 -0
- package/dist/lib/asyncAnswers.d.ts +10 -0
- package/dist/lib/automatedPrompts.d.ts +4 -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 +127 -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];
|
|
@@ -1829,6 +1880,62 @@ function appendAssistantText(turn, text, timestamp) {
|
|
|
1829
1880
|
turn.contentBlocks.push({ kind: "text", text: [text], timestamp });
|
|
1830
1881
|
}
|
|
1831
1882
|
|
|
1883
|
+
// src/lib/automatedPrompts.ts
|
|
1884
|
+
var CREW_CHAT_DELIVERY_RE = /^Crew chat · ([^\n]+) · message (\d+)(?:\n|$)/;
|
|
1885
|
+
var TASK_WAKEUP_START_RE = /^Delegated task \S+ (?:running|completed|error|cancelled|needs attention)\. Child session: /;
|
|
1886
|
+
function isReaderPrompt(text) {
|
|
1887
|
+
const trimmed = text.trim();
|
|
1888
|
+
if (!trimmed) return false;
|
|
1889
|
+
if (CREW_CHAT_DELIVERY_RE.test(trimmed) || TASK_WAKEUP_START_RE.test(trimmed)) return false;
|
|
1890
|
+
return parseAgentEnvelope(trimmed).sender === null;
|
|
1891
|
+
}
|
|
1892
|
+
|
|
1893
|
+
// src/lib/asyncAnswers.ts
|
|
1894
|
+
function promptText(content) {
|
|
1895
|
+
if (content === null) return "";
|
|
1896
|
+
if (typeof content === "string") return content;
|
|
1897
|
+
return content.flatMap((block) => block.type === "text" ? [block.text] : []).join("\n");
|
|
1898
|
+
}
|
|
1899
|
+
function linkAsyncAnswers(turns) {
|
|
1900
|
+
const answers = /* @__PURE__ */ new Map();
|
|
1901
|
+
let open4 = [];
|
|
1902
|
+
const answer = (text) => {
|
|
1903
|
+
if (open4.length === 0 || !isReaderPrompt(text)) return;
|
|
1904
|
+
for (const id of open4) answers.set(id, text.trim());
|
|
1905
|
+
open4 = [];
|
|
1906
|
+
};
|
|
1907
|
+
for (const turn of turns) {
|
|
1908
|
+
answer(promptText(turn.userMessage));
|
|
1909
|
+
for (const block of turn.contentBlocks) {
|
|
1910
|
+
if (block.kind === "queued_prompt") answer(block.content);
|
|
1911
|
+
else if (block.kind === "tool_calls") {
|
|
1912
|
+
for (const call of block.toolCalls) if (call.asyncQuestion) open4.push(call.id);
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
const stale = (call) => call.asyncQuestion === true && call.asyncAnswer !== answers.get(call.id);
|
|
1917
|
+
const relinked = /* @__PURE__ */ new Map();
|
|
1918
|
+
const relink = (call) => {
|
|
1919
|
+
if (!stale(call)) return call;
|
|
1920
|
+
let next = relinked.get(call);
|
|
1921
|
+
if (!next) {
|
|
1922
|
+
const { asyncAnswer: _previous, ...rest } = call;
|
|
1923
|
+
const reply = answers.get(call.id);
|
|
1924
|
+
next = reply === void 0 ? rest : { ...rest, asyncAnswer: reply };
|
|
1925
|
+
relinked.set(call, next);
|
|
1926
|
+
}
|
|
1927
|
+
return next;
|
|
1928
|
+
};
|
|
1929
|
+
return turns.map((turn) => {
|
|
1930
|
+
if (!turn.toolCalls.some(stale)) return turn;
|
|
1931
|
+
return {
|
|
1932
|
+
...turn,
|
|
1933
|
+
toolCalls: turn.toolCalls.map(relink),
|
|
1934
|
+
contentBlocks: turn.contentBlocks.map((block) => block.kind === "tool_calls" ? { ...block, toolCalls: block.toolCalls.map(relink) } : block)
|
|
1935
|
+
};
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1832
1939
|
// src/lib/codex-patches.ts
|
|
1833
1940
|
function isApplyPatchText(value) {
|
|
1834
1941
|
return value.includes("*** Begin Patch") && value.includes("*** End Patch");
|
|
@@ -2168,6 +2275,48 @@ function codexParentId(payload) {
|
|
|
2168
2275
|
}
|
|
2169
2276
|
return null;
|
|
2170
2277
|
}
|
|
2278
|
+
function inheritedHistoryFilter(records) {
|
|
2279
|
+
const meta = records.find((record2) => record2?.type === "session_meta");
|
|
2280
|
+
const start = meta?.payload?.subagent_history_start_ordinal;
|
|
2281
|
+
if (typeof start !== "number") return null;
|
|
2282
|
+
const reachesPast = (ordinal) => typeof ordinal === "number" && ordinal >= start;
|
|
2283
|
+
if (!reachesPast(meta?.rolloutLastOrdinal) && !records.some((record2) => reachesPast(record2?.ordinal))) return null;
|
|
2284
|
+
return (record2) => typeof record2.ordinal === "number" && record2.ordinal > 0 && record2.ordinal < start;
|
|
2285
|
+
}
|
|
2286
|
+
async function codexPageHeaderLine(firstLine, lastLines) {
|
|
2287
|
+
if (!firstLine.includes('"subagent_history_start_ordinal"')) return firstLine;
|
|
2288
|
+
const meta = safeParseLine(firstLine);
|
|
2289
|
+
if (meta?.type !== "session_meta") return firstLine;
|
|
2290
|
+
const lines = await lastLines();
|
|
2291
|
+
for (let index = lines.length - 1; index >= 0; index--) {
|
|
2292
|
+
const ordinal = safeParseLine(lines[index])?.ordinal;
|
|
2293
|
+
if (typeof ordinal === "number") return JSON.stringify({ ...meta, rolloutLastOrdinal: ordinal });
|
|
2294
|
+
}
|
|
2295
|
+
return firstLine;
|
|
2296
|
+
}
|
|
2297
|
+
function subAgentActivitySource(record2) {
|
|
2298
|
+
const payload = record2.payload;
|
|
2299
|
+
if (record2.type !== "event_msg" || !isObject3(payload)) return null;
|
|
2300
|
+
if (payload.type === "sub_agent_activity") return payload;
|
|
2301
|
+
if (payload.type === "item_completed" && isObject3(payload.item) && payload.item.type === "SubAgentActivity") return payload.item;
|
|
2302
|
+
return null;
|
|
2303
|
+
}
|
|
2304
|
+
function readSubAgentActivity(record2) {
|
|
2305
|
+
const source = subAgentActivitySource(record2);
|
|
2306
|
+
if (!source || typeof source.agent_thread_id !== "string" || typeof source.agent_path !== "string") return null;
|
|
2307
|
+
return {
|
|
2308
|
+
agentId: source.agent_thread_id,
|
|
2309
|
+
agentPath: source.agent_path,
|
|
2310
|
+
kind: typeof source.kind === "string" ? source.kind : "started",
|
|
2311
|
+
eventId: findString(source.event_id, source.id) ?? "",
|
|
2312
|
+
model: findString(source.model) || null,
|
|
2313
|
+
effort: findString(source.reasoning_effort) || null
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2316
|
+
function turnErrorMessage(payload) {
|
|
2317
|
+
if (payload.type !== "task_complete" || !isObject3(payload.error)) return "";
|
|
2318
|
+
return typeof payload.error.message === "string" ? payload.error.message.trim() : "";
|
|
2319
|
+
}
|
|
2171
2320
|
function isCodexRecord(record2) {
|
|
2172
2321
|
if (!record2 || typeof record2.type !== "string") return false;
|
|
2173
2322
|
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 +2514,39 @@ function createTurn2(turnId, timestamp, model) {
|
|
|
2365
2514
|
model
|
|
2366
2515
|
};
|
|
2367
2516
|
}
|
|
2368
|
-
function
|
|
2369
|
-
|
|
2370
|
-
|
|
2517
|
+
function codexPromptText(record2) {
|
|
2518
|
+
const payload = isObject3(record2.payload) ? record2.payload : null;
|
|
2519
|
+
if (record2.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
|
|
2520
|
+
return normalizePromptText(payload.message);
|
|
2371
2521
|
}
|
|
2372
|
-
if (record2.type === "response_item" &&
|
|
2373
|
-
return normalizePromptText(extractMessageText(
|
|
2522
|
+
if (record2.type === "response_item" && payload?.type === "message" && payload.role === "user") {
|
|
2523
|
+
return normalizePromptText(extractMessageText(payload, "input_text"));
|
|
2374
2524
|
}
|
|
2375
2525
|
return "";
|
|
2376
2526
|
}
|
|
2527
|
+
function createCodexPromptReader() {
|
|
2528
|
+
let echoPending = false;
|
|
2529
|
+
return (record2) => {
|
|
2530
|
+
const payload = isObject3(record2.payload) ? record2.payload : null;
|
|
2531
|
+
if (record2.type === "event_msg" && payload?.type === "user_message") {
|
|
2532
|
+
const isEcho = echoPending;
|
|
2533
|
+
echoPending = false;
|
|
2534
|
+
return isEcho ? "" : codexPromptText(record2);
|
|
2535
|
+
}
|
|
2536
|
+
if (record2.type !== "response_item") return "";
|
|
2537
|
+
const prompt = codexPromptText(record2);
|
|
2538
|
+
if (prompt) echoPending = true;
|
|
2539
|
+
else if (payload?.type !== "message" || payload.role !== "user") echoPending = false;
|
|
2540
|
+
return prompt;
|
|
2541
|
+
};
|
|
2542
|
+
}
|
|
2377
2543
|
function recordOpensTurn(record2, payload) {
|
|
2378
2544
|
if (record2.type === "session_meta") return false;
|
|
2379
2545
|
if (record2.type === "event_msg" && payload?.type === "task_started") return false;
|
|
2380
2546
|
if (record2.type === "response_item" && payload?.type === "message") {
|
|
2381
2547
|
if (payload.role === "developer" || payload.role === "system") return false;
|
|
2382
2548
|
if (payload.role === "user") {
|
|
2383
|
-
return
|
|
2549
|
+
return codexPromptText(record2) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
|
|
2384
2550
|
}
|
|
2385
2551
|
}
|
|
2386
2552
|
return true;
|
|
@@ -2400,9 +2566,10 @@ function extractMetadataFromRecords(records) {
|
|
|
2400
2566
|
let isSubagent = false;
|
|
2401
2567
|
let parentSessionId = null;
|
|
2402
2568
|
let agentPath = "/root";
|
|
2403
|
-
|
|
2569
|
+
const readPrompt = createCodexPromptReader();
|
|
2570
|
+
const isInherited = inheritedHistoryFilter(records);
|
|
2404
2571
|
for (const record2 of records) {
|
|
2405
|
-
if (!isObject3(record2.payload)) continue;
|
|
2572
|
+
if (!isObject3(record2.payload) || isInherited?.(record2)) continue;
|
|
2406
2573
|
if (record2.type === "session_meta") {
|
|
2407
2574
|
sessionId ||= typeof record2.payload.id === "string" ? record2.payload.id : "";
|
|
2408
2575
|
version ||= typeof record2.payload.cli_version === "string" ? record2.payload.cli_version : "";
|
|
@@ -2432,12 +2599,10 @@ function extractMetadataFromRecords(records) {
|
|
|
2432
2599
|
model ||= typeof record2.payload.model === "string" ? record2.payload.model : "";
|
|
2433
2600
|
cwd ||= typeof record2.payload.cwd === "string" ? record2.payload.cwd : "";
|
|
2434
2601
|
}
|
|
2435
|
-
const prompt =
|
|
2602
|
+
const prompt = readPrompt(record2);
|
|
2436
2603
|
if (!prompt) continue;
|
|
2437
|
-
if (prompt === previousPrompt) continue;
|
|
2438
2604
|
if (!firstUserMessage) firstUserMessage = prompt;
|
|
2439
2605
|
lastUserMessage = prompt;
|
|
2440
|
-
previousPrompt = prompt;
|
|
2441
2606
|
turnCount++;
|
|
2442
2607
|
if (!timestamp) timestamp = record2.timestamp ?? "";
|
|
2443
2608
|
lastTimestamp = record2.timestamp ?? lastTimestamp;
|
|
@@ -2507,6 +2672,7 @@ function walkCodexRecords(records, options) {
|
|
|
2507
2672
|
timestamp: info?.timestamp ?? eventTimestamp2,
|
|
2508
2673
|
tokenUsage: null,
|
|
2509
2674
|
model: info?.model ?? null,
|
|
2675
|
+
...info?.effort ? { effort: info.effort } : {},
|
|
2510
2676
|
isBackground: false,
|
|
2511
2677
|
prompt: info?.message || void 0,
|
|
2512
2678
|
status: update.status ?? "running"
|
|
@@ -2527,6 +2693,7 @@ function walkCodexRecords(records, options) {
|
|
|
2527
2693
|
agentMessage.agentName = info.nickname ?? (info.agentPath ? agentNameFromPath(info.agentPath) : agentMessage.agentName);
|
|
2528
2694
|
agentMessage.subagentType = info.agentType;
|
|
2529
2695
|
agentMessage.model = info.model;
|
|
2696
|
+
if (info.effort) agentMessage.effort = info.effort;
|
|
2530
2697
|
agentMessage.prompt = info.message || agentMessage.prompt;
|
|
2531
2698
|
}
|
|
2532
2699
|
if (update.text && !agentMessage.text.includes(update.text)) {
|
|
@@ -2550,6 +2717,7 @@ function walkCodexRecords(records, options) {
|
|
|
2550
2717
|
}
|
|
2551
2718
|
let current = null;
|
|
2552
2719
|
let currentTurnId = null;
|
|
2720
|
+
let queuedPromptEcho = false;
|
|
2553
2721
|
let currentModel = metadata.model || null;
|
|
2554
2722
|
let lastTurnTimestamp = "";
|
|
2555
2723
|
let pendingCompaction = null;
|
|
@@ -2597,12 +2765,14 @@ function walkCodexRecords(records, options) {
|
|
|
2597
2765
|
webSearchCalls.set(id, toolCall);
|
|
2598
2766
|
appendToolCall(targetTurn, toolCall, timestamp);
|
|
2599
2767
|
}
|
|
2768
|
+
const isInherited = inheritedHistoryFilter(records);
|
|
2600
2769
|
for (let index = 0; index < records.length; index++) {
|
|
2601
2770
|
const record2 = records[index];
|
|
2602
|
-
if (!isCodexRecord(record2)) continue;
|
|
2771
|
+
if (!isCodexRecord(record2) || isInherited?.(record2)) continue;
|
|
2603
2772
|
recordIndex = index;
|
|
2604
2773
|
const payload = isObject3(record2.payload) ? record2.payload : void 0;
|
|
2605
2774
|
const timestamp = record2.timestamp ?? "";
|
|
2775
|
+
if (record2.type !== "event_msg") queuedPromptEcho = false;
|
|
2606
2776
|
if (record2.type === "compacted") {
|
|
2607
2777
|
current = commitTurn(current);
|
|
2608
2778
|
pendingCompaction = "Conversation compacted";
|
|
@@ -2620,11 +2790,17 @@ function walkCodexRecords(records, options) {
|
|
|
2620
2790
|
continue;
|
|
2621
2791
|
}
|
|
2622
2792
|
if (record2.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
|
|
2793
|
+
if (queuedPromptEcho) {
|
|
2794
|
+
queuedPromptEcho = false;
|
|
2795
|
+
continue;
|
|
2796
|
+
}
|
|
2623
2797
|
if (current && (current.assistantText.length > 0 || current.toolCalls.length > 0 || current.thinking.length > 0)) {
|
|
2624
2798
|
current = commitTurn(current);
|
|
2625
2799
|
}
|
|
2800
|
+
const opensWindow = !sawTurnStart;
|
|
2626
2801
|
sawTurnStart = true;
|
|
2627
2802
|
current ??= createActiveTurn(currentTurnId, timestamp, currentModel);
|
|
2803
|
+
if (opensWindow) current.opensOnPrompt = true;
|
|
2628
2804
|
const localImages = (Array.isArray(payload.local_images) ? payload.local_images : []).filter(
|
|
2629
2805
|
(p) => typeof p === "string" && p.length > 0
|
|
2630
2806
|
);
|
|
@@ -2688,12 +2864,18 @@ function walkCodexRecords(records, options) {
|
|
|
2688
2864
|
}
|
|
2689
2865
|
continue;
|
|
2690
2866
|
}
|
|
2691
|
-
if (record2.type === "event_msg" && payload
|
|
2692
|
-
const
|
|
2693
|
-
|
|
2694
|
-
|
|
2867
|
+
if (record2.type === "event_msg" && payload) {
|
|
2868
|
+
const turnError = turnErrorMessage(payload);
|
|
2869
|
+
if (turnError) {
|
|
2870
|
+
appendAssistantText(current, turnError, timestamp);
|
|
2871
|
+
continue;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
const activity = readSubAgentActivity(record2);
|
|
2875
|
+
if (activity) {
|
|
2876
|
+
const { agentId, agentPath, eventId: eventId2, kind } = activity;
|
|
2695
2877
|
const spawnInfo = eventId2 ? spawnAgentCalls.get(eventId2) : void 0;
|
|
2696
|
-
const existingId = agentIdByPath.get(
|
|
2878
|
+
const existingId = agentIdByPath.get(agentPath);
|
|
2697
2879
|
const existing = agentRegistry.get(agentId) ?? (existingId ? agentRegistry.get(existingId) : void 0);
|
|
2698
2880
|
if (kind !== "started" && !existing && !spawnInfo) continue;
|
|
2699
2881
|
if (existingId && existingId !== agentId && !agentMessages.has(agentId)) {
|
|
@@ -2707,18 +2889,19 @@ function walkCodexRecords(records, options) {
|
|
|
2707
2889
|
}
|
|
2708
2890
|
const info = {
|
|
2709
2891
|
agentId,
|
|
2710
|
-
nickname: existing?.nickname ?? agentNameFromPath(
|
|
2711
|
-
agentPath
|
|
2892
|
+
nickname: existing?.nickname ?? agentNameFromPath(agentPath) ?? spawnInfo?.taskName ?? null,
|
|
2893
|
+
agentPath,
|
|
2712
2894
|
message: existing?.message ?? spawnInfo?.message ?? "",
|
|
2713
|
-
model: existing?.model ?? spawnInfo?.model ?? null,
|
|
2895
|
+
model: activity.model ?? existing?.model ?? spawnInfo?.model ?? null,
|
|
2896
|
+
effort: activity.effort ?? existing?.effort ?? null,
|
|
2714
2897
|
agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
|
|
2715
2898
|
timestamp: existing?.timestamp ?? (timestamp || spawnInfo?.timestamp || ""),
|
|
2716
2899
|
parentToolCallId: existing?.parentToolCallId ?? eventId2
|
|
2717
2900
|
};
|
|
2718
2901
|
agentRegistry.set(agentId, info);
|
|
2719
|
-
agentIdByPath.set(
|
|
2902
|
+
agentIdByPath.set(agentPath, agentId);
|
|
2720
2903
|
if (eventId2 && (kind === "started" || spawnInfo)) agentIdBySpawnCall.set(eventId2, agentId);
|
|
2721
|
-
const status = kind === "interrupted"
|
|
2904
|
+
const status = kind === "interrupted" || kind === "completed" ? kind : "running";
|
|
2722
2905
|
upsertAgentMessage(agentId, current, timestamp, { status });
|
|
2723
2906
|
continue;
|
|
2724
2907
|
}
|
|
@@ -2732,8 +2915,15 @@ function walkCodexRecords(records, options) {
|
|
|
2732
2915
|
appendAssistantText(current, extractMessageText(payload, "output_text"), timestamp);
|
|
2733
2916
|
continue;
|
|
2734
2917
|
}
|
|
2735
|
-
if (payload.type === "message" && payload.role === "user"
|
|
2918
|
+
if (payload.type === "message" && payload.role === "user") {
|
|
2736
2919
|
const text = normalizePromptText(extractMessageText(payload, "input_text"));
|
|
2920
|
+
if (current.userMessage !== null || current.contentBlocks.length > 0) {
|
|
2921
|
+
if (text) {
|
|
2922
|
+
current.contentBlocks.push({ kind: "queued_prompt", content: text, timestamp });
|
|
2923
|
+
queuedPromptEcho = true;
|
|
2924
|
+
}
|
|
2925
|
+
continue;
|
|
2926
|
+
}
|
|
2737
2927
|
const images = extractResponseMessageImages(payload);
|
|
2738
2928
|
const audio = extractResponseMessageAudio(payload);
|
|
2739
2929
|
if (text || images.length > 0 || audio.length > 0) {
|
|
@@ -2874,6 +3064,7 @@ function walkCodexRecords(records, options) {
|
|
|
2874
3064
|
agentPath: agentPath ?? existing?.agentPath ?? null,
|
|
2875
3065
|
message: existing?.message ?? spawnInfo?.message ?? "",
|
|
2876
3066
|
model: existing?.model ?? spawnInfo?.model ?? null,
|
|
3067
|
+
effort: existing?.effort ?? null,
|
|
2877
3068
|
agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
|
|
2878
3069
|
timestamp: existing?.timestamp ?? spawnInfo?.timestamp ?? timestamp,
|
|
2879
3070
|
parentToolCallId: existing?.parentToolCallId ?? toolCall.id
|
|
@@ -2974,6 +3165,7 @@ function walkCodexRecords(records, options) {
|
|
|
2974
3165
|
}
|
|
2975
3166
|
}
|
|
2976
3167
|
commitTurn(current);
|
|
3168
|
+
const linkedTurns = linkAsyncAnswers(turns);
|
|
2977
3169
|
return {
|
|
2978
3170
|
turnStartIndices,
|
|
2979
3171
|
sessionId: metadata.sessionId,
|
|
@@ -2983,8 +3175,8 @@ function walkCodexRecords(records, options) {
|
|
|
2983
3175
|
slug: metadata.slug,
|
|
2984
3176
|
name: "",
|
|
2985
3177
|
model: metadata.model,
|
|
2986
|
-
turns,
|
|
2987
|
-
stats: options?.skipStats ? createEmptySessionStats(
|
|
3178
|
+
turns: linkedTurns,
|
|
3179
|
+
stats: options?.skipStats ? createEmptySessionStats(linkedTurns.length) : computeStats(linkedTurns),
|
|
2988
3180
|
rawMessages: options?.skipStats ? [] : records,
|
|
2989
3181
|
branchedFrom: metadata.branchedFrom,
|
|
2990
3182
|
agentKind: "codex"
|
|
@@ -2992,8 +3184,10 @@ function walkCodexRecords(records, options) {
|
|
|
2992
3184
|
}
|
|
2993
3185
|
function parseCodexSession(jsonlText, options) {
|
|
2994
3186
|
const records = jsonlText.split("\n").map((line) => line.trim()).filter(Boolean).map(safeParseLine).filter(isCodexRecord);
|
|
3187
|
+
const isInherited = inheritedHistoryFilter(records);
|
|
3188
|
+
const ownRecords = isInherited ? records.filter((record2) => !isInherited(record2)) : records;
|
|
2995
3189
|
const { turnStartIndices: _starts, ...session } = walkCodexRecords(
|
|
2996
|
-
|
|
3190
|
+
ownRecords,
|
|
2997
3191
|
options
|
|
2998
3192
|
);
|
|
2999
3193
|
return session;
|
|
@@ -3018,40 +3212,48 @@ function parseJsonObject(value) {
|
|
|
3018
3212
|
return null;
|
|
3019
3213
|
}
|
|
3020
3214
|
}
|
|
3021
|
-
function
|
|
3022
|
-
const
|
|
3023
|
-
const
|
|
3215
|
+
function collectCodexBackgroundAgents(rawMessages) {
|
|
3216
|
+
const launched = /* @__PURE__ */ new Map();
|
|
3217
|
+
const alive = /* @__PURE__ */ new Set();
|
|
3218
|
+
const endedAt = /* @__PURE__ */ new Map();
|
|
3024
3219
|
const agentIdByPath = /* @__PURE__ */ new Map();
|
|
3025
3220
|
const spawnCalls = /* @__PURE__ */ new Map();
|
|
3026
3221
|
const waitCalls = /* @__PURE__ */ new Set();
|
|
3027
3222
|
const interruptCalls = /* @__PURE__ */ new Map();
|
|
3028
|
-
function markAlive(agentId, description) {
|
|
3029
|
-
if (
|
|
3030
|
-
|
|
3031
|
-
|
|
3223
|
+
function markAlive(agentId, description, index, startedAt) {
|
|
3224
|
+
if (endedAt.has(agentId)) return;
|
|
3225
|
+
alive.add(agentId);
|
|
3226
|
+
const launch = launched.get(agentId);
|
|
3227
|
+
if (!launch) launched.set(agentId, { launchedAt: index, description, startedAt });
|
|
3228
|
+
else if (!launch.description) launch.description = description;
|
|
3229
|
+
}
|
|
3230
|
+
function markEnded(agentId, index) {
|
|
3231
|
+
if (!endedAt.has(agentId)) endedAt.set(agentId, index);
|
|
3232
|
+
alive.delete(agentId);
|
|
3233
|
+
}
|
|
3234
|
+
for (const [index, msg] of rawMessages.entries()) {
|
|
3032
3235
|
const payload = isObject3(msg.payload) ? msg.payload : null;
|
|
3033
3236
|
if (!payload) continue;
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
const
|
|
3038
|
-
const existingId = agentIdByPath.get(
|
|
3039
|
-
const known = alive.has(agentId) ||
|
|
3237
|
+
const timestamp = typeof msg.timestamp === "string" ? msg.timestamp : void 0;
|
|
3238
|
+
const activity = readSubAgentActivity(msg);
|
|
3239
|
+
if (activity) {
|
|
3240
|
+
const { agentId, agentPath, kind, eventId: eventId2 } = activity;
|
|
3241
|
+
const existingId = agentIdByPath.get(agentPath);
|
|
3242
|
+
const known = alive.has(agentId) || endedAt.has(agentId) || existingId !== void 0 || spawnCalls.has(eventId2);
|
|
3040
3243
|
if (kind !== "started" && !known) continue;
|
|
3041
3244
|
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) ?? "");
|
|
3245
|
+
const prior = launched.get(existingId);
|
|
3246
|
+
launched.delete(existingId);
|
|
3247
|
+
const current = launched.get(agentId);
|
|
3248
|
+
if (prior && !current) launched.set(agentId, prior);
|
|
3249
|
+
else if (prior && current && !current.description) current.description = prior.description;
|
|
3250
|
+
if (alive.delete(existingId)) markAlive(agentId, "", index, timestamp);
|
|
3251
|
+
const priorEnd = endedAt.get(existingId);
|
|
3252
|
+
if (priorEnd !== void 0) markEnded(agentId, priorEnd);
|
|
3054
3253
|
}
|
|
3254
|
+
agentIdByPath.set(agentPath, agentId);
|
|
3255
|
+
if (kind === "interrupted" || kind === "completed") markEnded(agentId, index);
|
|
3256
|
+
else markAlive(agentId, spawnCalls.get(eventId2) ?? "", index, timestamp);
|
|
3055
3257
|
continue;
|
|
3056
3258
|
}
|
|
3057
3259
|
if (msg.type !== "response_item") continue;
|
|
@@ -3075,7 +3277,7 @@ function collectCodexPendingAgents(rawMessages) {
|
|
|
3075
3277
|
const output = parseJsonObject(payload.output);
|
|
3076
3278
|
const agentId = typeof output?.agent_id === "string" ? output.agent_id : "";
|
|
3077
3279
|
if (agentId) {
|
|
3078
|
-
markAlive(agentId, spawnCalls.get(callId) ?? "");
|
|
3280
|
+
markAlive(agentId, spawnCalls.get(callId) ?? "", index, timestamp);
|
|
3079
3281
|
const agentPath = typeof output?.task_name === "string" ? output.task_name : "";
|
|
3080
3282
|
if (agentPath && !agentIdByPath.has(agentPath)) agentIdByPath.set(agentPath, agentId);
|
|
3081
3283
|
}
|
|
@@ -3086,16 +3288,10 @@ function collectCodexPendingAgents(rawMessages) {
|
|
|
3086
3288
|
const statusValue = isObject3(status) ? status : {};
|
|
3087
3289
|
const lifecycle = typeof statusValue.status === "string" ? statusValue.status : "";
|
|
3088
3290
|
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
|
-
}
|
|
3291
|
+
if (isTerminal) markEnded(agentId, index);
|
|
3093
3292
|
}
|
|
3094
3293
|
} else if (interruptCalls.has(callId)) {
|
|
3095
|
-
for (const agentId of interruptCalls.get(callId) ?? [])
|
|
3096
|
-
done.add(agentId);
|
|
3097
|
-
alive.delete(agentId);
|
|
3098
|
-
}
|
|
3294
|
+
for (const agentId of interruptCalls.get(callId) ?? []) markEnded(agentId, index);
|
|
3099
3295
|
}
|
|
3100
3296
|
continue;
|
|
3101
3297
|
}
|
|
@@ -3103,12 +3299,14 @@ function collectCodexPendingAgents(rawMessages) {
|
|
|
3103
3299
|
const text = codexPayloadText(payload);
|
|
3104
3300
|
const messageType = text.match(/^Message Type:\s*([^\r\n]+)/)?.[1]?.trim().toUpperCase() ?? "";
|
|
3105
3301
|
if (!TERMINAL_INTER_AGENT_TYPES.has(messageType)) continue;
|
|
3106
|
-
|
|
3107
|
-
done.add(agentId);
|
|
3108
|
-
alive.delete(agentId);
|
|
3302
|
+
markEnded(agentIdByPath.get(payload.author) ?? payload.author, index);
|
|
3109
3303
|
}
|
|
3110
3304
|
}
|
|
3111
|
-
return [...
|
|
3305
|
+
return [...launched.entries()].map(([agentId, { description, startedAt, launchedAt }]) => ({
|
|
3306
|
+
agent: { description, startedAt },
|
|
3307
|
+
launchedAt,
|
|
3308
|
+
endedAt: alive.has(agentId) ? void 0 : endedAt.get(agentId) ?? launchedAt
|
|
3309
|
+
}));
|
|
3112
3310
|
}
|
|
3113
3311
|
function deriveCodexSessionStatus(rawMessages) {
|
|
3114
3312
|
for (let i = rawMessages.length - 1; i >= 0; i--) {
|
|
@@ -3117,16 +3315,7 @@ function deriveCodexSessionStatus(rawMessages) {
|
|
|
3117
3315
|
const payload = msg.payload;
|
|
3118
3316
|
switch (payload?.type) {
|
|
3119
3317
|
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" };
|
|
3318
|
+
return awaitingAgentsStatus(collectCodexBackgroundAgents(rawMessages)) ?? { status: "completed" };
|
|
3130
3319
|
}
|
|
3131
3320
|
case "task_started":
|
|
3132
3321
|
return { status: "processing" };
|
|
@@ -3924,33 +4113,32 @@ function isCopilotEventType(type) {
|
|
|
3924
4113
|
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
4114
|
}
|
|
3926
4115
|
function deriveCopilotSessionStatus(rawMessages) {
|
|
3927
|
-
const
|
|
3928
|
-
for (const event of rawMessages) {
|
|
4116
|
+
const agents = /* @__PURE__ */ new Map();
|
|
4117
|
+
for (const [index, event] of rawMessages.entries()) {
|
|
3929
4118
|
const agentId = typeof event.agentId === "string" ? event.agentId : "";
|
|
3930
4119
|
if (!agentId && (event.type === "abort" || event.type === "session.shutdown" || event.type === "session.error")) {
|
|
3931
|
-
|
|
4120
|
+
agents.clear();
|
|
3932
4121
|
continue;
|
|
3933
4122
|
}
|
|
3934
4123
|
if (!agentId || !event.type.startsWith("subagent.")) continue;
|
|
3935
4124
|
const data = isObject4(event.data) ? event.data : {};
|
|
4125
|
+
const launch = agents.get(agentId);
|
|
3936
4126
|
if (event.type === "subagent.completed" || event.type === "subagent.failed") {
|
|
3937
|
-
|
|
4127
|
+
if (launch) launch.endedAt ??= index;
|
|
3938
4128
|
continue;
|
|
3939
4129
|
}
|
|
3940
4130
|
if (event.type === "subagent.started" || event.type === "subagent.configured") {
|
|
3941
4131
|
const description = [data.agentDisplayName, data.description, data.agentName].find((value) => typeof value === "string") ?? "";
|
|
3942
|
-
|
|
4132
|
+
if (!launch || launch.endedAt !== void 0) {
|
|
4133
|
+
const startedAt = typeof event.timestamp === "string" ? event.timestamp : void 0;
|
|
4134
|
+
agents.set(agentId, { agent: { description, startedAt }, launchedAt: index });
|
|
4135
|
+
} else if (description) {
|
|
4136
|
+
launch.agent.description = description;
|
|
4137
|
+
}
|
|
3943
4138
|
}
|
|
3944
4139
|
}
|
|
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
|
-
}
|
|
4140
|
+
const awaiting = awaitingAgentsStatus([...agents.values()]);
|
|
4141
|
+
if (awaiting) return awaiting;
|
|
3954
4142
|
let sawUserActivity = false;
|
|
3955
4143
|
const completedPermissionRequests = /* @__PURE__ */ new Set();
|
|
3956
4144
|
for (let i = rawMessages.length - 1; i >= 0; i--) {
|
|
@@ -4036,6 +4224,7 @@ function copilotTurnBoundaries(records) {
|
|
|
4036
4224
|
|
|
4037
4225
|
// src/lib/agents.ts
|
|
4038
4226
|
var TERMINAL_AGENT_KIND = AGENT_KINDS[AGENT_KINDS.length - 1];
|
|
4227
|
+
var hasNoNoiseLines = () => false;
|
|
4039
4228
|
var codexFormat = {
|
|
4040
4229
|
kind: "codex",
|
|
4041
4230
|
descriptor: descriptorFor("codex"),
|
|
@@ -4045,6 +4234,8 @@ var codexFormat = {
|
|
|
4045
4234
|
append: appendCodexSession,
|
|
4046
4235
|
metadataFromLines: extractCodexMetadataFromLines,
|
|
4047
4236
|
status: deriveCodexSessionStatus,
|
|
4237
|
+
isNoiseLine: hasNoNoiseLines,
|
|
4238
|
+
pageHeaderLine: codexPageHeaderLine,
|
|
4048
4239
|
brandBranch: brandCodexBranch,
|
|
4049
4240
|
turnBoundaries: codexTurnBoundaries
|
|
4050
4241
|
};
|
|
@@ -4057,6 +4248,7 @@ var copilotFormat = {
|
|
|
4057
4248
|
append: appendCopilotSession,
|
|
4058
4249
|
metadataFromLines: extractCopilotMetadataFromLines,
|
|
4059
4250
|
status: deriveCopilotSessionStatus,
|
|
4251
|
+
isNoiseLine: hasNoNoiseLines,
|
|
4060
4252
|
brandBranch: brandCopilotBranch,
|
|
4061
4253
|
turnBoundaries: copilotTurnBoundaries
|
|
4062
4254
|
};
|
|
@@ -4070,6 +4262,7 @@ var claudeFormat = {
|
|
|
4070
4262
|
append: appendClaudeSession,
|
|
4071
4263
|
metadataFromLines: extractClaudeMetadataFromLines,
|
|
4072
4264
|
status: deriveClaudeSessionStatus,
|
|
4265
|
+
isNoiseLine: isClaudeNoiseLine,
|
|
4073
4266
|
brandBranch: brandClaudeBranch,
|
|
4074
4267
|
turnBoundaries: claudeTurnBoundaries
|
|
4075
4268
|
};
|
|
@@ -4099,6 +4292,9 @@ function formatForText(jsonlText) {
|
|
|
4099
4292
|
function formatForRecords(records) {
|
|
4100
4293
|
return firstMatch((format) => format.detectsRecords(records));
|
|
4101
4294
|
}
|
|
4295
|
+
function isAnyAgentNoiseLine(line) {
|
|
4296
|
+
return AGENT_KINDS.some((kind) => FORMATS[kind].isNoiseLine(line));
|
|
4297
|
+
}
|
|
4102
4298
|
|
|
4103
4299
|
// src/lib/parser.ts
|
|
4104
4300
|
function extractTextFromContent2(content) {
|
|
@@ -4124,8 +4320,55 @@ function getUserMessageImages(content) {
|
|
|
4124
4320
|
return content.filter((b) => b.type === "image");
|
|
4125
4321
|
}
|
|
4126
4322
|
|
|
4127
|
-
// src/lib/
|
|
4323
|
+
// src/lib/transcriptFile.ts
|
|
4128
4324
|
var import_node_fs = require("node:fs");
|
|
4325
|
+
var import_promises = require("node:fs/promises");
|
|
4326
|
+
var zlib = __toESM(require("node:zlib"));
|
|
4327
|
+
var COMPRESSED_SUFFIX = ".zst";
|
|
4328
|
+
var canReadCompressedTranscripts = typeof zlib.zstdDecompressSync === "function";
|
|
4329
|
+
function isCompressedTranscript(filePath) {
|
|
4330
|
+
return filePath.endsWith(COMPRESSED_SUFFIX);
|
|
4331
|
+
}
|
|
4332
|
+
function uncompressedTranscriptName(fileName) {
|
|
4333
|
+
return isCompressedTranscript(fileName) ? fileName.slice(0, -COMPRESSED_SUFFIX.length) : fileName;
|
|
4334
|
+
}
|
|
4335
|
+
function isListableTranscript(name, siblings) {
|
|
4336
|
+
const plainName = uncompressedTranscriptName(name);
|
|
4337
|
+
if (!plainName.endsWith(".jsonl")) return false;
|
|
4338
|
+
if (plainName === name) return true;
|
|
4339
|
+
return canReadCompressedTranscripts && !siblings.has(plainName);
|
|
4340
|
+
}
|
|
4341
|
+
function inflate(data) {
|
|
4342
|
+
if (!canReadCompressedTranscripts) {
|
|
4343
|
+
throw new Error("Reading a .jsonl.zst transcript needs Node.js 22.15 or newer, or Bun");
|
|
4344
|
+
}
|
|
4345
|
+
return zlib.zstdDecompressSync(data);
|
|
4346
|
+
}
|
|
4347
|
+
function readTranscriptTextSync(filePath) {
|
|
4348
|
+
const data = (0, import_node_fs.readFileSync)(filePath);
|
|
4349
|
+
return (isCompressedTranscript(filePath) ? inflate(data) : data).toString("utf-8");
|
|
4350
|
+
}
|
|
4351
|
+
async function readTranscriptText(filePath) {
|
|
4352
|
+
const data = await (0, import_promises.readFile)(filePath);
|
|
4353
|
+
return (isCompressedTranscript(filePath) ? inflate(data) : data).toString("utf-8");
|
|
4354
|
+
}
|
|
4355
|
+
async function openTranscript(filePath) {
|
|
4356
|
+
if (!isCompressedTranscript(filePath)) return (0, import_promises.open)(filePath, "r");
|
|
4357
|
+
const [fileStat, compressed] = await Promise.all([(0, import_promises.stat)(filePath), (0, import_promises.readFile)(filePath)]);
|
|
4358
|
+
const data = inflate(compressed);
|
|
4359
|
+
return {
|
|
4360
|
+
async read(buffer, offset, length, position) {
|
|
4361
|
+
const start = Math.min(Math.max(position, 0), data.length);
|
|
4362
|
+
return { bytesRead: data.copy(buffer, offset, start, Math.min(start + length, data.length)) };
|
|
4363
|
+
},
|
|
4364
|
+
stat: async () => ({ size: data.length, mtimeMs: fileStat.mtimeMs }),
|
|
4365
|
+
close: async () => {
|
|
4366
|
+
}
|
|
4367
|
+
};
|
|
4368
|
+
}
|
|
4369
|
+
|
|
4370
|
+
// src/lib/stores.ts
|
|
4371
|
+
var import_node_fs2 = require("node:fs");
|
|
4129
4372
|
var import_node_path2 = require("node:path");
|
|
4130
4373
|
|
|
4131
4374
|
// src/lib/dirs.ts
|
|
@@ -4152,14 +4395,14 @@ var MAX_WALK_DEPTH = 4;
|
|
|
4152
4395
|
var SUBAGENTS_DIR = "subagents";
|
|
4153
4396
|
function mtimeOf(filePath) {
|
|
4154
4397
|
try {
|
|
4155
|
-
return (0,
|
|
4398
|
+
return (0, import_node_fs2.statSync)(filePath).mtimeMs;
|
|
4156
4399
|
} catch {
|
|
4157
4400
|
return null;
|
|
4158
4401
|
}
|
|
4159
4402
|
}
|
|
4160
4403
|
function readDirSafe(dir) {
|
|
4161
4404
|
try {
|
|
4162
|
-
return (0,
|
|
4405
|
+
return (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true });
|
|
4163
4406
|
} catch {
|
|
4164
4407
|
return [];
|
|
4165
4408
|
}
|
|
@@ -4170,8 +4413,8 @@ function isWithin(root, target) {
|
|
|
4170
4413
|
}
|
|
4171
4414
|
function canonicalWithinRoot(root, filePath) {
|
|
4172
4415
|
try {
|
|
4173
|
-
const realRoot = (0,
|
|
4174
|
-
const real = (0,
|
|
4416
|
+
const realRoot = (0, import_node_fs2.realpathSync)(root);
|
|
4417
|
+
const real = (0, import_node_fs2.realpathSync)(filePath);
|
|
4175
4418
|
return isWithin(realRoot, real) ? real : null;
|
|
4176
4419
|
} catch {
|
|
4177
4420
|
return null;
|
|
@@ -4237,13 +4480,15 @@ function walkClaude(root, cutoffMs) {
|
|
|
4237
4480
|
function walkCodex(root, cutoffMs, dir = root, depth = 0) {
|
|
4238
4481
|
if (depth > MAX_WALK_DEPTH) return [];
|
|
4239
4482
|
const found = [];
|
|
4240
|
-
|
|
4483
|
+
const entries = readDirSafe(dir);
|
|
4484
|
+
const names = new Set(entries.map((entry) => entry.name));
|
|
4485
|
+
for (const entry of entries) {
|
|
4241
4486
|
const filePath = (0, import_node_path2.join)(dir, entry.name);
|
|
4242
4487
|
if (entry.isDirectory()) {
|
|
4243
4488
|
found.push(...walkCodex(root, cutoffMs, filePath, depth + 1));
|
|
4244
4489
|
continue;
|
|
4245
4490
|
}
|
|
4246
|
-
if (!entry.name
|
|
4491
|
+
if (!isListableTranscript(entry.name, names)) continue;
|
|
4247
4492
|
const mtimeMs = mtimeOf(filePath);
|
|
4248
4493
|
if (mtimeMs === null || mtimeMs < cutoffMs) continue;
|
|
4249
4494
|
found.push({
|
|
@@ -4304,14 +4549,18 @@ var WALKERS = {
|
|
|
4304
4549
|
find(root, sessionId) {
|
|
4305
4550
|
const walk = (dir, depth) => {
|
|
4306
4551
|
if (depth > MAX_WALK_DEPTH) return null;
|
|
4307
|
-
|
|
4552
|
+
const entries = readDirSafe(dir);
|
|
4553
|
+
const names = new Set(entries.map((entry) => entry.name));
|
|
4554
|
+
for (const entry of entries) {
|
|
4308
4555
|
const filePath = (0, import_node_path2.join)(dir, entry.name);
|
|
4309
4556
|
if (entry.isDirectory()) {
|
|
4310
4557
|
const match = walk(filePath, depth + 1);
|
|
4311
4558
|
if (match) return match;
|
|
4312
4559
|
continue;
|
|
4313
4560
|
}
|
|
4314
|
-
if (entry.name.endsWith(`${sessionId}.jsonl`))
|
|
4561
|
+
if (uncompressedTranscriptName(entry.name).endsWith(`${sessionId}.jsonl`) && isListableTranscript(entry.name, names)) {
|
|
4562
|
+
return filePath;
|
|
4563
|
+
}
|
|
4315
4564
|
}
|
|
4316
4565
|
return null;
|
|
4317
4566
|
};
|
|
@@ -4354,7 +4603,7 @@ function makeStore(kind, home, configuredId) {
|
|
|
4354
4603
|
ownsPath: (filePath) => {
|
|
4355
4604
|
if (isWithin((0, import_node_path2.resolve)(root()), (0, import_node_path2.resolve)(filePath))) return true;
|
|
4356
4605
|
try {
|
|
4357
|
-
return isWithin((0,
|
|
4606
|
+
return isWithin((0, import_node_fs2.realpathSync)(root()), (0, import_node_fs2.realpathSync)(filePath));
|
|
4358
4607
|
} catch {
|
|
4359
4608
|
return false;
|
|
4360
4609
|
}
|
|
@@ -4388,7 +4637,7 @@ function allStores() {
|
|
|
4388
4637
|
if (!entry.isDirectory()) continue;
|
|
4389
4638
|
const home = (0, import_node_path2.join)(root, "provider-instances", entry.name);
|
|
4390
4639
|
try {
|
|
4391
|
-
const config = JSON.parse((0,
|
|
4640
|
+
const config = JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.join)(home, "config.json"), "utf8"));
|
|
4392
4641
|
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
4642
|
} catch {
|
|
4394
4643
|
}
|
|
@@ -4463,7 +4712,7 @@ var SearchIndex = class {
|
|
|
4463
4712
|
const { count: totalRows } = this.db.prepare("SELECT COUNT(*) as count FROM search_content").get();
|
|
4464
4713
|
let dbSizeBytes = 0;
|
|
4465
4714
|
try {
|
|
4466
|
-
dbSizeBytes = (0,
|
|
4715
|
+
dbSizeBytes = (0, import_node_fs3.statSync)(this.dbPath).size;
|
|
4467
4716
|
} catch {
|
|
4468
4717
|
}
|
|
4469
4718
|
return {
|
|
@@ -4536,9 +4785,9 @@ var SearchIndex = class {
|
|
|
4536
4785
|
indexFile(filePath, sessionId, mtimeMs, opts) {
|
|
4537
4786
|
const resolvedSessionId = sessionId ?? identifyTranscript(filePath).sessionId;
|
|
4538
4787
|
if (mtimeMs == null) {
|
|
4539
|
-
mtimeMs = (0,
|
|
4788
|
+
mtimeMs = (0, import_node_fs3.statSync)(filePath).mtimeMs;
|
|
4540
4789
|
}
|
|
4541
|
-
const content = (
|
|
4790
|
+
const content = readTranscriptTextSync(filePath);
|
|
4542
4791
|
const session = parseSession(content, { skipStats: true });
|
|
4543
4792
|
const isSubagent = opts?.isSubagent ? 1 : 0;
|
|
4544
4793
|
const parentSessionId = opts?.parentSessionId ?? null;
|
|
@@ -4567,7 +4816,7 @@ var SearchIndex = class {
|
|
|
4567
4816
|
const files = this.db.prepare("SELECT file_path FROM indexed_files").all();
|
|
4568
4817
|
const missing = files.filter(({ file_path }) => {
|
|
4569
4818
|
try {
|
|
4570
|
-
(0,
|
|
4819
|
+
(0, import_node_fs3.statSync)(file_path);
|
|
4571
4820
|
return false;
|
|
4572
4821
|
} catch (error) {
|
|
4573
4822
|
const code = error.code;
|
|
@@ -4684,7 +4933,7 @@ var SearchIndex = class {
|
|
|
4684
4933
|
this.db.close();
|
|
4685
4934
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
4686
4935
|
try {
|
|
4687
|
-
(0,
|
|
4936
|
+
(0, import_node_fs3.unlinkSync)(this.dbPath + suffix);
|
|
4688
4937
|
} catch {
|
|
4689
4938
|
}
|
|
4690
4939
|
}
|
|
@@ -4708,7 +4957,7 @@ var SearchIndex = class {
|
|
|
4708
4957
|
const txn = this.db.transaction(() => {
|
|
4709
4958
|
for (const file of files) {
|
|
4710
4959
|
try {
|
|
4711
|
-
const content = (
|
|
4960
|
+
const content = readTranscriptTextSync(file.path);
|
|
4712
4961
|
const session = parseSession(content, { skipStats: true });
|
|
4713
4962
|
this.insertSessionContent(insert, file.sessionId, file.path, session);
|
|
4714
4963
|
insertFile.run(file.path, file.mtimeMs, file.sessionId, file.isSubagent ? 1 : 0, file.parentSessionId);
|
|
@@ -4770,8 +5019,8 @@ var SearchIndex = class {
|
|
|
4770
5019
|
};
|
|
4771
5020
|
|
|
4772
5021
|
// src/commands/search.ts
|
|
4773
|
-
var
|
|
4774
|
-
var
|
|
5022
|
+
var import_node_fs4 = require("node:fs");
|
|
5023
|
+
var import_promises2 = require("node:fs/promises");
|
|
4775
5024
|
var import_node_path3 = require("node:path");
|
|
4776
5025
|
|
|
4777
5026
|
// src/lib/response.ts
|
|
@@ -4809,9 +5058,9 @@ async function searchSessions(query, opts, searchIndex) {
|
|
|
4809
5058
|
let ownedIndex = false;
|
|
4810
5059
|
if (!index && searchIndex === void 0) {
|
|
4811
5060
|
try {
|
|
4812
|
-
const dbExists = (0,
|
|
5061
|
+
const dbExists = (0, import_node_fs4.existsSync)(DEFAULT_DB_PATH);
|
|
4813
5062
|
if (!dbExists) {
|
|
4814
|
-
(0,
|
|
5063
|
+
(0, import_node_fs4.mkdirSync)((0, import_node_path3.dirname)(DEFAULT_DB_PATH), { recursive: true });
|
|
4815
5064
|
}
|
|
4816
5065
|
index = new SearchIndex(DEFAULT_DB_PATH);
|
|
4817
5066
|
ownedIndex = true;
|
|
@@ -4885,7 +5134,7 @@ async function cwdFromFilePath(filePath) {
|
|
|
4885
5134
|
const cached = cwdCache.get(filePath);
|
|
4886
5135
|
if (cached !== void 0) return cached;
|
|
4887
5136
|
try {
|
|
4888
|
-
const fh = await (
|
|
5137
|
+
const fh = await openTranscript(filePath);
|
|
4889
5138
|
try {
|
|
4890
5139
|
const buf = Buffer.alloc(CWD_READ_BYTES);
|
|
4891
5140
|
const { bytesRead } = await fh.read(buf, 0, CWD_READ_BYTES, 0);
|
|
@@ -4943,7 +5192,7 @@ function searchField(text, location, query, caseSensitive, extras) {
|
|
|
4943
5192
|
async function discoverSingleSession(sessionId) {
|
|
4944
5193
|
const jsonlPath = await findSessionFile(sessionId);
|
|
4945
5194
|
if (!jsonlPath) return [];
|
|
4946
|
-
const s = await (0,
|
|
5195
|
+
const s = await (0, import_promises2.stat)(jsonlPath);
|
|
4947
5196
|
return [{ path: jsonlPath, mtimeMs: s.mtimeMs, sessionId }];
|
|
4948
5197
|
}
|
|
4949
5198
|
function discoverAllSessions(maxAgeMs) {
|
|
@@ -4951,7 +5200,7 @@ function discoverAllSessions(maxAgeMs) {
|
|
|
4951
5200
|
}
|
|
4952
5201
|
async function rawTextMatch(filePath, query, caseSensitive) {
|
|
4953
5202
|
try {
|
|
4954
|
-
const content = await (
|
|
5203
|
+
const content = await readTranscriptText(filePath);
|
|
4955
5204
|
const haystack = caseSensitive ? content : content.toLowerCase();
|
|
4956
5205
|
const needle = caseSensitive ? query : query.toLowerCase();
|
|
4957
5206
|
if (haystack.includes(needle)) return content;
|
|
@@ -5026,7 +5275,7 @@ async function walkSubagentFiles(parentJsonlPath, query, caseSensitive, currentD
|
|
|
5026
5275
|
const subDir = parentJsonlPath.replace(/\.jsonl$/, "") + "/subagents";
|
|
5027
5276
|
let files;
|
|
5028
5277
|
try {
|
|
5029
|
-
files = await (0,
|
|
5278
|
+
files = await (0, import_promises2.readdir)(subDir);
|
|
5030
5279
|
} catch {
|
|
5031
5280
|
return [];
|
|
5032
5281
|
}
|
|
@@ -5104,14 +5353,14 @@ async function rawScanSearch(query, sessionId, maxAgeMs, limit, caseSensitive, e
|
|
|
5104
5353
|
}
|
|
5105
5354
|
|
|
5106
5355
|
// src/commands/context.ts
|
|
5107
|
-
var
|
|
5356
|
+
var import_promises4 = require("node:fs/promises");
|
|
5108
5357
|
var import_node_path5 = require("node:path");
|
|
5109
5358
|
|
|
5110
5359
|
// src/lib/helpers.ts
|
|
5111
|
-
var
|
|
5360
|
+
var import_promises3 = require("node:fs/promises");
|
|
5112
5361
|
var import_node_path4 = require("node:path");
|
|
5113
5362
|
async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
|
|
5114
|
-
const entries = await (0,
|
|
5363
|
+
const entries = await (0, import_promises3.readdir)(dirs.PROJECTS_DIR, { withFileTypes: true });
|
|
5115
5364
|
for (const entry of entries) {
|
|
5116
5365
|
if (!entry.isDirectory() || entry.name === "memory") continue;
|
|
5117
5366
|
const filePath = (0, import_node_path4.join)(
|
|
@@ -5122,7 +5371,7 @@ async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
|
|
|
5122
5371
|
subagentFileName
|
|
5123
5372
|
);
|
|
5124
5373
|
try {
|
|
5125
|
-
const fh = await (0,
|
|
5374
|
+
const fh = await (0, import_promises3.open)(filePath, "r");
|
|
5126
5375
|
try {
|
|
5127
5376
|
const buf = Buffer.alloc(16384);
|
|
5128
5377
|
const { bytesRead } = await fh.read(buf, 0, 16384, 0);
|
|
@@ -5317,7 +5566,13 @@ function mapContentBlock(block) {
|
|
|
5317
5566
|
case "task_notification":
|
|
5318
5567
|
return { kind: "task_notification", content: block.content, timestamp: block.timestamp ?? null };
|
|
5319
5568
|
case "local_command":
|
|
5320
|
-
return {
|
|
5569
|
+
return {
|
|
5570
|
+
kind: "local_command",
|
|
5571
|
+
content: block.content,
|
|
5572
|
+
timestamp: block.timestamp ?? null,
|
|
5573
|
+
...block.contextUsage ? { contextUsage: block.contextUsage } : {},
|
|
5574
|
+
...block.usageReport ? { usageReport: block.usageReport } : {}
|
|
5575
|
+
};
|
|
5321
5576
|
default: {
|
|
5322
5577
|
const exhaustive = block;
|
|
5323
5578
|
return exhaustive;
|
|
@@ -5327,7 +5582,7 @@ function mapContentBlock(block) {
|
|
|
5327
5582
|
async function findSubagentFile(parentJsonlPath, agentId) {
|
|
5328
5583
|
const subagentsDir = parentJsonlPath.replace(/\.jsonl$/, "") + "/subagents";
|
|
5329
5584
|
try {
|
|
5330
|
-
const files = await (0,
|
|
5585
|
+
const files = await (0, import_promises4.readdir)(subagentsDir);
|
|
5331
5586
|
for (const f of files) {
|
|
5332
5587
|
if (!f.startsWith("agent-") || !f.endsWith(".jsonl")) continue;
|
|
5333
5588
|
const fileAgentId = f.replace("agent-", "").replace(".jsonl", "");
|
|
@@ -5341,12 +5596,12 @@ async function findSubagentFile(parentJsonlPath, agentId) {
|
|
|
5341
5596
|
}
|
|
5342
5597
|
async function findTeamContext(sessionId, subagentFileName) {
|
|
5343
5598
|
try {
|
|
5344
|
-
const teamEntries = await (0,
|
|
5599
|
+
const teamEntries = await (0, import_promises4.readdir)(dirs.TEAMS_DIR, { withFileTypes: true });
|
|
5345
5600
|
for (const entry of teamEntries) {
|
|
5346
5601
|
if (!entry.isDirectory()) continue;
|
|
5347
5602
|
const configPath = (0, import_node_path5.join)(dirs.TEAMS_DIR, entry.name, "config.json");
|
|
5348
5603
|
try {
|
|
5349
|
-
const raw = await (0,
|
|
5604
|
+
const raw = await (0, import_promises4.readFile)(configPath, "utf-8");
|
|
5350
5605
|
const config = JSON.parse(raw);
|
|
5351
5606
|
if (config.leadSessionId !== sessionId) continue;
|
|
5352
5607
|
const members = config.members ?? [];
|
|
@@ -5355,10 +5610,10 @@ async function findTeamContext(sessionId, subagentFileName) {
|
|
|
5355
5610
|
let currentTask = null;
|
|
5356
5611
|
try {
|
|
5357
5612
|
const taskDir = (0, import_node_path5.join)(dirs.TASKS_DIR, entry.name);
|
|
5358
|
-
const taskFiles = await (0,
|
|
5613
|
+
const taskFiles = await (0, import_promises4.readdir)(taskDir);
|
|
5359
5614
|
for (const tf of taskFiles) {
|
|
5360
5615
|
if (!tf.endsWith(".json")) continue;
|
|
5361
|
-
const taskRaw = await (0,
|
|
5616
|
+
const taskRaw = await (0, import_promises4.readFile)((0, import_node_path5.join)(taskDir, tf), "utf-8");
|
|
5362
5617
|
const task = JSON.parse(taskRaw);
|
|
5363
5618
|
if (task.owner === memberName && task.status === "in_progress") {
|
|
5364
5619
|
currentTask = { id: task.id, subject: task.subject, status: task.status };
|
|
@@ -5406,14 +5661,14 @@ function findAgentMetadata(session, agentId) {
|
|
|
5406
5661
|
async function getSessionOverview(sessionId) {
|
|
5407
5662
|
const jsonlPath = await findSessionFile(sessionId);
|
|
5408
5663
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5409
|
-
const content = await (
|
|
5664
|
+
const content = await readTranscriptText(jsonlPath);
|
|
5410
5665
|
const session = parseTranscript(content, jsonlPath);
|
|
5411
5666
|
return mapSessionToOverview(session);
|
|
5412
5667
|
}
|
|
5413
5668
|
async function getTurnDetail(sessionId, turnIndex) {
|
|
5414
5669
|
const jsonlPath = await findSessionFile(sessionId);
|
|
5415
5670
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5416
|
-
const content = await (
|
|
5671
|
+
const content = await readTranscriptText(jsonlPath);
|
|
5417
5672
|
const session = parseTranscript(content, jsonlPath);
|
|
5418
5673
|
if (turnIndex < 0 || turnIndex >= session.turns.length) return { error: "Turn not found" };
|
|
5419
5674
|
return mapTurnToDetail(session, turnIndex);
|
|
@@ -5421,11 +5676,11 @@ async function getTurnDetail(sessionId, turnIndex) {
|
|
|
5421
5676
|
async function getAgentOverview(sessionId, agentId) {
|
|
5422
5677
|
const jsonlPath = await findSessionFile(sessionId);
|
|
5423
5678
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5424
|
-
const content = await (
|
|
5679
|
+
const content = await readTranscriptText(jsonlPath);
|
|
5425
5680
|
const session = parseTranscript(content, jsonlPath);
|
|
5426
5681
|
const subagentFile = await findSubagentFile(jsonlPath, agentId);
|
|
5427
5682
|
if (!subagentFile) return { error: "Agent not found" };
|
|
5428
|
-
const subagentContent = await (
|
|
5683
|
+
const subagentContent = await readTranscriptText(subagentFile.filePath);
|
|
5429
5684
|
const subagentSession = parseTranscript(subagentContent, subagentFile.filePath);
|
|
5430
5685
|
const metadata = findAgentMetadata(session, agentId);
|
|
5431
5686
|
const parentToolCallId = findParentToolCallId(session, agentId);
|
|
@@ -5446,7 +5701,7 @@ async function getAgentTurnDetail(sessionId, agentId, turnIndex) {
|
|
|
5446
5701
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5447
5702
|
const subagentFile = await findSubagentFile(jsonlPath, agentId);
|
|
5448
5703
|
if (!subagentFile) return { error: "Agent not found" };
|
|
5449
|
-
const subagentContent = await (
|
|
5704
|
+
const subagentContent = await readTranscriptText(subagentFile.filePath);
|
|
5450
5705
|
const subagentSession = parseTranscript(subagentContent, subagentFile.filePath);
|
|
5451
5706
|
if (turnIndex < 0 || turnIndex >= subagentSession.turns.length) return { error: "Turn not found" };
|
|
5452
5707
|
return mapTurnToDetail(subagentSession, turnIndex);
|
|
@@ -5456,7 +5711,7 @@ async function getAgentTurnDetail(sessionId, agentId, turnIndex) {
|
|
|
5456
5711
|
var import_node_path6 = require("node:path");
|
|
5457
5712
|
|
|
5458
5713
|
// src/lib/metadata.ts
|
|
5459
|
-
var
|
|
5714
|
+
var import_promises5 = require("node:fs/promises");
|
|
5460
5715
|
|
|
5461
5716
|
// src/lib/sessionStatus.ts
|
|
5462
5717
|
function deriveSessionStatus(rawMessages) {
|
|
@@ -5481,6 +5736,7 @@ function scanClaudeMessages(lines) {
|
|
|
5481
5736
|
turnCount: 0
|
|
5482
5737
|
};
|
|
5483
5738
|
for (const line of lines) {
|
|
5739
|
+
if (isAnyAgentNoiseLine(line)) continue;
|
|
5484
5740
|
let record2;
|
|
5485
5741
|
try {
|
|
5486
5742
|
record2 = JSON.parse(line);
|
|
@@ -5509,11 +5765,11 @@ function scanClaudeMessages(lines) {
|
|
|
5509
5765
|
return meta;
|
|
5510
5766
|
}
|
|
5511
5767
|
async function readLines(filePath, size) {
|
|
5512
|
-
if (size <= FULL_READ_LIMIT) {
|
|
5513
|
-
const content = await (
|
|
5768
|
+
if (size <= FULL_READ_LIMIT || isCompressedTranscript(filePath)) {
|
|
5769
|
+
const content = await readTranscriptText(filePath);
|
|
5514
5770
|
return { lines: content.split("\n").filter(Boolean), isPartialRead: false };
|
|
5515
5771
|
}
|
|
5516
|
-
const handle = await (0,
|
|
5772
|
+
const handle = await (0, import_promises5.open)(filePath, "r");
|
|
5517
5773
|
try {
|
|
5518
5774
|
const buffer = Buffer.alloc(HEAD_READ_BYTES);
|
|
5519
5775
|
const { bytesRead } = await handle.read(buffer, 0, HEAD_READ_BYTES, 0);
|
|
@@ -5528,11 +5784,11 @@ async function readLines(filePath, size) {
|
|
|
5528
5784
|
}
|
|
5529
5785
|
}
|
|
5530
5786
|
async function getSessionMeta(filePath) {
|
|
5531
|
-
const fileStat = await (0,
|
|
5787
|
+
const fileStat = await (0, import_promises5.stat)(filePath);
|
|
5532
5788
|
let { lines, isPartialRead } = await readLines(filePath, fileStat.size);
|
|
5533
5789
|
const format = formatForText(lines.join("\n"));
|
|
5534
5790
|
if (isPartialRead && !format.descriptor.metadataFromHead) {
|
|
5535
|
-
lines = (await (0,
|
|
5791
|
+
lines = (await (0, import_promises5.readFile)(filePath, "utf-8")).split("\n").filter(Boolean);
|
|
5536
5792
|
isPartialRead = false;
|
|
5537
5793
|
}
|
|
5538
5794
|
const header = readHeader(format, lines);
|
|
@@ -5561,10 +5817,10 @@ async function getSessionStatus(filePath) {
|
|
|
5561
5817
|
const CHUNK = 4096;
|
|
5562
5818
|
const MAX_CHUNKS = 64;
|
|
5563
5819
|
try {
|
|
5564
|
-
const
|
|
5565
|
-
if (fileStat.size === 0) return { status: "idle" };
|
|
5566
|
-
const fh = await (0, import_promises4.open)(filePath, "r");
|
|
5820
|
+
const fh = await openTranscript(filePath);
|
|
5567
5821
|
try {
|
|
5822
|
+
const fileStat = await fh.stat();
|
|
5823
|
+
if (fileStat.size === 0) return { status: "idle" };
|
|
5568
5824
|
const meaningful = [];
|
|
5569
5825
|
let cursor = fileStat.size;
|
|
5570
5826
|
let leftover = "";
|
|
@@ -5580,7 +5836,7 @@ async function getSessionStatus(filePath) {
|
|
|
5580
5836
|
const startIdx = cursor > 0 ? 1 : 0;
|
|
5581
5837
|
for (let i = lines.length - 1; i >= startIdx; i--) {
|
|
5582
5838
|
const line = lines[i];
|
|
5583
|
-
if (!line) continue;
|
|
5839
|
+
if (!line || isAnyAgentNoiseLine(line)) continue;
|
|
5584
5840
|
let obj;
|
|
5585
5841
|
try {
|
|
5586
5842
|
obj = JSON.parse(line);
|
|
@@ -5711,11 +5967,11 @@ async function currentSession(cwd) {
|
|
|
5711
5967
|
}
|
|
5712
5968
|
|
|
5713
5969
|
// src/commands/index-cmd.ts
|
|
5714
|
-
var
|
|
5970
|
+
var import_node_fs5 = require("node:fs");
|
|
5715
5971
|
var import_node_path7 = require("node:path");
|
|
5716
5972
|
async function indexStats(dbPath) {
|
|
5717
5973
|
const path = dbPath ?? DEFAULT_DB_PATH;
|
|
5718
|
-
if (!(0,
|
|
5974
|
+
if (!(0, import_node_fs5.existsSync)(path)) {
|
|
5719
5975
|
return { error: `Database not found at ${path}. Run 'cogpit-memory index rebuild' to create it.` };
|
|
5720
5976
|
}
|
|
5721
5977
|
const index = new SearchIndex(path);
|
|
@@ -5725,7 +5981,7 @@ async function indexStats(dbPath) {
|
|
|
5725
5981
|
}
|
|
5726
5982
|
async function indexRebuild(dbPath) {
|
|
5727
5983
|
const path = dbPath ?? DEFAULT_DB_PATH;
|
|
5728
|
-
(0,
|
|
5984
|
+
(0, import_node_fs5.mkdirSync)((0, import_node_path7.dirname)(path), { recursive: true });
|
|
5729
5985
|
const index = new SearchIndex(path);
|
|
5730
5986
|
index.buildFull();
|
|
5731
5987
|
const stats = index.getStats();
|