cogpit-memory 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js 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 import_node_fs3 = require("node:fs");
40
- var import_promises = require("node:fs/promises");
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 import_node_fs2 = require("node:fs");
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$`, "i").exec(fileName);
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: false,
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({ kind: "local_command", content: msg.content, timestamp: msg.timestamp });
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 === "Task" || block.name === "Agent") {
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(parentId);
1471
+ const taskMeta = taskMetaMap.get(ownToolUseId);
1431
1472
  const agentMsg = {
1432
1473
  agentId: data.agentId,
1433
- parentToolUseId: parentId || void 0,
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 resolved = /* @__PURE__ */ new Set();
1708
+ const resolvedAt = /* @__PURE__ */ new Map();
1657
1709
  const queuedIds = /* @__PURE__ */ new Set();
1658
1710
  const deliveredIds = /* @__PURE__ */ new Set();
1659
- function noteNotifications(text, sink) {
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
- resolved.add(match[1]);
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
- resolved.add(match[1]);
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
- if (ids.length > 0) launches.push({ ids, description });
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") resolved.add(taskId);
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
- pendingDescriptions: launches.filter((launch) => !launch.ids.some((id) => resolved.has(id))).map((launch) => launch.description),
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
- if (work.pendingDescriptions.length > 0) {
1764
- return awaitingAgentsResult(work.pendingDescriptions, Math.max(0, pendingEnqueues));
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];
@@ -2159,6 +2210,48 @@ function codexParentId(payload) {
2159
2210
  }
2160
2211
  return null;
2161
2212
  }
2213
+ function inheritedHistoryFilter(records) {
2214
+ const meta = records.find((record2) => record2?.type === "session_meta");
2215
+ const start = meta?.payload?.subagent_history_start_ordinal;
2216
+ if (typeof start !== "number") return null;
2217
+ const reachesPast = (ordinal) => typeof ordinal === "number" && ordinal >= start;
2218
+ if (!reachesPast(meta?.rolloutLastOrdinal) && !records.some((record2) => reachesPast(record2?.ordinal))) return null;
2219
+ return (record2) => typeof record2.ordinal === "number" && record2.ordinal > 0 && record2.ordinal < start;
2220
+ }
2221
+ async function codexPageHeaderLine(firstLine, lastLines) {
2222
+ if (!firstLine.includes('"subagent_history_start_ordinal"')) return firstLine;
2223
+ const meta = safeParseLine(firstLine);
2224
+ if (meta?.type !== "session_meta") return firstLine;
2225
+ const lines = await lastLines();
2226
+ for (let index = lines.length - 1; index >= 0; index--) {
2227
+ const ordinal = safeParseLine(lines[index])?.ordinal;
2228
+ if (typeof ordinal === "number") return JSON.stringify({ ...meta, rolloutLastOrdinal: ordinal });
2229
+ }
2230
+ return firstLine;
2231
+ }
2232
+ function subAgentActivitySource(record2) {
2233
+ const payload = record2.payload;
2234
+ if (record2.type !== "event_msg" || !isObject3(payload)) return null;
2235
+ if (payload.type === "sub_agent_activity") return payload;
2236
+ if (payload.type === "item_completed" && isObject3(payload.item) && payload.item.type === "SubAgentActivity") return payload.item;
2237
+ return null;
2238
+ }
2239
+ function readSubAgentActivity(record2) {
2240
+ const source = subAgentActivitySource(record2);
2241
+ if (!source || typeof source.agent_thread_id !== "string" || typeof source.agent_path !== "string") return null;
2242
+ return {
2243
+ agentId: source.agent_thread_id,
2244
+ agentPath: source.agent_path,
2245
+ kind: typeof source.kind === "string" ? source.kind : "started",
2246
+ eventId: findString(source.event_id, source.id) ?? "",
2247
+ model: findString(source.model) || null,
2248
+ effort: findString(source.reasoning_effort) || null
2249
+ };
2250
+ }
2251
+ function turnErrorMessage(payload) {
2252
+ if (payload.type !== "task_complete" || !isObject3(payload.error)) return "";
2253
+ return typeof payload.error.message === "string" ? payload.error.message.trim() : "";
2254
+ }
2162
2255
  function isCodexRecord(record2) {
2163
2256
  if (!record2 || typeof record2.type !== "string") return false;
2164
2257
  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 +2449,39 @@ function createTurn2(turnId, timestamp, model) {
2356
2449
  model
2357
2450
  };
2358
2451
  }
2359
- function extractPromptFromRecord(record2) {
2360
- if (record2.type === "event_msg" && isObject3(record2.payload) && record2.payload.type === "user_message" && typeof record2.payload.message === "string") {
2361
- return normalizePromptText(record2.payload.message);
2452
+ function codexPromptText(record2) {
2453
+ const payload = isObject3(record2.payload) ? record2.payload : null;
2454
+ if (record2.type === "event_msg" && payload?.type === "user_message" && typeof payload.message === "string") {
2455
+ return normalizePromptText(payload.message);
2362
2456
  }
2363
- if (record2.type === "response_item" && isObject3(record2.payload) && record2.payload.type === "message" && record2.payload.role === "user") {
2364
- return normalizePromptText(extractMessageText(record2.payload, "input_text"));
2457
+ if (record2.type === "response_item" && payload?.type === "message" && payload.role === "user") {
2458
+ return normalizePromptText(extractMessageText(payload, "input_text"));
2365
2459
  }
2366
2460
  return "";
2367
2461
  }
2462
+ function createCodexPromptReader() {
2463
+ let echoPending = false;
2464
+ return (record2) => {
2465
+ const payload = isObject3(record2.payload) ? record2.payload : null;
2466
+ if (record2.type === "event_msg" && payload?.type === "user_message") {
2467
+ const isEcho = echoPending;
2468
+ echoPending = false;
2469
+ return isEcho ? "" : codexPromptText(record2);
2470
+ }
2471
+ if (record2.type !== "response_item") return "";
2472
+ const prompt = codexPromptText(record2);
2473
+ if (prompt) echoPending = true;
2474
+ else if (payload?.type !== "message" || payload.role !== "user") echoPending = false;
2475
+ return prompt;
2476
+ };
2477
+ }
2368
2478
  function recordOpensTurn(record2, payload) {
2369
2479
  if (record2.type === "session_meta") return false;
2370
2480
  if (record2.type === "event_msg" && payload?.type === "task_started") return false;
2371
2481
  if (record2.type === "response_item" && payload?.type === "message") {
2372
2482
  if (payload.role === "developer" || payload.role === "system") return false;
2373
2483
  if (payload.role === "user") {
2374
- return extractPromptFromRecord(record2) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
2484
+ return codexPromptText(record2) !== "" || extractResponseMessageImages(payload).length > 0 || extractResponseMessageAudio(payload).length > 0;
2375
2485
  }
2376
2486
  }
2377
2487
  return true;
@@ -2391,9 +2501,10 @@ function extractMetadataFromRecords(records) {
2391
2501
  let isSubagent = false;
2392
2502
  let parentSessionId = null;
2393
2503
  let agentPath = "/root";
2394
- let previousPrompt = "";
2504
+ const readPrompt = createCodexPromptReader();
2505
+ const isInherited = inheritedHistoryFilter(records);
2395
2506
  for (const record2 of records) {
2396
- if (!isObject3(record2.payload)) continue;
2507
+ if (!isObject3(record2.payload) || isInherited?.(record2)) continue;
2397
2508
  if (record2.type === "session_meta") {
2398
2509
  sessionId ||= typeof record2.payload.id === "string" ? record2.payload.id : "";
2399
2510
  version ||= typeof record2.payload.cli_version === "string" ? record2.payload.cli_version : "";
@@ -2423,12 +2534,10 @@ function extractMetadataFromRecords(records) {
2423
2534
  model ||= typeof record2.payload.model === "string" ? record2.payload.model : "";
2424
2535
  cwd ||= typeof record2.payload.cwd === "string" ? record2.payload.cwd : "";
2425
2536
  }
2426
- const prompt = extractPromptFromRecord(record2);
2537
+ const prompt = readPrompt(record2);
2427
2538
  if (!prompt) continue;
2428
- if (prompt === previousPrompt) continue;
2429
2539
  if (!firstUserMessage) firstUserMessage = prompt;
2430
2540
  lastUserMessage = prompt;
2431
- previousPrompt = prompt;
2432
2541
  turnCount++;
2433
2542
  if (!timestamp) timestamp = record2.timestamp ?? "";
2434
2543
  lastTimestamp = record2.timestamp ?? lastTimestamp;
@@ -2498,6 +2607,7 @@ function walkCodexRecords(records, options) {
2498
2607
  timestamp: info?.timestamp ?? eventTimestamp2,
2499
2608
  tokenUsage: null,
2500
2609
  model: info?.model ?? null,
2610
+ ...info?.effort ? { effort: info.effort } : {},
2501
2611
  isBackground: false,
2502
2612
  prompt: info?.message || void 0,
2503
2613
  status: update.status ?? "running"
@@ -2518,6 +2628,7 @@ function walkCodexRecords(records, options) {
2518
2628
  agentMessage.agentName = info.nickname ?? (info.agentPath ? agentNameFromPath(info.agentPath) : agentMessage.agentName);
2519
2629
  agentMessage.subagentType = info.agentType;
2520
2630
  agentMessage.model = info.model;
2631
+ if (info.effort) agentMessage.effort = info.effort;
2521
2632
  agentMessage.prompt = info.message || agentMessage.prompt;
2522
2633
  }
2523
2634
  if (update.text && !agentMessage.text.includes(update.text)) {
@@ -2588,9 +2699,10 @@ function walkCodexRecords(records, options) {
2588
2699
  webSearchCalls.set(id, toolCall);
2589
2700
  appendToolCall(targetTurn, toolCall, timestamp);
2590
2701
  }
2702
+ const isInherited = inheritedHistoryFilter(records);
2591
2703
  for (let index = 0; index < records.length; index++) {
2592
2704
  const record2 = records[index];
2593
- if (!isCodexRecord(record2)) continue;
2705
+ if (!isCodexRecord(record2) || isInherited?.(record2)) continue;
2594
2706
  recordIndex = index;
2595
2707
  const payload = isObject3(record2.payload) ? record2.payload : void 0;
2596
2708
  const timestamp = record2.timestamp ?? "";
@@ -2679,12 +2791,18 @@ function walkCodexRecords(records, options) {
2679
2791
  }
2680
2792
  continue;
2681
2793
  }
2682
- if (record2.type === "event_msg" && payload?.type === "sub_agent_activity" && typeof payload.agent_thread_id === "string" && typeof payload.agent_path === "string") {
2683
- const agentId = payload.agent_thread_id;
2684
- const eventId2 = typeof payload.event_id === "string" ? payload.event_id : "";
2685
- const kind = typeof payload.kind === "string" ? payload.kind : "started";
2794
+ if (record2.type === "event_msg" && payload) {
2795
+ const turnError = turnErrorMessage(payload);
2796
+ if (turnError) {
2797
+ appendAssistantText(current, turnError, timestamp);
2798
+ continue;
2799
+ }
2800
+ }
2801
+ const activity = readSubAgentActivity(record2);
2802
+ if (activity) {
2803
+ const { agentId, agentPath, eventId: eventId2, kind } = activity;
2686
2804
  const spawnInfo = eventId2 ? spawnAgentCalls.get(eventId2) : void 0;
2687
- const existingId = agentIdByPath.get(payload.agent_path);
2805
+ const existingId = agentIdByPath.get(agentPath);
2688
2806
  const existing = agentRegistry.get(agentId) ?? (existingId ? agentRegistry.get(existingId) : void 0);
2689
2807
  if (kind !== "started" && !existing && !spawnInfo) continue;
2690
2808
  if (existingId && existingId !== agentId && !agentMessages.has(agentId)) {
@@ -2698,18 +2816,19 @@ function walkCodexRecords(records, options) {
2698
2816
  }
2699
2817
  const info = {
2700
2818
  agentId,
2701
- nickname: existing?.nickname ?? agentNameFromPath(payload.agent_path) ?? spawnInfo?.taskName ?? null,
2702
- agentPath: payload.agent_path,
2819
+ nickname: existing?.nickname ?? agentNameFromPath(agentPath) ?? spawnInfo?.taskName ?? null,
2820
+ agentPath,
2703
2821
  message: existing?.message ?? spawnInfo?.message ?? "",
2704
- model: existing?.model ?? spawnInfo?.model ?? null,
2822
+ model: activity.model ?? existing?.model ?? spawnInfo?.model ?? null,
2823
+ effort: activity.effort ?? existing?.effort ?? null,
2705
2824
  agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
2706
2825
  timestamp: existing?.timestamp ?? (timestamp || spawnInfo?.timestamp || ""),
2707
2826
  parentToolCallId: existing?.parentToolCallId ?? eventId2
2708
2827
  };
2709
2828
  agentRegistry.set(agentId, info);
2710
- agentIdByPath.set(payload.agent_path, agentId);
2829
+ agentIdByPath.set(agentPath, agentId);
2711
2830
  if (eventId2 && (kind === "started" || spawnInfo)) agentIdBySpawnCall.set(eventId2, agentId);
2712
- const status = kind === "interrupted" ? "interrupted" : "running";
2831
+ const status = kind === "interrupted" || kind === "completed" ? kind : "running";
2713
2832
  upsertAgentMessage(agentId, current, timestamp, { status });
2714
2833
  continue;
2715
2834
  }
@@ -2865,6 +2984,7 @@ function walkCodexRecords(records, options) {
2865
2984
  agentPath: agentPath ?? existing?.agentPath ?? null,
2866
2985
  message: existing?.message ?? spawnInfo?.message ?? "",
2867
2986
  model: existing?.model ?? spawnInfo?.model ?? null,
2987
+ effort: existing?.effort ?? null,
2868
2988
  agentType: existing?.agentType ?? spawnInfo?.agentType ?? null,
2869
2989
  timestamp: existing?.timestamp ?? spawnInfo?.timestamp ?? timestamp,
2870
2990
  parentToolCallId: existing?.parentToolCallId ?? toolCall.id
@@ -2983,8 +3103,10 @@ function walkCodexRecords(records, options) {
2983
3103
  }
2984
3104
  function parseCodexSession(jsonlText, options) {
2985
3105
  const records = jsonlText.split("\n").map((line) => line.trim()).filter(Boolean).map(safeParseLine).filter(isCodexRecord);
3106
+ const isInherited = inheritedHistoryFilter(records);
3107
+ const ownRecords = isInherited ? records.filter((record2) => !isInherited(record2)) : records;
2986
3108
  const { turnStartIndices: _starts, ...session } = walkCodexRecords(
2987
- records,
3109
+ ownRecords,
2988
3110
  options
2989
3111
  );
2990
3112
  return session;
@@ -3009,40 +3131,48 @@ function parseJsonObject(value) {
3009
3131
  return null;
3010
3132
  }
3011
3133
  }
3012
- function collectCodexPendingAgents(rawMessages) {
3013
- const alive = /* @__PURE__ */ new Map();
3014
- const done = /* @__PURE__ */ new Set();
3134
+ function collectCodexBackgroundAgents(rawMessages) {
3135
+ const launched = /* @__PURE__ */ new Map();
3136
+ const alive = /* @__PURE__ */ new Set();
3137
+ const endedAt = /* @__PURE__ */ new Map();
3015
3138
  const agentIdByPath = /* @__PURE__ */ new Map();
3016
3139
  const spawnCalls = /* @__PURE__ */ new Map();
3017
3140
  const waitCalls = /* @__PURE__ */ new Set();
3018
3141
  const interruptCalls = /* @__PURE__ */ new Map();
3019
- function markAlive(agentId, description) {
3020
- if (!done.has(agentId)) alive.set(agentId, alive.get(agentId) || description);
3021
- }
3022
- for (const msg of rawMessages) {
3142
+ function markAlive(agentId, description, index, startedAt) {
3143
+ if (endedAt.has(agentId)) return;
3144
+ alive.add(agentId);
3145
+ const launch = launched.get(agentId);
3146
+ if (!launch) launched.set(agentId, { launchedAt: index, description, startedAt });
3147
+ else if (!launch.description) launch.description = description;
3148
+ }
3149
+ function markEnded(agentId, index) {
3150
+ if (!endedAt.has(agentId)) endedAt.set(agentId, index);
3151
+ alive.delete(agentId);
3152
+ }
3153
+ for (const [index, msg] of rawMessages.entries()) {
3023
3154
  const payload = isObject3(msg.payload) ? msg.payload : null;
3024
3155
  if (!payload) continue;
3025
- if (msg.type === "event_msg" && payload.type === "sub_agent_activity" && typeof payload.agent_thread_id === "string" && typeof payload.agent_path === "string") {
3026
- const agentId = payload.agent_thread_id;
3027
- const kind = typeof payload.kind === "string" ? payload.kind : "started";
3028
- const eventId2 = typeof payload.event_id === "string" ? payload.event_id : "";
3029
- const existingId = agentIdByPath.get(payload.agent_path);
3030
- const known = alive.has(agentId) || done.has(agentId) || existingId !== void 0 || spawnCalls.has(eventId2);
3156
+ const timestamp = typeof msg.timestamp === "string" ? msg.timestamp : void 0;
3157
+ const activity = readSubAgentActivity(msg);
3158
+ if (activity) {
3159
+ const { agentId, agentPath, kind, eventId: eventId2 } = activity;
3160
+ const existingId = agentIdByPath.get(agentPath);
3161
+ const known = alive.has(agentId) || endedAt.has(agentId) || existingId !== void 0 || spawnCalls.has(eventId2);
3031
3162
  if (kind !== "started" && !known) continue;
3032
3163
  if (existingId && existingId !== agentId) {
3033
- if (alive.has(existingId)) {
3034
- markAlive(agentId, alive.get(existingId) ?? "");
3035
- alive.delete(existingId);
3036
- }
3037
- if (done.has(existingId)) done.add(agentId);
3038
- }
3039
- agentIdByPath.set(payload.agent_path, agentId);
3040
- if (kind === "interrupted") {
3041
- done.add(agentId);
3042
- alive.delete(agentId);
3043
- } else {
3044
- markAlive(agentId, spawnCalls.get(eventId2) ?? "");
3164
+ const prior = launched.get(existingId);
3165
+ launched.delete(existingId);
3166
+ const current = launched.get(agentId);
3167
+ if (prior && !current) launched.set(agentId, prior);
3168
+ else if (prior && current && !current.description) current.description = prior.description;
3169
+ if (alive.delete(existingId)) markAlive(agentId, "", index, timestamp);
3170
+ const priorEnd = endedAt.get(existingId);
3171
+ if (priorEnd !== void 0) markEnded(agentId, priorEnd);
3045
3172
  }
3173
+ agentIdByPath.set(agentPath, agentId);
3174
+ if (kind === "interrupted" || kind === "completed") markEnded(agentId, index);
3175
+ else markAlive(agentId, spawnCalls.get(eventId2) ?? "", index, timestamp);
3046
3176
  continue;
3047
3177
  }
3048
3178
  if (msg.type !== "response_item") continue;
@@ -3066,7 +3196,7 @@ function collectCodexPendingAgents(rawMessages) {
3066
3196
  const output = parseJsonObject(payload.output);
3067
3197
  const agentId = typeof output?.agent_id === "string" ? output.agent_id : "";
3068
3198
  if (agentId) {
3069
- markAlive(agentId, spawnCalls.get(callId) ?? "");
3199
+ markAlive(agentId, spawnCalls.get(callId) ?? "", index, timestamp);
3070
3200
  const agentPath = typeof output?.task_name === "string" ? output.task_name : "";
3071
3201
  if (agentPath && !agentIdByPath.has(agentPath)) agentIdByPath.set(agentPath, agentId);
3072
3202
  }
@@ -3077,16 +3207,10 @@ function collectCodexPendingAgents(rawMessages) {
3077
3207
  const statusValue = isObject3(status) ? status : {};
3078
3208
  const lifecycle = typeof statusValue.status === "string" ? statusValue.status : "";
3079
3209
  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
- }
3210
+ if (isTerminal) markEnded(agentId, index);
3084
3211
  }
3085
3212
  } else if (interruptCalls.has(callId)) {
3086
- for (const agentId of interruptCalls.get(callId) ?? []) {
3087
- done.add(agentId);
3088
- alive.delete(agentId);
3089
- }
3213
+ for (const agentId of interruptCalls.get(callId) ?? []) markEnded(agentId, index);
3090
3214
  }
3091
3215
  continue;
3092
3216
  }
@@ -3094,12 +3218,14 @@ function collectCodexPendingAgents(rawMessages) {
3094
3218
  const text = codexPayloadText(payload);
3095
3219
  const messageType = text.match(/^Message Type:\s*([^\r\n]+)/)?.[1]?.trim().toUpperCase() ?? "";
3096
3220
  if (!TERMINAL_INTER_AGENT_TYPES.has(messageType)) continue;
3097
- const agentId = agentIdByPath.get(payload.author) ?? payload.author;
3098
- done.add(agentId);
3099
- alive.delete(agentId);
3221
+ markEnded(agentIdByPath.get(payload.author) ?? payload.author, index);
3100
3222
  }
3101
3223
  }
3102
- return [...alive.entries()].filter(([agentId]) => !done.has(agentId)).map(([, description]) => description);
3224
+ return [...launched.entries()].map(([agentId, { description, startedAt, launchedAt }]) => ({
3225
+ agent: { description, startedAt },
3226
+ launchedAt,
3227
+ endedAt: alive.has(agentId) ? void 0 : endedAt.get(agentId) ?? launchedAt
3228
+ }));
3103
3229
  }
3104
3230
  function deriveCodexSessionStatus(rawMessages) {
3105
3231
  for (let i = rawMessages.length - 1; i >= 0; i--) {
@@ -3108,16 +3234,7 @@ function deriveCodexSessionStatus(rawMessages) {
3108
3234
  const payload = msg.payload;
3109
3235
  switch (payload?.type) {
3110
3236
  case "task_complete": {
3111
- const pending = collectCodexPendingAgents(rawMessages);
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" };
3237
+ return awaitingAgentsStatus(collectCodexBackgroundAgents(rawMessages)) ?? { status: "completed" };
3121
3238
  }
3122
3239
  case "task_started":
3123
3240
  return { status: "processing" };
@@ -3915,33 +4032,32 @@ function isCopilotEventType(type) {
3915
4032
  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
4033
  }
3917
4034
  function deriveCopilotSessionStatus(rawMessages) {
3918
- const pendingAgents = /* @__PURE__ */ new Map();
3919
- for (const event of rawMessages) {
4035
+ const agents = /* @__PURE__ */ new Map();
4036
+ for (const [index, event] of rawMessages.entries()) {
3920
4037
  const agentId = typeof event.agentId === "string" ? event.agentId : "";
3921
4038
  if (!agentId && (event.type === "abort" || event.type === "session.shutdown" || event.type === "session.error")) {
3922
- pendingAgents.clear();
4039
+ agents.clear();
3923
4040
  continue;
3924
4041
  }
3925
4042
  if (!agentId || !event.type.startsWith("subagent.")) continue;
3926
4043
  const data = isObject4(event.data) ? event.data : {};
4044
+ const launch = agents.get(agentId);
3927
4045
  if (event.type === "subagent.completed" || event.type === "subagent.failed") {
3928
- pendingAgents.delete(agentId);
4046
+ if (launch) launch.endedAt ??= index;
3929
4047
  continue;
3930
4048
  }
3931
4049
  if (event.type === "subagent.started" || event.type === "subagent.configured") {
3932
4050
  const description = [data.agentDisplayName, data.description, data.agentName].find((value) => typeof value === "string") ?? "";
3933
- pendingAgents.set(agentId, description || pendingAgents.get(agentId) || "");
4051
+ if (!launch || launch.endedAt !== void 0) {
4052
+ const startedAt = typeof event.timestamp === "string" ? event.timestamp : void 0;
4053
+ agents.set(agentId, { agent: { description, startedAt }, launchedAt: index });
4054
+ } else if (description) {
4055
+ launch.agent.description = description;
4056
+ }
3934
4057
  }
3935
4058
  }
3936
- if (pendingAgents.size > 0) {
3937
- const descriptions = [...pendingAgents.values()];
3938
- return {
3939
- status: "awaiting_agents",
3940
- pendingQueue: 0,
3941
- pendingAgents: descriptions.length,
3942
- pendingAgentDescriptions: descriptions.filter((description) => description.length > 0)
3943
- };
3944
- }
4059
+ const awaiting = awaitingAgentsStatus([...agents.values()]);
4060
+ if (awaiting) return awaiting;
3945
4061
  let sawUserActivity = false;
3946
4062
  const completedPermissionRequests = /* @__PURE__ */ new Set();
3947
4063
  for (let i = rawMessages.length - 1; i >= 0; i--) {
@@ -4027,6 +4143,7 @@ function copilotTurnBoundaries(records) {
4027
4143
 
4028
4144
  // src/lib/agents.ts
4029
4145
  var TERMINAL_AGENT_KIND = AGENT_KINDS[AGENT_KINDS.length - 1];
4146
+ var hasNoNoiseLines = () => false;
4030
4147
  var codexFormat = {
4031
4148
  kind: "codex",
4032
4149
  descriptor: descriptorFor("codex"),
@@ -4036,6 +4153,8 @@ var codexFormat = {
4036
4153
  append: appendCodexSession,
4037
4154
  metadataFromLines: extractCodexMetadataFromLines,
4038
4155
  status: deriveCodexSessionStatus,
4156
+ isNoiseLine: hasNoNoiseLines,
4157
+ pageHeaderLine: codexPageHeaderLine,
4039
4158
  brandBranch: brandCodexBranch,
4040
4159
  turnBoundaries: codexTurnBoundaries
4041
4160
  };
@@ -4048,6 +4167,7 @@ var copilotFormat = {
4048
4167
  append: appendCopilotSession,
4049
4168
  metadataFromLines: extractCopilotMetadataFromLines,
4050
4169
  status: deriveCopilotSessionStatus,
4170
+ isNoiseLine: hasNoNoiseLines,
4051
4171
  brandBranch: brandCopilotBranch,
4052
4172
  turnBoundaries: copilotTurnBoundaries
4053
4173
  };
@@ -4061,6 +4181,7 @@ var claudeFormat = {
4061
4181
  append: appendClaudeSession,
4062
4182
  metadataFromLines: extractClaudeMetadataFromLines,
4063
4183
  status: deriveClaudeSessionStatus,
4184
+ isNoiseLine: isClaudeNoiseLine,
4064
4185
  brandBranch: brandClaudeBranch,
4065
4186
  turnBoundaries: claudeTurnBoundaries
4066
4187
  };
@@ -4090,6 +4211,9 @@ function formatForText(jsonlText) {
4090
4211
  function formatForRecords(records) {
4091
4212
  return firstMatch((format) => format.detectsRecords(records));
4092
4213
  }
4214
+ function isAnyAgentNoiseLine(line) {
4215
+ return AGENT_KINDS.some((kind) => FORMATS[kind].isNoiseLine(line));
4216
+ }
4093
4217
 
4094
4218
  // src/lib/parser.ts
4095
4219
  function extractTextFromContent2(content) {
@@ -4105,8 +4229,55 @@ function getUserMessageText(content) {
4105
4229
  return extractTextFromContent2(content);
4106
4230
  }
4107
4231
 
4108
- // src/lib/stores.ts
4232
+ // src/lib/transcriptFile.ts
4109
4233
  var import_node_fs = require("node:fs");
4234
+ var import_promises = require("node:fs/promises");
4235
+ var zlib = __toESM(require("node:zlib"));
4236
+ var COMPRESSED_SUFFIX = ".zst";
4237
+ var canReadCompressedTranscripts = typeof zlib.zstdDecompressSync === "function";
4238
+ function isCompressedTranscript(filePath) {
4239
+ return filePath.endsWith(COMPRESSED_SUFFIX);
4240
+ }
4241
+ function uncompressedTranscriptName(fileName) {
4242
+ return isCompressedTranscript(fileName) ? fileName.slice(0, -COMPRESSED_SUFFIX.length) : fileName;
4243
+ }
4244
+ function isListableTranscript(name, siblings) {
4245
+ const plainName = uncompressedTranscriptName(name);
4246
+ if (!plainName.endsWith(".jsonl")) return false;
4247
+ if (plainName === name) return true;
4248
+ return canReadCompressedTranscripts && !siblings.has(plainName);
4249
+ }
4250
+ function inflate(data) {
4251
+ if (!canReadCompressedTranscripts) {
4252
+ throw new Error("Reading a .jsonl.zst transcript needs Node.js 22.15 or newer, or Bun");
4253
+ }
4254
+ return zlib.zstdDecompressSync(data);
4255
+ }
4256
+ function readTranscriptTextSync(filePath) {
4257
+ const data = (0, import_node_fs.readFileSync)(filePath);
4258
+ return (isCompressedTranscript(filePath) ? inflate(data) : data).toString("utf-8");
4259
+ }
4260
+ async function readTranscriptText(filePath) {
4261
+ const data = await (0, import_promises.readFile)(filePath);
4262
+ return (isCompressedTranscript(filePath) ? inflate(data) : data).toString("utf-8");
4263
+ }
4264
+ async function openTranscript(filePath) {
4265
+ if (!isCompressedTranscript(filePath)) return (0, import_promises.open)(filePath, "r");
4266
+ const [fileStat, compressed] = await Promise.all([(0, import_promises.stat)(filePath), (0, import_promises.readFile)(filePath)]);
4267
+ const data = inflate(compressed);
4268
+ return {
4269
+ async read(buffer, offset, length, position) {
4270
+ const start = Math.min(Math.max(position, 0), data.length);
4271
+ return { bytesRead: data.copy(buffer, offset, start, Math.min(start + length, data.length)) };
4272
+ },
4273
+ stat: async () => ({ size: data.length, mtimeMs: fileStat.mtimeMs }),
4274
+ close: async () => {
4275
+ }
4276
+ };
4277
+ }
4278
+
4279
+ // src/lib/stores.ts
4280
+ var import_node_fs2 = require("node:fs");
4110
4281
  var import_node_path2 = require("node:path");
4111
4282
 
4112
4283
  // src/lib/dirs.ts
@@ -4133,14 +4304,14 @@ var MAX_WALK_DEPTH = 4;
4133
4304
  var SUBAGENTS_DIR = "subagents";
4134
4305
  function mtimeOf(filePath) {
4135
4306
  try {
4136
- return (0, import_node_fs.statSync)(filePath).mtimeMs;
4307
+ return (0, import_node_fs2.statSync)(filePath).mtimeMs;
4137
4308
  } catch {
4138
4309
  return null;
4139
4310
  }
4140
4311
  }
4141
4312
  function readDirSafe(dir) {
4142
4313
  try {
4143
- return (0, import_node_fs.readdirSync)(dir, { withFileTypes: true });
4314
+ return (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true });
4144
4315
  } catch {
4145
4316
  return [];
4146
4317
  }
@@ -4151,8 +4322,8 @@ function isWithin(root, target) {
4151
4322
  }
4152
4323
  function canonicalWithinRoot(root, filePath) {
4153
4324
  try {
4154
- const realRoot = (0, import_node_fs.realpathSync)(root);
4155
- const real = (0, import_node_fs.realpathSync)(filePath);
4325
+ const realRoot = (0, import_node_fs2.realpathSync)(root);
4326
+ const real = (0, import_node_fs2.realpathSync)(filePath);
4156
4327
  return isWithin(realRoot, real) ? real : null;
4157
4328
  } catch {
4158
4329
  return null;
@@ -4218,13 +4389,15 @@ function walkClaude(root, cutoffMs) {
4218
4389
  function walkCodex(root, cutoffMs, dir = root, depth = 0) {
4219
4390
  if (depth > MAX_WALK_DEPTH) return [];
4220
4391
  const found = [];
4221
- for (const entry of readDirSafe(dir)) {
4392
+ const entries = readDirSafe(dir);
4393
+ const names = new Set(entries.map((entry) => entry.name));
4394
+ for (const entry of entries) {
4222
4395
  const filePath = (0, import_node_path2.join)(dir, entry.name);
4223
4396
  if (entry.isDirectory()) {
4224
4397
  found.push(...walkCodex(root, cutoffMs, filePath, depth + 1));
4225
4398
  continue;
4226
4399
  }
4227
- if (!entry.name.endsWith(".jsonl")) continue;
4400
+ if (!isListableTranscript(entry.name, names)) continue;
4228
4401
  const mtimeMs = mtimeOf(filePath);
4229
4402
  if (mtimeMs === null || mtimeMs < cutoffMs) continue;
4230
4403
  found.push({
@@ -4285,14 +4458,18 @@ var WALKERS = {
4285
4458
  find(root, sessionId) {
4286
4459
  const walk = (dir, depth) => {
4287
4460
  if (depth > MAX_WALK_DEPTH) return null;
4288
- for (const entry of readDirSafe(dir)) {
4461
+ const entries = readDirSafe(dir);
4462
+ const names = new Set(entries.map((entry) => entry.name));
4463
+ for (const entry of entries) {
4289
4464
  const filePath = (0, import_node_path2.join)(dir, entry.name);
4290
4465
  if (entry.isDirectory()) {
4291
4466
  const match = walk(filePath, depth + 1);
4292
4467
  if (match) return match;
4293
4468
  continue;
4294
4469
  }
4295
- if (entry.name.endsWith(`${sessionId}.jsonl`)) return filePath;
4470
+ if (uncompressedTranscriptName(entry.name).endsWith(`${sessionId}.jsonl`) && isListableTranscript(entry.name, names)) {
4471
+ return filePath;
4472
+ }
4296
4473
  }
4297
4474
  return null;
4298
4475
  };
@@ -4335,7 +4512,7 @@ function makeStore(kind, home, configuredId) {
4335
4512
  ownsPath: (filePath) => {
4336
4513
  if (isWithin((0, import_node_path2.resolve)(root()), (0, import_node_path2.resolve)(filePath))) return true;
4337
4514
  try {
4338
- return isWithin((0, import_node_fs.realpathSync)(root()), (0, import_node_fs.realpathSync)(filePath));
4515
+ return isWithin((0, import_node_fs2.realpathSync)(root()), (0, import_node_fs2.realpathSync)(filePath));
4339
4516
  } catch {
4340
4517
  return false;
4341
4518
  }
@@ -4369,7 +4546,7 @@ function allStores() {
4369
4546
  if (!entry.isDirectory()) continue;
4370
4547
  const home = (0, import_node_path2.join)(root, "provider-instances", entry.name);
4371
4548
  try {
4372
- const config = JSON.parse((0, import_node_fs.readFileSync)((0, import_node_path2.join)(home, "config.json"), "utf8"));
4549
+ const config = JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.join)(home, "config.json"), "utf8"));
4373
4550
  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
4551
  } catch {
4375
4552
  }
@@ -4444,7 +4621,7 @@ var SearchIndex = class {
4444
4621
  const { count: totalRows } = this.db.prepare("SELECT COUNT(*) as count FROM search_content").get();
4445
4622
  let dbSizeBytes = 0;
4446
4623
  try {
4447
- dbSizeBytes = (0, import_node_fs2.statSync)(this.dbPath).size;
4624
+ dbSizeBytes = (0, import_node_fs3.statSync)(this.dbPath).size;
4448
4625
  } catch {
4449
4626
  }
4450
4627
  return {
@@ -4517,9 +4694,9 @@ var SearchIndex = class {
4517
4694
  indexFile(filePath, sessionId, mtimeMs, opts) {
4518
4695
  const resolvedSessionId = sessionId ?? identifyTranscript(filePath).sessionId;
4519
4696
  if (mtimeMs == null) {
4520
- mtimeMs = (0, import_node_fs2.statSync)(filePath).mtimeMs;
4697
+ mtimeMs = (0, import_node_fs3.statSync)(filePath).mtimeMs;
4521
4698
  }
4522
- const content = (0, import_node_fs2.readFileSync)(filePath, "utf-8");
4699
+ const content = readTranscriptTextSync(filePath);
4523
4700
  const session = parseSession(content, { skipStats: true });
4524
4701
  const isSubagent = opts?.isSubagent ? 1 : 0;
4525
4702
  const parentSessionId = opts?.parentSessionId ?? null;
@@ -4548,7 +4725,7 @@ var SearchIndex = class {
4548
4725
  const files = this.db.prepare("SELECT file_path FROM indexed_files").all();
4549
4726
  const missing = files.filter(({ file_path }) => {
4550
4727
  try {
4551
- (0, import_node_fs2.statSync)(file_path);
4728
+ (0, import_node_fs3.statSync)(file_path);
4552
4729
  return false;
4553
4730
  } catch (error) {
4554
4731
  const code = error.code;
@@ -4665,7 +4842,7 @@ var SearchIndex = class {
4665
4842
  this.db.close();
4666
4843
  for (const suffix of ["", "-wal", "-shm"]) {
4667
4844
  try {
4668
- (0, import_node_fs2.unlinkSync)(this.dbPath + suffix);
4845
+ (0, import_node_fs3.unlinkSync)(this.dbPath + suffix);
4669
4846
  } catch {
4670
4847
  }
4671
4848
  }
@@ -4689,7 +4866,7 @@ var SearchIndex = class {
4689
4866
  const txn = this.db.transaction(() => {
4690
4867
  for (const file of files) {
4691
4868
  try {
4692
- const content = (0, import_node_fs2.readFileSync)(file.path, "utf-8");
4869
+ const content = readTranscriptTextSync(file.path);
4693
4870
  const session = parseSession(content, { skipStats: true });
4694
4871
  this.insertSessionContent(insert, file.sessionId, file.path, session);
4695
4872
  insertFile.run(file.path, file.mtimeMs, file.sessionId, file.isSubagent ? 1 : 0, file.parentSessionId);
@@ -4785,9 +4962,9 @@ async function searchSessions(query, opts, searchIndex) {
4785
4962
  let ownedIndex = false;
4786
4963
  if (!index && searchIndex === void 0) {
4787
4964
  try {
4788
- const dbExists = (0, import_node_fs3.existsSync)(DEFAULT_DB_PATH);
4965
+ const dbExists = (0, import_node_fs4.existsSync)(DEFAULT_DB_PATH);
4789
4966
  if (!dbExists) {
4790
- (0, import_node_fs3.mkdirSync)((0, import_node_path3.dirname)(DEFAULT_DB_PATH), { recursive: true });
4967
+ (0, import_node_fs4.mkdirSync)((0, import_node_path3.dirname)(DEFAULT_DB_PATH), { recursive: true });
4791
4968
  }
4792
4969
  index = new SearchIndex(DEFAULT_DB_PATH);
4793
4970
  ownedIndex = true;
@@ -4861,7 +5038,7 @@ async function cwdFromFilePath(filePath) {
4861
5038
  const cached = cwdCache.get(filePath);
4862
5039
  if (cached !== void 0) return cached;
4863
5040
  try {
4864
- const fh = await (0, import_promises.open)(filePath, "r");
5041
+ const fh = await openTranscript(filePath);
4865
5042
  try {
4866
5043
  const buf = Buffer.alloc(CWD_READ_BYTES);
4867
5044
  const { bytesRead } = await fh.read(buf, 0, CWD_READ_BYTES, 0);
@@ -4919,7 +5096,7 @@ function searchField(text, location, query, caseSensitive, extras) {
4919
5096
  async function discoverSingleSession(sessionId) {
4920
5097
  const jsonlPath = await findSessionFile(sessionId);
4921
5098
  if (!jsonlPath) return [];
4922
- const s = await (0, import_promises.stat)(jsonlPath);
5099
+ const s = await (0, import_promises2.stat)(jsonlPath);
4923
5100
  return [{ path: jsonlPath, mtimeMs: s.mtimeMs, sessionId }];
4924
5101
  }
4925
5102
  function discoverAllSessions(maxAgeMs) {
@@ -4927,7 +5104,7 @@ function discoverAllSessions(maxAgeMs) {
4927
5104
  }
4928
5105
  async function rawTextMatch(filePath, query, caseSensitive) {
4929
5106
  try {
4930
- const content = await (0, import_promises.readFile)(filePath, "utf-8");
5107
+ const content = await readTranscriptText(filePath);
4931
5108
  const haystack = caseSensitive ? content : content.toLowerCase();
4932
5109
  const needle = caseSensitive ? query : query.toLowerCase();
4933
5110
  if (haystack.includes(needle)) return content;
@@ -5002,7 +5179,7 @@ async function walkSubagentFiles(parentJsonlPath, query, caseSensitive, currentD
5002
5179
  const subDir = parentJsonlPath.replace(/\.jsonl$/, "") + "/subagents";
5003
5180
  let files;
5004
5181
  try {
5005
- files = await (0, import_promises.readdir)(subDir);
5182
+ files = await (0, import_promises2.readdir)(subDir);
5006
5183
  } catch {
5007
5184
  return [];
5008
5185
  }
@@ -5080,14 +5257,14 @@ async function rawScanSearch(query, sessionId, maxAgeMs, limit, caseSensitive, e
5080
5257
  }
5081
5258
 
5082
5259
  // src/commands/context.ts
5083
- var import_promises3 = require("node:fs/promises");
5260
+ var import_promises4 = require("node:fs/promises");
5084
5261
  var import_node_path5 = require("node:path");
5085
5262
 
5086
5263
  // src/lib/helpers.ts
5087
- var import_promises2 = require("node:fs/promises");
5264
+ var import_promises3 = require("node:fs/promises");
5088
5265
  var import_node_path4 = require("node:path");
5089
5266
  async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
5090
- const entries = await (0, import_promises2.readdir)(dirs.PROJECTS_DIR, { withFileTypes: true });
5267
+ const entries = await (0, import_promises3.readdir)(dirs.PROJECTS_DIR, { withFileTypes: true });
5091
5268
  for (const entry of entries) {
5092
5269
  if (!entry.isDirectory() || entry.name === "memory") continue;
5093
5270
  const filePath = (0, import_node_path4.join)(
@@ -5098,7 +5275,7 @@ async function matchSubagentToMember(leadSessionId, subagentFileName, members) {
5098
5275
  subagentFileName
5099
5276
  );
5100
5277
  try {
5101
- const fh = await (0, import_promises2.open)(filePath, "r");
5278
+ const fh = await (0, import_promises3.open)(filePath, "r");
5102
5279
  try {
5103
5280
  const buf = Buffer.alloc(16384);
5104
5281
  const { bytesRead } = await fh.read(buf, 0, 16384, 0);
@@ -5293,7 +5470,13 @@ function mapContentBlock(block) {
5293
5470
  case "task_notification":
5294
5471
  return { kind: "task_notification", content: block.content, timestamp: block.timestamp ?? null };
5295
5472
  case "local_command":
5296
- return { kind: "local_command", content: block.content, timestamp: block.timestamp ?? null };
5473
+ return {
5474
+ kind: "local_command",
5475
+ content: block.content,
5476
+ timestamp: block.timestamp ?? null,
5477
+ ...block.contextUsage ? { contextUsage: block.contextUsage } : {},
5478
+ ...block.usageReport ? { usageReport: block.usageReport } : {}
5479
+ };
5297
5480
  default: {
5298
5481
  const exhaustive = block;
5299
5482
  return exhaustive;
@@ -5303,7 +5486,7 @@ function mapContentBlock(block) {
5303
5486
  async function findSubagentFile(parentJsonlPath, agentId) {
5304
5487
  const subagentsDir = parentJsonlPath.replace(/\.jsonl$/, "") + "/subagents";
5305
5488
  try {
5306
- const files = await (0, import_promises3.readdir)(subagentsDir);
5489
+ const files = await (0, import_promises4.readdir)(subagentsDir);
5307
5490
  for (const f of files) {
5308
5491
  if (!f.startsWith("agent-") || !f.endsWith(".jsonl")) continue;
5309
5492
  const fileAgentId = f.replace("agent-", "").replace(".jsonl", "");
@@ -5317,12 +5500,12 @@ async function findSubagentFile(parentJsonlPath, agentId) {
5317
5500
  }
5318
5501
  async function findTeamContext(sessionId, subagentFileName) {
5319
5502
  try {
5320
- const teamEntries = await (0, import_promises3.readdir)(dirs.TEAMS_DIR, { withFileTypes: true });
5503
+ const teamEntries = await (0, import_promises4.readdir)(dirs.TEAMS_DIR, { withFileTypes: true });
5321
5504
  for (const entry of teamEntries) {
5322
5505
  if (!entry.isDirectory()) continue;
5323
5506
  const configPath = (0, import_node_path5.join)(dirs.TEAMS_DIR, entry.name, "config.json");
5324
5507
  try {
5325
- const raw = await (0, import_promises3.readFile)(configPath, "utf-8");
5508
+ const raw = await (0, import_promises4.readFile)(configPath, "utf-8");
5326
5509
  const config = JSON.parse(raw);
5327
5510
  if (config.leadSessionId !== sessionId) continue;
5328
5511
  const members = config.members ?? [];
@@ -5331,10 +5514,10 @@ async function findTeamContext(sessionId, subagentFileName) {
5331
5514
  let currentTask = null;
5332
5515
  try {
5333
5516
  const taskDir = (0, import_node_path5.join)(dirs.TASKS_DIR, entry.name);
5334
- const taskFiles = await (0, import_promises3.readdir)(taskDir);
5517
+ const taskFiles = await (0, import_promises4.readdir)(taskDir);
5335
5518
  for (const tf of taskFiles) {
5336
5519
  if (!tf.endsWith(".json")) continue;
5337
- const taskRaw = await (0, import_promises3.readFile)((0, import_node_path5.join)(taskDir, tf), "utf-8");
5520
+ const taskRaw = await (0, import_promises4.readFile)((0, import_node_path5.join)(taskDir, tf), "utf-8");
5338
5521
  const task = JSON.parse(taskRaw);
5339
5522
  if (task.owner === memberName && task.status === "in_progress") {
5340
5523
  currentTask = { id: task.id, subject: task.subject, status: task.status };
@@ -5382,14 +5565,14 @@ function findAgentMetadata(session, agentId) {
5382
5565
  async function getSessionOverview(sessionId) {
5383
5566
  const jsonlPath = await findSessionFile(sessionId);
5384
5567
  if (!jsonlPath) return { error: "Session not found" };
5385
- const content = await (0, import_promises3.readFile)(jsonlPath, "utf-8");
5568
+ const content = await readTranscriptText(jsonlPath);
5386
5569
  const session = parseTranscript(content, jsonlPath);
5387
5570
  return mapSessionToOverview(session);
5388
5571
  }
5389
5572
  async function getTurnDetail(sessionId, turnIndex) {
5390
5573
  const jsonlPath = await findSessionFile(sessionId);
5391
5574
  if (!jsonlPath) return { error: "Session not found" };
5392
- const content = await (0, import_promises3.readFile)(jsonlPath, "utf-8");
5575
+ const content = await readTranscriptText(jsonlPath);
5393
5576
  const session = parseTranscript(content, jsonlPath);
5394
5577
  if (turnIndex < 0 || turnIndex >= session.turns.length) return { error: "Turn not found" };
5395
5578
  return mapTurnToDetail(session, turnIndex);
@@ -5397,11 +5580,11 @@ async function getTurnDetail(sessionId, turnIndex) {
5397
5580
  async function getAgentOverview(sessionId, agentId) {
5398
5581
  const jsonlPath = await findSessionFile(sessionId);
5399
5582
  if (!jsonlPath) return { error: "Session not found" };
5400
- const content = await (0, import_promises3.readFile)(jsonlPath, "utf-8");
5583
+ const content = await readTranscriptText(jsonlPath);
5401
5584
  const session = parseTranscript(content, jsonlPath);
5402
5585
  const subagentFile = await findSubagentFile(jsonlPath, agentId);
5403
5586
  if (!subagentFile) return { error: "Agent not found" };
5404
- const subagentContent = await (0, import_promises3.readFile)(subagentFile.filePath, "utf-8");
5587
+ const subagentContent = await readTranscriptText(subagentFile.filePath);
5405
5588
  const subagentSession = parseTranscript(subagentContent, subagentFile.filePath);
5406
5589
  const metadata = findAgentMetadata(session, agentId);
5407
5590
  const parentToolCallId = findParentToolCallId(session, agentId);
@@ -5422,7 +5605,7 @@ async function getAgentTurnDetail(sessionId, agentId, turnIndex) {
5422
5605
  if (!jsonlPath) return { error: "Session not found" };
5423
5606
  const subagentFile = await findSubagentFile(jsonlPath, agentId);
5424
5607
  if (!subagentFile) return { error: "Agent not found" };
5425
- const subagentContent = await (0, import_promises3.readFile)(subagentFile.filePath, "utf-8");
5608
+ const subagentContent = await readTranscriptText(subagentFile.filePath);
5426
5609
  const subagentSession = parseTranscript(subagentContent, subagentFile.filePath);
5427
5610
  if (turnIndex < 0 || turnIndex >= subagentSession.turns.length) return { error: "Turn not found" };
5428
5611
  return mapTurnToDetail(subagentSession, turnIndex);
@@ -5432,7 +5615,7 @@ async function getAgentTurnDetail(sessionId, agentId, turnIndex) {
5432
5615
  var import_node_path6 = require("node:path");
5433
5616
 
5434
5617
  // src/lib/metadata.ts
5435
- var import_promises4 = require("node:fs/promises");
5618
+ var import_promises5 = require("node:fs/promises");
5436
5619
 
5437
5620
  // src/lib/sessionStatus.ts
5438
5621
  function deriveSessionStatus(rawMessages) {
@@ -5457,6 +5640,7 @@ function scanClaudeMessages(lines) {
5457
5640
  turnCount: 0
5458
5641
  };
5459
5642
  for (const line of lines) {
5643
+ if (isAnyAgentNoiseLine(line)) continue;
5460
5644
  let record2;
5461
5645
  try {
5462
5646
  record2 = JSON.parse(line);
@@ -5485,11 +5669,11 @@ function scanClaudeMessages(lines) {
5485
5669
  return meta;
5486
5670
  }
5487
5671
  async function readLines(filePath, size) {
5488
- if (size <= FULL_READ_LIMIT) {
5489
- const content = await (0, import_promises4.readFile)(filePath, "utf-8");
5672
+ if (size <= FULL_READ_LIMIT || isCompressedTranscript(filePath)) {
5673
+ const content = await readTranscriptText(filePath);
5490
5674
  return { lines: content.split("\n").filter(Boolean), isPartialRead: false };
5491
5675
  }
5492
- const handle = await (0, import_promises4.open)(filePath, "r");
5676
+ const handle = await (0, import_promises5.open)(filePath, "r");
5493
5677
  try {
5494
5678
  const buffer = Buffer.alloc(HEAD_READ_BYTES);
5495
5679
  const { bytesRead } = await handle.read(buffer, 0, HEAD_READ_BYTES, 0);
@@ -5504,11 +5688,11 @@ async function readLines(filePath, size) {
5504
5688
  }
5505
5689
  }
5506
5690
  async function getSessionMeta(filePath) {
5507
- const fileStat = await (0, import_promises4.stat)(filePath);
5691
+ const fileStat = await (0, import_promises5.stat)(filePath);
5508
5692
  let { lines, isPartialRead } = await readLines(filePath, fileStat.size);
5509
5693
  const format = formatForText(lines.join("\n"));
5510
5694
  if (isPartialRead && !format.descriptor.metadataFromHead) {
5511
- lines = (await (0, import_promises4.readFile)(filePath, "utf-8")).split("\n").filter(Boolean);
5695
+ lines = (await (0, import_promises5.readFile)(filePath, "utf-8")).split("\n").filter(Boolean);
5512
5696
  isPartialRead = false;
5513
5697
  }
5514
5698
  const header = readHeader(format, lines);
@@ -5537,10 +5721,10 @@ async function getSessionStatus(filePath) {
5537
5721
  const CHUNK = 4096;
5538
5722
  const MAX_CHUNKS = 64;
5539
5723
  try {
5540
- const fileStat = await (0, import_promises4.stat)(filePath);
5541
- if (fileStat.size === 0) return { status: "idle" };
5542
- const fh = await (0, import_promises4.open)(filePath, "r");
5724
+ const fh = await openTranscript(filePath);
5543
5725
  try {
5726
+ const fileStat = await fh.stat();
5727
+ if (fileStat.size === 0) return { status: "idle" };
5544
5728
  const meaningful = [];
5545
5729
  let cursor = fileStat.size;
5546
5730
  let leftover = "";
@@ -5556,7 +5740,7 @@ async function getSessionStatus(filePath) {
5556
5740
  const startIdx = cursor > 0 ? 1 : 0;
5557
5741
  for (let i = lines.length - 1; i >= startIdx; i--) {
5558
5742
  const line = lines[i];
5559
- if (!line) continue;
5743
+ if (!line || isAnyAgentNoiseLine(line)) continue;
5560
5744
  let obj;
5561
5745
  try {
5562
5746
  obj = JSON.parse(line);
@@ -5687,11 +5871,11 @@ async function currentSession(cwd) {
5687
5871
  }
5688
5872
 
5689
5873
  // src/commands/index-cmd.ts
5690
- var import_node_fs4 = require("node:fs");
5874
+ var import_node_fs5 = require("node:fs");
5691
5875
  var import_node_path7 = require("node:path");
5692
5876
  async function indexStats(dbPath) {
5693
5877
  const path = dbPath ?? DEFAULT_DB_PATH;
5694
- if (!(0, import_node_fs4.existsSync)(path)) {
5878
+ if (!(0, import_node_fs5.existsSync)(path)) {
5695
5879
  return { error: `Database not found at ${path}. Run 'cogpit-memory index rebuild' to create it.` };
5696
5880
  }
5697
5881
  const index = new SearchIndex(path);
@@ -5701,7 +5885,7 @@ async function indexStats(dbPath) {
5701
5885
  }
5702
5886
  async function indexRebuild(dbPath) {
5703
5887
  const path = dbPath ?? DEFAULT_DB_PATH;
5704
- (0, import_node_fs4.mkdirSync)((0, import_node_path7.dirname)(path), { recursive: true });
5888
+ (0, import_node_fs5.mkdirSync)((0, import_node_path7.dirname)(path), { recursive: true });
5705
5889
  const index = new SearchIndex(path);
5706
5890
  index.buildFull();
5707
5891
  const stats = index.getStats();
@@ -5710,7 +5894,7 @@ async function indexRebuild(dbPath) {
5710
5894
  }
5711
5895
 
5712
5896
  // src/commands/install-skill.ts
5713
- var import_node_fs5 = require("node:fs");
5897
+ var import_node_fs6 = require("node:fs");
5714
5898
  var import_node_path8 = require("node:path");
5715
5899
  function findSkillContent() {
5716
5900
  const candidates = [];
@@ -5720,8 +5904,8 @@ function findSkillContent() {
5720
5904
  }
5721
5905
  for (const candidate of candidates) {
5722
5906
  try {
5723
- if ((0, import_node_fs5.existsSync)(candidate)) {
5724
- return (0, import_node_fs5.readFileSync)(candidate, "utf-8");
5907
+ if ((0, import_node_fs6.existsSync)(candidate)) {
5908
+ return (0, import_node_fs6.readFileSync)(candidate, "utf-8");
5725
5909
  }
5726
5910
  } catch {
5727
5911
  }
@@ -5731,10 +5915,10 @@ function findSkillContent() {
5731
5915
  function installSkill(cwd, global) {
5732
5916
  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
5917
  const skillDir = (0, import_node_path8.join)(root, "skills", "cogpit-memory");
5734
- (0, import_node_fs5.mkdirSync)(skillDir, { recursive: true });
5918
+ (0, import_node_fs6.mkdirSync)(skillDir, { recursive: true });
5735
5919
  const content = findSkillContent();
5736
5920
  const dest = (0, import_node_path8.join)(skillDir, "SKILL.md");
5737
- (0, import_node_fs5.writeFileSync)(dest, content);
5921
+ (0, import_node_fs6.writeFileSync)(dest, content);
5738
5922
  return { installed: true, path: skillDir };
5739
5923
  }
5740
5924