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/cli.js
CHANGED
|
@@ -36,8 +36,8 @@ __export(cli_exports, {
|
|
|
36
36
|
module.exports = __toCommonJS(cli_exports);
|
|
37
37
|
|
|
38
38
|
// src/commands/search.ts
|
|
39
|
-
var
|
|
40
|
-
var
|
|
39
|
+
var import_node_fs4 = require("node:fs");
|
|
40
|
+
var import_promises2 = require("node:fs/promises");
|
|
41
41
|
var import_node_path3 = require("node:path");
|
|
42
42
|
|
|
43
43
|
// src/lib/sqlite-node-shim.ts
|
|
@@ -45,7 +45,7 @@ var import_better_sqlite3 = __toESM(require("better-sqlite3"));
|
|
|
45
45
|
var Database = import_better_sqlite3.default;
|
|
46
46
|
|
|
47
47
|
// src/lib/search-index.ts
|
|
48
|
-
var
|
|
48
|
+
var import_node_fs3 = require("node:fs");
|
|
49
49
|
|
|
50
50
|
// src/lib/types.ts
|
|
51
51
|
var AGENT_KINDS = ["acp", "codex", "copilot", "claude"];
|
|
@@ -113,7 +113,7 @@ function base64DirNameCodec(prefix) {
|
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
115
|
function sessionIdFromJsonlName(fileName) {
|
|
116
|
-
const match = new RegExp(`(${SESSION_UUID})\\.jsonl
|
|
116
|
+
const match = new RegExp(`(${SESSION_UUID})\\.jsonl(?:\\.zst)?$`, "i").exec(fileName);
|
|
117
117
|
return match ? match[1] : null;
|
|
118
118
|
}
|
|
119
119
|
function ownTranscriptRoot(sessionId) {
|
|
@@ -283,7 +283,8 @@ var claude = {
|
|
|
283
283
|
fastTier: true,
|
|
284
284
|
lowPriorityInTerminal: true,
|
|
285
285
|
imageInput: true,
|
|
286
|
-
midTurnSteering:
|
|
286
|
+
midTurnSteering: true,
|
|
287
|
+
activeNotifications: true,
|
|
287
288
|
stopSession: true,
|
|
288
289
|
ultracode: true,
|
|
289
290
|
contextWindow: true,
|
|
@@ -369,6 +370,7 @@ var codex = {
|
|
|
369
370
|
bundledBySdk: false,
|
|
370
371
|
homeDirName: ".codex",
|
|
371
372
|
homeEnvVar: "CODEX_HOME",
|
|
373
|
+
sessionIdEnvVar: "CODEX_THREAD_ID",
|
|
372
374
|
installMarker: "",
|
|
373
375
|
homeIsDiscoverable: true,
|
|
374
376
|
process: {
|
|
@@ -419,6 +421,7 @@ var codex = {
|
|
|
419
421
|
lowPriorityInTerminal: false,
|
|
420
422
|
imageInput: true,
|
|
421
423
|
midTurnSteering: true,
|
|
424
|
+
activeNotifications: true,
|
|
422
425
|
stopSession: false,
|
|
423
426
|
ultracode: false,
|
|
424
427
|
contextWindow: false,
|
|
@@ -540,6 +543,7 @@ var copilot = {
|
|
|
540
543
|
lowPriorityInTerminal: false,
|
|
541
544
|
imageInput: false,
|
|
542
545
|
midTurnSteering: true,
|
|
546
|
+
activeNotifications: true,
|
|
543
547
|
stopSession: true,
|
|
544
548
|
ultracode: false,
|
|
545
549
|
contextWindow: false,
|
|
@@ -569,7 +573,7 @@ var acp = {
|
|
|
569
573
|
launchArgs: { permissions: () => [], model: () => [], effort: () => [], fastTier: () => [] },
|
|
570
574
|
cli: { ...copilot.cli, packageName: "", homebrew: null, wingetId: null, selfUpdate: null, requiresConfiguration: true, homeDirName: ".cogpit-acp", homeEnvVar: "COGPIT_ACP_HOME", homeIsDiscoverable: true, installMarker: "projects" },
|
|
571
575
|
config: { ...copilot.config, rootDirName: ".cogpit-acp", instructions: [], settings: [], skillsDir: null },
|
|
572
|
-
capabilities: { ...copilot.capabilities, undo: false, redo: false, nativeRewind: false, nativeFork: false, midTurnSteering: false, externalProcesses: false, autoPermissionMode: "never", toolPermissionRules: false, namedSessions: false }
|
|
576
|
+
capabilities: { ...copilot.capabilities, undo: false, redo: false, nativeRewind: false, nativeFork: false, midTurnSteering: false, activeNotifications: false, externalProcesses: false, autoPermissionMode: "never", toolPermissionRules: false, namedSessions: false }
|
|
573
577
|
};
|
|
574
578
|
var DESCRIPTORS = Object.freeze({
|
|
575
579
|
claude,
|
|
@@ -673,6 +677,27 @@ function readJsStringLiteral(source, startIndex) {
|
|
|
673
677
|
return null;
|
|
674
678
|
}
|
|
675
679
|
|
|
680
|
+
// src/lib/backgroundAgents.ts
|
|
681
|
+
function awaitingAgentsStatus(launches, pendingQueue = 0) {
|
|
682
|
+
if (!launches.some((launch) => launch.endedAt === void 0)) return null;
|
|
683
|
+
const ordered = [...launches].sort((a, b) => a.launchedAt - b.launchedAt);
|
|
684
|
+
let batchStart = 0;
|
|
685
|
+
let busyUntil = -Infinity;
|
|
686
|
+
ordered.forEach((launch, index) => {
|
|
687
|
+
if (busyUntil < launch.launchedAt) batchStart = index;
|
|
688
|
+
busyUntil = Math.max(busyUntil, launch.endedAt ?? Infinity);
|
|
689
|
+
});
|
|
690
|
+
const batch = ordered.slice(batchStart).map(({ agent, endedAt }) => ({ ...agent, done: endedAt !== void 0 }));
|
|
691
|
+
const running = batch.filter((agent) => !agent.done);
|
|
692
|
+
return {
|
|
693
|
+
status: "awaiting_agents",
|
|
694
|
+
pendingQueue,
|
|
695
|
+
pendingAgents: running.length,
|
|
696
|
+
pendingAgentDescriptions: running.map((agent) => agent.description).filter((description) => description.length > 0),
|
|
697
|
+
backgroundAgents: batch
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
|
|
676
701
|
// src/lib/messageTypeGuards.ts
|
|
677
702
|
function isUserMessage(msg) {
|
|
678
703
|
return msg.type === "user";
|
|
@@ -837,6 +862,17 @@ function isTaskNotificationRecord(msg) {
|
|
|
837
862
|
if (!text.includes("<task-notification>")) return false;
|
|
838
863
|
return text.replace(TASK_NOTIFICATION_BLOCK_RE, "").replace(ANY_TAG_RE, "").trim() === "";
|
|
839
864
|
}
|
|
865
|
+
function isTaskToolName(name) {
|
|
866
|
+
return name === "Task" || name === "Agent";
|
|
867
|
+
}
|
|
868
|
+
function readTaskMeta(input) {
|
|
869
|
+
const effort = input.effort;
|
|
870
|
+
return {
|
|
871
|
+
name: typeof input.name === "string" ? input.name : null,
|
|
872
|
+
subagentType: typeof input.subagent_type === "string" ? input.subagent_type : null,
|
|
873
|
+
effort: typeof effort === "string" || typeof effort === "number" ? String(effort) : null
|
|
874
|
+
};
|
|
875
|
+
}
|
|
840
876
|
function queuedCommandPrompt(msg) {
|
|
841
877
|
if (!isAttachmentMessage(msg)) return null;
|
|
842
878
|
const attachment = msg.attachment;
|
|
@@ -1178,7 +1214,13 @@ function buildTurnsWithStarts(messages) {
|
|
|
1178
1214
|
continue;
|
|
1179
1215
|
}
|
|
1180
1216
|
if (isSystemMessage(msg) && msg.subtype === "local_command" && msg.content) {
|
|
1181
|
-
current?.contentBlocks.push({
|
|
1217
|
+
current?.contentBlocks.push({
|
|
1218
|
+
kind: "local_command",
|
|
1219
|
+
content: msg.content,
|
|
1220
|
+
timestamp: msg.timestamp,
|
|
1221
|
+
...msg.contextUsage ? { contextUsage: msg.contextUsage } : {},
|
|
1222
|
+
...msg.usageReport ? { usageReport: msg.usageReport } : {}
|
|
1223
|
+
});
|
|
1182
1224
|
continue;
|
|
1183
1225
|
}
|
|
1184
1226
|
if (isQueueOperationMessage(msg)) {
|
|
@@ -1254,6 +1296,7 @@ function buildTurnsWithStarts(messages) {
|
|
|
1254
1296
|
parentToolUseId: toolUseId || void 0,
|
|
1255
1297
|
agentName: taskMeta?.name ?? null,
|
|
1256
1298
|
subagentType: taskMeta?.subagentType ?? null,
|
|
1299
|
+
...taskMeta?.effort ? { effort: taskMeta.effort } : {},
|
|
1257
1300
|
type: "assistant",
|
|
1258
1301
|
content: toolUseResult.content,
|
|
1259
1302
|
toolCalls: [],
|
|
@@ -1392,15 +1435,12 @@ function buildTurnsWithStarts(messages) {
|
|
|
1392
1435
|
current.toolCalls.push(tc);
|
|
1393
1436
|
msgToolCalls.push(tc);
|
|
1394
1437
|
pendingToolUses.set(block.id, { turn: current, index: idx });
|
|
1395
|
-
if (block.name
|
|
1438
|
+
if (isTaskToolName(block.name)) {
|
|
1396
1439
|
const input = block.input;
|
|
1397
1440
|
if (input.run_in_background === true) {
|
|
1398
1441
|
backgroundAgentParentIds.add(block.id);
|
|
1399
1442
|
}
|
|
1400
|
-
taskMetaMap.set(block.id,
|
|
1401
|
-
name: input.name ?? null,
|
|
1402
|
-
subagentType: input.subagent_type ?? null
|
|
1403
|
-
});
|
|
1443
|
+
taskMetaMap.set(block.id, readTaskMeta(input));
|
|
1404
1444
|
}
|
|
1405
1445
|
}
|
|
1406
1446
|
}
|
|
@@ -1411,6 +1451,7 @@ function buildTurnsWithStarts(messages) {
|
|
|
1411
1451
|
if (isProgressMessage(msg) && msg.data.type === "agent_progress") {
|
|
1412
1452
|
const data = msg.data;
|
|
1413
1453
|
const parentId = msg.parentToolUseID ?? "";
|
|
1454
|
+
const ownToolUseId = data.toolUseId ?? parentId;
|
|
1414
1455
|
let subAgentUsage = null;
|
|
1415
1456
|
if (data.message.type === "assistant") {
|
|
1416
1457
|
const innerMsg = data.message.message;
|
|
@@ -1427,12 +1468,14 @@ function buildTurnsWithStarts(messages) {
|
|
|
1427
1468
|
}
|
|
1428
1469
|
}
|
|
1429
1470
|
const innerModel = data.message.type === "assistant" ? data.message.message.model ?? null : null;
|
|
1430
|
-
const taskMeta = taskMetaMap.get(
|
|
1471
|
+
const taskMeta = taskMetaMap.get(ownToolUseId);
|
|
1431
1472
|
const agentMsg = {
|
|
1432
1473
|
agentId: data.agentId,
|
|
1433
|
-
parentToolUseId:
|
|
1474
|
+
parentToolUseId: ownToolUseId || void 0,
|
|
1475
|
+
...data.parentAgentId ? { parentAgentId: data.parentAgentId } : {},
|
|
1476
|
+
...taskMeta?.effort ? { effort: taskMeta.effort } : {},
|
|
1434
1477
|
agentName: taskMeta?.name ?? null,
|
|
1435
|
-
subagentType: taskMeta?.subagentType ?? null,
|
|
1478
|
+
subagentType: taskMeta?.subagentType ?? data.subagentType ?? null,
|
|
1436
1479
|
type: data.message.type,
|
|
1437
1480
|
content: data.message.message.content,
|
|
1438
1481
|
toolCalls: [],
|
|
@@ -1452,6 +1495,7 @@ function buildTurnsWithStarts(messages) {
|
|
|
1452
1495
|
} else if (block.type === "text") {
|
|
1453
1496
|
agentMsg.text.push(block.text);
|
|
1454
1497
|
} else if (block.type === "tool_use") {
|
|
1498
|
+
if (isTaskToolName(block.name)) taskMetaMap.set(block.id, readTaskMeta(block.input));
|
|
1455
1499
|
agentMsg.toolCalls.push({
|
|
1456
1500
|
id: block.id,
|
|
1457
1501
|
name: block.name,
|
|
@@ -1544,11 +1588,19 @@ function buildTurns(messages) {
|
|
|
1544
1588
|
function isClaudeSessionText() {
|
|
1545
1589
|
return true;
|
|
1546
1590
|
}
|
|
1591
|
+
var API_REQUEST_TYPE = '"type":"api-request';
|
|
1592
|
+
var RECORD_TYPE_WINDOW = 256;
|
|
1593
|
+
function isClaudeNoiseLine(line) {
|
|
1594
|
+
if (line.startsWith(`{${API_REQUEST_TYPE}`)) return true;
|
|
1595
|
+
const head = line.slice(0, RECORD_TYPE_WINDOW);
|
|
1596
|
+
const at = head.indexOf(API_REQUEST_TYPE);
|
|
1597
|
+
return at > 0 && head.lastIndexOf("{", at) === 0;
|
|
1598
|
+
}
|
|
1547
1599
|
function parseRecords(lines) {
|
|
1548
1600
|
const messages = [];
|
|
1549
1601
|
for (const line of lines) {
|
|
1550
1602
|
const trimmed = line.trim();
|
|
1551
|
-
if (!trimmed) continue;
|
|
1603
|
+
if (!trimmed || isClaudeNoiseLine(trimmed)) continue;
|
|
1552
1604
|
try {
|
|
1553
1605
|
messages.push(JSON.parse(trimmed));
|
|
1554
1606
|
} catch {
|
|
@@ -1653,21 +1705,24 @@ function userMessageTexts(msg) {
|
|
|
1653
1705
|
}
|
|
1654
1706
|
function collectClaudeBackgroundWork(rawMessages) {
|
|
1655
1707
|
const launches = [];
|
|
1656
|
-
const
|
|
1708
|
+
const resolvedAt = /* @__PURE__ */ new Map();
|
|
1657
1709
|
const queuedIds = /* @__PURE__ */ new Set();
|
|
1658
1710
|
const deliveredIds = /* @__PURE__ */ new Set();
|
|
1659
|
-
function
|
|
1711
|
+
function resolve2(id, index) {
|
|
1712
|
+
if (!resolvedAt.has(id)) resolvedAt.set(id, index);
|
|
1713
|
+
}
|
|
1714
|
+
function noteNotifications(text, index, sink) {
|
|
1660
1715
|
if (!text.includes(TASK_NOTIFICATION_MARKER)) return;
|
|
1661
1716
|
for (const match of text.matchAll(TASK_ID_RE)) {
|
|
1662
|
-
|
|
1717
|
+
resolve2(match[1], index);
|
|
1663
1718
|
sink?.add(match[1]);
|
|
1664
1719
|
}
|
|
1665
1720
|
for (const match of text.matchAll(TOOL_USE_ID_RE)) {
|
|
1666
|
-
|
|
1721
|
+
resolve2(match[1], index);
|
|
1667
1722
|
sink?.add(match[1]);
|
|
1668
1723
|
}
|
|
1669
1724
|
}
|
|
1670
|
-
for (const msg of rawMessages) {
|
|
1725
|
+
for (const [index, msg] of rawMessages.entries()) {
|
|
1671
1726
|
if (msg.type === "user") {
|
|
1672
1727
|
const toolUseResult = isObject(msg.toolUseResult) ? msg.toolUseResult : null;
|
|
1673
1728
|
if (toolUseResult?.status === "async_launched") {
|
|
@@ -1676,9 +1731,11 @@ function collectClaudeBackgroundWork(rawMessages) {
|
|
|
1676
1731
|
const toolUseIds = blocks.filter((block) => isObject(block) && block.type === "tool_result").map((block) => block.tool_use_id);
|
|
1677
1732
|
const ids = [toolUseResult.agentId, toolUseResult.taskId, ...toolUseIds].filter((id) => typeof id === "string" && id.length > 0);
|
|
1678
1733
|
const description = [toolUseResult.description, toolUseResult.workflowName, toolUseResult.summary].find((value) => typeof value === "string" && value.length > 0) ?? "";
|
|
1679
|
-
|
|
1734
|
+
const toolUseId = toolUseIds.find((id) => typeof id === "string" && id.length > 0);
|
|
1735
|
+
const startedAt = typeof msg.timestamp === "string" ? msg.timestamp : void 0;
|
|
1736
|
+
if (ids.length > 0) launches.push({ ids, launch: { agent: { description, startedAt, toolUseId }, launchedAt: index } });
|
|
1680
1737
|
}
|
|
1681
|
-
for (const text of userMessageTexts(msg)) noteNotifications(text, deliveredIds);
|
|
1738
|
+
for (const text of userMessageTexts(msg)) noteNotifications(text, index, deliveredIds);
|
|
1682
1739
|
continue;
|
|
1683
1740
|
}
|
|
1684
1741
|
if (msg.type === "assistant") {
|
|
@@ -1688,33 +1745,28 @@ function collectClaudeBackgroundWork(rawMessages) {
|
|
|
1688
1745
|
if (!isObject(block) || block.type !== "tool_use" || block.name !== "TaskStop") continue;
|
|
1689
1746
|
const input = isObject(block.input) ? block.input : null;
|
|
1690
1747
|
const taskId = input?.task_id ?? input?.shell_id;
|
|
1691
|
-
if (typeof taskId === "string")
|
|
1748
|
+
if (typeof taskId === "string") resolve2(taskId, index);
|
|
1692
1749
|
}
|
|
1693
1750
|
continue;
|
|
1694
1751
|
}
|
|
1695
1752
|
if (msg.type === "attachment") {
|
|
1696
1753
|
const attachment = isObject(msg.attachment) ? msg.attachment : null;
|
|
1697
|
-
if (typeof attachment?.prompt === "string") noteNotifications(attachment.prompt, deliveredIds);
|
|
1754
|
+
if (typeof attachment?.prompt === "string") noteNotifications(attachment.prompt, index, deliveredIds);
|
|
1698
1755
|
continue;
|
|
1699
1756
|
}
|
|
1700
1757
|
if (msg.type === "queue-operation" && typeof msg.content === "string") {
|
|
1701
1758
|
const op = msg.operation;
|
|
1702
|
-
noteNotifications(msg.content, op === "enqueue" ? queuedIds : deliveredIds);
|
|
1759
|
+
noteNotifications(msg.content, index, op === "enqueue" ? queuedIds : deliveredIds);
|
|
1703
1760
|
}
|
|
1704
1761
|
}
|
|
1705
1762
|
return {
|
|
1706
|
-
|
|
1763
|
+
launches: launches.map(({ ids, launch }) => {
|
|
1764
|
+
const ends = ids.flatMap((id) => resolvedAt.get(id) ?? []);
|
|
1765
|
+
return ends.length > 0 ? { ...launch, endedAt: Math.min(...ends) } : launch;
|
|
1766
|
+
}),
|
|
1707
1767
|
undeliveredNotifications: [...queuedIds].filter((id) => !deliveredIds.has(id)).length
|
|
1708
1768
|
};
|
|
1709
1769
|
}
|
|
1710
|
-
function awaitingAgentsResult(pendingDescriptions, pendingQueue) {
|
|
1711
|
-
return {
|
|
1712
|
-
status: "awaiting_agents",
|
|
1713
|
-
pendingQueue,
|
|
1714
|
-
pendingAgents: pendingDescriptions.length,
|
|
1715
|
-
pendingAgentDescriptions: pendingDescriptions.filter((description) => description.length > 0)
|
|
1716
|
-
};
|
|
1717
|
-
}
|
|
1718
1770
|
function deriveClaudeSessionStatus(rawMessages) {
|
|
1719
1771
|
let pendingEnqueues = 0;
|
|
1720
1772
|
let backgroundWork = null;
|
|
@@ -1760,9 +1812,8 @@ function deriveClaudeSessionStatus(rawMessages) {
|
|
|
1760
1812
|
if (stopReason === "end_turn") {
|
|
1761
1813
|
const work = getBackgroundWork();
|
|
1762
1814
|
if (deliveringNotification || work.undeliveredNotifications > 0) return result("processing");
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
}
|
|
1815
|
+
const awaiting = awaitingAgentsStatus(work.launches, Math.max(0, pendingEnqueues));
|
|
1816
|
+
if (awaiting) return awaiting;
|
|
1766
1817
|
let hasActivity = false;
|
|
1767
1818
|
for (let j = i - 1; j >= 0; j--) {
|
|
1768
1819
|
const m = rawMessages[j];
|
|
@@ -1820,6 +1871,62 @@ function appendAssistantText(turn, text, timestamp) {
|
|
|
1820
1871
|
turn.contentBlocks.push({ kind: "text", text: [text], timestamp });
|
|
1821
1872
|
}
|
|
1822
1873
|
|
|
1874
|
+
// src/lib/automatedPrompts.ts
|
|
1875
|
+
var CREW_CHAT_DELIVERY_RE = /^Crew chat · ([^\n]+) · message (\d+)(?:\n|$)/;
|
|
1876
|
+
var TASK_WAKEUP_START_RE = /^Delegated task \S+ (?:running|completed|error|cancelled|needs attention)\. Child session: /;
|
|
1877
|
+
function isReaderPrompt(text) {
|
|
1878
|
+
const trimmed = text.trim();
|
|
1879
|
+
if (!trimmed) return false;
|
|
1880
|
+
if (CREW_CHAT_DELIVERY_RE.test(trimmed) || TASK_WAKEUP_START_RE.test(trimmed)) return false;
|
|
1881
|
+
return parseAgentEnvelope(trimmed).sender === null;
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
// src/lib/asyncAnswers.ts
|
|
1885
|
+
function promptText(content) {
|
|
1886
|
+
if (content === null) return "";
|
|
1887
|
+
if (typeof content === "string") return content;
|
|
1888
|
+
return content.flatMap((block) => block.type === "text" ? [block.text] : []).join("\n");
|
|
1889
|
+
}
|
|
1890
|
+
function linkAsyncAnswers(turns) {
|
|
1891
|
+
const answers = /* @__PURE__ */ new Map();
|
|
1892
|
+
let open4 = [];
|
|
1893
|
+
const answer = (text) => {
|
|
1894
|
+
if (open4.length === 0 || !isReaderPrompt(text)) return;
|
|
1895
|
+
for (const id of open4) answers.set(id, text.trim());
|
|
1896
|
+
open4 = [];
|
|
1897
|
+
};
|
|
1898
|
+
for (const turn of turns) {
|
|
1899
|
+
answer(promptText(turn.userMessage));
|
|
1900
|
+
for (const block of turn.contentBlocks) {
|
|
1901
|
+
if (block.kind === "queued_prompt") answer(block.content);
|
|
1902
|
+
else if (block.kind === "tool_calls") {
|
|
1903
|
+
for (const call of block.toolCalls) if (call.asyncQuestion) open4.push(call.id);
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
const stale = (call) => call.asyncQuestion === true && call.asyncAnswer !== answers.get(call.id);
|
|
1908
|
+
const relinked = /* @__PURE__ */ new Map();
|
|
1909
|
+
const relink = (call) => {
|
|
1910
|
+
if (!stale(call)) return call;
|
|
1911
|
+
let next = relinked.get(call);
|
|
1912
|
+
if (!next) {
|
|
1913
|
+
const { asyncAnswer: _previous, ...rest } = call;
|
|
1914
|
+
const reply = answers.get(call.id);
|
|
1915
|
+
next = reply === void 0 ? rest : { ...rest, asyncAnswer: reply };
|
|
1916
|
+
relinked.set(call, next);
|
|
1917
|
+
}
|
|
1918
|
+
return next;
|
|
1919
|
+
};
|
|
1920
|
+
return turns.map((turn) => {
|
|
1921
|
+
if (!turn.toolCalls.some(stale)) return turn;
|
|
1922
|
+
return {
|
|
1923
|
+
...turn,
|
|
1924
|
+
toolCalls: turn.toolCalls.map(relink),
|
|
1925
|
+
contentBlocks: turn.contentBlocks.map((block) => block.kind === "tool_calls" ? { ...block, toolCalls: block.toolCalls.map(relink) } : block)
|
|
1926
|
+
};
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1823
1930
|
// src/lib/codex-patches.ts
|
|
1824
1931
|
function isApplyPatchText(value) {
|
|
1825
1932
|
return value.includes("*** Begin Patch") && value.includes("*** End Patch");
|
|
@@ -2159,6 +2266,48 @@ function codexParentId(payload) {
|
|
|
2159
2266
|
}
|
|
2160
2267
|
return null;
|
|
2161
2268
|
}
|
|
2269
|
+
function inheritedHistoryFilter(records) {
|
|
2270
|
+
const meta = records.find((record2) => record2?.type === "session_meta");
|
|
2271
|
+
const start = meta?.payload?.subagent_history_start_ordinal;
|
|
2272
|
+
if (typeof start !== "number") return null;
|
|
2273
|
+
const reachesPast = (ordinal) => typeof ordinal === "number" && ordinal >= start;
|
|
2274
|
+
if (!reachesPast(meta?.rolloutLastOrdinal) && !records.some((record2) => reachesPast(record2?.ordinal))) return null;
|
|
2275
|
+
return (record2) => typeof record2.ordinal === "number" && record2.ordinal > 0 && record2.ordinal < start;
|
|
2276
|
+
}
|
|
2277
|
+
async function codexPageHeaderLine(firstLine, lastLines) {
|
|
2278
|
+
if (!firstLine.includes('"subagent_history_start_ordinal"')) return firstLine;
|
|
2279
|
+
const meta = safeParseLine(firstLine);
|
|
2280
|
+
if (meta?.type !== "session_meta") return firstLine;
|
|
2281
|
+
const lines = await lastLines();
|
|
2282
|
+
for (let index = lines.length - 1; index >= 0; index--) {
|
|
2283
|
+
const ordinal = safeParseLine(lines[index])?.ordinal;
|
|
2284
|
+
if (typeof ordinal === "number") return JSON.stringify({ ...meta, rolloutLastOrdinal: ordinal });
|
|
2285
|
+
}
|
|
2286
|
+
return firstLine;
|
|
2287
|
+
}
|
|
2288
|
+
function subAgentActivitySource(record2) {
|
|
2289
|
+
const payload = record2.payload;
|
|
2290
|
+
if (record2.type !== "event_msg" || !isObject3(payload)) return null;
|
|
2291
|
+
if (payload.type === "sub_agent_activity") return payload;
|
|
2292
|
+
if (payload.type === "item_completed" && isObject3(payload.item) && payload.item.type === "SubAgentActivity") return payload.item;
|
|
2293
|
+
return null;
|
|
2294
|
+
}
|
|
2295
|
+
function readSubAgentActivity(record2) {
|
|
2296
|
+
const source = subAgentActivitySource(record2);
|
|
2297
|
+
if (!source || typeof source.agent_thread_id !== "string" || typeof source.agent_path !== "string") return null;
|
|
2298
|
+
return {
|
|
2299
|
+
agentId: source.agent_thread_id,
|
|
2300
|
+
agentPath: source.agent_path,
|
|
2301
|
+
kind: typeof source.kind === "string" ? source.kind : "started",
|
|
2302
|
+
eventId: findString(source.event_id, source.id) ?? "",
|
|
2303
|
+
model: findString(source.model) || null,
|
|
2304
|
+
effort: findString(source.reasoning_effort) || null
|
|
2305
|
+
};
|
|
2306
|
+
}
|
|
2307
|
+
function turnErrorMessage(payload) {
|
|
2308
|
+
if (payload.type !== "task_complete" || !isObject3(payload.error)) return "";
|
|
2309
|
+
return typeof payload.error.message === "string" ? payload.error.message.trim() : "";
|
|
2310
|
+
}
|
|
2162
2311
|
function isCodexRecord(record2) {
|
|
2163
2312
|
if (!record2 || typeof record2.type !== "string") return false;
|
|
2164
2313
|
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";
|
|
@@ -2356,22 +2505,39 @@ function createTurn2(turnId, timestamp, model) {
|
|
|
2356
2505
|
model
|
|
2357
2506
|
};
|
|
2358
2507
|
}
|
|
2359
|
-
function
|
|
2360
|
-
|
|
2361
|
-
|
|
2508
|
+
function codexPromptText(record2) {
|
|
2509
|
+
const payload = isObject3(record2.payload) ? record2.payload : null;
|
|
2510
|
+
if (record2.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
|
|
2511
|
+
return normalizePromptText(payload.message);
|
|
2362
2512
|
}
|
|
2363
|
-
if (record2.type === "response_item" &&
|
|
2364
|
-
return normalizePromptText(extractMessageText(
|
|
2513
|
+
if (record2.type === "response_item" && payload?.type === "message" && payload.role === "user") {
|
|
2514
|
+
return normalizePromptText(extractMessageText(payload, "input_text"));
|
|
2365
2515
|
}
|
|
2366
2516
|
return "";
|
|
2367
2517
|
}
|
|
2518
|
+
function createCodexPromptReader() {
|
|
2519
|
+
let echoPending = false;
|
|
2520
|
+
return (record2) => {
|
|
2521
|
+
const payload = isObject3(record2.payload) ? record2.payload : null;
|
|
2522
|
+
if (record2.type === "event_msg" && payload?.type === "user_message") {
|
|
2523
|
+
const isEcho = echoPending;
|
|
2524
|
+
echoPending = false;
|
|
2525
|
+
return isEcho ? "" : codexPromptText(record2);
|
|
2526
|
+
}
|
|
2527
|
+
if (record2.type !== "response_item") return "";
|
|
2528
|
+
const prompt = codexPromptText(record2);
|
|
2529
|
+
if (prompt) echoPending = true;
|
|
2530
|
+
else if (payload?.type !== "message" || payload.role !== "user") echoPending = false;
|
|
2531
|
+
return prompt;
|
|
2532
|
+
};
|
|
2533
|
+
}
|
|
2368
2534
|
function recordOpensTurn(record2, payload) {
|
|
2369
2535
|
if (record2.type === "session_meta") return false;
|
|
2370
2536
|
if (record2.type === "event_msg" && payload?.type === "task_started") return false;
|
|
2371
2537
|
if (record2.type === "response_item" && payload?.type === "message") {
|
|
2372
2538
|
if (payload.role === "developer" || payload.role === "system") return false;
|
|
2373
2539
|
if (payload.role === "user") {
|
|
2374
|
-
return
|
|
2540
|
+
return codexPromptText(record2) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
|
|
2375
2541
|
}
|
|
2376
2542
|
}
|
|
2377
2543
|
return true;
|
|
@@ -2391,9 +2557,10 @@ function extractMetadataFromRecords(records) {
|
|
|
2391
2557
|
let isSubagent = false;
|
|
2392
2558
|
let parentSessionId = null;
|
|
2393
2559
|
let agentPath = "/root";
|
|
2394
|
-
|
|
2560
|
+
const readPrompt = createCodexPromptReader();
|
|
2561
|
+
const isInherited = inheritedHistoryFilter(records);
|
|
2395
2562
|
for (const record2 of records) {
|
|
2396
|
-
if (!isObject3(record2.payload)) continue;
|
|
2563
|
+
if (!isObject3(record2.payload) || isInherited?.(record2)) continue;
|
|
2397
2564
|
if (record2.type === "session_meta") {
|
|
2398
2565
|
sessionId ||= typeof record2.payload.id === "string" ? record2.payload.id : "";
|
|
2399
2566
|
version ||= typeof record2.payload.cli_version === "string" ? record2.payload.cli_version : "";
|
|
@@ -2423,12 +2590,10 @@ function extractMetadataFromRecords(records) {
|
|
|
2423
2590
|
model ||= typeof record2.payload.model === "string" ? record2.payload.model : "";
|
|
2424
2591
|
cwd ||= typeof record2.payload.cwd === "string" ? record2.payload.cwd : "";
|
|
2425
2592
|
}
|
|
2426
|
-
const prompt =
|
|
2593
|
+
const prompt = readPrompt(record2);
|
|
2427
2594
|
if (!prompt) continue;
|
|
2428
|
-
if (prompt === previousPrompt) continue;
|
|
2429
2595
|
if (!firstUserMessage) firstUserMessage = prompt;
|
|
2430
2596
|
lastUserMessage = prompt;
|
|
2431
|
-
previousPrompt = prompt;
|
|
2432
2597
|
turnCount++;
|
|
2433
2598
|
if (!timestamp) timestamp = record2.timestamp ?? "";
|
|
2434
2599
|
lastTimestamp = record2.timestamp ?? lastTimestamp;
|
|
@@ -2498,6 +2663,7 @@ function walkCodexRecords(records, options) {
|
|
|
2498
2663
|
timestamp: info?.timestamp ?? eventTimestamp2,
|
|
2499
2664
|
tokenUsage: null,
|
|
2500
2665
|
model: info?.model ?? null,
|
|
2666
|
+
...info?.effort ? { effort: info.effort } : {},
|
|
2501
2667
|
isBackground: false,
|
|
2502
2668
|
prompt: info?.message || void 0,
|
|
2503
2669
|
status: update.status ?? "running"
|
|
@@ -2518,6 +2684,7 @@ function walkCodexRecords(records, options) {
|
|
|
2518
2684
|
agentMessage.agentName = info.nickname ?? (info.agentPath ? agentNameFromPath(info.agentPath) : agentMessage.agentName);
|
|
2519
2685
|
agentMessage.subagentType = info.agentType;
|
|
2520
2686
|
agentMessage.model = info.model;
|
|
2687
|
+
if (info.effort) agentMessage.effort = info.effort;
|
|
2521
2688
|
agentMessage.prompt = info.message || agentMessage.prompt;
|
|
2522
2689
|
}
|
|
2523
2690
|
if (update.text && !agentMessage.text.includes(update.text)) {
|
|
@@ -2541,6 +2708,7 @@ function walkCodexRecords(records, options) {
|
|
|
2541
2708
|
}
|
|
2542
2709
|
let current = null;
|
|
2543
2710
|
let currentTurnId = null;
|
|
2711
|
+
let queuedPromptEcho = false;
|
|
2544
2712
|
let currentModel = metadata.model || null;
|
|
2545
2713
|
let lastTurnTimestamp = "";
|
|
2546
2714
|
let pendingCompaction = null;
|
|
@@ -2588,12 +2756,14 @@ function walkCodexRecords(records, options) {
|
|
|
2588
2756
|
webSearchCalls.set(id, toolCall);
|
|
2589
2757
|
appendToolCall(targetTurn, toolCall, timestamp);
|
|
2590
2758
|
}
|
|
2759
|
+
const isInherited = inheritedHistoryFilter(records);
|
|
2591
2760
|
for (let index = 0; index < records.length; index++) {
|
|
2592
2761
|
const record2 = records[index];
|
|
2593
|
-
if (!isCodexRecord(record2)) continue;
|
|
2762
|
+
if (!isCodexRecord(record2) || isInherited?.(record2)) continue;
|
|
2594
2763
|
recordIndex = index;
|
|
2595
2764
|
const payload = isObject3(record2.payload) ? record2.payload : void 0;
|
|
2596
2765
|
const timestamp = record2.timestamp ?? "";
|
|
2766
|
+
if (record2.type !== "event_msg") queuedPromptEcho = false;
|
|
2597
2767
|
if (record2.type === "compacted") {
|
|
2598
2768
|
current = commitTurn(current);
|
|
2599
2769
|
pendingCompaction = "Conversation compacted";
|
|
@@ -2611,11 +2781,17 @@ function walkCodexRecords(records, options) {
|
|
|
2611
2781
|
continue;
|
|
2612
2782
|
}
|
|
2613
2783
|
if (record2.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
|
|
2784
|
+
if (queuedPromptEcho) {
|
|
2785
|
+
queuedPromptEcho = false;
|
|
2786
|
+
continue;
|
|
2787
|
+
}
|
|
2614
2788
|
if (current && (current.assistantText.length > 0 || current.toolCalls.length > 0 || current.thinking.length > 0)) {
|
|
2615
2789
|
current = commitTurn(current);
|
|
2616
2790
|
}
|
|
2791
|
+
const opensWindow = !sawTurnStart;
|
|
2617
2792
|
sawTurnStart = true;
|
|
2618
2793
|
current ??= createActiveTurn(currentTurnId, timestamp, currentModel);
|
|
2794
|
+
if (opensWindow) current.opensOnPrompt = true;
|
|
2619
2795
|
const localImages = (Array.isArray(payload.local_images) ? payload.local_images : []).filter(
|
|
2620
2796
|
(p) => typeof p === "string" && p.length > 0
|
|
2621
2797
|
);
|
|
@@ -2679,12 +2855,18 @@ function walkCodexRecords(records, options) {
|
|
|
2679
2855
|
}
|
|
2680
2856
|
continue;
|
|
2681
2857
|
}
|
|
2682
|
-
if (record2.type === "event_msg" && payload
|
|
2683
|
-
const
|
|
2684
|
-
|
|
2685
|
-
|
|
2858
|
+
if (record2.type === "event_msg" && payload) {
|
|
2859
|
+
const turnError = turnErrorMessage(payload);
|
|
2860
|
+
if (turnError) {
|
|
2861
|
+
appendAssistantText(current, turnError, timestamp);
|
|
2862
|
+
continue;
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
const activity = readSubAgentActivity(record2);
|
|
2866
|
+
if (activity) {
|
|
2867
|
+
const { agentId, agentPath, eventId: eventId2, kind } = activity;
|
|
2686
2868
|
const spawnInfo = eventId2 ? spawnAgentCalls.get(eventId2) : void 0;
|
|
2687
|
-
const existingId = agentIdByPath.get(
|
|
2869
|
+
const existingId = agentIdByPath.get(agentPath);
|
|
2688
2870
|
const existing = agentRegistry.get(agentId) ?? (existingId ? agentRegistry.get(existingId) : void 0);
|
|
2689
2871
|
if (kind !== "started" && !existing && !spawnInfo) continue;
|
|
2690
2872
|
if (existingId && existingId !== agentId && !agentMessages.has(agentId)) {
|
|
@@ -2698,18 +2880,19 @@ function walkCodexRecords(records, options) {
|
|
|
2698
2880
|
}
|
|
2699
2881
|
const info = {
|
|
2700
2882
|
agentId,
|
|
2701
|
-
nickname: existing?.nickname ?? agentNameFromPath(
|
|
2702
|
-
agentPath
|
|
2883
|
+
nickname: existing?.nickname ?? agentNameFromPath(agentPath) ?? spawnInfo?.taskName ?? null,
|
|
2884
|
+
agentPath,
|
|
2703
2885
|
message: existing?.message ?? spawnInfo?.message ?? "",
|
|
2704
|
-
model: existing?.model ?? spawnInfo?.model ?? null,
|
|
2886
|
+
model: activity.model ?? existing?.model ?? spawnInfo?.model ?? null,
|
|
2887
|
+
effort: activity.effort ?? existing?.effort ?? null,
|
|
2705
2888
|
agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
|
|
2706
2889
|
timestamp: existing?.timestamp ?? (timestamp || spawnInfo?.timestamp || ""),
|
|
2707
2890
|
parentToolCallId: existing?.parentToolCallId ?? eventId2
|
|
2708
2891
|
};
|
|
2709
2892
|
agentRegistry.set(agentId, info);
|
|
2710
|
-
agentIdByPath.set(
|
|
2893
|
+
agentIdByPath.set(agentPath, agentId);
|
|
2711
2894
|
if (eventId2 && (kind === "started" || spawnInfo)) agentIdBySpawnCall.set(eventId2, agentId);
|
|
2712
|
-
const status = kind === "interrupted"
|
|
2895
|
+
const status = kind === "interrupted" || kind === "completed" ? kind : "running";
|
|
2713
2896
|
upsertAgentMessage(agentId, current, timestamp, { status });
|
|
2714
2897
|
continue;
|
|
2715
2898
|
}
|
|
@@ -2723,8 +2906,15 @@ function walkCodexRecords(records, options) {
|
|
|
2723
2906
|
appendAssistantText(current, extractMessageText(payload, "output_text"), timestamp);
|
|
2724
2907
|
continue;
|
|
2725
2908
|
}
|
|
2726
|
-
if (payload.type === "message" && payload.role === "user"
|
|
2909
|
+
if (payload.type === "message" && payload.role === "user") {
|
|
2727
2910
|
const text = normalizePromptText(extractMessageText(payload, "input_text"));
|
|
2911
|
+
if (current.userMessage !== null || current.contentBlocks.length > 0) {
|
|
2912
|
+
if (text) {
|
|
2913
|
+
current.contentBlocks.push({ kind: "queued_prompt", content: text, timestamp });
|
|
2914
|
+
queuedPromptEcho = true;
|
|
2915
|
+
}
|
|
2916
|
+
continue;
|
|
2917
|
+
}
|
|
2728
2918
|
const images = extractResponseMessageImages(payload);
|
|
2729
2919
|
const audio = extractResponseMessageAudio(payload);
|
|
2730
2920
|
if (text || images.length > 0 || audio.length > 0) {
|
|
@@ -2865,6 +3055,7 @@ function walkCodexRecords(records, options) {
|
|
|
2865
3055
|
agentPath: agentPath ?? existing?.agentPath ?? null,
|
|
2866
3056
|
message: existing?.message ?? spawnInfo?.message ?? "",
|
|
2867
3057
|
model: existing?.model ?? spawnInfo?.model ?? null,
|
|
3058
|
+
effort: existing?.effort ?? null,
|
|
2868
3059
|
agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
|
|
2869
3060
|
timestamp: existing?.timestamp ?? spawnInfo?.timestamp ?? timestamp,
|
|
2870
3061
|
parentToolCallId: existing?.parentToolCallId ?? toolCall.id
|
|
@@ -2965,6 +3156,7 @@ function walkCodexRecords(records, options) {
|
|
|
2965
3156
|
}
|
|
2966
3157
|
}
|
|
2967
3158
|
commitTurn(current);
|
|
3159
|
+
const linkedTurns = linkAsyncAnswers(turns);
|
|
2968
3160
|
return {
|
|
2969
3161
|
turnStartIndices,
|
|
2970
3162
|
sessionId: metadata.sessionId,
|
|
@@ -2974,8 +3166,8 @@ function walkCodexRecords(records, options) {
|
|
|
2974
3166
|
slug: metadata.slug,
|
|
2975
3167
|
name: "",
|
|
2976
3168
|
model: metadata.model,
|
|
2977
|
-
turns,
|
|
2978
|
-
stats: options?.skipStats ? createEmptySessionStats(
|
|
3169
|
+
turns: linkedTurns,
|
|
3170
|
+
stats: options?.skipStats ? createEmptySessionStats(linkedTurns.length) : computeStats(linkedTurns),
|
|
2979
3171
|
rawMessages: options?.skipStats ? [] : records,
|
|
2980
3172
|
branchedFrom: metadata.branchedFrom,
|
|
2981
3173
|
agentKind: "codex"
|
|
@@ -2983,8 +3175,10 @@ function walkCodexRecords(records, options) {
|
|
|
2983
3175
|
}
|
|
2984
3176
|
function parseCodexSession(jsonlText, options) {
|
|
2985
3177
|
const records = jsonlText.split("\n").map((line) => line.trim()).filter(Boolean).map(safeParseLine).filter(isCodexRecord);
|
|
3178
|
+
const isInherited = inheritedHistoryFilter(records);
|
|
3179
|
+
const ownRecords = isInherited ? records.filter((record2) => !isInherited(record2)) : records;
|
|
2986
3180
|
const { turnStartIndices: _starts, ...session } = walkCodexRecords(
|
|
2987
|
-
|
|
3181
|
+
ownRecords,
|
|
2988
3182
|
options
|
|
2989
3183
|
);
|
|
2990
3184
|
return session;
|
|
@@ -3009,40 +3203,48 @@ function parseJsonObject(value) {
|
|
|
3009
3203
|
return null;
|
|
3010
3204
|
}
|
|
3011
3205
|
}
|
|
3012
|
-
function
|
|
3013
|
-
const
|
|
3014
|
-
const
|
|
3206
|
+
function collectCodexBackgroundAgents(rawMessages) {
|
|
3207
|
+
const launched = /* @__PURE__ */ new Map();
|
|
3208
|
+
const alive = /* @__PURE__ */ new Set();
|
|
3209
|
+
const endedAt = /* @__PURE__ */ new Map();
|
|
3015
3210
|
const agentIdByPath = /* @__PURE__ */ new Map();
|
|
3016
3211
|
const spawnCalls = /* @__PURE__ */ new Map();
|
|
3017
3212
|
const waitCalls = /* @__PURE__ */ new Set();
|
|
3018
3213
|
const interruptCalls = /* @__PURE__ */ new Map();
|
|
3019
|
-
function markAlive(agentId, description) {
|
|
3020
|
-
if (
|
|
3021
|
-
|
|
3022
|
-
|
|
3214
|
+
function markAlive(agentId, description, index, startedAt) {
|
|
3215
|
+
if (endedAt.has(agentId)) return;
|
|
3216
|
+
alive.add(agentId);
|
|
3217
|
+
const launch = launched.get(agentId);
|
|
3218
|
+
if (!launch) launched.set(agentId, { launchedAt: index, description, startedAt });
|
|
3219
|
+
else if (!launch.description) launch.description = description;
|
|
3220
|
+
}
|
|
3221
|
+
function markEnded(agentId, index) {
|
|
3222
|
+
if (!endedAt.has(agentId)) endedAt.set(agentId, index);
|
|
3223
|
+
alive.delete(agentId);
|
|
3224
|
+
}
|
|
3225
|
+
for (const [index, msg] of rawMessages.entries()) {
|
|
3023
3226
|
const payload = isObject3(msg.payload) ? msg.payload : null;
|
|
3024
3227
|
if (!payload) continue;
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
const
|
|
3029
|
-
const existingId = agentIdByPath.get(
|
|
3030
|
-
const known = alive.has(agentId) ||
|
|
3228
|
+
const timestamp = typeof msg.timestamp === "string" ? msg.timestamp : void 0;
|
|
3229
|
+
const activity = readSubAgentActivity(msg);
|
|
3230
|
+
if (activity) {
|
|
3231
|
+
const { agentId, agentPath, kind, eventId: eventId2 } = activity;
|
|
3232
|
+
const existingId = agentIdByPath.get(agentPath);
|
|
3233
|
+
const known = alive.has(agentId) || endedAt.has(agentId) || existingId !== void 0 || spawnCalls.has(eventId2);
|
|
3031
3234
|
if (kind !== "started" && !known) continue;
|
|
3032
3235
|
if (existingId && existingId !== agentId) {
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
if (
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
done.add(agentId);
|
|
3042
|
-
alive.delete(agentId);
|
|
3043
|
-
} else {
|
|
3044
|
-
markAlive(agentId, spawnCalls.get(eventId2) ?? "");
|
|
3236
|
+
const prior = launched.get(existingId);
|
|
3237
|
+
launched.delete(existingId);
|
|
3238
|
+
const current = launched.get(agentId);
|
|
3239
|
+
if (prior && !current) launched.set(agentId, prior);
|
|
3240
|
+
else if (prior && current && !current.description) current.description = prior.description;
|
|
3241
|
+
if (alive.delete(existingId)) markAlive(agentId, "", index, timestamp);
|
|
3242
|
+
const priorEnd = endedAt.get(existingId);
|
|
3243
|
+
if (priorEnd !== void 0) markEnded(agentId, priorEnd);
|
|
3045
3244
|
}
|
|
3245
|
+
agentIdByPath.set(agentPath, agentId);
|
|
3246
|
+
if (kind === "interrupted" || kind === "completed") markEnded(agentId, index);
|
|
3247
|
+
else markAlive(agentId, spawnCalls.get(eventId2) ?? "", index, timestamp);
|
|
3046
3248
|
continue;
|
|
3047
3249
|
}
|
|
3048
3250
|
if (msg.type !== "response_item") continue;
|
|
@@ -3066,7 +3268,7 @@ function collectCodexPendingAgents(rawMessages) {
|
|
|
3066
3268
|
const output = parseJsonObject(payload.output);
|
|
3067
3269
|
const agentId = typeof output?.agent_id === "string" ? output.agent_id : "";
|
|
3068
3270
|
if (agentId) {
|
|
3069
|
-
markAlive(agentId, spawnCalls.get(callId) ?? "");
|
|
3271
|
+
markAlive(agentId, spawnCalls.get(callId) ?? "", index, timestamp);
|
|
3070
3272
|
const agentPath = typeof output?.task_name === "string" ? output.task_name : "";
|
|
3071
3273
|
if (agentPath && !agentIdByPath.has(agentPath)) agentIdByPath.set(agentPath, agentId);
|
|
3072
3274
|
}
|
|
@@ -3077,16 +3279,10 @@ function collectCodexPendingAgents(rawMessages) {
|
|
|
3077
3279
|
const statusValue = isObject3(status) ? status : {};
|
|
3078
3280
|
const lifecycle = typeof statusValue.status === "string" ? statusValue.status : "";
|
|
3079
3281
|
const isTerminal = typeof statusValue.completed === "string" || typeof statusValue.failed === "string" || typeof statusValue.error === "string" || typeof statusValue.interrupted === "string" || lifecycle === "completed" || lifecycle === "failed" || lifecycle === "interrupted";
|
|
3080
|
-
if (isTerminal)
|
|
3081
|
-
done.add(agentId);
|
|
3082
|
-
alive.delete(agentId);
|
|
3083
|
-
}
|
|
3282
|
+
if (isTerminal) markEnded(agentId, index);
|
|
3084
3283
|
}
|
|
3085
3284
|
} else if (interruptCalls.has(callId)) {
|
|
3086
|
-
for (const agentId of interruptCalls.get(callId) ?? [])
|
|
3087
|
-
done.add(agentId);
|
|
3088
|
-
alive.delete(agentId);
|
|
3089
|
-
}
|
|
3285
|
+
for (const agentId of interruptCalls.get(callId) ?? []) markEnded(agentId, index);
|
|
3090
3286
|
}
|
|
3091
3287
|
continue;
|
|
3092
3288
|
}
|
|
@@ -3094,12 +3290,14 @@ function collectCodexPendingAgents(rawMessages) {
|
|
|
3094
3290
|
const text = codexPayloadText(payload);
|
|
3095
3291
|
const messageType = text.match(/^Message Type:\s*([^\r\n]+)/)?.[1]?.trim().toUpperCase() ?? "";
|
|
3096
3292
|
if (!TERMINAL_INTER_AGENT_TYPES.has(messageType)) continue;
|
|
3097
|
-
|
|
3098
|
-
done.add(agentId);
|
|
3099
|
-
alive.delete(agentId);
|
|
3293
|
+
markEnded(agentIdByPath.get(payload.author) ?? payload.author, index);
|
|
3100
3294
|
}
|
|
3101
3295
|
}
|
|
3102
|
-
return [...
|
|
3296
|
+
return [...launched.entries()].map(([agentId, { description, startedAt, launchedAt }]) => ({
|
|
3297
|
+
agent: { description, startedAt },
|
|
3298
|
+
launchedAt,
|
|
3299
|
+
endedAt: alive.has(agentId) ? void 0 : endedAt.get(agentId) ?? launchedAt
|
|
3300
|
+
}));
|
|
3103
3301
|
}
|
|
3104
3302
|
function deriveCodexSessionStatus(rawMessages) {
|
|
3105
3303
|
for (let i = rawMessages.length - 1; i >= 0; i--) {
|
|
@@ -3108,16 +3306,7 @@ function deriveCodexSessionStatus(rawMessages) {
|
|
|
3108
3306
|
const payload = msg.payload;
|
|
3109
3307
|
switch (payload?.type) {
|
|
3110
3308
|
case "task_complete": {
|
|
3111
|
-
|
|
3112
|
-
if (pending.length > 0) {
|
|
3113
|
-
return {
|
|
3114
|
-
status: "awaiting_agents",
|
|
3115
|
-
pendingQueue: 0,
|
|
3116
|
-
pendingAgents: pending.length,
|
|
3117
|
-
pendingAgentDescriptions: pending.filter((description) => description.length > 0)
|
|
3118
|
-
};
|
|
3119
|
-
}
|
|
3120
|
-
return { status: "completed" };
|
|
3309
|
+
return awaitingAgentsStatus(collectCodexBackgroundAgents(rawMessages)) ?? { status: "completed" };
|
|
3121
3310
|
}
|
|
3122
3311
|
case "task_started":
|
|
3123
3312
|
return { status: "processing" };
|
|
@@ -3915,33 +4104,32 @@ function isCopilotEventType(type) {
|
|
|
3915
4104
|
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."));
|
|
3916
4105
|
}
|
|
3917
4106
|
function deriveCopilotSessionStatus(rawMessages) {
|
|
3918
|
-
const
|
|
3919
|
-
for (const event of rawMessages) {
|
|
4107
|
+
const agents = /* @__PURE__ */ new Map();
|
|
4108
|
+
for (const [index, event] of rawMessages.entries()) {
|
|
3920
4109
|
const agentId = typeof event.agentId === "string" ? event.agentId : "";
|
|
3921
4110
|
if (!agentId && (event.type === "abort" || event.type === "session.shutdown" || event.type === "session.error")) {
|
|
3922
|
-
|
|
4111
|
+
agents.clear();
|
|
3923
4112
|
continue;
|
|
3924
4113
|
}
|
|
3925
4114
|
if (!agentId || !event.type.startsWith("subagent.")) continue;
|
|
3926
4115
|
const data = isObject4(event.data) ? event.data : {};
|
|
4116
|
+
const launch = agents.get(agentId);
|
|
3927
4117
|
if (event.type === "subagent.completed" || event.type === "subagent.failed") {
|
|
3928
|
-
|
|
4118
|
+
if (launch) launch.endedAt ??= index;
|
|
3929
4119
|
continue;
|
|
3930
4120
|
}
|
|
3931
4121
|
if (event.type === "subagent.started" || event.type === "subagent.configured") {
|
|
3932
4122
|
const description = [data.agentDisplayName, data.description, data.agentName].find((value) => typeof value === "string") ?? "";
|
|
3933
|
-
|
|
4123
|
+
if (!launch || launch.endedAt !== void 0) {
|
|
4124
|
+
const startedAt = typeof event.timestamp === "string" ? event.timestamp : void 0;
|
|
4125
|
+
agents.set(agentId, { agent: { description, startedAt }, launchedAt: index });
|
|
4126
|
+
} else if (description) {
|
|
4127
|
+
launch.agent.description = description;
|
|
4128
|
+
}
|
|
3934
4129
|
}
|
|
3935
4130
|
}
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
return {
|
|
3939
|
-
status: "awaiting_agents",
|
|
3940
|
-
pendingQueue: 0,
|
|
3941
|
-
pendingAgents: descriptions.length,
|
|
3942
|
-
pendingAgentDescriptions: descriptions.filter((description) => description.length > 0)
|
|
3943
|
-
};
|
|
3944
|
-
}
|
|
4131
|
+
const awaiting = awaitingAgentsStatus([...agents.values()]);
|
|
4132
|
+
if (awaiting) return awaiting;
|
|
3945
4133
|
let sawUserActivity = false;
|
|
3946
4134
|
const completedPermissionRequests = /* @__PURE__ */ new Set();
|
|
3947
4135
|
for (let i = rawMessages.length - 1; i >= 0; i--) {
|
|
@@ -4027,6 +4215,7 @@ function copilotTurnBoundaries(records) {
|
|
|
4027
4215
|
|
|
4028
4216
|
// src/lib/agents.ts
|
|
4029
4217
|
var TERMINAL_AGENT_KIND = AGENT_KINDS[AGENT_KINDS.length - 1];
|
|
4218
|
+
var hasNoNoiseLines = () => false;
|
|
4030
4219
|
var codexFormat = {
|
|
4031
4220
|
kind: "codex",
|
|
4032
4221
|
descriptor: descriptorFor("codex"),
|
|
@@ -4036,6 +4225,8 @@ var codexFormat = {
|
|
|
4036
4225
|
append: appendCodexSession,
|
|
4037
4226
|
metadataFromLines: extractCodexMetadataFromLines,
|
|
4038
4227
|
status: deriveCodexSessionStatus,
|
|
4228
|
+
isNoiseLine: hasNoNoiseLines,
|
|
4229
|
+
pageHeaderLine: codexPageHeaderLine,
|
|
4039
4230
|
brandBranch: brandCodexBranch,
|
|
4040
4231
|
turnBoundaries: codexTurnBoundaries
|
|
4041
4232
|
};
|
|
@@ -4048,6 +4239,7 @@ var copilotFormat = {
|
|
|
4048
4239
|
append: appendCopilotSession,
|
|
4049
4240
|
metadataFromLines: extractCopilotMetadataFromLines,
|
|
4050
4241
|
status: deriveCopilotSessionStatus,
|
|
4242
|
+
isNoiseLine: hasNoNoiseLines,
|
|
4051
4243
|
brandBranch: brandCopilotBranch,
|
|
4052
4244
|
turnBoundaries: copilotTurnBoundaries
|
|
4053
4245
|
};
|
|
@@ -4061,6 +4253,7 @@ var claudeFormat = {
|
|
|
4061
4253
|
append: appendClaudeSession,
|
|
4062
4254
|
metadataFromLines: extractClaudeMetadataFromLines,
|
|
4063
4255
|
status: deriveClaudeSessionStatus,
|
|
4256
|
+
isNoiseLine: isClaudeNoiseLine,
|
|
4064
4257
|
brandBranch: brandClaudeBranch,
|
|
4065
4258
|
turnBoundaries: claudeTurnBoundaries
|
|
4066
4259
|
};
|
|
@@ -4090,6 +4283,9 @@ function formatForText(jsonlText) {
|
|
|
4090
4283
|
function formatForRecords(records) {
|
|
4091
4284
|
return firstMatch((format) => format.detectsRecords(records));
|
|
4092
4285
|
}
|
|
4286
|
+
function isAnyAgentNoiseLine(line) {
|
|
4287
|
+
return AGENT_KINDS.some((kind) => FORMATS[kind].isNoiseLine(line));
|
|
4288
|
+
}
|
|
4093
4289
|
|
|
4094
4290
|
// src/lib/parser.ts
|
|
4095
4291
|
function extractTextFromContent2(content) {
|
|
@@ -4105,8 +4301,55 @@ function getUserMessageText(content) {
|
|
|
4105
4301
|
return extractTextFromContent2(content);
|
|
4106
4302
|
}
|
|
4107
4303
|
|
|
4108
|
-
// src/lib/
|
|
4304
|
+
// src/lib/transcriptFile.ts
|
|
4109
4305
|
var import_node_fs = require("node:fs");
|
|
4306
|
+
var import_promises = require("node:fs/promises");
|
|
4307
|
+
var zlib = __toESM(require("node:zlib"));
|
|
4308
|
+
var COMPRESSED_SUFFIX = ".zst";
|
|
4309
|
+
var canReadCompressedTranscripts = typeof zlib.zstdDecompressSync === "function";
|
|
4310
|
+
function isCompressedTranscript(filePath) {
|
|
4311
|
+
return filePath.endsWith(COMPRESSED_SUFFIX);
|
|
4312
|
+
}
|
|
4313
|
+
function uncompressedTranscriptName(fileName) {
|
|
4314
|
+
return isCompressedTranscript(fileName) ? fileName.slice(0, -COMPRESSED_SUFFIX.length) : fileName;
|
|
4315
|
+
}
|
|
4316
|
+
function isListableTranscript(name, siblings) {
|
|
4317
|
+
const plainName = uncompressedTranscriptName(name);
|
|
4318
|
+
if (!plainName.endsWith(".jsonl")) return false;
|
|
4319
|
+
if (plainName === name) return true;
|
|
4320
|
+
return canReadCompressedTranscripts && !siblings.has(plainName);
|
|
4321
|
+
}
|
|
4322
|
+
function inflate(data) {
|
|
4323
|
+
if (!canReadCompressedTranscripts) {
|
|
4324
|
+
throw new Error("Reading a .jsonl.zst transcript needs Node.js 22.15 or newer, or Bun");
|
|
4325
|
+
}
|
|
4326
|
+
return zlib.zstdDecompressSync(data);
|
|
4327
|
+
}
|
|
4328
|
+
function readTranscriptTextSync(filePath) {
|
|
4329
|
+
const data = (0, import_node_fs.readFileSync)(filePath);
|
|
4330
|
+
return (isCompressedTranscript(filePath) ? inflate(data) : data).toString("utf-8");
|
|
4331
|
+
}
|
|
4332
|
+
async function readTranscriptText(filePath) {
|
|
4333
|
+
const data = await (0, import_promises.readFile)(filePath);
|
|
4334
|
+
return (isCompressedTranscript(filePath) ? inflate(data) : data).toString("utf-8");
|
|
4335
|
+
}
|
|
4336
|
+
async function openTranscript(filePath) {
|
|
4337
|
+
if (!isCompressedTranscript(filePath)) return (0, import_promises.open)(filePath, "r");
|
|
4338
|
+
const [fileStat, compressed] = await Promise.all([(0, import_promises.stat)(filePath), (0, import_promises.readFile)(filePath)]);
|
|
4339
|
+
const data = inflate(compressed);
|
|
4340
|
+
return {
|
|
4341
|
+
async read(buffer, offset, length, position) {
|
|
4342
|
+
const start = Math.min(Math.max(position, 0), data.length);
|
|
4343
|
+
return { bytesRead: data.copy(buffer, offset, start, Math.min(start + length, data.length)) };
|
|
4344
|
+
},
|
|
4345
|
+
stat: async () => ({ size: data.length, mtimeMs: fileStat.mtimeMs }),
|
|
4346
|
+
close: async () => {
|
|
4347
|
+
}
|
|
4348
|
+
};
|
|
4349
|
+
}
|
|
4350
|
+
|
|
4351
|
+
// src/lib/stores.ts
|
|
4352
|
+
var import_node_fs2 = require("node:fs");
|
|
4110
4353
|
var import_node_path2 = require("node:path");
|
|
4111
4354
|
|
|
4112
4355
|
// src/lib/dirs.ts
|
|
@@ -4133,14 +4376,14 @@ var MAX_WALK_DEPTH = 4;
|
|
|
4133
4376
|
var SUBAGENTS_DIR = "subagents";
|
|
4134
4377
|
function mtimeOf(filePath) {
|
|
4135
4378
|
try {
|
|
4136
|
-
return (0,
|
|
4379
|
+
return (0, import_node_fs2.statSync)(filePath).mtimeMs;
|
|
4137
4380
|
} catch {
|
|
4138
4381
|
return null;
|
|
4139
4382
|
}
|
|
4140
4383
|
}
|
|
4141
4384
|
function readDirSafe(dir) {
|
|
4142
4385
|
try {
|
|
4143
|
-
return (0,
|
|
4386
|
+
return (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true });
|
|
4144
4387
|
} catch {
|
|
4145
4388
|
return [];
|
|
4146
4389
|
}
|
|
@@ -4151,8 +4394,8 @@ function isWithin(root, target) {
|
|
|
4151
4394
|
}
|
|
4152
4395
|
function canonicalWithinRoot(root, filePath) {
|
|
4153
4396
|
try {
|
|
4154
|
-
const realRoot = (0,
|
|
4155
|
-
const real = (0,
|
|
4397
|
+
const realRoot = (0, import_node_fs2.realpathSync)(root);
|
|
4398
|
+
const real = (0, import_node_fs2.realpathSync)(filePath);
|
|
4156
4399
|
return isWithin(realRoot, real) ? real : null;
|
|
4157
4400
|
} catch {
|
|
4158
4401
|
return null;
|
|
@@ -4218,13 +4461,15 @@ function walkClaude(root, cutoffMs) {
|
|
|
4218
4461
|
function walkCodex(root, cutoffMs, dir = root, depth = 0) {
|
|
4219
4462
|
if (depth > MAX_WALK_DEPTH) return [];
|
|
4220
4463
|
const found = [];
|
|
4221
|
-
|
|
4464
|
+
const entries = readDirSafe(dir);
|
|
4465
|
+
const names = new Set(entries.map((entry) => entry.name));
|
|
4466
|
+
for (const entry of entries) {
|
|
4222
4467
|
const filePath = (0, import_node_path2.join)(dir, entry.name);
|
|
4223
4468
|
if (entry.isDirectory()) {
|
|
4224
4469
|
found.push(...walkCodex(root, cutoffMs, filePath, depth + 1));
|
|
4225
4470
|
continue;
|
|
4226
4471
|
}
|
|
4227
|
-
if (!entry.name
|
|
4472
|
+
if (!isListableTranscript(entry.name, names)) continue;
|
|
4228
4473
|
const mtimeMs = mtimeOf(filePath);
|
|
4229
4474
|
if (mtimeMs === null || mtimeMs < cutoffMs) continue;
|
|
4230
4475
|
found.push({
|
|
@@ -4285,14 +4530,18 @@ var WALKERS = {
|
|
|
4285
4530
|
find(root, sessionId) {
|
|
4286
4531
|
const walk = (dir, depth) => {
|
|
4287
4532
|
if (depth > MAX_WALK_DEPTH) return null;
|
|
4288
|
-
|
|
4533
|
+
const entries = readDirSafe(dir);
|
|
4534
|
+
const names = new Set(entries.map((entry) => entry.name));
|
|
4535
|
+
for (const entry of entries) {
|
|
4289
4536
|
const filePath = (0, import_node_path2.join)(dir, entry.name);
|
|
4290
4537
|
if (entry.isDirectory()) {
|
|
4291
4538
|
const match = walk(filePath, depth + 1);
|
|
4292
4539
|
if (match) return match;
|
|
4293
4540
|
continue;
|
|
4294
4541
|
}
|
|
4295
|
-
if (entry.name.endsWith(`${sessionId}.jsonl`))
|
|
4542
|
+
if (uncompressedTranscriptName(entry.name).endsWith(`${sessionId}.jsonl`) && isListableTranscript(entry.name, names)) {
|
|
4543
|
+
return filePath;
|
|
4544
|
+
}
|
|
4296
4545
|
}
|
|
4297
4546
|
return null;
|
|
4298
4547
|
};
|
|
@@ -4335,7 +4584,7 @@ function makeStore(kind, home, configuredId) {
|
|
|
4335
4584
|
ownsPath: (filePath) => {
|
|
4336
4585
|
if (isWithin((0, import_node_path2.resolve)(root()), (0, import_node_path2.resolve)(filePath))) return true;
|
|
4337
4586
|
try {
|
|
4338
|
-
return isWithin((0,
|
|
4587
|
+
return isWithin((0, import_node_fs2.realpathSync)(root()), (0, import_node_fs2.realpathSync)(filePath));
|
|
4339
4588
|
} catch {
|
|
4340
4589
|
return false;
|
|
4341
4590
|
}
|
|
@@ -4369,7 +4618,7 @@ function allStores() {
|
|
|
4369
4618
|
if (!entry.isDirectory()) continue;
|
|
4370
4619
|
const home = (0, import_node_path2.join)(root, "provider-instances", entry.name);
|
|
4371
4620
|
try {
|
|
4372
|
-
const config = JSON.parse((0,
|
|
4621
|
+
const config = JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.join)(home, "config.json"), "utf8"));
|
|
4373
4622
|
if (config.providerInstance?.id === entry.name && config.providerInstance.agent && AGENT_KINDS.includes(config.providerInstance.agent)) stores.push(makeStore(config.providerInstance.agent, home, entry.name));
|
|
4374
4623
|
} catch {
|
|
4375
4624
|
}
|
|
@@ -4444,7 +4693,7 @@ var SearchIndex = class {
|
|
|
4444
4693
|
const { count: totalRows } = this.db.prepare("SELECT COUNT(*) as count FROM search_content").get();
|
|
4445
4694
|
let dbSizeBytes = 0;
|
|
4446
4695
|
try {
|
|
4447
|
-
dbSizeBytes = (0,
|
|
4696
|
+
dbSizeBytes = (0, import_node_fs3.statSync)(this.dbPath).size;
|
|
4448
4697
|
} catch {
|
|
4449
4698
|
}
|
|
4450
4699
|
return {
|
|
@@ -4517,9 +4766,9 @@ var SearchIndex = class {
|
|
|
4517
4766
|
indexFile(filePath, sessionId, mtimeMs, opts) {
|
|
4518
4767
|
const resolvedSessionId = sessionId ?? identifyTranscript(filePath).sessionId;
|
|
4519
4768
|
if (mtimeMs == null) {
|
|
4520
|
-
mtimeMs = (0,
|
|
4769
|
+
mtimeMs = (0, import_node_fs3.statSync)(filePath).mtimeMs;
|
|
4521
4770
|
}
|
|
4522
|
-
const content = (
|
|
4771
|
+
const content = readTranscriptTextSync(filePath);
|
|
4523
4772
|
const session = parseSession(content, { skipStats: true });
|
|
4524
4773
|
const isSubagent = opts?.isSubagent ? 1 : 0;
|
|
4525
4774
|
const parentSessionId = opts?.parentSessionId ?? null;
|
|
@@ -4548,7 +4797,7 @@ var SearchIndex = class {
|
|
|
4548
4797
|
const files = this.db.prepare("SELECT file_path FROM indexed_files").all();
|
|
4549
4798
|
const missing = files.filter(({ file_path }) => {
|
|
4550
4799
|
try {
|
|
4551
|
-
(0,
|
|
4800
|
+
(0, import_node_fs3.statSync)(file_path);
|
|
4552
4801
|
return false;
|
|
4553
4802
|
} catch (error) {
|
|
4554
4803
|
const code = error.code;
|
|
@@ -4665,7 +4914,7 @@ var SearchIndex = class {
|
|
|
4665
4914
|
this.db.close();
|
|
4666
4915
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
4667
4916
|
try {
|
|
4668
|
-
(0,
|
|
4917
|
+
(0, import_node_fs3.unlinkSync)(this.dbPath + suffix);
|
|
4669
4918
|
} catch {
|
|
4670
4919
|
}
|
|
4671
4920
|
}
|
|
@@ -4689,7 +4938,7 @@ var SearchIndex = class {
|
|
|
4689
4938
|
const txn = this.db.transaction(() => {
|
|
4690
4939
|
for (const file of files) {
|
|
4691
4940
|
try {
|
|
4692
|
-
const content = (
|
|
4941
|
+
const content = readTranscriptTextSync(file.path);
|
|
4693
4942
|
const session = parseSession(content, { skipStats: true });
|
|
4694
4943
|
this.insertSessionContent(insert, file.sessionId, file.path, session);
|
|
4695
4944
|
insertFile.run(file.path, file.mtimeMs, file.sessionId, file.isSubagent ? 1 : 0, file.parentSessionId);
|
|
@@ -4785,9 +5034,9 @@ async function searchSessions(query, opts, searchIndex) {
|
|
|
4785
5034
|
let ownedIndex = false;
|
|
4786
5035
|
if (!index && searchIndex === void 0) {
|
|
4787
5036
|
try {
|
|
4788
|
-
const dbExists = (0,
|
|
5037
|
+
const dbExists = (0, import_node_fs4.existsSync)(DEFAULT_DB_PATH);
|
|
4789
5038
|
if (!dbExists) {
|
|
4790
|
-
(0,
|
|
5039
|
+
(0, import_node_fs4.mkdirSync)((0, import_node_path3.dirname)(DEFAULT_DB_PATH), { recursive: true });
|
|
4791
5040
|
}
|
|
4792
5041
|
index = new SearchIndex(DEFAULT_DB_PATH);
|
|
4793
5042
|
ownedIndex = true;
|
|
@@ -4861,7 +5110,7 @@ async function cwdFromFilePath(filePath) {
|
|
|
4861
5110
|
const cached = cwdCache.get(filePath);
|
|
4862
5111
|
if (cached !== void 0) return cached;
|
|
4863
5112
|
try {
|
|
4864
|
-
const fh = await (
|
|
5113
|
+
const fh = await openTranscript(filePath);
|
|
4865
5114
|
try {
|
|
4866
5115
|
const buf = Buffer.alloc(CWD_READ_BYTES);
|
|
4867
5116
|
const { bytesRead } = await fh.read(buf, 0, CWD_READ_BYTES, 0);
|
|
@@ -4919,7 +5168,7 @@ function searchField(text, location, query, caseSensitive, extras) {
|
|
|
4919
5168
|
async function discoverSingleSession(sessionId) {
|
|
4920
5169
|
const jsonlPath = await findSessionFile(sessionId);
|
|
4921
5170
|
if (!jsonlPath) return [];
|
|
4922
|
-
const s = await (0,
|
|
5171
|
+
const s = await (0, import_promises2.stat)(jsonlPath);
|
|
4923
5172
|
return [{ path: jsonlPath, mtimeMs: s.mtimeMs, sessionId }];
|
|
4924
5173
|
}
|
|
4925
5174
|
function discoverAllSessions(maxAgeMs) {
|
|
@@ -4927,7 +5176,7 @@ function discoverAllSessions(maxAgeMs) {
|
|
|
4927
5176
|
}
|
|
4928
5177
|
async function rawTextMatch(filePath, query, caseSensitive) {
|
|
4929
5178
|
try {
|
|
4930
|
-
const content = await (
|
|
5179
|
+
const content = await readTranscriptText(filePath);
|
|
4931
5180
|
const haystack = caseSensitive ? content : content.toLowerCase();
|
|
4932
5181
|
const needle = caseSensitive ? query : query.toLowerCase();
|
|
4933
5182
|
if (haystack.includes(needle)) return content;
|
|
@@ -5002,7 +5251,7 @@ async function walkSubagentFiles(parentJsonlPath, query, caseSensitive, currentD
|
|
|
5002
5251
|
const subDir = parentJsonlPath.replace(/\.jsonl$/, "") + "/subagents";
|
|
5003
5252
|
let files;
|
|
5004
5253
|
try {
|
|
5005
|
-
files = await (0,
|
|
5254
|
+
files = await (0, import_promises2.readdir)(subDir);
|
|
5006
5255
|
} catch {
|
|
5007
5256
|
return [];
|
|
5008
5257
|
}
|
|
@@ -5080,14 +5329,14 @@ async function rawScanSearch(query, sessionId, maxAgeMs, limit, caseSensitive, e
|
|
|
5080
5329
|
}
|
|
5081
5330
|
|
|
5082
5331
|
// src/commands/context.ts
|
|
5083
|
-
var
|
|
5332
|
+
var import_promises4 = require("node:fs/promises");
|
|
5084
5333
|
var import_node_path5 = require("node:path");
|
|
5085
5334
|
|
|
5086
5335
|
// src/lib/helpers.ts
|
|
5087
|
-
var
|
|
5336
|
+
var import_promises3 = require("node:fs/promises");
|
|
5088
5337
|
var import_node_path4 = require("node:path");
|
|
5089
5338
|
async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
|
|
5090
|
-
const entries = await (0,
|
|
5339
|
+
const entries = await (0, import_promises3.readdir)(dirs.PROJECTS_DIR, { withFileTypes: true });
|
|
5091
5340
|
for (const entry of entries) {
|
|
5092
5341
|
if (!entry.isDirectory() || entry.name === "memory") continue;
|
|
5093
5342
|
const filePath = (0, import_node_path4.join)(
|
|
@@ -5098,7 +5347,7 @@ async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
|
|
|
5098
5347
|
subagentFileName
|
|
5099
5348
|
);
|
|
5100
5349
|
try {
|
|
5101
|
-
const fh = await (0,
|
|
5350
|
+
const fh = await (0, import_promises3.open)(filePath, "r");
|
|
5102
5351
|
try {
|
|
5103
5352
|
const buf = Buffer.alloc(16384);
|
|
5104
5353
|
const { bytesRead } = await fh.read(buf, 0, 16384, 0);
|
|
@@ -5293,7 +5542,13 @@ function mapContentBlock(block) {
|
|
|
5293
5542
|
case "task_notification":
|
|
5294
5543
|
return { kind: "task_notification", content: block.content, timestamp: block.timestamp ?? null };
|
|
5295
5544
|
case "local_command":
|
|
5296
|
-
return {
|
|
5545
|
+
return {
|
|
5546
|
+
kind: "local_command",
|
|
5547
|
+
content: block.content,
|
|
5548
|
+
timestamp: block.timestamp ?? null,
|
|
5549
|
+
...block.contextUsage ? { contextUsage: block.contextUsage } : {},
|
|
5550
|
+
...block.usageReport ? { usageReport: block.usageReport } : {}
|
|
5551
|
+
};
|
|
5297
5552
|
default: {
|
|
5298
5553
|
const exhaustive = block;
|
|
5299
5554
|
return exhaustive;
|
|
@@ -5303,7 +5558,7 @@ function mapContentBlock(block) {
|
|
|
5303
5558
|
async function findSubagentFile(parentJsonlPath, agentId) {
|
|
5304
5559
|
const subagentsDir = parentJsonlPath.replace(/\.jsonl$/, "") + "/subagents";
|
|
5305
5560
|
try {
|
|
5306
|
-
const files = await (0,
|
|
5561
|
+
const files = await (0, import_promises4.readdir)(subagentsDir);
|
|
5307
5562
|
for (const f of files) {
|
|
5308
5563
|
if (!f.startsWith("agent-") || !f.endsWith(".jsonl")) continue;
|
|
5309
5564
|
const fileAgentId = f.replace("agent-", "").replace(".jsonl", "");
|
|
@@ -5317,12 +5572,12 @@ async function findSubagentFile(parentJsonlPath, agentId) {
|
|
|
5317
5572
|
}
|
|
5318
5573
|
async function findTeamContext(sessionId, subagentFileName) {
|
|
5319
5574
|
try {
|
|
5320
|
-
const teamEntries = await (0,
|
|
5575
|
+
const teamEntries = await (0, import_promises4.readdir)(dirs.TEAMS_DIR, { withFileTypes: true });
|
|
5321
5576
|
for (const entry of teamEntries) {
|
|
5322
5577
|
if (!entry.isDirectory()) continue;
|
|
5323
5578
|
const configPath = (0, import_node_path5.join)(dirs.TEAMS_DIR, entry.name, "config.json");
|
|
5324
5579
|
try {
|
|
5325
|
-
const raw = await (0,
|
|
5580
|
+
const raw = await (0, import_promises4.readFile)(configPath, "utf-8");
|
|
5326
5581
|
const config = JSON.parse(raw);
|
|
5327
5582
|
if (config.leadSessionId !== sessionId) continue;
|
|
5328
5583
|
const members = config.members ?? [];
|
|
@@ -5331,10 +5586,10 @@ async function findTeamContext(sessionId, subagentFileName) {
|
|
|
5331
5586
|
let currentTask = null;
|
|
5332
5587
|
try {
|
|
5333
5588
|
const taskDir = (0, import_node_path5.join)(dirs.TASKS_DIR, entry.name);
|
|
5334
|
-
const taskFiles = await (0,
|
|
5589
|
+
const taskFiles = await (0, import_promises4.readdir)(taskDir);
|
|
5335
5590
|
for (const tf of taskFiles) {
|
|
5336
5591
|
if (!tf.endsWith(".json")) continue;
|
|
5337
|
-
const taskRaw = await (0,
|
|
5592
|
+
const taskRaw = await (0, import_promises4.readFile)((0, import_node_path5.join)(taskDir, tf), "utf-8");
|
|
5338
5593
|
const task = JSON.parse(taskRaw);
|
|
5339
5594
|
if (task.owner === memberName && task.status === "in_progress") {
|
|
5340
5595
|
currentTask = { id: task.id, subject: task.subject, status: task.status };
|
|
@@ -5382,14 +5637,14 @@ function findAgentMetadata(session, agentId) {
|
|
|
5382
5637
|
async function getSessionOverview(sessionId) {
|
|
5383
5638
|
const jsonlPath = await findSessionFile(sessionId);
|
|
5384
5639
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5385
|
-
const content = await (
|
|
5640
|
+
const content = await readTranscriptText(jsonlPath);
|
|
5386
5641
|
const session = parseTranscript(content, jsonlPath);
|
|
5387
5642
|
return mapSessionToOverview(session);
|
|
5388
5643
|
}
|
|
5389
5644
|
async function getTurnDetail(sessionId, turnIndex) {
|
|
5390
5645
|
const jsonlPath = await findSessionFile(sessionId);
|
|
5391
5646
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5392
|
-
const content = await (
|
|
5647
|
+
const content = await readTranscriptText(jsonlPath);
|
|
5393
5648
|
const session = parseTranscript(content, jsonlPath);
|
|
5394
5649
|
if (turnIndex < 0 || turnIndex >= session.turns.length) return { error: "Turn not found" };
|
|
5395
5650
|
return mapTurnToDetail(session, turnIndex);
|
|
@@ -5397,11 +5652,11 @@ async function getTurnDetail(sessionId, turnIndex) {
|
|
|
5397
5652
|
async function getAgentOverview(sessionId, agentId) {
|
|
5398
5653
|
const jsonlPath = await findSessionFile(sessionId);
|
|
5399
5654
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5400
|
-
const content = await (
|
|
5655
|
+
const content = await readTranscriptText(jsonlPath);
|
|
5401
5656
|
const session = parseTranscript(content, jsonlPath);
|
|
5402
5657
|
const subagentFile = await findSubagentFile(jsonlPath, agentId);
|
|
5403
5658
|
if (!subagentFile) return { error: "Agent not found" };
|
|
5404
|
-
const subagentContent = await (
|
|
5659
|
+
const subagentContent = await readTranscriptText(subagentFile.filePath);
|
|
5405
5660
|
const subagentSession = parseTranscript(subagentContent, subagentFile.filePath);
|
|
5406
5661
|
const metadata = findAgentMetadata(session, agentId);
|
|
5407
5662
|
const parentToolCallId = findParentToolCallId(session, agentId);
|
|
@@ -5422,7 +5677,7 @@ async function getAgentTurnDetail(sessionId, agentId, turnIndex) {
|
|
|
5422
5677
|
if (!jsonlPath) return { error: "Session not found" };
|
|
5423
5678
|
const subagentFile = await findSubagentFile(jsonlPath, agentId);
|
|
5424
5679
|
if (!subagentFile) return { error: "Agent not found" };
|
|
5425
|
-
const subagentContent = await (
|
|
5680
|
+
const subagentContent = await readTranscriptText(subagentFile.filePath);
|
|
5426
5681
|
const subagentSession = parseTranscript(subagentContent, subagentFile.filePath);
|
|
5427
5682
|
if (turnIndex < 0 || turnIndex >= subagentSession.turns.length) return { error: "Turn not found" };
|
|
5428
5683
|
return mapTurnToDetail(subagentSession, turnIndex);
|
|
@@ -5432,7 +5687,7 @@ async function getAgentTurnDetail(sessionId, agentId, turnIndex) {
|
|
|
5432
5687
|
var import_node_path6 = require("node:path");
|
|
5433
5688
|
|
|
5434
5689
|
// src/lib/metadata.ts
|
|
5435
|
-
var
|
|
5690
|
+
var import_promises5 = require("node:fs/promises");
|
|
5436
5691
|
|
|
5437
5692
|
// src/lib/sessionStatus.ts
|
|
5438
5693
|
function deriveSessionStatus(rawMessages) {
|
|
@@ -5457,6 +5712,7 @@ function scanClaudeMessages(lines) {
|
|
|
5457
5712
|
turnCount: 0
|
|
5458
5713
|
};
|
|
5459
5714
|
for (const line of lines) {
|
|
5715
|
+
if (isAnyAgentNoiseLine(line)) continue;
|
|
5460
5716
|
let record2;
|
|
5461
5717
|
try {
|
|
5462
5718
|
record2 = JSON.parse(line);
|
|
@@ -5485,11 +5741,11 @@ function scanClaudeMessages(lines) {
|
|
|
5485
5741
|
return meta;
|
|
5486
5742
|
}
|
|
5487
5743
|
async function readLines(filePath, size) {
|
|
5488
|
-
if (size <= FULL_READ_LIMIT) {
|
|
5489
|
-
const content = await (
|
|
5744
|
+
if (size <= FULL_READ_LIMIT || isCompressedTranscript(filePath)) {
|
|
5745
|
+
const content = await readTranscriptText(filePath);
|
|
5490
5746
|
return { lines: content.split("\n").filter(Boolean), isPartialRead: false };
|
|
5491
5747
|
}
|
|
5492
|
-
const handle = await (0,
|
|
5748
|
+
const handle = await (0, import_promises5.open)(filePath, "r");
|
|
5493
5749
|
try {
|
|
5494
5750
|
const buffer = Buffer.alloc(HEAD_READ_BYTES);
|
|
5495
5751
|
const { bytesRead } = await handle.read(buffer, 0, HEAD_READ_BYTES, 0);
|
|
@@ -5504,11 +5760,11 @@ async function readLines(filePath, size) {
|
|
|
5504
5760
|
}
|
|
5505
5761
|
}
|
|
5506
5762
|
async function getSessionMeta(filePath) {
|
|
5507
|
-
const fileStat = await (0,
|
|
5763
|
+
const fileStat = await (0, import_promises5.stat)(filePath);
|
|
5508
5764
|
let { lines, isPartialRead } = await readLines(filePath, fileStat.size);
|
|
5509
5765
|
const format = formatForText(lines.join("\n"));
|
|
5510
5766
|
if (isPartialRead && !format.descriptor.metadataFromHead) {
|
|
5511
|
-
lines = (await (0,
|
|
5767
|
+
lines = (await (0, import_promises5.readFile)(filePath, "utf-8")).split("\n").filter(Boolean);
|
|
5512
5768
|
isPartialRead = false;
|
|
5513
5769
|
}
|
|
5514
5770
|
const header = readHeader(format, lines);
|
|
@@ -5537,10 +5793,10 @@ async function getSessionStatus(filePath) {
|
|
|
5537
5793
|
const CHUNK = 4096;
|
|
5538
5794
|
const MAX_CHUNKS = 64;
|
|
5539
5795
|
try {
|
|
5540
|
-
const
|
|
5541
|
-
if (fileStat.size === 0) return { status: "idle" };
|
|
5542
|
-
const fh = await (0, import_promises4.open)(filePath, "r");
|
|
5796
|
+
const fh = await openTranscript(filePath);
|
|
5543
5797
|
try {
|
|
5798
|
+
const fileStat = await fh.stat();
|
|
5799
|
+
if (fileStat.size === 0) return { status: "idle" };
|
|
5544
5800
|
const meaningful = [];
|
|
5545
5801
|
let cursor = fileStat.size;
|
|
5546
5802
|
let leftover = "";
|
|
@@ -5556,7 +5812,7 @@ async function getSessionStatus(filePath) {
|
|
|
5556
5812
|
const startIdx = cursor > 0 ? 1 : 0;
|
|
5557
5813
|
for (let i = lines.length - 1; i >= startIdx; i--) {
|
|
5558
5814
|
const line = lines[i];
|
|
5559
|
-
if (!line) continue;
|
|
5815
|
+
if (!line || isAnyAgentNoiseLine(line)) continue;
|
|
5560
5816
|
let obj;
|
|
5561
5817
|
try {
|
|
5562
5818
|
obj = JSON.parse(line);
|
|
@@ -5687,11 +5943,11 @@ async function currentSession(cwd) {
|
|
|
5687
5943
|
}
|
|
5688
5944
|
|
|
5689
5945
|
// src/commands/index-cmd.ts
|
|
5690
|
-
var
|
|
5946
|
+
var import_node_fs5 = require("node:fs");
|
|
5691
5947
|
var import_node_path7 = require("node:path");
|
|
5692
5948
|
async function indexStats(dbPath) {
|
|
5693
5949
|
const path = dbPath ?? DEFAULT_DB_PATH;
|
|
5694
|
-
if (!(0,
|
|
5950
|
+
if (!(0, import_node_fs5.existsSync)(path)) {
|
|
5695
5951
|
return { error: `Database not found at ${path}. Run 'cogpit-memory index rebuild' to create it.` };
|
|
5696
5952
|
}
|
|
5697
5953
|
const index = new SearchIndex(path);
|
|
@@ -5701,7 +5957,7 @@ async function indexStats(dbPath) {
|
|
|
5701
5957
|
}
|
|
5702
5958
|
async function indexRebuild(dbPath) {
|
|
5703
5959
|
const path = dbPath ?? DEFAULT_DB_PATH;
|
|
5704
|
-
(0,
|
|
5960
|
+
(0, import_node_fs5.mkdirSync)((0, import_node_path7.dirname)(path), { recursive: true });
|
|
5705
5961
|
const index = new SearchIndex(path);
|
|
5706
5962
|
index.buildFull();
|
|
5707
5963
|
const stats = index.getStats();
|
|
@@ -5710,7 +5966,7 @@ async function indexRebuild(dbPath) {
|
|
|
5710
5966
|
}
|
|
5711
5967
|
|
|
5712
5968
|
// src/commands/install-skill.ts
|
|
5713
|
-
var
|
|
5969
|
+
var import_node_fs6 = require("node:fs");
|
|
5714
5970
|
var import_node_path8 = require("node:path");
|
|
5715
5971
|
function findSkillContent() {
|
|
5716
5972
|
const candidates = [];
|
|
@@ -5720,8 +5976,8 @@ function findSkillContent() {
|
|
|
5720
5976
|
}
|
|
5721
5977
|
for (const candidate of candidates) {
|
|
5722
5978
|
try {
|
|
5723
|
-
if ((0,
|
|
5724
|
-
return (0,
|
|
5979
|
+
if ((0, import_node_fs6.existsSync)(candidate)) {
|
|
5980
|
+
return (0, import_node_fs6.readFileSync)(candidate, "utf-8");
|
|
5725
5981
|
}
|
|
5726
5982
|
} catch {
|
|
5727
5983
|
}
|
|
@@ -5731,10 +5987,10 @@ function findSkillContent() {
|
|
|
5731
5987
|
function installSkill(cwd, global) {
|
|
5732
5988
|
const root = global ? (0, import_node_path8.join)(process.env.HOME ?? process.env.USERPROFILE ?? "~", ".claude") : (0, import_node_path8.join)(cwd ?? process.cwd(), ".claude");
|
|
5733
5989
|
const skillDir = (0, import_node_path8.join)(root, "skills", "cogpit-memory");
|
|
5734
|
-
(0,
|
|
5990
|
+
(0, import_node_fs6.mkdirSync)(skillDir, { recursive: true });
|
|
5735
5991
|
const content = findSkillContent();
|
|
5736
5992
|
const dest = (0, import_node_path8.join)(skillDir, "SKILL.md");
|
|
5737
|
-
(0,
|
|
5993
|
+
(0, import_node_fs6.writeFileSync)(dest, content);
|
|
5738
5994
|
return { installed: true, path: skillDir };
|
|
5739
5995
|
}
|
|
5740
5996
|
|